diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/arch/i386/boot/compressed/head.S linux.2.5.47-ac6/arch/i386/boot/compressed/head.S --- linux.2.5.47/arch/i386/boot/compressed/head.S 2002-10-31 14:57:24.000000000 +0000 +++ linux.2.5.47-ac6/arch/i386/boot/compressed/head.S 2002-10-31 15:05:49.000000000 +0000 @@ -31,7 +31,7 @@ startup_32: cld cli - movl $(__KERNEL_DS),%eax + movl $(__BOOT_DS),%eax movl %eax,%ds movl %eax,%es movl %eax,%fs @@ -74,7 +74,7 @@ popl %esi # discard address popl %esi # real mode pointer xorl %ebx,%ebx - ljmp $(__KERNEL_CS), $0x100000 + ljmp $(__BOOT_CS), $0x100000 /* * We come here, if we were loaded high. @@ -101,7 +101,7 @@ popl %eax # hcount movl $0x100000,%edi cli # make sure we don't get interrupted - ljmp $(__KERNEL_CS), $0x1000 # and jump to the move routine + ljmp $(__BOOT_CS), $0x1000 # and jump to the move routine /* * Routine (template) for moving the decompressed kernel in place, @@ -124,5 +124,5 @@ movsl movl %ebx,%esi # Restore setup pointer xorl %ebx,%ebx - ljmp $(__KERNEL_CS), $0x100000 + ljmp $(__BOOT_CS), $0x100000 move_routine_end: diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/arch/i386/boot/compressed/misc.c linux.2.5.47-ac6/arch/i386/boot/compressed/misc.c --- linux.2.5.47/arch/i386/boot/compressed/misc.c 2002-10-31 14:57:24.000000000 +0000 +++ linux.2.5.47-ac6/arch/i386/boot/compressed/misc.c 2002-10-31 15:05:49.000000000 +0000 @@ -299,7 +299,7 @@ struct { long * a; short b; - } stack_start = { & user_stack [STACK_SIZE] , __KERNEL_DS }; + } stack_start = { & user_stack [STACK_SIZE] , __BOOT_DS }; static void setup_normal_output_buffer(void) { @@ -377,3 +377,7 @@ if (high_loaded) close_output_buffer_if_we_run_high(mv); return high_loaded; } + +/* We don't actually check for stack overflows this early. */ +__asm__(".globl mcount ; mcount: ret\n"); + diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/arch/i386/boot/setup.S linux.2.5.47-ac6/arch/i386/boot/setup.S --- linux.2.5.47/arch/i386/boot/setup.S 2002-10-31 15:05:00.000000000 +0000 +++ linux.2.5.47-ac6/arch/i386/boot/setup.S 2002-10-31 15:17:17.000000000 +0000 @@ -476,6 +476,24 @@ movsb popw %ds no_mca: +#ifdef CONFIG_VOYAGER + movb $0xff, 0x40 # flag on config found + movb $0xc0, %al + mov $0xff, %ah + int $0x15 # put voyager config info at es:di + jc no_voyager + movw $0x40, %si # place voyager info in apm table + cld + movw $7, %cx +voyager_rep: + movb %es:(%di), %al + movb %al,(%si) + incw %di + incw %si + decw %cx + jnz voyager_rep +no_voyager: +#endif # Check for PS/2 pointing device movw %cs, %ax # aka SETUPSEG subw $DELTA_INITSEG, %ax # aka INITSEG @@ -740,6 +758,7 @@ A20_ENABLE_LOOPS = 255 # Total loops to try +#ifndef CONFIG_VOYAGER a20_try_loop: # First, see if we are on a system with no A20 gate. @@ -758,11 +777,14 @@ jnz a20_done # Try enabling A20 through the keyboard controller +#endif /* CONFIG_VOYAGER */ a20_kbc: call empty_8042 +#ifndef CONFIG_VOYAGER call a20_test # Just in case the BIOS worked jnz a20_done # but had a delayed reaction. +#endif movb $0xD1, %al # command write outb %al, $0x64 @@ -772,6 +794,7 @@ outb %al, $0x60 call empty_8042 +#ifndef CONFIG_VOYAGER # Wait until a20 really *is* enabled; it can take a fair amount of # time on certain systems; Toshiba Tecras are known to have this # problem. @@ -819,6 +842,7 @@ # If we get here, all is good a20_done: +#endif /* CONFIG_VOYAGER */ # set up gdt and idt lidt idt_48 # load idt with 0,0 xorl %eax, %eax # Compute gdt_base @@ -870,7 +894,7 @@ subw $DELTA_INITSEG, %si shll $4, %esi # Convert to 32-bit pointer # NOTE: For high loaded big kernels we need a -# jmpi 0x100000,__KERNEL_CS +# jmpi 0x100000,__BOOT_CS # # but we yet haven't reloaded the CS register, so the default size # of the target offset still is 16 bit. @@ -881,7 +905,7 @@ .byte 0x66, 0xea # prefix + jmpi-opcode code32: .long 0x1000 # will be set to 0x100000 # for big kernels - .word __KERNEL_CS + .word __BOOT_CS # Here's a bunch of information about your current kernel.. kernel_version: .ascii UTS_RELEASE @@ -985,6 +1009,7 @@ .string "INT15 refuses to access high mem, giving up." +#ifndef CONFIG_VOYAGER # This routine tests whether or not A20 is enabled. If so, it # exits with zf = 0. # @@ -1015,6 +1040,8 @@ popw %cx ret +#endif /* CONFIG_VOYAGER */ + # This routine checks that the keyboard command queue is empty # (after emptying the output buffers) # @@ -1075,13 +1102,19 @@ # Descriptor tables # -# NOTE: if you think the GDT is large, you can make it smaller by just -# defining the KERNEL_CS and KERNEL_DS entries and shifting the gdt -# address down by GDT_ENTRY_KERNEL_CS*8. This puts bogus entries into -# the GDT, but those wont be used so it's not a problem. +# NOTE: The intel manual says gdt should be sixteen bytes aligned for +# efficiency reasons. However, there are machines which are known not +# to boot with misaligned GDTs, so alter this at your peril! If you alter +# GDT_ENTRY_BOOT_CS (in asm/segment.h) remember to leave at least two +# empty GDT entries (one for NULL and one reserved). +# +# NOTE: On some CPUs, the GDT must be 8 byte aligned. This is +# true for the Voyager Quad CPU card which will not boot without +# This directive. 16 byte aligment is recommended by intel. # + .align 16 gdt: - .fill GDT_ENTRY_KERNEL_CS,8,0 + .fill GDT_ENTRY_BOOT_CS,8,0 .word 0xFFFF # 4Gb - (0x100000*0x1000 = 4Gb) .word 0 # base address = 0 @@ -1094,12 +1127,17 @@ .word 0x9200 # data read/write .word 0x00CF # granularity = 4096, 386 # (+5th nibble of limit) +gdt_end: + .align 4 + + .word 0 # alignment byte idt_48: .word 0 # idt limit = 0 .word 0, 0 # idt base = 0L -gdt_48: - .word GDT_ENTRY_KERNEL_CS*8 + 16 - 1 # gdt limit + .word 0 # alignment byte +gdt_48: + .word gdt_end - gdt - 1 # gdt limit .word 0, 0 # gdt base (filled in later) # Include video setup & detection code diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/arch/i386/boot98/bootsect.S linux.2.5.47-ac6/arch/i386/boot98/bootsect.S --- linux.2.5.47/arch/i386/boot98/bootsect.S 1970-01-01 01:00:00.000000000 +0100 +++ linux.2.5.47-ac6/arch/i386/boot98/bootsect.S 2002-10-31 15:05:52.000000000 +0000 @@ -0,0 +1,397 @@ +/* + * bootsect.S - boot sector for NEC PC-9800 series + * + * Linux/98 project at Kyoto University Microcomputer Club (KMC) + * FUJITA Norimasa, TAKAI Kousuke 1997-1998 + * rewritten by TAKAI Kousuke (as86 -> gas), Nov 1999 + * + * Based on: + * bootsect.S Copyright (C) 1991, 1992 Linus Torvalds + * modified by Drew Eckhardt + * modified by Bruce Evans (bde) + * + * bootsect.S is loaded at 0x1FC00 or 0x1FE00 by the bios-startup routines, + * and moves itself out of the way to address 0x90000, and jumps there. + * + * It then loads 'setup' directly after itself (0x90200), and the system + * at 0x10000, using BIOS interrupts. + * + * NOTE! currently system is at most (8*65536-4096) bytes long. This should + * be no problem, even in the future. I want to keep it simple. This 508 kB + * kernel size should be enough, especially as this doesn't contain the + * buffer cache as in minix (and especially now that the kernel is + * compressed :-) + * + * The loader has been made as simple as possible, and continuous + * read errors will result in a unbreakable loop. Reboot by hand. It + * loads pretty fast by getting whole tracks at a time whenever possible. + */ + +#include /* for CONFIG_ROOT_RDONLY */ +#include + +SETUPSECTS = 4 /* default nr of setup-sectors */ +BOOTSEG = 0x1FC0 /* original address of boot-sector */ +INITSEG = DEF_INITSEG /* we move boot here - out of the way */ +SETUPSEG = DEF_SETUPSEG /* setup starts here */ +SYSSEG = DEF_SYSSEG /* system loaded at 0x10000 (65536) */ +SYSSIZE = DEF_SYSSIZE /* system size: # of 16-byte clicks */ + /* to be loaded */ +ROOT_DEV = 0 /* ROOT_DEV is now written by "build" */ +SWAP_DEV = 0 /* SWAP_DEV is now written by "build" */ + +#ifndef SVGA_MODE +#define SVGA_MODE ASK_VGA +#endif + +#ifndef RAMDISK +#define RAMDISK 0 +#endif + +#ifndef ROOT_RDONLY +#define ROOT_RDONLY 1 +#endif + +/* normal/hireso text VRAM segments */ +#define NORMAL_TEXT 0xa000 +#define HIRESO_TEXT 0xe000 + +/* bios work area addresses */ +#define EXPMMSZ 0x0401 +#define BIOS_FLAG 0x0501 +#define DISK_BOOT 0x0584 + +.code16 +.text + +.global _start +_start: + +#if 0 /* hook for debugger, harmless unless BIOS is fussy (old HP) */ + int $0x3 +#endif + jmp real_start + .ascii "Linux 98" + .word 0 +real_start: + xorw %di, %di /* %di = 0 */ + movw %di, %ss /* %ss = 0 */ + movw $0x03F0, %sp + pushw %cx /* for hint */ + + movw $0x0A00, %ax /* normal mode defaults (80x25) */ + + testb $0x08, %ss:BIOS_FLAG /* check hi-reso bit */ + jnz set_crt_mode +/* + * Hi-Reso (high-resolution) machine. + * + * Some hi-reso machines have no RAMs on bank 8/A (0x080000 - 0x0BFFFF). + * On such machines we get two RAM banks from top of protect menory and + * map them on bank 8/A. + * These work-around must be done before moving myself on INITSEG (0x090000-). + */ + movw $(HIRESO_TEXT >> 8), %cs:(vram + 1) /* text VRAM segment */ + + /* set memory window */ + movb $0x08, %al + outb %al, $0x91 /* map native RAM (if any) */ + movb $0x0A, %al + outb %al, $0x93 + + /* check bank ram A */ + pushw $0xA500 + popw %ds + movw (%di), %cx /* %si == 0 from entry */ + notw %cx + movw %cx, (%di) + + movw $0x43F, %dx /* cache flush for 486 and up. */ + movb $0xA0, %al + outb %al, %dx + + cmpw %cx, (%di) + je hireso_done + + /* + * Write test failed; we have no native RAM on 080000h - 0BFFFFh. + * Take 256KB of RAM from top of protected memory. + */ + movb %ss:EXPMMSZ, %al + subb $2, %al /* reduce 2 x 128KB */ + movb %al, %ss:EXPMMSZ + addb %al, %al + addb $0x10, %al + outb %al, $0x91 + addb $2, %al + outb %al, $0x93 + +hireso_done: + movb $0x10, %al /* CRT mode 80x31, %ah still 0Ah */ + +set_crt_mode: + int $0x18 /* set CRT mode */ + + movb $0x0C, %ah /* turn on text displaying */ + int $0x18 + + xorw %dx, %dx /* position cursor to home */ + movb $0x13, %ah + int $0x18 + + movb $0x11, %ah /* turn cursor displaying on */ + int $0x18 + + /* move 1 kilobytes from [BOOTSEG:0000h] to [INITSEG:0000h] */ + cld + xorw %si, %si + pushw $INITSEG + popw %es + movw $512, %cx /* %di == 0 from entry */ + rep + cs + movsw + + ljmp $INITSEG, $go + +go: + pushw %cs + popw %ds /* %ds = %cs */ + + popw %dx /* %dh = saved %ch passed from BIOS */ + movb %ss:DISK_BOOT, %al + andb $0xf0, %al /* %al = Device Address */ + movb $18, %ch /* 18 secs/track, 512 b/sec (1440 KB) */ + cmpb $0x30, %al + je try512 + cmpb $0x90, %al /* 1 MB I/F, 1 MB floppy */ + je try1.2M + cmpb $0xf0, %al /* 640 KB I/F, 1 MB floppy */ + je try1.2M + movb $9, %ch /* 9 secs/track, 512 b/sec ( 720 KB) */ + cmpb $0x10, %al /* 1 MB I/F, 640 KB floppy */ + je try512 + cmpb $0x70, %al /* 640 KB I/F, 640 KB floppy */ + jne error /* unknown device? */ + + /* XXX: Does it make sense to support 8 secs/track, 512 b/sec + (640 KB) floppy? */ + +try512: movb $2, %cl /* 512 b/sec */ +lasttry:call tryload +/* + * Display error message and halt + */ +error: movw $error_msg, %si + call print +wait_reboot: + movb $0x0, %ah + int $0x18 /* wait keyboard input */ +1: movb $0, %al + outb %al, $0xF0 /* reset CPU */ + jmp 1b /* just in case... */ + +try1.2M:cmpb $2, %dh + je try2HC + movw $0x0803, %cx /* 8 secs/track, 1024 b/sec (1232 KB) */ + call tryload + movb $15, %ch /* 15 secs/track, 512 b/sec (1200 KB) */ + jmp try512 +try2HC: movw $0x0F02, %cx /* 15 secs/track, 512 b/sec (1200 KB) */ + call tryload + movw $0x0803, %cx /* 8 secs/track, 1024 b/sec (1232 KB) */ + jmp lasttry + +/* + * Try to load SETUP and SYSTEM provided geometry information in %cx. + * This routine *will not* return on successful load... + */ +tryload: + movw %cx, sectlen + movb %ss:DISK_BOOT, %al + movb $0x7, %ah /* recalibrate the drive */ + int $0x1b + jc error /* recalibration should succeed */ + + /* + * Load SETUP into memory. It is assumed that SETUP fits into + * first cylinder (2 tracks, 9KB on 2DD, 15-18KB on 2HD). + */ + movb $0, %bl + movb setup_sects, %bh + incb %bh + shlw %bx /* %bx = (setup_sects + 1) * 512 */ + movw $128, %bp + shlw %cl, %bp /* %bp = */ + subw %bp, %bx /* length to load */ + movw $0x0002, %dx /* head 0, sector 2 */ + movb %cl, %ch /* `N' for sector address */ + movb $0, %cl /* cylinder 0 */ + pushw %cs + popw %es /* %es = %cs (= INITSEG) */ + movb $0xd6, %ah /* read, multi-track, MFM */ + int $0x1b /* load it! */ + jc read_error + + movw $loading_msg, %si + call print + + movw $SYSSEG, %ax + movw %ax, %es /* %es = SYSSEG */ + +/* + * This routine loads the system at address 0x10000, making sure + * no 64kB boundaries are crossed. We try to load it as fast as + * possible, loading whole tracks whenever we can. + * + * in: es - starting address segment (normally 0x1000) + */ + movb %ch, %cl + addb $7, %cl /* %cl = log2 */ + shrw %cl, %bx /* %bx = # of phys. sectors in SETUP */ + addb %bl, %dl /* %dl = start sector # of SYSTEM */ + decb %dl /* %dl is 0-based in below loop */ + +rp_read_newseg: + xorw %bp, %bp /* = starting address within segment */ +#ifdef __BIG_KERNEL__ + bootsect_kludge = 0x220 /* 0x200 (size of bootsector) + 0x20 (offset */ + lcall *bootsect_kludge /* of bootsect_kludge in setup.S */ +#else + movw %es, %ax + subw $SYSSEG, %ax +#endif + cmpw syssize, %ax + ja boot /* done! */ + +rp_read: + movb sectors, %al + addb %al, %al + movb %al, %ch /* # of sectors on both surface */ + subb %dl, %al /* # of sectors left on this track */ + movb $0, %ah + shlw %cl, %ax /* # of bytes left on this track */ + movw %ax, %bx /* transfer length */ + addw %bp, %ax /* cross 64K boundary? */ + jnc 1f /* ok. */ + jz 1f /* also ok. */ + /* + * Oops, we are crossing 64K boundary... + * Adjust transfer length to make transfer fit in the boundary. + * + * Note: sector size is assumed to be a measure of 65536. + */ + xorw %bx, %bx + subw %bp, %bx +1: pushw %dx + movw $dot_msg, %si /* give progress message */ + call print + xchgw %ax, %dx + movb $0, %ah + divb sectors + xchgb %al, %ah + xchgw %ax, %dx /* %dh = head # / %dl = sector # */ + incb %dl /* fix %dl to 1-based */ + pushw %cx + movw cylinder, %cx + movb $0xd6, %ah /* read, multi-track, seek, MFM */ + movb %ss:DISK_BOOT, %al + int $0x1b + popw %cx + popw %dx + jc read_error + movw %bx, %ax /* # of bytes just read */ + shrw %cl, %ax /* %ax = # of sectors just read */ + addb %al, %dl /* advance sector # */ + cmpb %ch, %dl /* %ch = # of sectors/cylinder */ + jb 2f + incb cylinder /* next cylinder */ + xorb %dl, %dl /* sector 0 */ +2: addw %bx, %bp /* advance offset pointer */ + jnc rp_read + /* offset pointer wrapped; advance segment pointer. */ + movw %es, %ax + addw $0x1000, %ax + movw %ax, %es + jmp rp_read_newseg + +read_error: + ret + +boot: movw %cs, %ax /* = INITSEG */ + /* movw %ax, %ds */ + movw %ax, %ss + movw $0x4000, %sp /* 0x4000 is arbitrary value >= + * length of bootsect + length of + * setup + room for stack; + * PC-9800 never have BIOS workareas + * on high memory. + */ +/* + * After that we check which root-device to use. If the device is + * not defined, /dev/fd0 (2, 0) will be used. + */ + cmpw $0, root_dev + jne 3f + movb $2, root_dev+1 +3: + +/* + * After that (everything loaded), we jump to the setup-routine + * loaded directly after the bootblock: + */ + ljmp $SETUPSEG, $0 + +/* + * Subroutine for print string on console. + * %cs:%si - pointer to message + */ +print: + pushaw + pushw %ds + pushw %es + pushw %cs + popw %ds + lesw curpos, %di /* %es:%di = current text VRAM addr. */ +1: xorw %ax, %ax + lodsb + testb %al, %al + jz 2f /* end of string */ + stosw /* character code */ + movb $0xE1, %es:0x2000-2(%di) /* character attribute */ + jmp 1b +2: movw %di, %dx + movb $0x13, %ah + int $0x18 /* move cursor to current point */ + popw %es + popw %ds + popaw + ret + +loading_msg: + .string "Loading" +dot_msg: + .string "." +error_msg: + .string "Read Error!" + + .org 490 + +curpos: .word 160 /* current cursor position */ +vram: .word NORMAL_TEXT /* text VRAM segment */ + +cylinder: .byte 0 /* current cylinder (lower byte) */ +sectlen: .byte 0 /* (log2 of ) - 7 */ +sectors: .byte 0x0F /* default is 2HD (15 sector/track) */ + +# XXX: This is a fairly snug fit. + +.org 497 +setup_sects: .byte SETUPSECTS +root_flags: .word ROOT_RDONLY +syssize: .word SYSSIZE +swap_dev: .word SWAP_DEV +ram_size: .word RAMDISK +vid_mode: .word SVGA_MODE +root_dev: .word ROOT_DEV +boot_flag: .word 0xAA55 diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/arch/i386/boot98/compressed/head.S linux.2.5.47-ac6/arch/i386/boot98/compressed/head.S --- linux.2.5.47/arch/i386/boot98/compressed/head.S 1970-01-01 01:00:00.000000000 +0100 +++ linux.2.5.47-ac6/arch/i386/boot98/compressed/head.S 2002-11-15 15:33:42.000000000 +0000 @@ -0,0 +1,128 @@ +/* + * linux/boot/head.S + * + * Copyright (C) 1991, 1992, 1993 Linus Torvalds + */ + +/* + * head.S contains the 32-bit startup code. + * + * NOTE!!! Startup happens at absolute address 0x00001000, which is also where + * the page directory will exist. The startup code will be overwritten by + * the page directory. [According to comments etc elsewhere on a compressed + * kernel it will end up at 0x1000 + 1Mb I hope so as I assume this. - AC] + * + * Page 0 is deliberately kept safe, since System Management Mode code in + * laptops may need to access the BIOS data stored there. This is also + * useful for future device drivers that either access the BIOS via VM86 + * mode. + */ + +/* + * High loaded stuff by Hans Lermen & Werner Almesberger, Feb. 1996 + */ +.text + +#include +#include + + .globl startup_32 + +startup_32: + cld + cli + movl $(__BOOT_DS),%eax + movl %eax,%ds + movl %eax,%es + movl %eax,%fs + movl %eax,%gs + + lss stack_start,%esp + xorl %eax,%eax +1: incl %eax # check that A20 really IS enabled + movl %eax,0x000000 # loop forever if it isn't + cmpl %eax,0x100000 + je 1b + +/* + * Initialize eflags. Some BIOS's leave bits like NT set. This would + * confuse the debugger if this code is traced. + * XXX - best to initialize before switching to protected mode. + */ + pushl $0 + popfl +/* + * Clear BSS + */ + xorl %eax,%eax + movl $_edata,%edi + movl $_end,%ecx + subl %edi,%ecx + cld + rep + stosb +/* + * Do the decompression, and jump to the new kernel.. + */ + subl $16,%esp # place for structure on the stack + movl %esp,%eax + pushl %esi # real mode pointer as second arg + pushl %eax # address of structure as first arg + call decompress_kernel + orl %eax,%eax + jnz 3f + popl %esi # discard address + popl %esi # real mode pointer + xorl %ebx,%ebx + ljmp $(__BOOT_CS), $0x100000 + +/* + * We come here, if we were loaded high. + * We need to move the move-in-place routine down to 0x1000 + * and then start it with the buffer addresses in registers, + * which we got from the stack. + */ +3: + movl $move_routine_start,%esi + movl $0x1000,%edi + movl $move_routine_end,%ecx + subl %esi,%ecx + addl $3,%ecx + shrl $2,%ecx + cld + rep + movsl + + popl %esi # discard the address + popl %ebx # real mode pointer + popl %esi # low_buffer_start + popl %ecx # lcount + popl %edx # high_buffer_start + popl %eax # hcount + movl $0x100000,%edi + cli # make sure we don't get interrupted + ljmp $(__BOOT_CS), $0x1000 # and jump to the move routine + +/* + * Routine (template) for moving the decompressed kernel in place, + * if we were high loaded. This _must_ PIC-code ! + */ +move_routine_start: + movl %ecx,%ebp + shrl $2,%ecx + rep + movsl + movl %ebp,%ecx + andl $3,%ecx + rep + movsb + movl %edx,%esi + movl %eax,%ecx # NOTE: rep movsb won't move if %ecx == 0 + addl $3,%ecx + shrl $2,%ecx + rep + movsl + movl %ebx,%esi # Restore setup pointer + xorl %ebx,%ebx + ljmp $(__BOOT_CS), $0x100000 +move_routine_end: diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/arch/i386/boot98/compressed/Makefile linux.2.5.47-ac6/arch/i386/boot98/compressed/Makefile --- linux.2.5.47/arch/i386/boot98/compressed/Makefile 1970-01-01 01:00:00.000000000 +0100 +++ linux.2.5.47-ac6/arch/i386/boot98/compressed/Makefile 2002-10-31 15:05:52.000000000 +0000 @@ -0,0 +1,26 @@ +# +# linux/arch/i386/boot/compressed/Makefile +# +# create a compressed vmlinux image from the original vmlinux +# + +EXTRA_TARGETS := vmlinux vmlinux.bin vmlinux.bin.gz head.o misc.o piggy.o +EXTRA_AFLAGS := -traditional + +include $(TOPDIR)/Rules.make + +LDFLAGS_vmlinux := -Ttext $(IMAGE_OFFSET) -e startup_32 + +$(obj)/vmlinux: $(obj)/head.o $(obj)/misc.o $(obj)/piggy.o FORCE + $(call if_changed,ld) + +$(obj)/vmlinux.bin: vmlinux FORCE + $(call if_changed,objcopy) + +$(obj)/vmlinux.bin.gz: $(obj)/vmlinux.bin FORCE + $(call if_changed,gzip) + +LDFLAGS_piggy.o := -r --format binary --oformat elf32-i386 -T + +$(obj)/piggy.o: $(obj)/vmlinux.scr $(obj)/vmlinux.bin.gz FORCE + $(call if_changed,ld) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/arch/i386/boot98/compressed/misc.c linux.2.5.47-ac6/arch/i386/boot98/compressed/misc.c --- linux.2.5.47/arch/i386/boot98/compressed/misc.c 1970-01-01 01:00:00.000000000 +0100 +++ linux.2.5.47-ac6/arch/i386/boot98/compressed/misc.c 2002-11-15 15:33:42.000000000 +0000 @@ -0,0 +1,379 @@ +/* + * misc.c + * + * This is a collection of several routines from gzip-1.0.3 + * adapted for Linux. + * + * malloc by Hannu Savolainen 1993 and Matthias Urlichs 1994 + * puts by Nick Holloway 1993, better puts by Martin Mares 1995 + * High loaded stuff by Hans Lermen & Werner Almesberger, Feb. 1996 + */ + +#include +#include +#include +#include +#ifdef STANDARD_MEMORY_BIOS_CALL +#undef STANDARD_MEMORY_BIOS_CALL +#endif + +/* + * gzip declarations + */ + +#define OF(args) args +#define STATIC static + +#undef memset +#undef memcpy + +/* + * Why do we do this? Don't ask me.. + * + * Incomprehensible are the ways of bootloaders. + */ +static void* memset(void *, int, size_t); +static void* memcpy(void *, __const void *, size_t); +#define memzero(s, n) memset ((s), 0, (n)) + +typedef unsigned char uch; +typedef unsigned short ush; +typedef unsigned long ulg; + +#define WSIZE 0x8000 /* Window size must be at least 32k, */ + /* and a power of two */ + +static uch *inbuf; /* input buffer */ +static uch window[WSIZE]; /* Sliding window buffer */ + +static unsigned insize = 0; /* valid bytes in inbuf */ +static unsigned inptr = 0; /* index of next byte to be processed in inbuf */ +static unsigned outcnt = 0; /* bytes in output buffer */ + +/* gzip flag byte */ +#define ASCII_FLAG 0x01 /* bit 0 set: file probably ASCII text */ +#define CONTINUATION 0x02 /* bit 1 set: continuation of multi-part gzip file */ +#define EXTRA_FIELD 0x04 /* bit 2 set: extra field present */ +#define ORIG_NAME 0x08 /* bit 3 set: original file name present */ +#define COMMENT 0x10 /* bit 4 set: file comment present */ +#define ENCRYPTED 0x20 /* bit 5 set: file is encrypted */ +#define RESERVED 0xC0 /* bit 6,7: reserved */ + +#define get_byte() (inptr < insize ? inbuf[inptr++] : fill_inbuf()) + +/* Diagnostic functions */ +#ifdef DEBUG +# define Assert(cond,msg) {if(!(cond)) error(msg);} +# define Trace(x) fprintf x +# define Tracev(x) {if (verbose) fprintf x ;} +# define Tracevv(x) {if (verbose>1) fprintf x ;} +# define Tracec(c,x) {if (verbose && (c)) fprintf x ;} +# define Tracecv(c,x) {if (verbose>1 && (c)) fprintf x ;} +#else +# define Assert(cond,msg) +# define Trace(x) +# define Tracev(x) +# define Tracevv(x) +# define Tracec(c,x) +# define Tracecv(c,x) +#endif + +static int fill_inbuf(void); +static void flush_window(void); +static void error(char *m); +static void gzip_mark(void **); +static void gzip_release(void **); + +/* + * This is set up by the setup-routine at boot-time + */ +static unsigned char *real_mode; /* Pointer to real-mode data */ + +#define EXT_MEM_K (*(unsigned short *)(real_mode + 0x2)) +#ifndef STANDARD_MEMORY_BIOS_CALL +#define ALT_MEM_K (*(unsigned long *)(real_mode + 0x1e0)) +#endif +#define SCREEN_INFO (*(struct screen_info *)(real_mode+0)) + +extern char input_data[]; +extern int input_len; + +static long bytes_out = 0; +static uch *output_data; +static unsigned long output_ptr = 0; + +static void *malloc(int size); +static void free(void *where); + +static void puts(const char *); + +extern int end; +static long free_mem_ptr = (long)&end; +static long free_mem_end_ptr; + +#define INPLACE_MOVE_ROUTINE 0x1000 +#define LOW_BUFFER_START 0x2000 +#define LOW_BUFFER_MAX 0x90000 +#define HEAP_SIZE 0x3000 +static unsigned int low_buffer_end, low_buffer_size; +static int high_loaded =0; +static uch *high_buffer_start /* = (uch *)(((ulg)&end) + HEAP_SIZE)*/; + +static char *vidmem = (char *)0xa0000; +static int lines, cols; + +#ifdef CONFIG_X86_NUMAQ +static void * xquad_portio = NULL; +#endif + +#include "../../../../lib/inflate.c" + +static void *malloc(int size) +{ + void *p; + + if (size <0) error("Malloc error\n"); + if (free_mem_ptr <= 0) error("Memory error\n"); + + free_mem_ptr = (free_mem_ptr + 3) & ~3; /* Align */ + + p = (void *)free_mem_ptr; + free_mem_ptr += size; + + if (free_mem_ptr >= free_mem_end_ptr) + error("\nOut of memory\n"); + + return p; +} + +static void free(void *where) +{ /* Don't care */ +} + +static void gzip_mark(void **ptr) +{ + *ptr = (void *) free_mem_ptr; +} + +static void gzip_release(void **ptr) +{ + free_mem_ptr = (long) *ptr; +} + +static void scroll(void) +{ + int i; + + memcpy ( vidmem, vidmem + cols * 2, ( lines - 1 ) * cols * 2 ); + for ( i = ( lines - 1 ) * cols * 2; i < lines * cols * 2; i += 2 ) + vidmem[i] = ' '; +} + +static void puts(const char *s) +{ + int x,y,pos; + char c; + + x = SCREEN_INFO.orig_x; + y = SCREEN_INFO.orig_y; + + while ( ( c = *s++ ) != '\0' ) { + if ( c == '\n' ) { + x = 0; + if ( ++y >= lines ) { + scroll(); + y--; + } + } else { + vidmem [ ( x + cols * y ) * 2 ] = c; + if ( ++x >= cols ) { + x = 0; + if ( ++y >= lines ) { + scroll(); + y--; + } + } + } + } + + SCREEN_INFO.orig_x = x; + SCREEN_INFO.orig_y = y; + + pos = x + cols * y; /* Update cursor position */ + while (!(inb_p(0x60) & 4)); + outb_p(0x49, 0x62); + outb_p(pos & 0xff, 0x60); + outb_p((pos >> 8) & 0xff, 0x60); +} + +static void* memset(void* s, int c, size_t n) +{ + int i; + char *ss = (char*)s; + + for (i=0;i> 8); + } + crc = c; + bytes_out += (ulg)outcnt; + output_ptr += (ulg)outcnt; + outcnt = 0; +} + +static void flush_window_high(void) +{ + ulg c = crc; /* temporary variable */ + unsigned n; + uch *in, ch; + in = window; + for (n = 0; n < outcnt; n++) { + ch = *output_data++ = *in++; + if ((ulg)output_data == low_buffer_end) output_data=high_buffer_start; + c = crc_32_tab[((int)c ^ ch) & 0xff] ^ (c >> 8); + } + crc = c; + bytes_out += (ulg)outcnt; + outcnt = 0; +} + +static void flush_window(void) +{ + if (high_loaded) flush_window_high(); + else flush_window_low(); +} + +static void error(char *x) +{ + puts("\n\n"); + puts(x); + puts("\n\n -- System halted"); + + while(1); /* Halt */ +} + +#define STACK_SIZE (4096) + +long user_stack [STACK_SIZE]; + +struct { + long * a; + short b; + } stack_start = { & user_stack [STACK_SIZE] , __BOOT_DS }; + +static void setup_normal_output_buffer(void) +{ +#ifdef STANDARD_MEMORY_BIOS_CALL + if (EXT_MEM_K < 1024) error("Less than 2MB of memory.\n"); +#else + if ((ALT_MEM_K > EXT_MEM_K ? ALT_MEM_K : EXT_MEM_K) < 1024) error("Less than 2MB of memory.\n"); +#endif + output_data = (char *)0x100000; /* Points to 1M */ + free_mem_end_ptr = (long)real_mode; +} + +struct moveparams { + uch *low_buffer_start; int lcount; + uch *high_buffer_start; int hcount; +}; + +static void setup_output_buffer_if_we_run_high(struct moveparams *mv) +{ + high_buffer_start = (uch *)(((ulg)&end) + HEAP_SIZE); +#ifdef STANDARD_MEMORY_BIOS_CALL + if (EXT_MEM_K < (3*1024)) error("Less than 4MB of memory.\n"); +#else + if ((ALT_MEM_K > EXT_MEM_K ? ALT_MEM_K : EXT_MEM_K) < (3*1024)) error("Less than 4MB of memory.\n"); +#endif + mv->low_buffer_start = output_data = (char *)LOW_BUFFER_START; + low_buffer_end = ((unsigned int)real_mode > LOW_BUFFER_MAX + ? LOW_BUFFER_MAX : (unsigned int)real_mode) & ~0xfff; + low_buffer_size = low_buffer_end - LOW_BUFFER_START; + high_loaded = 1; + free_mem_end_ptr = (long)high_buffer_start; + if ( (0x100000 + low_buffer_size) > ((ulg)high_buffer_start)) { + high_buffer_start = (uch *)(0x100000 + low_buffer_size); + mv->hcount = 0; /* say: we need not to move high_buffer */ + } + else mv->hcount = -1; + mv->high_buffer_start = high_buffer_start; +} + +static void close_output_buffer_if_we_run_high(struct moveparams *mv) +{ + if (bytes_out > low_buffer_size) { + mv->lcount = low_buffer_size; + if (mv->hcount) + mv->hcount = bytes_out - low_buffer_size; + } else { + mv->lcount = bytes_out; + mv->hcount = 0; + } +} + + +asmlinkage int decompress_kernel(struct moveparams *mv, void *rmode) +{ + real_mode = rmode; + + vidmem = (char *)(((unsigned int)SCREEN_INFO.orig_video_page) << 4); + + lines = SCREEN_INFO.orig_video_lines; + cols = SCREEN_INFO.orig_video_cols; + + if (free_mem_ptr < 0x100000) setup_normal_output_buffer(); + else setup_output_buffer_if_we_run_high(mv); + + makecrc(); + puts("Uncompressing Linux... "); + gunzip(); + puts("Ok, booting the kernel.\n"); + if (high_loaded) close_output_buffer_if_we_run_high(mv); + return high_loaded; +} + +/* We don't actually check for stack overflows this early. */ +__asm__(".globl mcount ; mcount: ret\n"); + diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/arch/i386/boot98/compressed/vmlinux.scr linux.2.5.47-ac6/arch/i386/boot98/compressed/vmlinux.scr --- linux.2.5.47/arch/i386/boot98/compressed/vmlinux.scr 1970-01-01 01:00:00.000000000 +0100 +++ linux.2.5.47-ac6/arch/i386/boot98/compressed/vmlinux.scr 2002-10-31 15:05:52.000000000 +0000 @@ -0,0 +1,9 @@ +SECTIONS +{ + .data : { + input_len = .; + LONG(input_data_end - input_data) input_data = .; + *(.data) + input_data_end = .; + } +} diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/arch/i386/boot98/install.sh linux.2.5.47-ac6/arch/i386/boot98/install.sh --- linux.2.5.47/arch/i386/boot98/install.sh 1970-01-01 01:00:00.000000000 +0100 +++ linux.2.5.47-ac6/arch/i386/boot98/install.sh 2002-10-31 15:05:52.000000000 +0000 @@ -0,0 +1,40 @@ +#!/bin/sh +# +# arch/i386/boot/install.sh +# +# 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 by Linus Torvalds +# +# Adapted from code in arch/i386/boot/Makefile by H. Peter Anvin +# +# "make install" script for i386 architecture +# +# Arguments: +# $1 - kernel version +# $2 - kernel image file +# $3 - kernel map file +# $4 - default install path (blank if root directory) +# + +# User may have a custom install script + +if [ -x ~/bin/installkernel ]; then exec ~/bin/installkernel "$@"; fi +if [ -x /sbin/installkernel ]; then exec /sbin/installkernel "$@"; fi + +# Default install - same as make zlilo + +if [ -f $4/vmlinuz ]; then + mv $4/vmlinuz $4/vmlinuz.old +fi + +if [ -f $4/System.map ]; then + mv $4/System.map $4/System.old +fi + +cat $2 > $4/vmlinuz +cp $3 $4/System.map + +if [ -x /sbin/lilo ]; then /sbin/lilo; else /etc/lilo/install; fi diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/arch/i386/boot98/Makefile linux.2.5.47-ac6/arch/i386/boot98/Makefile --- linux.2.5.47/arch/i386/boot98/Makefile 1970-01-01 01:00:00.000000000 +0100 +++ linux.2.5.47-ac6/arch/i386/boot98/Makefile 2002-11-15 15:33:42.000000000 +0000 @@ -0,0 +1,90 @@ +# +# arch/i386/boot/Makefile +# +# 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) 1994 by Linus Torvalds +# + +# ROOT_DEV specifies the default root-device when making the image. +# This can be either FLOPPY, CURRENT, /dev/xxxx or empty, in which case +# the default of FLOPPY is used by 'build'. + +ROOT_DEV := CURRENT + +# If you want to preset the SVGA mode, uncomment the next line and +# set SVGA_MODE to whatever number you want. +# Set it to -DSVGA_MODE=NORMAL_VGA if you just want the EGA/VGA mode. +# The number is the same as you would ordinarily press at bootup. + +SVGA_MODE := -DSVGA_MODE=NORMAL_VGA + +# If you want the RAM disk device, define this to be the size in blocks. + +#RAMDISK := -DRAMDISK=512 + +EXTRA_TARGETS := vmlinux.bin bootsect bootsect.o \ + setup setup.o zImage bzImage + +subdir- := compressed + +host-progs := tools/build + +# Default + +boot: bzImage + +include $(TOPDIR)/Rules.make + +# --------------------------------------------------------------------------- + +$(obj)/zImage: IMAGE_OFFSET := 0x1000 +$(obj)/zImage: EXTRA_AFLAGS := -traditional $(SVGA_MODE) $(RAMDISK) +$(obj)/bzImage: IMAGE_OFFSET := 0x100000 +$(obj)/bzImage: EXTRA_AFLAGS := -traditional $(SVGA_MODE) $(RAMDISK) -D__BIG_KERNEL__ +$(obj)/bzImage: BUILDFLAGS := -b + +quiet_cmd_image = BUILD $@ +cmd_image = $(obj)/tools/build $(BUILDFLAGS) $(obj)/bootsect $(obj)/setup \ + $(obj)/vmlinux.bin $(ROOT_DEV) > $@ + +$(obj)/zImage $(obj)/bzImage: $(obj)/bootsect $(obj)/setup \ + $(obj)/vmlinux.bin $(obj)/tools/build FORCE + $(call if_changed,image) + +$(obj)/vmlinux.bin: $(obj)/compressed/vmlinux FORCE + $(call if_changed,objcopy) + +LDFLAGS_bootsect := -Ttext 0x0 -s --oformat binary +LDFLAGS_setup := -Ttext 0x0 -s --oformat binary -e begtext + +$(obj)/setup $(obj)/bootsect: %: %.o FORCE + $(call if_changed,ld) + +$(obj)/compressed/vmlinux: FORCE + +@$(call descend,$(obj)/compressed,IMAGE_OFFSET=$(IMAGE_OFFSET) \ + $(obj)/compressed/vmlinux) + + +zdisk: $(BOOTIMAGE) + dd bs=8192 if=$(BOOTIMAGE) of=/dev/fd0 + +zlilo: $(BOOTIMAGE) + if [ -f $(INSTALL_PATH)/vmlinuz ]; then mv $(INSTALL_PATH)/vmlinuz $(INSTALL_PATH)/vmlinuz.old; fi + if [ -f $(INSTALL_PATH)/System.map ]; then mv $(INSTALL_PATH)/System.map $(INSTALL_PATH)/System.old; fi + cat $(BOOTIMAGE) > $(INSTALL_PATH)/vmlinuz + cp System.map $(INSTALL_PATH)/ + if [ -x /sbin/lilo ]; then /sbin/lilo; else /etc/lilo/install; fi + +install: $(BOOTIMAGE) + sh $(src)/install.sh $(KERNELRELEASE) $(BOOTIMAGE) System.map "$(INSTALL_PATH)" + +archhelp: + @echo '* bzImage - Compressed kernel image (arch/$(ARCH)/boot/bzImage)' + @echo ' install - Install kernel using' + @echo ' (your) ~/bin/installkernel or' + @echo ' (distribution) /sbin/installkernel or' + @echo ' install to $$(INSTALL_PATH) and run lilo' + diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/arch/i386/boot98/setup.S linux.2.5.47-ac6/arch/i386/boot98/setup.S --- linux.2.5.47/arch/i386/boot98/setup.S 1970-01-01 01:00:00.000000000 +0100 +++ linux.2.5.47-ac6/arch/i386/boot98/setup.S 2002-11-15 15:33:42.000000000 +0000 @@ -0,0 +1,961 @@ +/* + * setup.S Copyright (C) 1991, 1992 Linus Torvalds + * + * setup.s is responsible for getting the system data from the BIOS, + * and putting them into the appropriate places in system memory. + * both setup.s and system has been loaded by the bootblock. + * + * This code asks the bios for memory/disk/other parameters, and + * puts them in a "safe" place: 0x90000-0x901FF, ie where the + * boot-block used to be. It is then up to the protected mode + * system to read them from there before the area is overwritten + * for buffer-blocks. + * + * Move PS/2 aux init code to psaux.c + * (troyer@saifr00.cfsat.Honeywell.COM) 03Oct92 + * + * some changes and additional features by Christoph Niemann, + * March 1993/June 1994 (Christoph.Niemann@linux.org) + * + * add APM BIOS checking by Stephen Rothwell, May 1994 + * (sfr@canb.auug.org.au) + * + * High load stuff, initrd support and position independency + * by Hans Lermen & Werner Almesberger, February 1996 + * , + * + * Video handling moved to video.S by Martin Mares, March 1996 + * + * + * Extended memory detection scheme retwiddled by orc@pell.chi.il.us (david + * parsons) to avoid loadlin confusion, July 1997 + * + * Transcribed from Intel (as86) -> AT&T (gas) by Chris Noe, May 1999. + * + * + * Fix to work around buggy BIOSes which dont use carry bit correctly + * and/or report extended memory in CX/DX for e801h memory size detection + * call. As a result the kernel got wrong figures. The int15/e801h docs + * from Ralf Brown interrupt list seem to indicate AX/BX should be used + * anyway. So to avoid breaking many machines (presumably there was a reason + * to orginally use CX/DX instead of AX/BX), we do a kludge to see + * if CX/DX have been changed in the e801 call and if so use AX/BX . + * Michael Miller, April 2001 + * + * New A20 code ported from SYSLINUX by H. Peter Anvin. AMD Elan bugfixes + * by Robert Schwebel, December 2001 + * + * Heavily modified for NEC PC-9800 series by Kyoto University Microcomputer + * Club (KMC) Linux/98 project , 1997-1999 + */ + +#include +#include +#include +#include +#include +#include +#include + +/* Signature words to ensure LILO loaded us right */ +#define SIG1 0xAA55 +#define SIG2 0x5A5A + +#define HIRESO_TEXT 0xe000 +#define NORMAL_TEXT 0xa000 + +#define BIOS_FLAG2 0x0400 +#define BIOS_FLAG5 0x0458 +#define RDISK_EQUIP 0x0488 +#define BIOS_FLAG 0x0501 +#define KB_SHFT_STS 0x053a +#define DISK_EQUIP 0x055c + +INITSEG = DEF_INITSEG # 0x9000, we move boot here, out of the way +SYSSEG = DEF_SYSSEG # 0x1000, system loaded at 0x10000 (65536). +SETUPSEG = DEF_SETUPSEG # 0x9020, this is the current segment + # ... and the former contents of CS + +DELTA_INITSEG = SETUPSEG - INITSEG # 0x0020 + +.code16 +.globl begtext, begdata, begbss, endtext, enddata, endbss + +.text +begtext: +.data +begdata: +.bss +begbss: +.text + +start: + jmp trampoline + +# This is the setup header, and it must start at %cs:2 (old 0x9020:2) + + .ascii "HdrS" # header signature + .word 0x0203 # header version number (>= 0x0105) + # or else old loadlin-1.5 will fail) +realmode_swtch: .word 0, 0 # default_switch, SETUPSEG +start_sys_seg: .word SYSSEG + .word kernel_version # pointing to kernel version string + # above section of header is compatible + # with loadlin-1.5 (header v1.5). Don't + # change it. + +type_of_loader: .byte 0 # = 0, old one (LILO, Loadlin, + # Bootlin, SYSLX, bootsect...) + # See Documentation/i386/boot.txt for + # assigned ids + +# flags, unused bits must be zero (RFU) bit within loadflags +loadflags: +LOADED_HIGH = 1 # If set, the kernel is loaded high +CAN_USE_HEAP = 0x80 # If set, the loader also has set + # heap_end_ptr to tell how much + # space behind setup.S can be used for + # heap purposes. + # Only the loader knows what is free +#ifndef __BIG_KERNEL__ + .byte 0 +#else + .byte LOADED_HIGH +#endif + +setup_move_size: .word 0x8000 # size to move, when setup is not + # loaded at 0x90000. We will move setup + # to 0x90000 then just before jumping + # into the kernel. However, only the + # loader knows how much data behind + # us also needs to be loaded. + +code32_start: # here loaders can put a different + # start address for 32-bit code. +#ifndef __BIG_KERNEL__ + .long 0x1000 # 0x1000 = default for zImage +#else + .long 0x100000 # 0x100000 = default for big kernel +#endif + +ramdisk_image: .long 0 # address of loaded ramdisk image + # Here the loader puts the 32-bit + # address where it loaded the image. + # This only will be read by the kernel. + +ramdisk_size: .long 0 # its size in bytes + +bootsect_kludge: + .word bootsect_helper, SETUPSEG + +heap_end_ptr: .word modelist+1024 # (Header version 0x0201 or later) + # space from here (exclusive) down to + # end of setup code can be used by setup + # for local heap purposes. + +pad1: .word 0 +cmd_line_ptr: .long 0 # (Header version 0x0202 or later) + # If nonzero, a 32-bit pointer + # to the kernel command line. + # The command line should be + # located between the start of + # setup and the end of low + # memory (0xa0000), or it may + # get overwritten before it + # gets read. If this field is + # used, there is no longer + # anything magical about the + # 0x90000 segment; the setup + # can be located anywhere in + # low memory 0x10000 or higher. + +ramdisk_max: .long __MAXMEM-1 # (Header version 0x0203 or later) + # The highest safe address for + # the contents of an initrd + +trampoline: call start_of_setup + .space 1024 +# End of setup header ##################################################### + +start_of_setup: +# Set %ds = %cs, we know that SETUPSEG = %cs at this point + movw %cs, %ax # aka SETUPSEG + movw %ax, %ds +# Check signature at end of setup + cmpw $SIG1, setup_sig1 + jne bad_sig + + cmpw $SIG2, setup_sig2 + jne bad_sig + + jmp good_sig1 + +# Routine to print asciiz string at ds:si +prtstr: + lodsb + andb %al, %al + jz fin + + call prtchr + jmp prtstr + +fin: ret + +no_sig_mess: .string "No setup signature found ..." + +good_sig1: + jmp good_sig + +# We now have to find the rest of the setup code/data +bad_sig: + movw %cs, %ax # SETUPSEG + subw $DELTA_INITSEG, %ax # INITSEG + movw %ax, %ds + xorb %bh, %bh + movb (497), %bl # get setup sect from bootsect + subw $4, %bx # LILO loads 4 sectors of setup + shlw $8, %bx # convert to words (1sect=2^8 words) + movw %bx, %cx + shrw $3, %bx # convert to segment + addw $SYSSEG, %bx + movw %bx, %cs:start_sys_seg +# Move rest of setup code/data to here + movw $2048, %di # four sectors loaded by LILO + subw %si, %si + pushw %cs + popw %es + movw $SYSSEG, %ax + movw %ax, %ds + rep + movsw + movw %cs, %ax # aka SETUPSEG + movw %ax, %ds + cmpw $SIG1, setup_sig1 + jne no_sig + + cmpw $SIG2, setup_sig2 + jne no_sig + + jmp good_sig + +no_sig: + lea no_sig_mess, %si + call prtstr + +no_sig_loop: + hlt + jmp no_sig_loop + +good_sig: + movw %cs, %ax # aka SETUPSEG + subw $DELTA_INITSEG, %ax # aka INITSEG + movw %ax, %ds +# Check if an old loader tries to load a big-kernel + testb $LOADED_HIGH, %cs:loadflags # Do we have a big kernel? + jz loader_ok # No, no danger for old loaders. + + cmpb $0, %cs:type_of_loader # Do we have a loader that + # can deal with us? + jnz loader_ok # Yes, continue. + + pushw %cs # No, we have an old loader, + popw %ds # die. + lea loader_panic_mess, %si + call prtstr + + jmp no_sig_loop + +loader_panic_mess: .string "Wrong loader, giving up..." + +loader_ok: +# Get memory size (extended mem, kB) + +# On PC-9800, memory size detection is done completely in 32-bit +# kernel initialize code (kernel/setup.c). + pushw %es + xorl %eax, %eax + movw %ax, %es + movb %al, (E820NR) # PC-9800 has no E820 + movb %es:(0x401), %al + shll $7, %eax + addw $1024, %ax + movw %ax, (2) + movl %eax, (0x1e0) + movw %es:(0x594), %ax + shll $10, %eax + addl %eax, (0x1e0) + popw %es + +# Check for video adapter and its parameters and allow the +# user to browse video modes. + call video # NOTE: we need %ds pointing + # to bootsector + +# Get text video mode + movb $0x0B, %ah + int $0x18 # CRT mode sense + movw $(20 << 8) + 40, %cx + testb $0x10, %al + jnz 3f + movb $20, %ch + testb $0x01, %al + jnz 1f + movb $25, %ch + jmp 1f +3: # If bit 4 was 1, it means either 1) 31 lines for hi-reso mode, + # or 2) 30 lines for PC-9821. + movb $31, %ch # hireso mode value + pushw $0 + popw %es + testb $0x08, %es:BIOS_FLAG + jnz 1f + movb $30, %ch +1: # Now we got # of rows in %ch + movb %ch, (14) + + testb $0x02, %al + jnz 2f + movb $80, %cl +2: # Now we got # of columns in %cl + movb %cl, (7) + + # Next, get horizontal frequency if supported + movw $0x3100, %ax + int $0x18 # Call CRT bios + movb %al, (6) # If 31h is unsupported, %al remains 0 + +# Get hd0-3 data... + pushw %ds # aka INITSEG + popw %es + xorw %ax, %ax + movw %ax, %ds + cld + movw $0x0080, %di + movb DISK_EQUIP+1, %ah + movb $0x80, %al + +get_hd_info: + shrb %ah + pushw %ax + jnc 1f + movb $0x84, %ah + int $0x1b + jnc 2f # Success +1: xorw %cx, %cx # `0 cylinders' means no drive +2: # Attention! Work area (drive_info) is arranged for PC-9800. + movw %cx, %ax # # of cylinders + stosw + movw %dx, %ax # # of sectors / # of heads + stosw + movw %bx, %ax # sector size in bytes + stosw + popw %ax + incb %al + cmpb $0x84, %al + jb get_hd_info + +# Get fd data... + movw DISK_EQUIP, %ax + andw $0xf00f, %ax + orb %al, %ah + movb RDISK_EQUIP, %al + notb %al + andb %al, %ah # ignore all `RAM drive' + + movb $0x30, %al + +get_fd_info: + shrb %ah + pushw %ax + jnc 1f + movb $0xc4, %ah + int $0x1b + movb %ah, %al + andb $4, %al # 1.44MB support flag + shrb %al + addb $2, %al # %al = 2 (1.2MB) or 4 (1.44MB) + jmp 2f +1: movb $0, %al # no drive +2: stosb + popw %ax + incb %al + testb $0x04, %al + jz get_fd_info + + addb $(0xb0 - 0x34), %al + jnc get_fd_info # check FDs on 640KB I/F + + pushw %es + popw %ds # %ds got bootsector again +#if 0 + mov $0, (0x1ff) # default is no pointing device +#endif + +#if defined(CONFIG_APM) || defined(CONFIG_APM_MODULE) +# Then check for an APM BIOS... + # %ds points to the bootsector + movw $0, 0x40 # version = 0 means no APM BIOS + movw $0x09a00, %ax # APM BIOS installation check + xorw %bx, %bx + int $0x1f + jc done_apm_bios # Nope, no APM BIOS + + cmpw $0x0504d, %bx # Check for "PM" signature + jne done_apm_bios # No signature, no APM BIOS + + testb $0x02, %cl # Is 32 bit supported? + je done_apm_bios # No 32-bit, no (good) APM BIOS + + movw $0x09a04, %ax # Disconnect first just in case + xorw %bx, %bx + int $0x1f # ignore return code + movw $0x09a03, %ax # 32 bit connect + xorl %ebx, %ebx + int $0x1f + jc no_32_apm_bios # Ack, error. + + movw %ax, (66) # BIOS code segment + movl %ebx, (68) # BIOS entry point offset + movw %cx, (72) # BIOS 16 bit code segment + movw %dx, (74) # BIOS data segment + movl %esi, (78) # BIOS code segment length + movw %di, (82) # BIOS data segment length +# Redo the installation check as the 32 bit connect +# modifies the flags returned on some BIOSs + movw $0x09a00, %ax # APM BIOS installation check + xorw %bx, %bx + int $0x1f + jc apm_disconnect # error -> shouldn't happen + + cmpw $0x0504d, %bx # check for "PM" signature + jne apm_disconnect # no sig -> shouldn't happen + + movw %ax, (64) # record the APM BIOS version + movw %cx, (76) # and flags + jmp done_apm_bios + +apm_disconnect: # Tidy up + movw $0x09a04, %ax # Disconnect + xorw %bx, %bx + int $0x1f # ignore return code + + jmp done_apm_bios + +no_32_apm_bios: + andw $0xfffd, (76) # remove 32 bit support bit +done_apm_bios: +#endif + +# Pass cursor position to kernel... + movw %cs:cursor_address, %ax + shrw %ax # cursor_address is 2 bytes unit + movb $80, %cl + divb %cl + xchgb %al, %ah # (0) = %al = X, (1) = %ah = Y + movw %ax, (0) + +#if 0 + movw $msg_cpos, %si + call prtstr_cs + call prthex + call prtstr_cs + movw %ds, %ax + call prthex + call prtstr_cs + movb $0x11, %ah + int $0x18 + movb $0, %ah + int $0x18 + .section .rodata, "a" +msg_cpos: .string "Cursor position: 0x" + .string ", %ds:0x" + .string "\r\n" + .previous +#endif + +# Now we want to move to protected mode ... + cmpw $0, %cs:realmode_swtch + jz rmodeswtch_normal + + lcall *%cs:realmode_swtch + + jmp rmodeswtch_end + +rmodeswtch_normal: + pushw %cs + call default_switch + +rmodeswtch_end: +# we get the code32 start address and modify the below 'jmpi' +# (loader may have changed it) + movl %cs:code32_start, %eax + movl %eax, %cs:code32 + +# Now we move the system to its rightful place ... but we check if we have a +# big-kernel. In that case we *must* not move it ... + testb $LOADED_HIGH, %cs:loadflags + jz do_move0 # .. then we have a normal low + # loaded zImage + # .. or else we have a high + # loaded bzImage + jmp end_move # ... and we skip moving + +do_move0: + movw $0x100, %ax # start of destination segment + movw %cs, %bp # aka SETUPSEG + subw $DELTA_INITSEG, %bp # aka INITSEG + movw %cs:start_sys_seg, %bx # start of source segment + cld +do_move: + movw %ax, %es # destination segment + incb %ah # instead of add ax,#0x100 + movw %bx, %ds # source segment + addw $0x100, %bx + subw %di, %di + subw %si, %si + movw $0x800, %cx + rep + movsw + cmpw %bp, %bx # assume start_sys_seg > 0x200, + # so we will perhaps read one + # page more than needed, but + # never overwrite INITSEG + # because destination is a + # minimum one page below source + jb do_move + +end_move: +# then we load the segment descriptors + movw %cs, %ax # aka SETUPSEG + movw %ax, %ds + +# Check whether we need to be downward compatible with version <=201 + cmpl $0, cmd_line_ptr + jne end_move_self # loader uses version >=202 features + cmpb $0x20, type_of_loader + je end_move_self # bootsect loader, we know of it + +# Boot loader doesnt support boot protocol version 2.02. +# If we have our code not at 0x90000, we need to move it there now. +# We also then need to move the params behind it (commandline) +# Because we would overwrite the code on the current IP, we move +# it in two steps, jumping high after the first one. + movw %cs, %ax + cmpw $SETUPSEG, %ax + je end_move_self + + cli # make sure we really have + # interrupts disabled ! + # because after this the stack + # should not be used + subw $DELTA_INITSEG, %ax # aka INITSEG + movw %ss, %dx + cmpw %ax, %dx + jb move_self_1 + + addw $INITSEG, %dx + subw %ax, %dx # this will go into %ss after + # the move +move_self_1: + movw %ax, %ds + movw $INITSEG, %ax # real INITSEG + movw %ax, %es + movw %cs:setup_move_size, %cx + std # we have to move up, so we use + # direction down because the + # areas may overlap + movw %cx, %di + decw %di + movw %di, %si + subw $move_self_here+0x200, %cx + rep + movsb + ljmp $SETUPSEG, $move_self_here + +move_self_here: + movw $move_self_here+0x200, %cx + rep + movsb + movw $SETUPSEG, %ax + movw %ax, %ds + movw %dx, %ss + +end_move_self: # now we are at the right place + lidt idt_48 # load idt with 0,0 + xorl %eax, %eax # Compute gdt_base + movw %ds, %ax # (Convert %ds:gdt to a linear ptr) + shll $4, %eax + addl $gdt, %eax + movl %eax, (gdt_48+2) + lgdt gdt_48 # load gdt with whatever is + # appropriate + +# that was painless, now we enable A20 + + outb %al, $0xf2 # A20 on + movb $0x02, %al + outb %al, $0xf6 # also A20 on; making ITF's + # way our model + + # PC-9800 seems to enable A20 at the moment of `outb'; + # so we don't wait unlike IBM PCs (see ../setup.S). + +# enable DMA to access memory over 0x100000 (1MB). + + movw $0x439, %dx + inb %dx, %al + andb $(~4), %al + outb %al, %dx + +# Set DMA to increment its bank address automatically at 16MB boundary. +# Initial setting is 64KB boundary mode so that we can't run DMA crossing +# physical address 0xXXXXFFFF. + + movb $0x0c, %al + outb %al, $0x29 # ch. 0 + movb $0x0d, %al + outb %al, $0x29 # ch. 1 + movb $0x0e, %al + outb %al, $0x29 # ch. 2 + movb $0x0f, %al + outb %al, $0x29 # ch. 3 + movb $0x50, %al + outb %al, $0x11 # reinitialize DMAC + +# make sure any possible coprocessor is properly reset.. + movb $0, %al + outb %al, $0xf8 + outb %al, $0x5f # delay + +# well, that went ok, I hope. Now we mask all interrupts - the rest +# is done in init_IRQ(). + movb $0xFF, %al # mask all interrupts for now + outb %al, $0x0A + outb %al, $0x5f # delay + + movb $0x7F, %al # mask all irq's but irq7 which + outb %al, $0x02 # is cascaded + +# Well, that certainly wasn't fun :-(. Hopefully it works, and we don't +# need no steenking BIOS anyway (except for the initial loading :-). +# The BIOS-routine wants lots of unnecessary data, and it's less +# "interesting" anyway. This is how REAL programmers do it. +# +# Well, now's the time to actually move into protected mode. To make +# things as simple as possible, we do no register set-up or anything, +# we let the gnu-compiled 32-bit programs do that. We just jump to +# absolute address 0x1000 (or the loader supplied one), +# in 32-bit protected mode. +# +# Note that the short jump isn't strictly needed, although there are +# reasons why it might be a good idea. It won't hurt in any case. + movw $1, %ax # protected mode (PE) bit + lmsw %ax # This is it! + jmp flush_instr + +flush_instr: + xorw %bx, %bx # Flag to indicate a boot + xorl %esi, %esi # Pointer to real-mode code + movw %cs, %si + subw $DELTA_INITSEG, %si + shll $4, %esi # Convert to 32-bit pointer +# NOTE: For high loaded big kernels we need a +# jmpi 0x100000,__BOOT_CS +# +# but we yet haven't reloaded the CS register, so the default size +# of the target offset still is 16 bit. +# However, using an operand prefix (0x66), the CPU will properly +# take our 48 bit far pointer. (INTeL 80386 Programmer's Reference +# Manual, Mixing 16-bit and 32-bit code, page 16-6) + + .byte 0x66, 0xea # prefix + jmpi-opcode +code32: .long 0x1000 # will be set to 0x100000 + # for big kernels + .word __BOOT_CS + +# Here's a bunch of information about your current kernel.. +kernel_version: .ascii UTS_RELEASE + .ascii " (" + .ascii LINUX_COMPILE_BY + .ascii "@" + .ascii LINUX_COMPILE_HOST + .ascii ") " + .ascii UTS_VERSION + .byte 0 + +# This is the default real mode switch routine. +# to be called just before protected mode transition +default_switch: + cli # no interrupts allowed ! + outb %al, $0x50 # disable NMI for bootup + # sequence + lret + +# This routine only gets called, if we get loaded by the simple +# bootsect loader _and_ have a bzImage to load. +# Because there is no place left in the 512 bytes of the boot sector, +# we must emigrate to code space here. +bootsect_helper: + cmpw $0, %cs:bootsect_es + jnz bootsect_second + + movb $0x20, %cs:type_of_loader + movw %es, %ax + shrw $4, %ax + movb %ah, %cs:bootsect_src_base+2 + movw %es, %ax + movw %ax, %cs:bootsect_es + subw $SYSSEG, %ax + lret # nothing else to do for now + +bootsect_second: + pushw %bx + pushw %cx + pushw %si + pushw %di + testw %bp, %bp # 64K full ? + jne bootsect_ex + + xorw %cx, %cx # zero means full 64K + pushw %cs + popw %es + movw $bootsect_gdt, %bx + xorw %si, %si # source address + xorw %di, %di # destination address + movb $0x90, %ah + int $0x1f + jc bootsect_panic # this, if INT1F fails + + movw %cs:bootsect_es, %es # we reset %es to always point + incb %cs:bootsect_dst_base+2 # to 0x10000 +bootsect_ex: + movb %cs:bootsect_dst_base+2, %ah + shlb $4, %ah # we now have the number of + # moved frames in %ax + xorb %al, %al + popw %di + popw %si + popw %cx + popw %bx + lret + +bootsect_gdt: + .word 0, 0, 0, 0 + .word 0, 0, 0, 0 + +bootsect_src: + .word 0xffff + +bootsect_src_base: + .byte 0x00, 0x00, 0x01 # base = 0x010000 + .byte 0x93 # typbyte + .word 0 # limit16,base24 =0 + +bootsect_dst: + .word 0xffff + +bootsect_dst_base: + .byte 0x00, 0x00, 0x10 # base = 0x100000 + .byte 0x93 # typbyte + .word 0 # limit16,base24 =0 + .word 0, 0, 0, 0 # BIOS CS + .word 0, 0, 0, 0 # BIOS DS + +bootsect_es: + .word 0 + +bootsect_panic: + pushw %cs + popw %ds + cld + leaw bootsect_panic_mess, %si + call prtstr + +bootsect_panic_loop: + jmp bootsect_panic_loop + +bootsect_panic_mess: + .string "INT1F refuses to access high mem, giving up." + +# This routine prints one character (in %al) on console. +# PC-9800 doesn't have BIOS-function to do it like IBM PC's INT 10h - 0Eh, +# so we hardcode `prtchr' subroutine here. +prtchr: + pushaw + pushw %es + cmpb $0, %cs:prtchr_initialized + jnz prtchr_ok + xorw %cx, %cx + movw %cx, %es + testb $0x8, %es:BIOS_FLAG + jz 1f + movb $(HIRESO_TEXT >> 8), %cs:cursor_address+3 + movw $(80 * 31 * 2), %cs:max_cursor_offset +1: pushw %ax + call get_cursor_position + movw %ax, %cs:cursor_address + popw %ax + movb $1, %cs:prtchr_initialized +prtchr_ok: + lesw %cs:cursor_address, %di + movw $160, %bx + movb $0, %ah + cmpb $13, %al + je do_cr + cmpb $10, %al + je do_lf + + # normal (printable) character + stosw + movb $0xe1, %es:0x2000-2(%di) + jmp 1f + +do_cr: movw %di, %ax + divb %bl # %al = Y, %ah = X * 2 + mulb %bl + movw %ax, %dx + jmp 2f + +do_lf: addw %bx, %di +1: movw %cs:max_cursor_offset, %cx + cmpw %cx, %di + movw %di, %dx + jb 2f + # cursor reaches bottom of screen; scroll it + subw %bx, %dx + xorw %di, %di + movw %bx, %si + cld + subw %bx, %cx + shrw %cx + pushw %cx + rep; es; movsw + movb $32, %al # clear bottom line characters + movb $80, %cl + rep; stosw + movw $0x2000, %di + popw %cx + leaw (%bx,%di), %si + rep; es; movsw + movb $0xe1, %al # clear bottom line attributes + movb $80, %cl + rep; stosw +2: movw %dx, %cs:cursor_address + movb $0x13, %ah # move cursor to right position + int $0x18 + popw %es + popaw + ret + +cursor_address: + .word 0 + .word NORMAL_TEXT +max_cursor_offset: + .word 80 * 25 * 2 # for normal 80x25 mode + +# putstr may called without running through start_of_setup (via bootsect_panic) +# so we should initialize ourselves on demand. +prtchr_initialized: + .byte 0 + +# This routine queries GDC (graphic display controller) for current cursor +# position. Cursor position is returned in %ax (CPU offset address). +get_cursor_position: +1: inb $0x60, %al + outb %al, $0x5f # delay + outb %al, $0x5f # delay + testb $0x04, %al # Is FIFO empty? + jz 1b # no -> wait until empty + + movb $0xe0, %al # CSRR command + outb %al, $0x62 # command write + outb %al, $0x5f # delay + outb %al, $0x5f # delay + +2: inb $0x60, %al + outb %al, $0x5f # delay + outb %al, $0x5f # delay + testb $0x01, %al # Is DATA READY? + jz 2b # no -> wait until ready + + inb $0x62, %al # read xAD (L) + outb %al, $0x5f # delay + outb %al, $0x5f # delay + movb %al, %ah + inb $0x62, %al # read xAD (H) + outb %al, $0x5f # delay + outb %al, $0x5f # delay + xchgb %al, %ah # correct byte order + pushw %ax + inb $0x62, %al # read yAD (L) + outb %al, $0x5f # delay + outb %al, $0x5f # delay + inb $0x62, %al # read yAD (M) + outb %al, $0x5f # delay + outb %al, $0x5f # delay + inb $0x62, %al # read yAD (H) + # yAD is not our interest, + # so discard it. + popw %ax + addw %ax, %ax # convert to CPU address + ret + +# Descriptor tables +# +# NOTE: The intel manual says gdt should be sixteen bytes aligned for +# efficiency reasons. However, there are machines which are known not +# to boot with misaligned GDTs, so alter this at your peril! If you alter +# GDT_ENTRY_BOOT_CS (in asm/segment.h) remember to leave at least two +# empty GDT entries (one for NULL and one reserved). +# +# NOTE: On some CPUs, the GDT must be 8 byte aligned. This is +# true for the Voyager Quad CPU card which will not boot without +# This directive. 16 byte aligment is recommended by intel. +# + .align 16 +gdt: + .fill GDT_ENTRY_BOOT_CS,8,0 + + .word 0xFFFF # 4Gb - (0x100000*0x1000 = 4Gb) + .word 0 # base address = 0 + .word 0x9A00 # code read/exec + .word 0x00CF # granularity = 4096, 386 + # (+5th nibble of limit) + + .word 0xFFFF # 4Gb - (0x100000*0x1000 = 4Gb) + .word 0 # base address = 0 + .word 0x9200 # data read/write + .word 0x00CF # granularity = 4096, 386 + # (+5th nibble of limit) +gdt_end: + .align 4 + + .word 0 # alignment byte +idt_48: + .word 0 # idt limit = 0 + .word 0, 0 # idt base = 0L + + .word 0 # alignment byte +gdt_48: + .word gdt_end - gdt - 1 # gdt limit + .word 0, 0 # gdt base (filled in later) + +# Include video setup & detection code + +#include "video.S" + +# Setup signature -- must be last +setup_sig1: .word SIG1 +setup_sig2: .word SIG2 + +# After this point, there is some free space which is used by the video mode +# handling code to store the temporary mode table (not used by the kernel). + +modelist: + +.text +endtext: +.data +enddata: +.bss +endbss: diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/arch/i386/boot98/tools/build.c linux.2.5.47-ac6/arch/i386/boot98/tools/build.c --- linux.2.5.47/arch/i386/boot98/tools/build.c 1970-01-01 01:00:00.000000000 +0100 +++ linux.2.5.47-ac6/arch/i386/boot98/tools/build.c 2002-10-31 15:05:52.000000000 +0000 @@ -0,0 +1,188 @@ +/* + * $Id: build.c,v 1.5 1997/05/19 12:29:58 mj Exp $ + * + * Copyright (C) 1991, 1992 Linus Torvalds + * Copyright (C) 1997 Martin Mares + */ + +/* + * This file builds a disk-image from three different files: + * + * - bootsect: exactly 512 bytes of 8086 machine code, loads the rest + * - setup: 8086 machine code, sets up system parm + * - system: 80386 code for actual system + * + * It does some checking that all files are of the correct type, and + * just writes the result to stdout, removing headers and padding to + * the right amount. It also writes some system data to stderr. + */ + +/* + * Changes by tytso to allow root device specification + * High loaded stuff by Hans Lermen & Werner Almesberger, Feb. 1996 + * Cross compiling fixes by Gertjan van Wingerde, July 1996 + * Rewritten by Martin Mares, April 1997 + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +typedef unsigned char byte; +typedef unsigned short word; +typedef unsigned long u32; + +#define DEFAULT_MAJOR_ROOT 0 +#define DEFAULT_MINOR_ROOT 0 + +/* Minimal number of setup sectors (see also bootsect.S) */ +#define SETUP_SECTS 4 + +byte buf[1024]; +int fd; +int is_big_kernel; + +void die(const char * str, ...) +{ + va_list args; + va_start(args, str); + vfprintf(stderr, str, args); + fputc('\n', stderr); + exit(1); +} + +void file_open(const char *name) +{ + if ((fd = open(name, O_RDONLY, 0)) < 0) + die("Unable to open `%s': %m", name); +} + +void usage(void) +{ + die("Usage: build [-b] bootsect setup system [rootdev] [> image]"); +} + +int main(int argc, char ** argv) +{ + unsigned int i, c, sz, setup_sectors; + u32 sys_size; + byte major_root, minor_root; + struct stat sb; + + if (argc > 2 && !strcmp(argv[1], "-b")) + { + is_big_kernel = 1; + argc--, argv++; + } + if ((argc < 4) || (argc > 5)) + usage(); + if (argc > 4) { + if (!strcmp(argv[4], "CURRENT")) { + if (stat("/", &sb)) { + perror("/"); + die("Couldn't stat /"); + } + major_root = major(sb.st_dev); + minor_root = minor(sb.st_dev); + } else if (strcmp(argv[4], "FLOPPY")) { + if (stat(argv[4], &sb)) { + perror(argv[4]); + die("Couldn't stat root device."); + } + major_root = major(sb.st_rdev); + minor_root = minor(sb.st_rdev); + } else { + major_root = 0; + minor_root = 0; + } + } else { + major_root = DEFAULT_MAJOR_ROOT; + minor_root = DEFAULT_MINOR_ROOT; + } + fprintf(stderr, "Root device is (%d, %d)\n", major_root, minor_root); + + file_open(argv[1]); + i = read(fd, buf, sizeof(buf)); + fprintf(stderr,"Boot sector %d bytes.\n",i); + if (i != 512) + die("Boot block must be exactly 512 bytes"); + if (buf[510] != 0x55 || buf[511] != 0xaa) + die("Boot block hasn't got boot flag (0xAA55)"); + buf[508] = minor_root; + buf[509] = major_root; + if (write(1, buf, 512) != 512) + die("Write call failed"); + close (fd); + + file_open(argv[2]); /* Copy the setup code */ + for (i=0 ; (c=read(fd, buf, sizeof(buf)))>0 ; i+=c ) + if (write(1, buf, c) != c) + die("Write call failed"); + if (c != 0) + die("read-error on `setup'"); + close (fd); + + setup_sectors = (i + 511) / 512; /* Pad unused space with zeros */ + if (!(setup_sectors & 1)) + setup_sectors++; /* setup_sectors must be odd on NEC PC-9800 */ + fprintf(stderr, "Setup is %d bytes.\n", i); + memset(buf, 0, sizeof(buf)); + while (i < setup_sectors * 512) { + c = setup_sectors * 512 - i; + if (c > sizeof(buf)) + c = sizeof(buf); + if (write(1, buf, c) != c) + die("Write call failed"); + i += c; + } + + file_open(argv[3]); + if (fstat (fd, &sb)) + die("Unable to stat `%s': %m", argv[3]); + sz = sb.st_size; + fprintf (stderr, "System is %d kB\n", sz/1024); + sys_size = (sz + 15) / 16; + /* 0x28000*16 = 2.5 MB, conservative estimate for the current maximum */ + if (sys_size > (is_big_kernel ? 0x28000 : DEF_SYSSIZE)) + die("System is too big. Try using %smodules.", + is_big_kernel ? "" : "bzImage or "); + if (sys_size > 0xefff) + fprintf(stderr,"warning: kernel is too big for standalone boot " + "from floppy\n"); + while (sz > 0) { + int l, n; + + l = (sz > sizeof(buf)) ? sizeof(buf) : sz; + if ((n=read(fd, buf, l)) != l) { + if (n < 0) + die("Error reading %s: %m", argv[3]); + else + die("%s: Unexpected EOF", argv[3]); + } + if (write(1, buf, l) != l) + die("Write failed"); + sz -= l; + } + close(fd); + + if (lseek(1, 497, SEEK_SET) != 497) /* Write sizes to the bootsector */ + die("Output: seek failed"); + buf[0] = setup_sectors; + if (write(1, buf, 1) != 1) + die("Write of setup sector count failed"); + if (lseek(1, 500, SEEK_SET) != 500) + die("Output: seek failed"); + buf[0] = (sys_size & 0xff); + buf[1] = ((sys_size >> 8) & 0xff); + if (write(1, buf, 2) != 2) + die("Write of image length failed"); + + return 0; /* Everything is OK */ +} diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/arch/i386/boot98/video.S linux.2.5.47-ac6/arch/i386/boot98/video.S --- linux.2.5.47/arch/i386/boot98/video.S 1970-01-01 01:00:00.000000000 +0100 +++ linux.2.5.47-ac6/arch/i386/boot98/video.S 2002-10-31 15:05:52.000000000 +0000 @@ -0,0 +1,262 @@ +/* video.S + * + * Video mode setup, etc. for NEC PC-9800 series. + * + * Copyright (C) 1997,98,99 Linux/98 project + * + * Based on the video.S for IBM PC: + * copyright (C) Martin Mares + */ + +/* Positions of various video parameters passed to the kernel */ +/* (see also include/linux/tty.h) */ +#define PARAM_CURSOR_POS 0x00 +#define PARAM_VIDEO_PAGE 0x04 +#define PARAM_VIDEO_MODE 0x06 +#define PARAM_VIDEO_COLS 0x07 +#define PARAM_VIDEO_EGA_BX 0x0a +#define PARAM_VIDEO_LINES 0x0e +#define PARAM_HAVE_VGA 0x0f +#define PARAM_FONT_POINTS 0x10 + +#define PARAM_VIDEO98_COMPAT 0x0a +#define PARAM_VIDEO98_HIRESO 0x0b +#define PARAM_VIDEO98_MACHTYPE 0x0c +#define PARAM_VIDEO98_LINES 0x0e +#define PARAM_VIDEO98_COLS 0x0f + +# PARAM_LFB_* and PARAM_VESAPM_* are unused on PC-9800. + +# This is the main entry point called by setup.S +# %ds *must* be pointing to the bootsector +video: xorw %ax, %ax + movw %ax, %es # %es = 0 + + movb %es:BIOS_FLAG, %al + movb %al, PARAM_VIDEO_MODE + + movb $0, PARAM_VIDEO98_HIRESO # 0 = normal + movw $NORMAL_TEXT, PARAM_VIDEO_PAGE + testb $0x8, %al + movw $(80 * 256 + 25), %ax + jz 1f + # hireso machine. + movb $1, PARAM_VIDEO98_HIRESO # !0 = hi-reso + movb $(HIRESO_TEXT >> 8), PARAM_VIDEO_PAGE + 1 + movw $(80 * 256 + 31), %ax +1: movw %ax, PARAM_VIDEO98_LINES # also sets VIDEO98_COLS + + movb $0xc0, %ch # 400-line graphic mode + movb $0x42, %ah + int $0x18 + + movw $80, PARAM_VIDEO_COLS + + movw $msg_probing, %si + call prtstr_cs + +# Check vendor from font pattern of `A'... + +1: inb $0x60, %al # wait V-sync + testb $0x20, %al + jnz 1b +2: inb $0x60, %al + testb $0x20, %al + jz 2b + + movb $0x00, %al # select font of `A' + outb %al, $0xa1 + movb $0x41, %al + outb %al, $0xa3 + + movw $8, %cx + movw PARAM_VIDEO_PAGE, %ax + cmpw $NORMAL_TEXT, %ax + je 3f + movb $24, %cl # for hi-reso machine +3: addw $0x400, %ax # %ax = CG window segment + pushw %ds + movw %ax, %ds + xorw %dx, %dx # get sum of `A' pattern... + xorw %si, %si +4: lodsw + addw %ax, %dx + loop 4b + popw %ds + + movw %dx, %ax + movw $msg_nec, %si + xorw %bx, %bx # vendor info will go into %bx + testb $8, %es:BIOS_FLAG + jnz check_hireso_vendor + cmpw $0xc7f8, %ax + je 5f + jmp 6f +check_hireso_vendor: + cmpw $0x9639, %ax # XXX: NOT VERIFIED!!! + je 5f +6: incw %bx # compatible machine + movw $msg_compat, %si +5: movb %bl, PARAM_VIDEO98_COMPAT + call prtstr_cs + + movw $msg_fontdata, %si + call prtstr_cs # " (CG sum of A = 0x" + movw %dx, %ax + call prthex + call prtstr_cs # ") PC-98" + + movb $'0', %al + pushw %ds + pushw $0xf8e8 + popw %ds + cmpw $0x2198, (0) + popw %ds + jne 7f + movb $'2', %al +7: call prtchr + call prtstr_cs # "1 " + + movb $0, PARAM_VIDEO98_MACHTYPE +#if 0 /* XXX - This check is bogus? [0000:BIOS_FLAG2]-bit7 does NOT + indicate whether it is a note machine, but merely indicates + whether it has ``RAM drive''. */ +# check note machine + testb $0x80, %es:BIOS_FLAG2 + jnz is_note + pushw %ds + pushw $0xfd80 + popw %ds + movb (4), %al + popw %ds + cmpb $0x20, %al # EPSON note A + je epson_note + cmpb $0x22, %al # EPSON note W + je epson_note + cmpb $0x27, %al # EPSON note AE + je epson_note + cmpb $0x2a, %al # EPSON note WR + jne note_done +epson_note: + movb $1, PARAM_VIDEO98_MACHTYPE + movw $msg_note, %si + call prtstr_cs +note_done: +#endif + +# print h98 ? (only NEC) + cmpb $0, PARAM_VIDEO98_COMPAT + jnz 8f # not NEC -> not H98 + + testb $0x80, %es:BIOS_FLAG5 + jz 8f # have NESA bus -> H98 + movw $msg_h98, %si + call prtstr_cs + orb $2, PARAM_VIDEO98_MACHTYPE +8: testb $0x40, %es:BIOS_FLAG5 + jz 9f + movw $msg_gs, %si + call prtstr_cs # only prints it :-) +9: + movw $msg_normal, %si # "normal" + testb $0x8, %es:BIOS_FLAG + jz 1f + movw $msg_hireso, %si +1: call prtstr_cs + + movw $msg_sysclk, %si + call prtstr_cs + movb $'5', %al + testb $0x80, %es:BIOS_FLAG + jz 2f + movb $'8', %al +2: call prtchr + call prtstr_cs + +#if 0 + testb $0x40, %es:(0x45c) + jz no_30line # no 30-line support + + movb %es:KB_SHFT_STS, %al + testb $0x01, %al # is SHIFT key pressed? + jz no_30line + + testb $0x10, %al # is CTRL key pressed? + jnz line40 + + # switch to 30-line mode + movb $30, PARAM_VIDEO98_LINES + movw $msg_30line, %si + jmp 3f + +line40: + movb $37, PARAM_VIDEO98_LINES + movw $40, PARAM_VIDEO_LINES + movw $msg_40line, %si +3: call prtstr_cs + + movb $0x32, %bh + movw $0x300c, %ax + int $0x18 # switch video mode + movb $0x0c, %ah + int $0x18 # turn on text plane + movw %cs:cursor_address, %dx + movb $0x13, %ah + int $0x18 # move cursor to correct place + mov $0x11, %ah + int $0x18 # turn on text plane + + call prtstr_cs # "Ok.\r\n" +no_30line: +#endif + ret + +prtstr_cs: + pushw %ds + pushw %cs + popw %ds + call prtstr + popw %ds + ret + +# prthex is for debugging purposes, and prints %ax in hexadecimal. +prthex: pushw %cx + movw $4, %cx +1: rolw $4, %ax + pushw %ax + andb $0xf, %al + cmpb $10, %al + sbbb $0x69, %al + das + call prtchr + popw %ax + loop 1b + popw %cx + ret + +msg_probing: .string "Probing machine: " + +msg_nec: .string "NEC" +msg_compat: .string "compatible" + +msg_fontdata: .string " (CG sum of A = 0x" + .string ") PC-98" + .string "1 " + +msg_gs: .string "(GS) " +msg_h98: .string "(H98) " + +msg_normal: .string "normal" +msg_hireso: .string "Hi-reso" + +msg_sysclk: .string " mode, system clock " + .string "MHz\r\n" + +#if 0 +msg_40line: # cpp will concat following lines, so the assembler can deal. + .ascii "\ +Video mode will be adjusted to 37-line (so-called ``40-line'') mode later.\r\n\ +THIS MODE MAY DAMAGE YOUR MONITOR PHYSICALLY. USE AT YOUR OWN RISK.\r\n" +msg_30line: .string "Switching video mode to 30-line (640x480) mode... " + .string "Ok.\r\n" +#endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/arch/i386/Kconfig linux.2.5.47-ac6/arch/i386/Kconfig --- linux.2.5.47/arch/i386/Kconfig 2002-11-11 16:39:08.000000000 +0000 +++ linux.2.5.47-ac6/arch/i386/Kconfig 2002-11-18 15:53:58.000000000 +0000 @@ -62,6 +62,7 @@ SL/SLC/SLC2/SLC3/SX/SX2 and UMC U5D or U5S. - "586" for generic Pentium CPUs lacking the TSC (time stamp counter) register. + - "MediaGX/Geode" for the NatSemi Geode and Cyrix MediaGX. - "Pentium-Classic" for the Intel Pentium. - "Pentium-MMX" for the Intel Pentium MMX. - "Pentium-Pro" for the Intel Pentium Pro/Celeron/Pentium II. @@ -126,6 +127,13 @@ treated almost like Pentium IIIs, but with a different cache shift. +config MGEODE + bool "MediaGX/Geode" + help + Select this option for a Cyrix MediaGX or National Semiconductor + Geode platform. This enables the user of some extended features + and passes the appropriate optimisation flags to GCC. + config MK6 bool "K6/K6-II/K6-III" help @@ -198,7 +206,7 @@ config X86_L1_CACHE_SHIFT int - default "5" if MWINCHIP3D || MWINCHIP2 || MWINCHIPC6 || MCRUSOE || MCYRIXIII || MK6 || MPENTIUMIII || M686 || M586MMX || M586TSC || M586 + default "5" if MWINCHIP3D || MWINCHIP2 || MWINCHIPC6 || MCRUSOE || MCYRIXIII || MK6 || MPENTIUMIII || M686 || M586MMX || M586TSC || M586 || MGEODE default "4" if MELAN || M486 || M386 default "6" if MK7 default "7" if MPENTIUM4 @@ -215,7 +223,7 @@ config X86_PPRO_FENCE bool - depends on M686 || M586MMX || M586TSC || M586 || M486 || M386 + depends on M686 || M586MMX || M586TSC || M586 || M486 || M386 || MGEODE default y config X86_F00F_BUG @@ -245,17 +253,12 @@ config X86_USE_STRING_486 bool - depends on MELAN || M586MMX || M586TSC || M586 || M486 + depends on MELAN || M586MMX || M586TSC || M586 || M486 || MGEODE default y config X86_ALIGNMENT_16 bool - depends on MWINCHIP3D || MWINCHIP2 || MWINCHIPC6 || MCYRIXIII || MELAN || MK6 || M586MMX || M586TSC || M586 || M486 - default y - -config X86_TSC - bool - depends on MWINCHIP3D || MWINCHIP2 || MCRUSOE || MCYRIXIII || MK7 || MK6 || MPENTIUM4 || MPENTIUMIII || M686 || M586MMX || M586TSC + depends on MWINCHIP3D || MWINCHIP2 || MWINCHIPC6 || MCYRIXIII || MELAN || MK6 || M586MMX || M586TSC || M586 || M486 || MGEODE default y config X86_GOOD_APIC @@ -278,9 +281,13 @@ depends on MCYRIXIII || MK7 default y +config X86_HAVE_CMOV + depends on M686 || MPENTIUMIII || MPENTIUMIV || MK7 || MCRUSOE + default y + config X86_OOSTORE bool - depends on MWINCHIP3D || MWINCHIP2 || MWINCHIPC6 + depends on MWINCHIP3D || MWINCHIP2 || MWINCHIPC6 || MGEODE default y config HUGETLB_PAGE @@ -335,8 +342,21 @@ Say Y here if you are building a kernel for a desktop, embedded or real-time system. Say N if you are unsure. +config VOYAGER + bool "NCR Voyager Architecture" + ---help--- + Voyager is a MCA based 32 way capable SMP architecture proprietary + to NCR Corp. Machine classes 345x/35xx/4100/51xx are voyager based. + + *** WARNING *** + + If you do not specifically know you have a Voyager based machine, + say N here otherwise the kernel you build will not be bootable. + + config X86_UP_APIC bool "Local APIC support on uniprocessors" if !SMP + depends on !VOYAGER ---help--- A local APIC (Advanced Programmable Interrupt Controller) is an integrated interrupt controller in the CPU. If you have a single-CPU @@ -429,6 +449,10 @@ depends on NUMA default y +config X86_CYCLONE + bool "Cyclone Counter Support" + depends on X86_NUMA + config X86_MCE bool "Machine Check Exception" ---help--- @@ -455,8 +479,8 @@ Disable this if you don't want to see these messages. Seeing the messages this option prints out may be indicative of dying hardware, or out-of-spec (ie, overclocked) hardware. - This option only does something on certain CPUs. - (AMD Athlon/Duron and Intel Pentium 4) + This option only does something on certain CPUs. + (AMD Athlon/Duron and Intel Pentium 4) config X86_MCE_P4THERMAL bool "check for P4 thermal throttling interrupt." @@ -788,6 +812,7 @@ menu "Power management options (ACPI, APM)" + depends on !VOYAGER source "drivers/acpi/Kconfig" @@ -971,11 +996,12 @@ config X86_LOCAL_APIC bool - depends on !VISWS && SMP || VISWS + depends on ((!VISWS && SMP) || VISWS) && !VOYAGER default y config PCI bool "PCI support" if !VISWS + depends on !VOYAGER default y if VISWS help Find out whether you have a PCI motherboard. PCI is the name of a @@ -990,7 +1016,7 @@ config X86_IO_APIC bool - depends on !VISWS && SMP + depends on !VISWS && SMP && !VOYAGER default y choice @@ -1034,6 +1060,7 @@ config SCx200 tristate "NatSemi SCx200 support" + depends on !VOYAGER help This provides basic support for the National Semiconductor SCx200 processor. Right now this is just a driver for the GPIO pins. @@ -1047,6 +1074,7 @@ config ISA bool "ISA support" + depends on !VOYAGER help Find out whether you have ISA slots on your motherboard. ISA is the name of a bus system, i.e. the way the CPU talks to the other stuff @@ -1071,8 +1099,9 @@ Otherwise, say N. config MCA - bool "MCA support" + bool "MCA support" if !VOYAGER depends on !VISWS + default y if VOYAGER help MicroChannel Architecture is found in some IBM PS/2 machines and laptops. It is a bus system similar to PCI or ISA. See @@ -1612,14 +1641,41 @@ symbolic stack backtraces. This increases the size of the kernel somewhat, as all symbols have to be loaded into the kernel image. +config X86_STACK_CHECK + bool "Check for stack overflows" + depends on DEBUG_KERNEL + help + Say Y here to have the kernel attempt to detect when the per-task + kernel stack overflows. + + Some older versions of gcc don't handle the -p option correctly. + Kernprof is affected by the same problem, which is described here: + http://oss.sgi.com/projects/kernprof/faq.html#Q9 + + Basically, if you get oopses in __free_pages_ok during boot when + you have this turned on, you need to fix gcc. The Redhat 2.96 + version and gcc-3.x seem to work. + + If not debugging a stack overflow problem, say N + +config FRAME_POINTER + bool + depends on X86_STACK_CHECK + default y + +config IOMMU_DEBUG + bool + depends on DEBUG_KERNEL + default y + config X86_EXTRA_IRQS bool - depends on X86_LOCAL_APIC + depends on X86_LOCAL_APIC || VOYAGER default y config X86_FIND_SMP_CONFIG bool - depends on X86_LOCAL_APIC + depends on X86_LOCAL_APIC || VOYAGER default y config X86_MPPARSE @@ -1637,15 +1693,20 @@ config X86_SMP bool - depends on SMP + depends on SMP && !VOYAGER default y config X86_HT bool - depends on SMP + depends on SMP && !VOYAGER default y config X86_BIOS_REBOOT bool + depends on !VOYAGER default y +config X86_TRAMPOLINE + bool + depends on SMP + default y diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/arch/i386/kernel/apic.c linux.2.5.47-ac6/arch/i386/kernel/apic.c --- linux.2.5.47/arch/i386/kernel/apic.c 2002-10-31 14:57:24.000000000 +0000 +++ linux.2.5.47-ac6/arch/i386/kernel/apic.c 2002-11-15 16:06:07.000000000 +0000 @@ -33,6 +33,8 @@ #include #include "mach_apic.h" +#include "io_ports.h" + void __init apic_intr_init(void) { #ifdef CONFIG_SMP @@ -759,9 +761,9 @@ spin_lock_irqsave(&i8253_lock, flags); - outb_p(0x00, 0x43); - count = inb_p(0x40); - count |= inb_p(0x40) << 8; + outb_p(0x00, PIT_MODE); + count = inb_p(PIT_CH0); + count |= inb_p(PIT_CH0) << 8; spin_unlock_irqrestore(&i8253_lock, flags); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/arch/i386/kernel/cpu/common.c linux.2.5.47-ac6/arch/i386/kernel/cpu/common.c --- linux.2.5.47/arch/i386/kernel/cpu/common.c 2002-11-11 16:39:08.000000000 +0000 +++ linux.2.5.47-ac6/arch/i386/kernel/cpu/common.c 2002-11-17 00:19:07.000000000 +0000 @@ -1,6 +1,7 @@ #include #include #include +#include #include #include #include @@ -15,8 +16,6 @@ struct cpu_dev * cpu_devs[X86_VENDOR_NUM] = {}; -extern void mcheck_init(struct cpuinfo_x86 *c); - static void default_init(struct cpuinfo_x86 * c) { /* Not much we can do here... */ @@ -42,25 +41,6 @@ } __setup("cachesize=", cachesize_setup); -#ifndef CONFIG_X86_TSC -static int tsc_disable __initdata = 0; - -static int __init tsc_setup(char *str) -{ - tsc_disable = 1; - return 1; -} -#else -#define tsc_disable 0 - -static int __init tsc_setup(char *str) -{ - printk("notsc: Kernel compiled with CONFIG_X86_TSC, cannot disable TSC.\n"); - return 1; -} -#endif -__setup("notsc", tsc_setup); - int __init get_model_name(struct cpuinfo_x86 *c) { unsigned int *v; @@ -362,17 +342,6 @@ mcheck_init(c); #endif } -/* - * Perform early boot up checks for a valid TSC. See arch/i386/kernel/time.c - */ - -void __init dodgy_tsc(void) -{ - get_cpu_vendor(&boot_cpu_data); - if (( boot_cpu_data.x86_vendor == X86_VENDOR_CYRIX ) || - ( boot_cpu_data.x86_vendor == X86_VENDOR_NSC )) - cpu_devs[X86_VENDOR_CYRIX]->c_init(&boot_cpu_data); -} void __init print_cpu_info(struct cpuinfo_x86 *c) { diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/arch/i386/kernel/cpu/cpufreq/longhaul.c linux.2.5.47-ac6/arch/i386/kernel/cpu/cpufreq/longhaul.c --- linux.2.5.47/arch/i386/kernel/cpu/cpufreq/longhaul.c 2002-10-31 14:57:23.000000000 +0000 +++ linux.2.5.47-ac6/arch/i386/kernel/cpu/cpufreq/longhaul.c 2002-11-12 15:30:54.000000000 +0000 @@ -1,5 +1,5 @@ /* - * $Id: longhaul.c,v 1.72 2002/09/29 23:43:10 db Exp $ + * $Id: longhaul.c,v 1.77 2002/10/31 21:17:40 db Exp $ * * (C) 2001 Dave Jones. * (C) 2002 Padraig Brady. @@ -436,8 +436,10 @@ switch (longhaul) { case 1: /* Ugh, Longhaul v1 didn't have the min/max MSRs. - Assume max = whatever we booted at. */ + Assume min=3.0x & max = whatever we booted at. */ + minmult = 30; maxmult = longhaul_get_cpu_mult(); + minfsb = maxfsb = current_fsb; break; case 2 ... 3: diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/arch/i386/kernel/cpu/cyrix.c linux.2.5.47-ac6/arch/i386/kernel/cpu/cyrix.c --- linux.2.5.47/arch/i386/kernel/cpu/cyrix.c 2002-11-11 16:39:08.000000000 +0000 +++ linux.2.5.47-ac6/arch/i386/kernel/cpu/cyrix.c 2002-11-15 02:02:21.000000000 +0000 @@ -106,6 +106,89 @@ } } + +static void __init set_cx86_reorder(void) +{ +#ifdef CONFIG_OOSTORE + u8 ccr3; + + printk(KERN_INFO "Enable Memory access reorder on Cyrix/NSC processor.\n"); + ccr3 = getCx86(CX86_CCR3); + setCx86(CX86_CCR3, (ccr3 & 0x0f) | 0x10); /* enable MAPEN  */ + + /* Load/Store Serialize to mem access disable (=reorder it)  */ + setCx86(CX86_PCR0, getCx86(CX86_PCR0) & ~0x80); +#ifdef CONFIG_NOHIGHMEM + /* set load/store serialize from 1GB to 4GB */ + ccr3 |= 0xe0; +#endif + setCx86(CX86_CCR3, ccr3); +#endif +} + +static void __init set_cx86_memwb(void) +{ + u32 cr0; + + printk(KERN_INFO "Enable Memory-Write-back mode on Cyrix/NSC processor.\n"); + + /* CCR2 bit 2: unlock NW bit */ + setCx86(CX86_CCR2, getCx86(CX86_CCR2) & ~0x04); + /* set 'Not Write-through' */ + cr0 = 0x20000000; + __asm__("movl %%cr0,%%eax\n\t" + "orl %0,%%eax\n\t" + "movl %%eax,%%cr0\n" + : : "r" (cr0) + :"ax"); + /* CCR2 bit 2: lock NW bit and set WT1 */ + setCx86(CX86_CCR2, getCx86(CX86_CCR2) | 0x14 ); +} + +static void __init set_cx86_inc(void) +{ + unsigned char ccr3; + + printk(KERN_INFO "Enable Incrementor on Cyrix/NSC processor.\n"); + + ccr3 = getCx86(CX86_CCR3); + setCx86(CX86_CCR3, (ccr3 & 0x0f) | 0x10); /* enable MAPEN  */ + /* PCR1 -- Performance Control */ + /* Incrementor on, whatever that is */ + setCx86(CX86_PCR1, getCx86(CX86_PCR1) | 0x02); + /* PCR0 -- Performance Control */ + /* Incrementor Margin 10 */ + setCx86(CX86_PCR0, getCx86(CX86_PCR0) | 0x04); + setCx86(CX86_CCR3, ccr3); /* disable MAPEN */ +} + +/* + * Configure later MediaGX and/or Geode processor. + */ + +static void __init geode_configure(void) +{ + unsigned long flags; + u8 ccr3, ccr4; + unsigned long cr0; + local_irq_save(flags); + + ccr3 = getCx86(CX86_CCR3); + setCx86(CX86_CCR3, (ccr3 & 0x0f) | 0x10); /* Enable */ + + ccr4 = getCx86(CX86_CCR4); + ccr4 |= 0x38; /* FPU fast, DTE cache, Mem bypass */ + + setCx86(CX86_CCR3, ccr3); + + set_cx86_memwb(); + set_cx86_reorder(); + set_cx86_inc(); + + local_irq_restore(flags); +} + + static void __init init_cyrix(struct cpuinfo_x86 *c) { unsigned char dir0, dir0_msn, dir0_lsn, dir1 = 0; @@ -201,7 +284,10 @@ if (c->cpuid_level == 2) { /* Enable cxMMX extensions (GX1 Datasheet 54) */ setCx86(CX86_CCR7, getCx86(CX86_CCR7)|1); - + + /* GXlv/GXm/GX1 */ + if((dir1 >= 0x50 && dir1 <= 0x54) || dir1 >= 0x63) + geode_configure(); get_model_name(c); /* get CPU marketing name */ return; } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/arch/i386/kernel/cpu/proc.c linux.2.5.47-ac6/arch/i386/kernel/cpu/proc.c --- linux.2.5.47/arch/i386/kernel/cpu/proc.c 2002-11-05 13:54:42.000000000 +0000 +++ linux.2.5.47-ac6/arch/i386/kernel/cpu/proc.c 2002-11-17 00:19:07.000000000 +0000 @@ -74,7 +74,7 @@ /* Cache size */ if (c->x86_cache_size >= 0) seq_printf(m, "cache size\t: %d KB\n", c->x86_cache_size); -#ifdef CONFIG_SMP +#ifdef CONFIG_X86_HT if (cpu_has_ht) { extern int phys_proc_id[NR_CPUS]; seq_printf(m, "physical id\t: %d\n", phys_proc_id[n]); @@ -83,7 +83,7 @@ #endif /* We use exception 16 if we have hardware math and we've either seen it or the CPU claims it is internal */ - fpu_exception = c->hard_math && (ignore_irq13 || cpu_has_fpu); + fpu_exception = c->hard_math && (ignore_fpu_irq || cpu_has_fpu); seq_printf(m, "fdiv_bug\t: %s\n" "hlt_bug\t\t: %s\n" "f00f_bug\t: %s\n" diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/arch/i386/kernel/dmi_scan.c linux.2.5.47-ac6/arch/i386/kernel/dmi_scan.c --- linux.2.5.47/arch/i386/kernel/dmi_scan.c 2002-10-31 15:05:00.000000000 +0000 +++ linux.2.5.47-ac6/arch/i386/kernel/dmi_scan.c 2002-11-04 14:15:46.000000000 +0000 @@ -288,6 +288,23 @@ return 0; } + +/* + * Some BIOS32 PnP corrupt memory or just plain do not work + */ + +static __init int pnpbios_is_horked(struct dmi_blacklist *d) +{ + if (! (dmi_broken & BROKEN_PNP_BIOS)) + { + /* In the absence of the party responsible we'll have to + settle for just disabling the functionality */ + dmi_broken |= BROKEN_PNP_BIOS; + printk(KERN_INFO "%s machine detected. Disabling BIOS plug and play.\n", d->ident); + } + return 0; +} + /* * Some machines, usually laptops, can't handle an enabled local APIC. * The symptoms include hangs or reboots when suspending or resuming, @@ -773,7 +790,13 @@ MATCH(DMI_PRODUCT_VERSION, "HP Pavilion Notebook Model GE"), MATCH(DMI_BOARD_VERSION, "OmniBook N32N-736") } }, - + + { pnpbios_is_horked, "Gateway Solo 5300 seriels laptop", { /* PnPBIOS crashes */ + MATCH(DMI_SYS_VENDOR, "Gateway"), + MATCH(DMI_BIOS_VERSION, "22.07"), + MATCH(DMI_PRODUCT_NAME, "Solo5300"), + NO_MATCH + } }, /* * Generic per vendor APM settings diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/arch/i386/kernel/entry.S linux.2.5.47-ac6/arch/i386/kernel/entry.S --- linux.2.5.47/arch/i386/kernel/entry.S 2002-11-11 16:39:08.000000000 +0000 +++ linux.2.5.47-ac6/arch/i386/kernel/entry.S 2002-11-15 02:07:03.000000000 +0000 @@ -66,7 +66,9 @@ OLDSS = 0x38 CF_MASK = 0x00000001 +TF_MASK = 0x00000100 IF_MASK = 0x00000200 +DF_MASK = 0x00000400 NT_MASK = 0x00004000 VM_MASK = 0x00020000 @@ -134,9 +136,20 @@ movl %eax,EFLAGS(%esp) # movl %edx,EIP(%esp) # Now we move them to their "normal" places movl %ecx,CS(%esp) # + + # + # Call gates don't clear TF and NT in eflags like + # traps do, so we need to do it ourselves. + # %eax already contains eflags (but it may have + # DF set, clear that also) + # + andl $~(DF_MASK | TF_MASK | NT_MASK),%eax + pushl %eax + popfl + movl %esp, %ebx pushl %ebx - andl $-8192, %ebx # GET_THREAD_INFO + GET_THREAD_INFO_WITH_ESP(%ebx) # GET_THREAD_INFO movl TI_EXEC_DOMAIN(%ebx), %edx # Get the execution domain movl 4(%edx), %edx # Get the lcall7 handler for the domain pushl $0x7 @@ -156,9 +169,20 @@ movl %eax,EFLAGS(%esp) # movl %edx,EIP(%esp) # Now we move them to their "normal" places movl %ecx,CS(%esp) # + + # + # Call gates don't clear TF and NT in eflags like + # traps do, so we need to do it ourselves. + # %eax already contains eflags (but it may have + # DF set, clear that also) + # + andl $~(DF_MASK | TF_MASK | NT_MASK),%eax + pushl %eax + popfl + movl %esp, %ebx pushl %ebx - andl $-8192, %ebx # GET_THREAD_INFO + GET_THREAD_INFO_WITH_ESP(%ebx) # GET_THREAD_INFO movl TI_EXEC_DOMAIN(%ebx), %edx # Get the execution domain movl 4(%edx), %edx # Get the lcall7 handler for the domain pushl $0x27 @@ -334,7 +358,45 @@ ALIGN common_interrupt: SAVE_ALL + + + GET_THREAD_INFO(%ebx) + movl TI_IRQ_STACK(%ebx),%ecx + movl TI_TASK(%ebx),%edx + movl %esp,%eax + leal (THREAD_SIZE-4)(%ecx),%esi # %ecx+THREAD_SIZE is next stack + # -4 keeps us in the right one + testl %ecx,%ecx # is there a valid irq_stack? + + # switch to the irq stack +#ifdef CONFIG_X86_HAVE_CMOV + cmovnz %esi,%esp +#else + jz 1f + mov %esi,%esp +1: +#endif + + # update the task pointer in the irq stack + GET_THREAD_INFO(%esi) + movl %edx,TI_TASK(%esi) + + # update the preempt count in the irq stack + movl TI_PRE_COUNT(%ebx),%ecx + movl %ecx,TI_PRE_COUNT(%esi) + call do_IRQ + + movl %eax,%esp # potentially restore non-irq stack + + # copy flags from the irq stack back into the task's thread_info + # %esi is saved over the do_IRQ call and contains the irq stack + # thread_info pointer + # %ebx contains the original thread_info pointer + movl TI_FLAGS(%esi),%eax + movl $0,TI_FLAGS(%esi) + LOCK orl %eax,TI_FLAGS(%ebx) + jmp ret_from_intr #define BUILD_INTERRUPT(name, nr) \ @@ -483,6 +545,61 @@ pushl $do_spurious_interrupt_bug jmp error_code + +#ifdef CONFIG_X86_STACK_CHECK +.data + .globl stack_overflowed +stack_overflowed: + .long 0 +.text + +ENTRY(mcount) + push %eax + movl $(THREAD_SIZE - 1),%eax + andl %esp,%eax + cmpl $STACK_WARN,%eax /* more than half the stack is used*/ + jle 1f +2: + popl %eax + ret +1: + lock; btsl $0,stack_overflowed + jc 2b + + # switch to overflow stack + movl %esp,%eax + movl $(stack_overflow_stack + THREAD_SIZE - 4),%esp + + pushf + cli + pushl %eax + + # push eip then esp of error for stack_overflow_panic + pushl 4(%eax) + pushl %eax + + # update the task pointer and cpu in the overflow stack's thread_info. + GET_THREAD_INFO_WITH_ESP(%eax) + movl TI_TASK(%eax),%ebx + movl %ebx,stack_overflow_stack+TI_TASK + movl TI_CPU(%eax),%ebx + movl %ebx,stack_overflow_stack+TI_CPU + + call stack_overflow + + # pop off call arguments + addl $8,%esp + + popl %eax + popf + movl %eax,%esp + popl %eax + movl $0,stack_overflowed + ret + +#warning stack check enabled +#endif + .data ENTRY(sys_call_table) .long sys_ni_syscall /* 0 - old "setup()" system call*/ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/arch/i386/kernel/head.S linux.2.5.47-ac6/arch/i386/kernel/head.S --- linux.2.5.47/arch/i386/kernel/head.S 2002-10-31 14:57:24.000000000 +0000 +++ linux.2.5.47-ac6/arch/i386/kernel/head.S 2002-11-11 20:23:28.000000000 +0000 @@ -1,5 +1,5 @@ /* - * linux/arch/i386/head.S -- the 32-bit startup code. + * linux/arch/i386/kernel/head.S -- the 32-bit startup code. * * Copyright (C) 1991, 1992 Linus Torvalds * @@ -15,6 +15,8 @@ #include #include #include +#include +#include #define OLD_CL_MAGIC_ADDR 0x90020 #define OLD_CL_MAGIC 0xA33F @@ -46,7 +48,7 @@ * Set segments to known values */ cld - movl $(__KERNEL_DS),%eax + movl $(__BOOT_DS),%eax movl %eax,%ds movl %eax,%es movl %eax,%fs @@ -305,8 +307,8 @@ ret ENTRY(stack_start) - .long init_thread_union+8192 - .long __KERNEL_DS + .long init_thread_union+THREAD_SIZE + .long __BOOT_DS /* This is the default interrupt "handler" :-) */ int_msg: @@ -349,12 +351,12 @@ .long idt_table # boot GDT descriptor (later on used by CPU#0): - + .word 0 # 32 bit align gdt_desc.address cpu_gdt_descr: .word GDT_ENTRIES*8-1 .long cpu_gdt_table - .fill NR_CPUS-1,6,0 # space for the other GDT descriptors + .fill NR_CPUS-1,8,0 # space for the other GDT descriptors /* * This is initialized to create an identity-mapping at 0-8M (for bootup @@ -405,10 +407,21 @@ */ .data -ALIGN /* * The Global Descriptor Table contains 28 quadwords, per-CPU. */ +#ifdef CONFIG_SMP +/* + * The boot_gdt_table must mirror the equivalent in setup.S and is + * used only by the trampoline for booting other CPUs + */ + .align L1_CACHE_BYTES +ENTRY(boot_gdt_table) + .fill GDT_ENTRY_BOOT_CS,8,0 + .quad 0x00cf9a000000ffff /* kernel 4GB code at 0x00000000 */ + .quad 0x00cf92000000ffff /* kernel 4GB data at 0x00000000 */ +#endif + .align L1_CACHE_BYTES ENTRY(cpu_gdt_table) .quad 0x0000000000000000 /* NULL descriptor */ .quad 0x0000000000000000 /* 0x0b reserved */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/arch/i386/kernel/i386_ksyms.c linux.2.5.47-ac6/arch/i386/kernel/i386_ksyms.c --- linux.2.5.47/arch/i386/kernel/i386_ksyms.c 2002-11-05 13:54:42.000000000 +0000 +++ linux.2.5.47-ac6/arch/i386/kernel/i386_ksyms.c 2002-11-05 14:00:33.000000000 +0000 @@ -216,3 +216,8 @@ EXPORT_SYMBOL(edd); EXPORT_SYMBOL(eddnr); #endif + +#ifdef CONFIG_X86_STACK_CHECK +extern void mcount(void); +EXPORT_SYMBOL_NOVERS(mcount); +#endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/arch/i386/kernel/i8259.c linux.2.5.47-ac6/arch/i386/kernel/i8259.c --- linux.2.5.47/arch/i386/kernel/i8259.c 2002-10-31 14:57:24.000000000 +0000 +++ linux.2.5.47-ac6/arch/i386/kernel/i8259.c 2002-10-31 15:05:48.000000000 +0000 @@ -25,6 +25,8 @@ #include +#include "io_ports.h" + /* * This is the 'legacy' 8259A Programmable Interrupt Controller, * present in the majority of PC/AT boxes. @@ -74,8 +76,8 @@ static unsigned int cached_irq_mask = 0xffff; #define __byte(x,y) (((unsigned char *)&(y))[x]) -#define cached_21 (__byte(0,cached_irq_mask)) -#define cached_A1 (__byte(1,cached_irq_mask)) +#define cached_master_mask (__byte(0,cached_irq_mask)) +#define cached_slave_mask (__byte(1,cached_irq_mask)) /* * Not all IRQs can be routed through the IO-APIC, eg. on certain (older) @@ -96,9 +98,9 @@ spin_lock_irqsave(&i8259A_lock, flags); cached_irq_mask |= mask; if (irq & 8) - outb(cached_A1,0xA1); + outb(cached_slave_mask, PIC_SLAVE_IMR); else - outb(cached_21,0x21); + outb(cached_master_mask, PIC_MASTER_IMR); spin_unlock_irqrestore(&i8259A_lock, flags); } @@ -110,9 +112,9 @@ spin_lock_irqsave(&i8259A_lock, flags); cached_irq_mask &= mask; if (irq & 8) - outb(cached_A1,0xA1); + outb(cached_slave_mask, PIC_SLAVE_IMR); else - outb(cached_21,0x21); + outb(cached_master_mask, PIC_MASTER_IMR); spin_unlock_irqrestore(&i8259A_lock, flags); } @@ -124,9 +126,9 @@ spin_lock_irqsave(&i8259A_lock, flags); if (irq < 8) - ret = inb(0x20) & mask; + ret = inb(PIC_MASTER_CMD) & mask; else - ret = inb(0xA0) & (mask >> 8); + ret = inb(PIC_SLAVE_CMD) & (mask >> 8); spin_unlock_irqrestore(&i8259A_lock, flags); return ret; @@ -152,14 +154,14 @@ int irqmask = 1<> 8); - outb(0x0A,0xA0); /* back to the IRR register */ + outb(0x0B,PIC_SLAVE_CMD); /* ISR register */ + value = inb(PIC_SLAVE_CMD) & (irqmask >> 8); + outb(0x0A,PIC_SLAVE_CMD); /* back to the IRR register */ return value; } @@ -196,14 +198,14 @@ handle_real_irq: if (irq & 8) { - inb(0xA1); /* DUMMY - (do we need this?) */ - outb(cached_A1,0xA1); - outb(0x60+(irq&7),0xA0);/* 'Specific EOI' to slave */ - outb(0x62,0x20); /* 'Specific EOI' to master-IRQ2 */ + inb(PIC_SLAVE_IMR); /* DUMMY - (do we need this?) */ + outb(cached_slave_mask, PIC_SLAVE_IMR); + outb(0x60+(irq&7),PIC_SLAVE_CMD);/* 'Specific EOI' to slave */ + outb(0x60+PIC_CASCADE_IR,PIC_MASTER_CMD); /* 'Specific EOI' to master-IRQ2 */ } else { - inb(0x21); /* DUMMY - (do we need this?) */ - outb(cached_21,0x21); - outb(0x60+irq,0x20); /* 'Specific EOI' to master */ + inb(PIC_MASTER_IMR); /* DUMMY - (do we need this?) */ + outb(cached_master_mask, PIC_MASTER_IMR); + outb(0x60+irq,PIC_MASTER_CMD); /* 'Specific EOI to master */ } spin_unlock_irqrestore(&i8259A_lock, flags); return; @@ -275,26 +277,24 @@ spin_lock_irqsave(&i8259A_lock, flags); - outb(0xff, 0x21); /* mask all of 8259A-1 */ - outb(0xff, 0xA1); /* mask all of 8259A-2 */ + outb(0xff, PIC_MASTER_IMR); /* mask all of 8259A-1 */ + outb(0xff, PIC_SLAVE_IMR); /* mask all of 8259A-2 */ /* * outb_p - this has to work on a wide range of PC hardware. */ - outb_p(0x11, 0x20); /* ICW1: select 8259A-1 init */ - outb_p(0x20 + 0, 0x21); /* ICW2: 8259A-1 IR0-7 mapped to 0x20-0x27 */ - outb_p(0x04, 0x21); /* 8259A-1 (the master) has a slave on IR2 */ - if (auto_eoi) - outb_p(0x03, 0x21); /* master does Auto EOI */ - else - outb_p(0x01, 0x21); /* master expects normal EOI */ - - outb_p(0x11, 0xA0); /* ICW1: select 8259A-2 init */ - outb_p(0x20 + 8, 0xA1); /* ICW2: 8259A-2 IR0-7 mapped to 0x28-0x2f */ - outb_p(0x02, 0xA1); /* 8259A-2 is a slave on master's IR2 */ - outb_p(0x01, 0xA1); /* (slave's support for AEOI in flat mode - is to be investigated) */ - + outb_p(0x11, PIC_MASTER_CMD); /* ICW1: select 8259A-1 init */ + outb_p(0x20 + 0, PIC_MASTER_IMR); /* ICW2: 8259A-1 IR0-7 mapped to 0x20-0x27 */ + outb_p(1U << PIC_CASCADE_IR, PIC_MASTER_IMR); /* 8259A-1 (the master) has a slave on IR2 */ + if (auto_eoi) /* master does Auto EOI */ + outb_p(MASTER_ICW4_DEFAULT | PIC_ICW4_AEOI, PIC_MASTER_IMR); + else /* master expects normal EOI */ + outb_p(MASTER_ICW4_DEFAULT, PIC_MASTER_IMR); + + outb_p(0x11, PIC_SLAVE_CMD); /* ICW1: select 8259A-2 init */ + outb_p(0x20 + 8, PIC_SLAVE_IMR); /* ICW2: 8259A-2 IR0-7 mapped to 0x28-0x2f */ + outb_p(PIC_CASCADE_IR, PIC_SLAVE_IMR); /* 8259A-2 is a slave on master's IR2 */ + outb_p(SLAVE_ICW4_DEFAULT, PIC_SLAVE_IMR); /* (slave's support for AEOI in flat mode is to be investigated) */ if (auto_eoi) /* * in AEOI mode we just have to mask the interrupt @@ -306,8 +306,8 @@ udelay(100); /* wait for 8259A to initialize */ - outb(cached_21, 0x21); /* restore master IRQ mask */ - outb(cached_A1, 0xA1); /* restore slave IRQ mask */ + outb(cached_master_mask, PIC_MASTER_IMR); /* restore master IRQ mask */ + outb(cached_slave_mask, PIC_SLAVE_IMR); /* restore slave IRQ mask */ spin_unlock_irqrestore(&i8259A_lock, flags); } @@ -324,11 +324,17 @@ * be shot. */ +/* + * =PC9800NOTE= In NEC PC-9800, we use irq8 instead of irq13! + */ + static void math_error_irq(int cpl, void *dev_id, struct pt_regs *regs) { extern void math_error(void *); +#ifndef CONFIG_PC9800 outb(0,0xF0); - if (ignore_irq13 || !boot_cpu_data.hard_math) +#endif + if (ignore_fpu_irq || !boot_cpu_data.hard_math) return; math_error((void *)regs->eip); } @@ -337,7 +343,7 @@ * New motherboards sometimes make IRQ 13 be a PCI interrupt, * so allow interrupt sharing. */ -static struct irqaction irq13 = { math_error_irq, 0, 0, "fpu", NULL, NULL }; +static struct irqaction fpu_irq = { math_error_irq, 0, 0, "fpu", NULL, NULL }; void __init init_ISA_irqs (void) { @@ -393,14 +399,14 @@ * Set the clock to HZ Hz, we already have a valid * vector now: */ - outb_p(0x34,0x43); /* binary, mode 2, LSB/MSB, ch 0 */ - outb_p(LATCH & 0xff , 0x40); /* LSB */ - outb(LATCH >> 8 , 0x40); /* MSB */ + outb_p(0x34, PIT_MODE); /* binary, mode 2, LSB/MSB, ch 0 */ + outb_p(LATCH & 0xff, PIT_CH0); /* LSB */ + outb(LATCH >> 8 , PIT_CH0); /* MSB */ /* * External FPU? Set up irq13 if so, for * original braindamaged IBM FERR coupling. */ if (boot_cpu_data.hard_math && !cpu_has_fpu) - setup_irq(13, &irq13); + setup_irq(FPU_IRQ, &fpu_irq); } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/arch/i386/kernel/init_task.c linux.2.5.47-ac6/arch/i386/kernel/init_task.c --- linux.2.5.47/arch/i386/kernel/init_task.c 2002-10-31 14:57:24.000000000 +0000 +++ linux.2.5.47-ac6/arch/i386/kernel/init_task.c 2002-10-31 15:05:48.000000000 +0000 @@ -13,6 +13,14 @@ static struct signal_struct init_signals = INIT_SIGNALS(init_signals); struct mm_struct init_mm = INIT_MM(init_mm); +union thread_union init_irq_union + __attribute__((__section__(".data.init_task"))); + +#ifdef CONFIG_X86_STACK_CHECK +union thread_union stack_overflow_stack + __attribute__((__section__(".data.init_task"))); +#endif + /* * Initial thread structure. * diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/arch/i386/kernel/io_apic.c linux.2.5.47-ac6/arch/i386/kernel/io_apic.c --- linux.2.5.47/arch/i386/kernel/io_apic.c 2002-10-31 14:57:24.000000000 +0000 +++ linux.2.5.47-ac6/arch/i386/kernel/io_apic.c 2002-11-15 16:06:53.000000000 +0000 @@ -37,6 +37,8 @@ #include #include "mach_apic.h" +#include "io_ports.h" + #undef APIC_LOCKUP_DEBUG #define APIC_LOCKUP_DEBUG @@ -354,7 +356,9 @@ if ((mp_bus_id_to_type[lbus] == MP_BUS_ISA || mp_bus_id_to_type[lbus] == MP_BUS_EISA || - mp_bus_id_to_type[lbus] == MP_BUS_MCA) && + mp_bus_id_to_type[lbus] == MP_BUS_MCA || + mp_bus_id_to_type[lbus] == MP_BUS_NEC98 + ) && (mp_irqs[i].mpc_irqtype == type) && (mp_irqs[i].mpc_srcbusirq == irq)) @@ -448,6 +452,12 @@ #define default_MCA_trigger(idx) (1) #define default_MCA_polarity(idx) (0) +/* NEC98 interrupts are always polarity zero edge triggered, + * when listed as conforming in the MP table. */ + +#define default_NEC98_trigger(idx) (0) +#define default_NEC98_polarity(idx) (0) + static int __init MPBIOS_polarity(int idx) { int bus = mp_irqs[idx].mpc_srcbus; @@ -482,6 +492,11 @@ polarity = default_MCA_polarity(idx); break; } + case MP_BUS_NEC98: /* NEC 98 pin */ + { + polarity = default_NEC98_polarity(idx); + break; + } default: { printk(KERN_WARNING "broken BIOS!!\n"); @@ -551,6 +566,11 @@ trigger = default_MCA_trigger(idx); break; } + case MP_BUS_NEC98: /* NEC 98 pin */ + { + trigger = default_NEC98_trigger(idx); + break; + } default: { printk(KERN_WARNING "broken BIOS!!\n"); @@ -612,6 +632,7 @@ case MP_BUS_ISA: /* ISA pin */ case MP_BUS_EISA: case MP_BUS_MCA: + case MP_BUS_NEC98: { irq = mp_irqs[idx].mpc_srcbusirq; break; @@ -1718,7 +1739,7 @@ * Additionally, something is definitely wrong with irq9 * on PIIX4 boards. */ -#define PIC_IRQS (1<<2) +#define PIC_IRQS (1 << PIC_CASCADE_IR) void __init setup_IO_APIC(void) { diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/arch/i386/kernel/irq.c linux.2.5.47-ac6/arch/i386/kernel/irq.c --- linux.2.5.47/arch/i386/kernel/irq.c 2002-11-05 13:54:42.000000000 +0000 +++ linux.2.5.47-ac6/arch/i386/kernel/irq.c 2002-11-05 14:00:43.000000000 +0000 @@ -311,7 +311,8 @@ * SMP cross-CPU interrupts have their own specific * handlers). */ -asmlinkage unsigned int do_IRQ(struct pt_regs regs) +struct pt_regs *do_IRQ(struct pt_regs *regs) __attribute__((regparm(1))); +struct pt_regs *do_IRQ(struct pt_regs *regs) { /* * We ack quickly, we don't want the irq controller @@ -323,7 +324,7 @@ * 0 return value means that this irq is already being * handled by some other CPU. (or is disabled) */ - int irq = regs.orig_eax & 0xff; /* high bits used in ret_from_ code */ + int irq = regs->orig_eax & 0xff; /* high bits used in ret_from_ code */ int cpu = smp_processor_id(); irq_desc_t *desc = irq_desc + irq; struct irqaction * action; @@ -388,7 +389,7 @@ */ for (;;) { spin_unlock(&desc->lock); - handle_IRQ_event(irq, ®s, action); + handle_IRQ_event(irq, regs, action); spin_lock(&desc->lock); if (likely(!(desc->status & IRQ_PENDING))) @@ -407,7 +408,7 @@ irq_exit(); - return 1; + return regs; } /** diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/arch/i386/kernel/Makefile linux.2.5.47-ac6/arch/i386/kernel/Makefile --- linux.2.5.47/arch/i386/kernel/Makefile 2002-11-11 16:39:08.000000000 +0000 +++ linux.2.5.47-ac6/arch/i386/kernel/Makefile 2002-11-11 16:42:21.000000000 +0000 @@ -4,7 +4,7 @@ EXTRA_TARGETS := head.o init_task.o -export-objs := mca.o i386_ksyms.o time.o +export-objs := mca.o i386_ksyms.o time.o pci-dma.o obj-y := process.o semaphore.o signal.o entry.o traps.o irq.o vm86.o \ ptrace.o i8259.o ioport.o ldt.o setup.o time.o sys_i386.o \ @@ -20,7 +20,8 @@ obj-$(CONFIG_APM) += apm.o obj-$(CONFIG_ACPI) += acpi.o obj-$(CONFIG_ACPI_SLEEP) += acpi_wakeup.o -obj-$(CONFIG_X86_SMP) += smp.o smpboot.o trampoline.o +obj-$(CONFIG_X86_SMP) += smp.o smpboot.o +obj-$(CONFIG_X86_TRAMPOLINE) += trampoline.o obj-$(CONFIG_X86_MPPARSE) += mpparse.o obj-$(CONFIG_X86_LOCAL_APIC) += apic.o nmi.o obj-$(CONFIG_X86_IO_APIC) += io_apic.o diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/arch/i386/kernel/mpparse.c linux.2.5.47-ac6/arch/i386/kernel/mpparse.c --- linux.2.5.47/arch/i386/kernel/mpparse.c 2002-10-31 14:57:24.000000000 +0000 +++ linux.2.5.47-ac6/arch/i386/kernel/mpparse.c 2002-11-15 16:07:10.000000000 +0000 @@ -236,6 +236,8 @@ mp_current_pci_id++; } else if (strncmp(str, BUSTYPE_MCA, sizeof(BUSTYPE_MCA)-1) == 0) { mp_bus_id_to_type[m->mpc_busid] = MP_BUS_MCA; + } else if (strncmp(str, BUSTYPE_NEC98, sizeof(BUSTYPE_NEC98)-1) == 0) { + mp_bus_id_to_type[m->mpc_busid] = MP_BUS_NEC98; } else { printk("Unknown bustype %s - ignoring\n", str); } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/arch/i386/kernel/pci-dma.c linux.2.5.47-ac6/arch/i386/kernel/pci-dma.c --- linux.2.5.47/arch/i386/kernel/pci-dma.c 2002-10-31 14:57:24.000000000 +0000 +++ linux.2.5.47-ac6/arch/i386/kernel/pci-dma.c 2002-10-31 15:05:48.000000000 +0000 @@ -11,6 +11,7 @@ #include #include #include +#include #include void *pci_alloc_consistent(struct pci_dev *hwdev, size_t size, @@ -24,6 +25,7 @@ ret = (void *)__get_free_pages(gfp, get_order(size)); if (ret != NULL) { + iommu_alloc(size); memset(ret, 0, size); *dma_handle = virt_to_phys(ret); } @@ -33,5 +35,35 @@ void pci_free_consistent(struct pci_dev *hwdev, size_t size, void *vaddr, dma_addr_t dma_handle) { + iommu_free(size); free_pages((unsigned long)vaddr, get_order(size)); } + +atomic_t iommu_count; + +#define WARN_INTERVAL (3600*HZ) /* once a hour */ +static unsigned long last_warned = -WARN_INTERVAL; + +/* could print a backtrace because it's likely that the buggy driver + hits it. */ +void iommu_overflow(void) +{ + if (!time_before(last_warned + WARN_INTERVAL, jiffies)) + return; + last_warned = jiffies; + + printk("pci_map_* overflow. You likely have a buggy driver.\n"); +} + +void iommu_underflow(void) +{ + if (!time_before(last_warned + WARN_INTERVAL, jiffies)) + return; + last_warned = jiffies; + + printk("pci_map_* underflow. You likely have a buggy driver.\n"); +} + +EXPORT_SYMBOL(iommu_count); +EXPORT_SYMBOL(iommu_overflow); +EXPORT_SYMBOL(iommu_underflow); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/arch/i386/kernel/process.c linux.2.5.47-ac6/arch/i386/kernel/process.c --- linux.2.5.47/arch/i386/kernel/process.c 2002-11-11 16:39:08.000000000 +0000 +++ linux.2.5.47-ac6/arch/i386/kernel/process.c 2002-11-11 16:46:25.000000000 +0000 @@ -157,7 +157,25 @@ __setup("idle=", idle_setup); -void show_regs(struct pt_regs * regs) +void stack_overflow(unsigned long esp, unsigned long eip) +{ + int panicing = ((esp&(THREAD_SIZE-1)) <= STACK_PANIC); + + printk( "esp: 0x%lx masked: 0x%lx STACK_PANIC:0x%lx %d %d\n", + esp, (esp&(THREAD_SIZE-1)), STACK_PANIC, (((esp&(THREAD_SIZE-1)) <= STACK_PANIC)), panicing ); + + if (panicing) + print_symbol("stack overflow from %s\n", eip); + else + print_symbol("excessive stack use from %s\n", eip); + printk("esp: %p\n", (void*)esp); + show_trace((void*)esp); + + if (panicing) + panic("stack overflow\n"); +} + +asmlinkage void show_regs(struct pt_regs * regs) { unsigned long cr0 = 0L, cr2 = 0L, cr3 = 0L, cr4 = 0L; @@ -434,6 +452,7 @@ /* never put a printk in __switch_to... printk() calls wake_up*() indirectly */ + next_p->thread_info->irq_stack = prev_p->thread_info->irq_stack; unlazy_fpu(prev_p); /* diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/arch/i386/kernel/reboot.c linux.2.5.47-ac6/arch/i386/kernel/reboot.c --- linux.2.5.47/arch/i386/kernel/reboot.c 2002-10-31 14:57:24.000000000 +0000 +++ linux.2.5.47-ac6/arch/i386/kernel/reboot.c 2002-10-31 15:05:48.000000000 +0000 @@ -8,6 +8,7 @@ #include #include #include +#include "mach_reboot.h" /* * Power off function, if any @@ -125,15 +126,6 @@ 0xea, 0x00, 0x00, 0xff, 0xff /* ljmp $0xffff,$0x0000 */ }; -static inline void kb_wait(void) -{ - int i; - - for (i=0; i<0x10000; i++) - if ((inb_p(0x64) & 0x02) == 0) - break; -} - /* * Switch to real mode and then execute the code * specified by the code and length parameters. @@ -264,13 +256,7 @@ /* rebooting needs to touch the page at absolute addr 0 */ *((unsigned short *)__va(0x472)) = reboot_mode; for (;;) { - int i; - for (i=0; i<100; i++) { - kb_wait(); - udelay(50); - outb(0xfe,0x64); /* pulse reset low */ - udelay(50); - } + mach_reboot(); /* That didn't work - force a triple fault.. */ __asm__ __volatile__("lidt %0": :"m" (no_idt)); __asm__ __volatile__("int3"); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/arch/i386/kernel/setup.c linux.2.5.47-ac6/arch/i386/kernel/setup.c --- linux.2.5.47/arch/i386/kernel/setup.c 2002-10-31 15:05:00.000000000 +0000 +++ linux.2.5.47-ac6/arch/i386/kernel/setup.c 2002-10-31 15:05:48.000000000 +0000 @@ -47,7 +47,6 @@ * Machine setup.. */ -char ignore_irq13; /* set if exception 16 works */ struct cpuinfo_x86 boot_cpu_data = { 0, 0, 0, 0, -1, 1, 0, 0, -1 }; unsigned long mmu_cr4_features; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/arch/i386/kernel/smpboot.c linux.2.5.47-ac6/arch/i386/kernel/smpboot.c --- linux.2.5.47/arch/i386/kernel/smpboot.c 2002-11-05 13:54:42.000000000 +0000 +++ linux.2.5.47-ac6/arch/i386/kernel/smpboot.c 2002-11-15 16:05:22.000000000 +0000 @@ -70,6 +70,11 @@ /* Per CPU bogomips and other parameters */ struct cpuinfo_x86 cpu_data[NR_CPUS] __cacheline_aligned; +/* Per CPU interrupt stacks */ +extern union thread_union init_irq_union; +union thread_union *irq_stacks[NR_CPUS] __cacheline_aligned = + { &init_irq_union, }; + /* Set when the idlers are all forked */ int smp_threads_ready; @@ -159,10 +164,8 @@ goto valid_k7; /* If we get here, it's not a certified SMP capable AMD system. */ - printk (KERN_INFO "WARNING: This combination of AMD processors is not suitable for SMP.\n"); tainted |= TAINT_UNSAFE_SMP; } - valid_k7: ; } @@ -765,6 +768,28 @@ return (send_status | accept_status); } +static void __init setup_irq_stack(struct task_struct *p, int cpu) +{ + unsigned long stk; + + stk = __get_free_pages(GFP_KERNEL, THREAD_ORDER+1); + if (!stk) + panic("I can't seem to allocate my irq stack. Oh well, giving up."); + + irq_stacks[cpu] = (void *)stk; + memset(irq_stacks[cpu], 0, THREAD_SIZE); + irq_stacks[cpu]->thread_info.cpu = cpu; + irq_stacks[cpu]->thread_info.preempt_count = 1; + /* interrupts are not preemptable */ + p->thread_info->irq_stack = (void *)irq_stacks[cpu]; + + /* If we want to make the irq stack more than one unit + * deep, we can chain then off of the irq_stack pointer + * here. + */ +} + + extern unsigned long cpu_initialized; static void __init do_boot_cpu (int apicid) @@ -788,6 +813,8 @@ if (IS_ERR(idle)) panic("failed fork for CPU %d", cpu); + setup_irq_stack(idle, cpu); + /* * We remove it from the pidhash and the runqueue * once we got the process: @@ -805,7 +832,13 @@ /* So we see what's up */ printk("Booting processor %d/%d eip %lx\n", cpu, apicid, start_eip); - stack_start.esp = (void *) (1024 + PAGE_SIZE + (char *)idle->thread_info); + + /* The -4 is to correct for the fact that the stack pointer + * is used to find the location of the thread_info structure + * by masking off several of the LSBs. Without the -4, esp + * is pointing to the page after the one the stack is on. + */ + stack_start.esp = (void *)(THREAD_SIZE - 4 + (char *)idle->thread_info); /* * This grunge runs the startup process for @@ -1128,6 +1161,15 @@ if (smp_b_stepping) printk(KERN_WARNING "WARNING: SMP operation may be unreliable with B stepping processors.\n"); + + /* See if we found multiple Athons and not all are "MP" */ + if (tainted&TAINT_UNSAFE_SMP) + { + if(cpucount) + printk (KERN_INFO "WARNING: This combination of AMD processors is not suitable for SMP.\n"); + else /* Not SMP so ok */ + tainted &= ~TAINT_UNSAFE_SMP; + } Dprintk("Boot done.\n"); /* diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/arch/i386/kernel/timers/Makefile linux.2.5.47-ac6/arch/i386/kernel/timers/Makefile --- linux.2.5.47/arch/i386/kernel/timers/Makefile 2002-10-31 14:57:24.000000000 +0000 +++ linux.2.5.47-ac6/arch/i386/kernel/timers/Makefile 2002-11-17 00:19:36.000000000 +0000 @@ -2,10 +2,8 @@ # Makefile for x86 timers # -obj-y := timer.o +obj-y:= timer.o timer_tsc.o timer_pit.o -obj-y += timer_tsc.o -obj-y += timer_pit.o -obj-$(CONFIG_X86_CYCLONE) += timer_cyclone.o +obj-$(CONFIG_X86_CYCLONE) += timer_cyclone.o include $(TOPDIR)/Rules.make diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/arch/i386/kernel/timers/timer.c linux.2.5.47-ac6/arch/i386/kernel/timers/timer.c --- linux.2.5.47/arch/i386/kernel/timers/timer.c 2002-10-31 14:57:24.000000000 +0000 +++ linux.2.5.47-ac6/arch/i386/kernel/timers/timer.c 2002-11-17 00:19:07.000000000 +0000 @@ -8,9 +8,7 @@ /* list of timers, ordered by preference, NULL terminated */ static struct timer_opts* timers[] = { &timer_tsc, -#ifndef CONFIG_X86_TSC &timer_pit, -#endif NULL, }; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/arch/i386/kernel/timers/timer_pit.c linux.2.5.47-ac6/arch/i386/kernel/timers/timer_pit.c --- linux.2.5.47/arch/i386/kernel/timers/timer_pit.c 2002-11-05 13:54:42.000000000 +0000 +++ linux.2.5.47-ac6/arch/i386/kernel/timers/timer_pit.c 2002-11-05 14:01:02.000000000 +0000 @@ -9,7 +9,9 @@ #include #include #include +#include #include +#include extern spinlock_t i8259A_lock; extern spinlock_t i8253_lock; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/arch/i386/kernel/timers/timer_tsc.c linux.2.5.47-ac6/arch/i386/kernel/timers/timer_tsc.c --- linux.2.5.47/arch/i386/kernel/timers/timer_tsc.c 2002-11-11 16:39:08.000000000 +0000 +++ linux.2.5.47-ac6/arch/i386/kernel/timers/timer_tsc.c 2002-11-17 00:19:07.000000000 +0000 @@ -11,6 +11,10 @@ #include #include +/* processor.h for distable_tsc flag */ +#include + +int tsc_disable __initdata = 0; extern int x86_udelay_tsc; extern spinlock_t i8253_lock; @@ -287,6 +291,18 @@ return -ENODEV; } +/* disable flag for tsc. Takes effect by clearing the TSC cpu flag + * in cpu/common.c */ +static int __init tsc_setup(char *str) +{ + tsc_disable = 1; + return 1; +} + +__setup("notsc", tsc_setup); + + + /************************************************************/ /* tsc timer_opts struct */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/arch/i386/kernel/trampoline.S linux.2.5.47-ac6/arch/i386/kernel/trampoline.S --- linux.2.5.47/arch/i386/kernel/trampoline.S 2002-10-31 14:57:24.000000000 +0000 +++ linux.2.5.47-ac6/arch/i386/kernel/trampoline.S 2002-10-31 15:05:48.000000000 +0000 @@ -36,7 +36,7 @@ ENTRY(trampoline_data) r_base = . - wbinvd # Needed for NUMA-Q should be harmless for others + wbinvd mov %cs, %ax # Code and data in the same place mov %ax, %ds @@ -54,7 +54,7 @@ lmsw %ax # into protected mode jmp flush_instr flush_instr: - ljmpl $__KERNEL_CS, $0x00100000 + ljmpl $__BOOT_CS, $0x00100000 # jump to startup_32 in arch/i386/kernel/head.S idt_48: @@ -67,8 +67,8 @@ # gdt_48: - .word 0x0800 # gdt limit = 2048, 256 GDT entries - .long cpu_gdt_table-__PAGE_OFFSET # gdt base = gdt (first SMP CPU) + .word __BOOT_DS + 7 # gdt limit + .long boot_gdt_table-__PAGE_OFFSET # gdt base = gdt (first SMP CPU) .globl trampoline_end trampoline_end: diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/arch/i386/kernel/traps.c linux.2.5.47-ac6/arch/i386/kernel/traps.c --- linux.2.5.47/arch/i386/kernel/traps.c 2002-11-11 16:39:08.000000000 +0000 +++ linux.2.5.47-ac6/arch/i386/kernel/traps.c 2002-11-18 16:48:33.000000000 +0000 @@ -56,6 +56,9 @@ struct desc_struct default_ldt[] = { { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }; +/* Do we ignore FPU interrupts ? */ +char ignore_fpu_irq = 0; + /* * The IDT has to be page-aligned to simplify the Pentium * F0 0F bug workaround.. We have a special link segment @@ -84,7 +87,7 @@ asmlinkage void spurious_interrupt_bug(void); asmlinkage void machine_check(void); -static int kstack_depth_to_print = 24; +static int kstack_depth_to_print = 10; /* @@ -246,6 +249,9 @@ printk("%02x ", c); } } + local_irq_disable(); + for ( ; ; ) + ; printk("\n"); } @@ -702,7 +708,7 @@ asmlinkage void do_coprocessor_error(struct pt_regs * regs, long error_code) { - ignore_irq13 = 1; + ignore_fpu_irq = 1; math_error((void *)regs->eip); } @@ -759,7 +765,7 @@ { if (cpu_has_xmm) { /* Handle SIMD FPU exceptions on PIII+ processors. */ - ignore_irq13 = 1; + ignore_fpu_irq = 1; simd_math_error((void *)regs->eip); } else { /* diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/arch/i386/kernel/vm86.c linux.2.5.47-ac6/arch/i386/kernel/vm86.c --- linux.2.5.47/arch/i386/kernel/vm86.c 2002-10-31 14:57:24.000000000 +0000 +++ linux.2.5.47-ac6/arch/i386/kernel/vm86.c 2002-10-31 15:05:48.000000000 +0000 @@ -30,6 +30,7 @@ * */ +#include #include #include #include @@ -735,7 +736,7 @@ static inline void handle_irq_zombies(void) { int i; - for (i=3; i<16; i++) { + for (i=FIRST_VM86_IRQ; i<=LAST_VM86_IRQ; i++) { if (vm86_irqs[i].tsk) { if (task_valid(vm86_irqs[i].tsk)) continue; free_vm86_irq(i); @@ -748,7 +749,7 @@ int bit; unsigned long flags; - if ( (irqnumber<3) || (irqnumber>15) ) return 0; + if (invalid_vm86_irq(irqnumber)) return 0; if (vm86_irqs[irqnumber].tsk != current) return 0; spin_lock_irqsave(&irqbits_lock, flags); bit = irqbits & (1 << irqnumber); @@ -774,7 +775,7 @@ handle_irq_zombies(); if (!capable(CAP_SYS_ADMIN)) return -EPERM; if (!((1 << sig) & ALLOWED_SIGS)) return -EPERM; - if ( (irq<3) || (irq>15) ) return -EPERM; + if (invalid_vm86_irq(irq)) return -EPERM; if (vm86_irqs[irq].tsk) return -EPERM; ret = request_irq(irq, &irq_handler, 0, VM86_IRQNAME, 0); if (ret) return ret; @@ -784,7 +785,7 @@ } case VM86_FREE_IRQ: { handle_irq_zombies(); - if ( (irqnumber<3) || (irqnumber>15) ) return -EPERM; + if (invalid_vm86_irq(irqnumber)) return -EPERM; if (!vm86_irqs[irqnumber].tsk) return 0; if (vm86_irqs[irqnumber].tsk != current) return -EPERM; free_vm86_irq(irqnumber); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/arch/i386/lib/mmx.c linux.2.5.47-ac6/arch/i386/lib/mmx.c --- linux.2.5.47/arch/i386/lib/mmx.c 2002-10-31 14:57:24.000000000 +0000 +++ linux.2.5.47-ac6/arch/i386/lib/mmx.c 2002-10-31 15:05:49.000000000 +0000 @@ -170,56 +170,17 @@ /* maybe the prefetch stuff can go before the expensive fnsave... * but that is for later. -AV */ - __asm__ __volatile__ ( - "1: prefetch (%0)\n" - " prefetch 64(%0)\n" - " prefetch 128(%0)\n" - " prefetch 192(%0)\n" - " prefetch 256(%0)\n" - "2: \n" - ".section .fixup, \"ax\"\n" - "3: movw $0x1AEB, 1b\n" /* jmp on 26 bytes */ - " jmp 2b\n" - ".previous\n" - ".section __ex_table,\"a\"\n" - " .align 4\n" - " .long 1b, 3b\n" - ".previous" - : : "r" (from) ); - - for(i=0; i<(4096-320)/64; i++) - { - __asm__ __volatile__ ( - "1: prefetch 320(%0)\n" - "2: movq (%0), %%mm0\n" - " movntq %%mm0, (%1)\n" - " movq 8(%0), %%mm1\n" - " movntq %%mm1, 8(%1)\n" - " movq 16(%0), %%mm2\n" - " movntq %%mm2, 16(%1)\n" - " movq 24(%0), %%mm3\n" - " movntq %%mm3, 24(%1)\n" - " movq 32(%0), %%mm4\n" - " movntq %%mm4, 32(%1)\n" - " movq 40(%0), %%mm5\n" - " movntq %%mm5, 40(%1)\n" - " movq 48(%0), %%mm6\n" - " movntq %%mm6, 48(%1)\n" - " movq 56(%0), %%mm7\n" - " movntq %%mm7, 56(%1)\n" - ".section .fixup, \"ax\"\n" - "3: movw $0x05EB, 1b\n" /* jmp on 5 bytes */ - " jmp 2b\n" - ".previous\n" - ".section __ex_table,\"a\"\n" - " .align 4\n" - " .long 1b, 3b\n" - ".previous" - : : "r" (from), "r" (to) : "memory"); - from+=64; - to+=64; + for (i=4096-256;i>0;i-=256) { + int scratch; + __asm__ __volatile( + "movl 192(%1,%2),%0\n" + "movl 128(%1,%2),%0\n" + "movl 64(%1,%2),%0\n" + "movl 0(%1,%2),%0\n" + : "=&r" (scratch) + : "r" (from), "r" (i)); } - for(i=(4096-320)/64; i<4096/64; i++) + for(i=0; i<4096/64; i++) { __asm__ __volatile__ ( "2: movq (%0), %%mm0\n" diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/arch/i386/mach-defaults/pci-functions.h linux.2.5.47-ac6/arch/i386/mach-defaults/pci-functions.h --- linux.2.5.47/arch/i386/mach-defaults/pci-functions.h 1970-01-01 01:00:00.000000000 +0100 +++ linux.2.5.47-ac6/arch/i386/mach-defaults/pci-functions.h 2002-10-31 15:05:52.000000000 +0000 @@ -0,0 +1,19 @@ +/* + * PCI BIOS function numbering for conventional PCI BIOS + * systems + */ + +#define PCIBIOS_PCI_FUNCTION_ID 0xb1XX +#define PCIBIOS_PCI_BIOS_PRESENT 0xb101 +#define PCIBIOS_FIND_PCI_DEVICE 0xb102 +#define PCIBIOS_FIND_PCI_CLASS_CODE 0xb103 +#define PCIBIOS_GENERATE_SPECIAL_CYCLE 0xb106 +#define PCIBIOS_READ_CONFIG_BYTE 0xb108 +#define PCIBIOS_READ_CONFIG_WORD 0xb109 +#define PCIBIOS_READ_CONFIG_DWORD 0xb10a +#define PCIBIOS_WRITE_CONFIG_BYTE 0xb10b +#define PCIBIOS_WRITE_CONFIG_WORD 0xb10c +#define PCIBIOS_WRITE_CONFIG_DWORD 0xb10d +#define PCIBIOS_GET_ROUTING_OPTIONS 0xb10e +#define PCIBIOS_SET_PCI_HW_INT 0xb10f + diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/arch/i386/mach-generic/io_ports.h linux.2.5.47-ac6/arch/i386/mach-generic/io_ports.h --- linux.2.5.47/arch/i386/mach-generic/io_ports.h 1970-01-01 01:00:00.000000000 +0100 +++ linux.2.5.47-ac6/arch/i386/mach-generic/io_ports.h 2002-10-31 15:05:52.000000000 +0000 @@ -0,0 +1,30 @@ +/* + * arch/i386/mach-generic/io_ports.h + * + * Machine specific IO port address definition for generic. + * Written by Osamu Tomita + */ +#ifndef _MACH_IO_PORTS_H +#define _MACH_IO_PORTS_H + +/* i8253A PIT registers */ +#define PIT_MODE 0x43 +#define PIT_CH0 0x40 +#define PIT_CH2 0x42 + +/* i8259A PIC registers */ +#define PIC_MASTER_CMD 0x20 +#define PIC_MASTER_IMR 0x21 +#define PIC_MASTER_ISR PIC_MASTER_CMD +#define PIC_MASTER_POLL PIC_MASTER_ISR +#define PIC_MASTER_OCW3 PIC_MASTER_ISR +#define PIC_SLAVE_CMD 0xa0 +#define PIC_SLAVE_IMR 0xa1 + +/* i8259A PIC related value */ +#define PIC_CASCADE_IR 2 +#define MASTER_ICW4_DEFAULT 0x01 +#define SLAVE_ICW4_DEFAULT 0x01 +#define PIC_ICW4_AEOI 2 + +#endif /* !_MACH_IO_PORTS_H */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/arch/i386/mach-generic/irq_vectors.h linux.2.5.47-ac6/arch/i386/mach-generic/irq_vectors.h --- linux.2.5.47/arch/i386/mach-generic/irq_vectors.h 2002-10-31 14:57:24.000000000 +0000 +++ linux.2.5.47-ac6/arch/i386/mach-generic/irq_vectors.h 2002-10-31 15:05:52.000000000 +0000 @@ -82,4 +82,11 @@ #define NR_IRQS 16 #endif +#define FPU_IRQ 13 + +#define FIRST_VM86_IRQ 3 +#define LAST_VM86_IRQ 15 +#define invalid_vm86_irq(irq) ((irq) < 3 || (irq) > 15) + + #endif /* _ASM_IRQ_VECTORS_H */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/arch/i386/mach-generic/mach_reboot.h linux.2.5.47-ac6/arch/i386/mach-generic/mach_reboot.h --- linux.2.5.47/arch/i386/mach-generic/mach_reboot.h 1970-01-01 01:00:00.000000000 +0100 +++ linux.2.5.47-ac6/arch/i386/mach-generic/mach_reboot.h 2002-10-31 15:05:52.000000000 +0000 @@ -0,0 +1,30 @@ +/* + * arch/i386/mach-generic/mach_reboot.h + * + * Machine specific reboot functions for generic. + * Split out from reboot.c by Osamu Tomita + */ +#ifndef _MACH_REBOOT_H +#define _MACH_REBOOT_H + +static inline void kb_wait(void) +{ + int i; + + for (i = 0; i < 0x10000; i++) + if ((inb_p(0x64) & 0x02) == 0) + break; +} + +static inline void mach_reboot(void) +{ + int i; + for (i = 0; i < 100; i++) { + kb_wait(); + udelay(50); + outb(0xfe, 0x64); /* pulse reset low */ + udelay(50); + } +} + +#endif /* !_MACH_REBOOT_H */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/arch/i386/mach-pc9800/entry_arch.h linux.2.5.47-ac6/arch/i386/mach-pc9800/entry_arch.h --- linux.2.5.47/arch/i386/mach-pc9800/entry_arch.h 1970-01-01 01:00:00.000000000 +0100 +++ linux.2.5.47-ac6/arch/i386/mach-pc9800/entry_arch.h 2002-10-31 15:05:52.000000000 +0000 @@ -0,0 +1 @@ +#include "../mach-generic/entry_arch.h" diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/arch/i386/mach-pc9800/io_ports.h linux.2.5.47-ac6/arch/i386/mach-pc9800/io_ports.h --- linux.2.5.47/arch/i386/mach-pc9800/io_ports.h 1970-01-01 01:00:00.000000000 +0100 +++ linux.2.5.47-ac6/arch/i386/mach-pc9800/io_ports.h 2002-10-31 15:05:52.000000000 +0000 @@ -0,0 +1,30 @@ +/* + * arch/i386/mach-pc9800/io_ports.h + * + * Machine specific IO port address definition for PC-9800. + * Written by Osamu Tomita + */ +#ifndef _MACH_IO_PORTS_H +#define _MACH_IO_PORTS_H + +/* i8253A PIT registers */ +#define PIT_MODE 0x77 +#define PIT_CH0 0x71 +#define PIT_CH2 0x75 + +/* i8259A PIC registers */ +#define PIC_MASTER_CMD 0x00 +#define PIC_MASTER_IMR 0x02 +#define PIC_MASTER_ISR PIC_MASTER_CMD +#define PIC_MASTER_POLL PIC_MASTER_ISR +#define PIC_MASTER_OCW3 PIC_MASTER_ISR +#define PIC_SLAVE_CMD 0x08 +#define PIC_SLAVE_IMR 0x0a + +/* i8259A PIC related values */ +#define PIC_CASCADE_IR 7 +#define MASTER_ICW4_DEFAULT 0x1d +#define SLAVE_ICW4_DEFAULT 0x09 +#define PIC_ICW4_AEOI 0x02 + +#endif /* !_MACH_IO_PORTS_H */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/arch/i386/mach-pc9800/irq_vectors.h linux.2.5.47-ac6/arch/i386/mach-pc9800/irq_vectors.h --- linux.2.5.47/arch/i386/mach-pc9800/irq_vectors.h 1970-01-01 01:00:00.000000000 +0100 +++ linux.2.5.47-ac6/arch/i386/mach-pc9800/irq_vectors.h 2002-10-31 15:05:52.000000000 +0000 @@ -0,0 +1,93 @@ +/* + * This file should contain #defines for all of the interrupt vector + * numbers used by this architecture. + * + * In addition, there are some standard defines: + * + * FIRST_EXTERNAL_VECTOR: + * The first free place for external interrupts + * + * SYSCALL_VECTOR: + * The IRQ vector a syscall makes the user to kernel transition + * under. + * + * TIMER_IRQ: + * The IRQ number the timer interrupt comes in at. + * + * NR_IRQS: + * The total number of interrupt vectors (including all the + * architecture specific interrupts) needed. + * + */ +#ifndef _ASM_IRQ_VECTORS_H +#define _ASM_IRQ_VECTORS_H + +/* + * IDT vectors usable for external interrupt sources start + * at 0x20: + */ +#define FIRST_EXTERNAL_VECTOR 0x20 + +#define SYSCALL_VECTOR 0x80 + +/* + * Vectors 0x20-0x2f are used for ISA interrupts. + */ + +/* + * Special IRQ vectors used by the SMP architecture, 0xf0-0xff + * + * some of the following vectors are 'rare', they are merged + * into a single vector (CALL_FUNCTION_VECTOR) to save vector space. + * TLB, reschedule and local APIC vectors are performance-critical. + * + * Vectors 0xf0-0xfa are free (reserved for future Linux use). + */ +#define SPURIOUS_APIC_VECTOR 0xff +#define ERROR_APIC_VECTOR 0xfe +#define INVALIDATE_TLB_VECTOR 0xfd +#define RESCHEDULE_VECTOR 0xfc +#define CALL_FUNCTION_VECTOR 0xfb + +#define THERMAL_APIC_VECTOR 0xf0 +/* + * Local APIC timer IRQ vector is on a different priority level, + * to work around the 'lost local interrupt if more than 2 IRQ + * sources per level' errata. + */ +#define LOCAL_TIMER_VECTOR 0xef + +/* + * First APIC vector available to drivers: (vectors 0x30-0xee) + * we start at 0x31 to spread out vectors evenly between priority + * levels. (0x80 is the syscall vector) + */ +#define FIRST_DEVICE_VECTOR 0x31 +#define FIRST_SYSTEM_VECTOR 0xef + +#define TIMER_IRQ 0 + +/* + * 16 8259A IRQ's, 208 potential APIC interrupt sources. + * Right now the APIC is mostly only used for SMP. + * 256 vectors is an architectural limit. (we can have + * more than 256 devices theoretically, but they will + * have to use shared interrupts) + * Since vectors 0x00-0x1f are used/reserved for the CPU, + * the usable vector space is 0x20-0xff (224 vectors) + */ +#ifdef CONFIG_X86_IO_APIC +#define NR_IRQS 224 +#else +#define NR_IRQS 16 +#endif + +#define FPU_IRQ 8 + +#define FIRST_VM86_IRQ 2 +#define LAST_VM86_IRQ 15 +#define invalid_vm86_irq(irq) ((irq) < 2 || (irq) == 7 || (irq) > 15) + +#endif /* _ASM_IRQ_VECTORS_H */ + + diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/arch/i386/mach-pc9800/mach_apic.h linux.2.5.47-ac6/arch/i386/mach-pc9800/mach_apic.h --- linux.2.5.47/arch/i386/mach-pc9800/mach_apic.h 1970-01-01 01:00:00.000000000 +0100 +++ linux.2.5.47-ac6/arch/i386/mach-pc9800/mach_apic.h 2002-10-31 15:05:52.000000000 +0000 @@ -0,0 +1 @@ +#include "../mach-generic/mach_apic.h" diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/arch/i386/mach-pc9800/mach_reboot.h linux.2.5.47-ac6/arch/i386/mach-pc9800/mach_reboot.h --- linux.2.5.47/arch/i386/mach-pc9800/mach_reboot.h 1970-01-01 01:00:00.000000000 +0100 +++ linux.2.5.47-ac6/arch/i386/mach-pc9800/mach_reboot.h 2002-10-31 15:05:52.000000000 +0000 @@ -0,0 +1,21 @@ +/* + * arch/i386/mach-pc9800/mach_reboot.h + * + * Machine specific reboot functions for PC-9800. + * Written by Osamu Tomita + */ +#ifndef _MACH_REBOOT_H +#define _MACH_REBOOT_H + +#ifdef CMOS_WRITE +#undef CMOS_WRITE +#define CMOS_WRITE(a,b) do{}while(0) +#endif + +static inline void mach_reboot(void) +{ + outb(0, 0xf0); /* signal CPU reset */ + mdelay(1); +} + +#endif /* !_MACH_REBOOT_H */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/arch/i386/mach-pc9800/Makefile linux.2.5.47-ac6/arch/i386/mach-pc9800/Makefile --- linux.2.5.47/arch/i386/mach-pc9800/Makefile 1970-01-01 01:00:00.000000000 +0100 +++ linux.2.5.47-ac6/arch/i386/mach-pc9800/Makefile 2002-10-31 15:05:52.000000000 +0000 @@ -0,0 +1,15 @@ +# +# Makefile for the linux kernel. +# +# 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 in the main makefile... + +EXTRA_CFLAGS += -I../kernel +export-objs := + +obj-y := setup.o + +include $(TOPDIR)/Rules.make diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/arch/i386/mach-pc9800/pci-functions.h linux.2.5.47-ac6/arch/i386/mach-pc9800/pci-functions.h --- linux.2.5.47/arch/i386/mach-pc9800/pci-functions.h 1970-01-01 01:00:00.000000000 +0100 +++ linux.2.5.47-ac6/arch/i386/mach-pc9800/pci-functions.h 2002-10-31 15:05:52.000000000 +0000 @@ -0,0 +1,20 @@ +/* + * PCI BIOS function codes for the PC9800. Different to + * standard PC systems + */ + +/* Note: PC-9800 confirms PCI 2.1 on only few models */ + +#define PCIBIOS_PCI_FUNCTION_ID 0xccXX +#define PCIBIOS_PCI_BIOS_PRESENT 0xcc81 +#define PCIBIOS_FIND_PCI_DEVICE 0xcc82 +#define PCIBIOS_FIND_PCI_CLASS_CODE 0xcc83 +/* PCIBIOS_GENERATE_SPECIAL_CYCLE 0xcc86 (not supported by bios) */ +#define PCIBIOS_READ_CONFIG_BYTE 0xcc88 +#define PCIBIOS_READ_CONFIG_WORD 0xcc89 +#define PCIBIOS_READ_CONFIG_DWORD 0xcc8a +#define PCIBIOS_WRITE_CONFIG_BYTE 0xcc8b +#define PCIBIOS_WRITE_CONFIG_WORD 0xcc8c +#define PCIBIOS_WRITE_CONFIG_DWORD 0xcc8d +#define PCIBIOS_GET_ROUTING_OPTIONS 0xcc8e /* PCI 2.1 only */ +#define PCIBIOS_SET_PCI_HW_INT 0xcc8f /* PCI 2.1 only */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/arch/i386/mach-pc9800/setup_arch_post.h linux.2.5.47-ac6/arch/i386/mach-pc9800/setup_arch_post.h --- linux.2.5.47/arch/i386/mach-pc9800/setup_arch_post.h 1970-01-01 01:00:00.000000000 +0100 +++ linux.2.5.47-ac6/arch/i386/mach-pc9800/setup_arch_post.h 2002-10-31 15:05:52.000000000 +0000 @@ -0,0 +1,29 @@ +/** + * machine_specific_memory_setup - Hook for machine specific memory setup. + * + * Description: + * This is included late in kernel/setup.c so that it can make + * use of all of the static functions. + **/ + +static inline char * __init machine_specific_memory_setup(void) +{ + char *who; + unsigned long low_mem_size, lower_high, higher_high; + + + who = "BIOS (common area)"; + + low_mem_size = ((*(unsigned char *)__va(PC9800SCA_BIOS_FLAG) & 7) + 1) << 17; + add_memory_region(0, low_mem_size, 1); + lower_high = (__u32) *(__u8 *) bus_to_virt(PC9800SCA_EXPMMSZ) << 17; + higher_high = (__u32) *(__u16 *) bus_to_virt(PC9800SCA_MMSZ16M) << 20; + if (lower_high != 0x00f00000UL) { + add_memory_region(HIGH_MEMORY, lower_high, 1); + add_memory_region(0x01000000UL, higher_high, 1); + } + else + add_memory_region(HIGH_MEMORY, lower_high + higher_high, 1); + + return who; +} diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/arch/i386/mach-pc9800/setup_arch_pre.h linux.2.5.47-ac6/arch/i386/mach-pc9800/setup_arch_pre.h --- linux.2.5.47/arch/i386/mach-pc9800/setup_arch_pre.h 1970-01-01 01:00:00.000000000 +0100 +++ linux.2.5.47-ac6/arch/i386/mach-pc9800/setup_arch_pre.h 2002-10-31 15:05:52.000000000 +0000 @@ -0,0 +1,36 @@ +/* Hook to call BIOS initialisation function */ + +/* no action for generic */ + +#define ARCH_SETUP arch_setup_pc9800(); + +#include +#include +#include +#include + +int CLOCK_TICK_RATE; +unsigned long tick_usec; /* ACTHZ period (usec) */ +unsigned long tick_nsec; /* USER_HZ period (nsec) */ +unsigned char pc9800_misc_flags; +/* (bit 0) 1:High Address Video ram exists 0:otherwise */ + +#ifdef CONFIG_SMP +#define MPC_TABLE_SIZE 512 +#define MPC_TABLE ((char *) (PARAM+0x400)) +char mpc_table[MPC_TABLE_SIZE]; +#endif + +static inline void arch_setup_pc9800(void) +{ + CLOCK_TICK_RATE = PC9800_8MHz_P() ? 1996800 : 2457600; + printk(KERN_DEBUG "CLOCK_TICK_RATE = %d\n", CLOCK_TICK_RATE); + tick_usec = TICK_USEC; /* ACTHZ period (usec) */ + tick_nsec = TICK_NSEC(TICK_USEC); /* USER_HZ period (nsec) */ + + pc9800_misc_flags = PC9800_MISC_FLAGS; +#ifdef CONFIG_SMP + if ((*(u32 *)(MPC_TABLE)) == 0x504d4350) + memcpy(mpc_table, MPC_TABLE, *(u16 *)(MPC_TABLE + 4)); +#endif /* CONFIG_SMP */ +} diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/arch/i386/mach-pc9800/setup.c linux.2.5.47-ac6/arch/i386/mach-pc9800/setup.c --- linux.2.5.47/arch/i386/mach-pc9800/setup.c 1970-01-01 01:00:00.000000000 +0100 +++ linux.2.5.47-ac6/arch/i386/mach-pc9800/setup.c 2002-10-31 15:05:52.000000000 +0000 @@ -0,0 +1,117 @@ +/* + * Machine specific setup for generic + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +struct sys_desc_table_struct { + unsigned short length; + unsigned char table[0]; +}; + +/* Indicates PC-9800 architecture No:0 Yes:1 */ +extern int pc98; + +/** + * pre_intr_init_hook - initialisation prior to setting up interrupt vectors + * + * Description: + * Perform any necessary interrupt initialisation prior to setting up + * the "ordinary" interrupt call gates. For legacy reasons, the ISA + * interrupts should be initialised here if the machine emulates a PC + * in any way. + **/ +void __init pre_intr_init_hook(void) +{ + init_ISA_irqs(); +} + +/* + * IRQ7 is cascade interrupt to second interrupt controller + */ +static struct irqaction irq7 = { no_action, 0, 0, "cascade", NULL, NULL}; + +/** + * intr_init_hook - post gate setup interrupt initialisation + * + * Description: + * Fill in any interrupts that may have been left out by the general + * init_IRQ() routine. interrupts having to do with the machine rather + * than the devices on the I/O bus (like APIC interrupts in intel MP + * systems) are started here. + **/ +void __init intr_init_hook(void) +{ +#ifdef CONFIG_X86_LOCAL_APIC + apic_intr_init(); +#endif + + setup_irq(7, &irq7); +} + +/** + * pre_setup_arch_hook - hook called prior to any setup_arch() execution + * + * Description: + * generally used to activate any machine specific identification + * routines that may be needed before setup_arch() runs. On VISWS + * this is used to get the board revision and type. + **/ +void __init pre_setup_arch_hook(void) +{ + SYS_DESC_TABLE.length = 0; + MCA_bus = 0; + pc98 = 1; +} + +/** + * trap_init_hook - initialise system specific traps + * + * Description: + * Called as the final act of trap_init(). Used in VISWS to initialise + * the various board specific APIC traps. + **/ +void __init trap_init_hook(void) +{ +} + +static struct irqaction irq0 = { timer_interrupt, SA_INTERRUPT, 0, "timer", NULL, NULL}; + +/** + * time_init_hook - do any specific initialisations for the system timer. + * + * Description: + * Must plug the system timer interrupt source at HZ into the IRQ listed + * in irq_vectors.h:TIMER_IRQ + **/ +void __init time_init_hook(void) +{ + setup_irq(0, &irq0); +} + +#ifdef CONFIG_MCA +/** + * mca_nmi_hook - hook into MCA specific NMI chain + * + * Description: + * The MCA (Microchannel Arcitecture) has an NMI chain for NMI sources + * along the MCA bus. Use this to hook into that chain if you will need + * it. + **/ +void __init mca_nmi_hook(void) +{ + /* If I recall correctly, there's a whole bunch of other things that + * we can do to check for NMI problems, but that's all I know about + * at the moment. + */ + + printk("NMI generated from unknown source!\n"); +} +#endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/arch/i386/mach-summit/io_ports.h linux.2.5.47-ac6/arch/i386/mach-summit/io_ports.h --- linux.2.5.47/arch/i386/mach-summit/io_ports.h 1970-01-01 01:00:00.000000000 +0100 +++ linux.2.5.47-ac6/arch/i386/mach-summit/io_ports.h 2002-10-31 15:05:52.000000000 +0000 @@ -0,0 +1 @@ +#include "../mach-generic/io_ports.h" diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/arch/i386/mach-summit/mach_reboot.h linux.2.5.47-ac6/arch/i386/mach-summit/mach_reboot.h --- linux.2.5.47/arch/i386/mach-summit/mach_reboot.h 1970-01-01 01:00:00.000000000 +0100 +++ linux.2.5.47-ac6/arch/i386/mach-summit/mach_reboot.h 2002-10-31 15:05:52.000000000 +0000 @@ -0,0 +1 @@ +#include "../mach-generic/mach_reboot.h" diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/arch/i386/mach-visws/io_ports.h linux.2.5.47-ac6/arch/i386/mach-visws/io_ports.h --- linux.2.5.47/arch/i386/mach-visws/io_ports.h 1970-01-01 01:00:00.000000000 +0100 +++ linux.2.5.47-ac6/arch/i386/mach-visws/io_ports.h 2002-10-31 15:05:52.000000000 +0000 @@ -0,0 +1 @@ +#include "../mach-generic/io_ports.h" diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/arch/i386/mach-visws/irq_vectors.h linux.2.5.47-ac6/arch/i386/mach-visws/irq_vectors.h --- linux.2.5.47/arch/i386/mach-visws/irq_vectors.h 2002-10-31 14:57:24.000000000 +0000 +++ linux.2.5.47-ac6/arch/i386/mach-visws/irq_vectors.h 2002-10-31 15:05:52.000000000 +0000 @@ -61,4 +61,6 @@ #define NR_IRQS 16 #endif +#define FPU_IRQ 13 + #endif /* _ASM_IRQ_VECTORS_H */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/arch/i386/mach-visws/mach_reboot.h linux.2.5.47-ac6/arch/i386/mach-visws/mach_reboot.h --- linux.2.5.47/arch/i386/mach-visws/mach_reboot.h 1970-01-01 01:00:00.000000000 +0100 +++ linux.2.5.47-ac6/arch/i386/mach-visws/mach_reboot.h 2002-10-31 15:05:52.000000000 +0000 @@ -0,0 +1 @@ +#include "../mach-generic/mach_reboot.h" diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/arch/i386/mach-voyager/io_ports.h linux.2.5.47-ac6/arch/i386/mach-voyager/io_ports.h --- linux.2.5.47/arch/i386/mach-voyager/io_ports.h 1970-01-01 01:00:00.000000000 +0100 +++ linux.2.5.47-ac6/arch/i386/mach-voyager/io_ports.h 2002-11-17 00:19:07.000000000 +0000 @@ -0,0 +1 @@ +#include "../mach-generic/io_ports.h" diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/arch/i386/mach-voyager/irq_vectors.h linux.2.5.47-ac6/arch/i386/mach-voyager/irq_vectors.h --- linux.2.5.47/arch/i386/mach-voyager/irq_vectors.h 2002-10-31 15:05:00.000000000 +0000 +++ linux.2.5.47-ac6/arch/i386/mach-voyager/irq_vectors.h 2002-10-31 15:05:52.000000000 +0000 @@ -57,6 +57,12 @@ #define NR_IRQS 224 +#define FPU_IRQ 13 + +#define FIRST_VM86_IRQ 3 +#define LAST_VM86_IRQ 15 +#define invalid_vm86_irq(irq) ((irq) < 3 || (irq) > 15) + #ifndef __ASSEMBLY__ extern asmlinkage void vic_cpi_interrupt(void); extern asmlinkage void vic_sys_interrupt(void); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/arch/i386/mach-voyager/setup.c linux.2.5.47-ac6/arch/i386/mach-voyager/setup.c --- linux.2.5.47/arch/i386/mach-voyager/setup.c 2002-10-31 15:05:00.000000000 +0000 +++ linux.2.5.47-ac6/arch/i386/mach-voyager/setup.c 2002-11-17 00:19:07.000000000 +0000 @@ -29,6 +29,9 @@ void __init pre_setup_arch_hook(void) { + /* Voyagers run their CPUs from independent clocks, so disable + * the TSC code because we can't sync them */ + tsc_disable = 1; } void __init trap_init_hook(void) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/arch/i386/mach-voyager/voyager_basic.c linux.2.5.47-ac6/arch/i386/mach-voyager/voyager_basic.c --- linux.2.5.47/arch/i386/mach-voyager/voyager_basic.c 2002-10-31 15:05:00.000000000 +0000 +++ linux.2.5.47-ac6/arch/i386/mach-voyager/voyager_basic.c 2002-11-17 00:19:07.000000000 +0000 @@ -21,6 +21,7 @@ #include #include #include +#include #include #include #include @@ -41,6 +42,21 @@ struct voyager_SUS *voyager_SUS = NULL; +#ifdef CONFIG_SMP +static void +voyager_dump(int dummy1, struct pt_regs *dummy2, struct tty_struct *dummy3) +{ + /* get here via a sysrq */ + voyager_smp_dump(); +} + +static struct sysrq_key_op sysrq_voyager_dump_op = { + .handler = voyager_dump, + .help_msg = "voyager", + .action_msg = "Dump Voyager Status\n", +}; +#endif + void voyager_detect(struct voyager_bios_info *bios) { @@ -62,6 +78,9 @@ printk("\n**WARNING**: Voyager HAL only supports Levels 4 and 5 Architectures at the moment\n\n"); /* install the power off handler */ pm_power_off = voyager_power_off; +#ifdef CONFIG_SMP + register_sysrq_key('c', &sysrq_voyager_dump_op); +#endif } else { printk("\n\n**WARNING**: No Voyager Subsystem Found\n"); } @@ -143,15 +162,6 @@ return retval; } -void -voyager_dump() -{ - /* get here via a sysrq */ -#ifdef CONFIG_SMP - voyager_smp_dump(); -#endif -} - /* voyager specific handling code for timer interrupts. Used to hand * off the timer tick to the SMP code, since the VIC doesn't have an * internal timer (The QIC does, but that's another story). */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/arch/i386/mach-voyager/voyager_smp.c linux.2.5.47-ac6/arch/i386/mach-voyager/voyager_smp.c --- linux.2.5.47/arch/i386/mach-voyager/voyager_smp.c 2002-10-31 15:05:00.000000000 +0000 +++ linux.2.5.47-ac6/arch/i386/mach-voyager/voyager_smp.c 2002-11-17 00:19:07.000000000 +0000 @@ -450,6 +450,7 @@ struct cpuinfo_x86 *c=&cpu_data[id]; *c = boot_cpu_data; + identify_cpu(c); } @@ -512,6 +513,11 @@ /* if we're a quad, we may need to bootstrap other CPUs */ do_quad_bootstrap(); + /* FIXME: this is rather a poor hack to prevent the CPU + * activating softirqs while it's supposed to be waiting for + * permission to proceed. Without this, the new per CPU stuff + * in the softirqs will fail */ + local_irq_disable(); set_bit(cpuid, &cpu_callin_map); /* signal that we're done */ @@ -519,6 +525,7 @@ while (!test_bit(cpuid, &smp_commenced_mask)) rep_nop(); + local_irq_enable(); local_flush_tlb(); @@ -764,6 +771,9 @@ /* enable our own CPIs */ vic_enable_cpi(); + + set_bit(boot_cpu_id, &cpu_online_map); + set_bit(boot_cpu_id, &cpu_callout_map); /* loop over all the extended VIC CPUs and boot them. The * Quad CPUs must be bootstrapped by their extended VIC cpu */ @@ -1312,12 +1322,9 @@ static inline void wrapper_smp_local_timer_interrupt(struct pt_regs *regs) { - __u8 cpu = smp_processor_id(); - irq_enter(); smp_local_timer_interrupt(regs); irq_exit(); - } /* local (per CPU) timer interrupt. It does both profiling and diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/arch/i386/Makefile linux.2.5.47-ac6/arch/i386/Makefile --- linux.2.5.47/arch/i386/Makefile 2002-11-11 16:39:08.000000000 +0000 +++ linux.2.5.47-ac6/arch/i386/Makefile 2002-11-11 16:42:21.000000000 +0000 @@ -49,8 +49,16 @@ ifdef CONFIG_VISWS MACHINE := mach-visws else +ifdef CONFIG_VOYAGER +MACHINE := mach-voyager +else MACHINE := mach-generic endif +endif + +ifdef CONFIG_X86_STACK_CHECK +CFLAGS += -p +endif HEAD := arch/i386/kernel/head.o arch/i386/kernel/init_task.o @@ -63,8 +71,8 @@ # FIXME: is drivers- right ? drivers-$(CONFIG_OPROFILE) += arch/i386/oprofile/ -CFLAGS += -Iarch/i386/$(MACHINE) -AFLAGS += -Iarch/i386/$(MACHINE) +CFLAGS += -Iarch/i386/$(MACHINE) -Iarch/i386/mach-defaults +AFLAGS += -Iarch/i386/$(MACHINE) -Iarch/i386/mach-defaults makeboot = $(call descend,arch/i386/boot,$(1)) @@ -91,6 +99,7 @@ +@$(call makeboot,BOOTIMAGE=$(BOOTIMAGE) install) archclean: - @$(MAKE) -f scripts/Makefile.clean obj=arch/i386/boot + $(MAKE) -f scripts/Makefile.clean obj=arch/i386/boot + $(MAKE) -f scripts/Makefile.clean obj=arch/i386/boot98 archmrproper: diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/arch/i386/pci/direct.c linux.2.5.47-ac6/arch/i386/pci/direct.c --- linux.2.5.47/arch/i386/pci/direct.c 2002-10-31 14:57:24.000000000 +0000 +++ linux.2.5.47-ac6/arch/i386/pci/direct.c 2002-10-31 15:05:49.000000000 +0000 @@ -261,7 +261,6 @@ } local_irq_restore(flags); - pci_root_ops = NULL; return 0; } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/arch/i386/pci/pcbios.c linux.2.5.47-ac6/arch/i386/pci/pcbios.c --- linux.2.5.47/arch/i386/pci/pcbios.c 2002-10-31 14:57:24.000000000 +0000 +++ linux.2.5.47-ac6/arch/i386/pci/pcbios.c 2002-10-31 15:05:49.000000000 +0000 @@ -5,22 +5,9 @@ #include #include #include "pci.h" +#include "pci-functions.h" -#define PCIBIOS_PCI_FUNCTION_ID 0xb1XX -#define PCIBIOS_PCI_BIOS_PRESENT 0xb101 -#define PCIBIOS_FIND_PCI_DEVICE 0xb102 -#define PCIBIOS_FIND_PCI_CLASS_CODE 0xb103 -#define PCIBIOS_GENERATE_SPECIAL_CYCLE 0xb106 -#define PCIBIOS_READ_CONFIG_BYTE 0xb108 -#define PCIBIOS_READ_CONFIG_WORD 0xb109 -#define PCIBIOS_READ_CONFIG_DWORD 0xb10a -#define PCIBIOS_WRITE_CONFIG_BYTE 0xb10b -#define PCIBIOS_WRITE_CONFIG_WORD 0xb10c -#define PCIBIOS_WRITE_CONFIG_DWORD 0xb10d -#define PCIBIOS_GET_ROUTING_OPTIONS 0xb10e -#define PCIBIOS_SET_PCI_HW_INT 0xb10f - /* BIOS32 signature: "_32_" */ #define BIOS32_SIGNATURE (('_' << 0) + ('3' << 8) + ('2' << 16) + ('_' << 24)) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/arch/ia64/hp/sim/simscsi.c linux.2.5.47-ac6/arch/ia64/hp/sim/simscsi.c --- linux.2.5.47/arch/ia64/hp/sim/simscsi.c 2002-11-05 13:54:42.000000000 +0000 +++ linux.2.5.47-ac6/arch/ia64/hp/sim/simscsi.c 2002-11-11 20:22:07.000000000 +0000 @@ -115,6 +115,9 @@ { templ->proc_name = "simscsi"; host = scsi_register(templ, 0); + if(host == NULL) + return 0; + return 1; /* fake one SCSI host adapter */ } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/arch/s390/boot/Makefile linux.2.5.47-ac6/arch/s390/boot/Makefile --- linux.2.5.47/arch/s390/boot/Makefile 2002-10-31 14:57:34.000000000 +0000 +++ linux.2.5.47-ac6/arch/s390/boot/Makefile 2002-10-31 15:05:57.000000000 +0000 @@ -1,28 +1,27 @@ # -# arch/s390/boot/Makefile +# Makefile for the linux s390-specific parts of the memory manager. # EXTRA_AFLAGS := -traditional include $(TOPDIR)/Rules.make -%.lnk: %.o - $(LD) $(LDFLAGS) -Ttext 0x0 -o $@ $< +quiet_cmd_listing = OBJDUMP $(echo_target) +cmd_listing = $(OBJDUMP) --disassemble --disassemble-all \ + --disassemble-zeroes --reloc vmlinux > $@ -%.boot: %.lnk - $(OBJCOPY) $(OBJCOPYFLAGS) $< $@ +$(obj)/image: vmlinux + $(call if_changed,objcopy) -image: $(TOPDIR)/vmlinux \ - iplfba.boot ipleckd.boot ipldump.boot - $(OBJCOPY) $(OBJCOPYFLAGS) $(TOPDIR)/vmlinux image - $(NM) $(TOPDIR)/vmlinux | grep -v '\(compiled\)\|\( [aUw] \)\|\(\.\)\|\(LASH[RL]DI\)' | sort > $(TOPDIR)/System.map +$(obj)/listing: vmlinux + $(call if_changed,listing) -listing: ../../../vmlinux - $(OBJDUMP) --disassemble --disassemble-all --disassemble-zeroes --reloc $(TOPDIR)/vmlinux > listing +image: $(obj)/image + +listing: $(obj)/listing clean: - rm -f image listing iplfba.boot ipleckd.boot ipldump.boot + rm -f $(obj)/image $(obj)/listing install: $(CONFIGURE) $(BOOTIMAGE) - sh -x ./install.sh $(KERNELRELEASE) $(BOOTIMAGE) $(TOPDIR)/System.map $(TOPDIR)/Kerntypes "$(INSTALL_PATH)" - + sh -x $(obj)/install.sh $(KERNELRELEASE) $(BOOTIMAGE) System.map Kerntypes "$(INSTALL_PATH)" diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/arch/s390/defconfig linux.2.5.47-ac6/arch/s390/defconfig --- linux.2.5.47/arch/s390/defconfig 2002-10-31 14:57:35.000000000 +0000 +++ linux.2.5.47-ac6/arch/s390/defconfig 2002-11-01 11:32:19.000000000 +0000 @@ -39,7 +39,7 @@ # CONFIG_SMP=y CONFIG_MATHEMU=y -CONFIG_NR_CPUS=64 +CONFIG_NR_CPUS=32 # # I/O subsystem configuration @@ -147,7 +147,7 @@ CONFIG_DASD=y CONFIG_DASD_ECKD=y CONFIG_DASD_FBA=y -# CONFIG_DASD_DIAG is not set +CONFIG_DASD_DIAG=y # # Multi-device support (RAID and LVM) @@ -301,7 +301,7 @@ # CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set CONFIG_PROC_FS=y -CONFIG_DEVFS_FS=y +# CONFIG_DEVFS_FS is not set # CONFIG_DEVFS_MOUNT is not set # CONFIG_DEVFS_DEBUG is not set # CONFIG_DEVPTS_FS is not set @@ -325,13 +325,16 @@ # CONFIG_INTERMEZZO_FS is not set CONFIG_NFS_FS=y # CONFIG_NFS_V3 is not set +# CONFIG_NFS_V4 is not set # CONFIG_ROOT_NFS is not set CONFIG_NFSD=y # CONFIG_NFSD_V3 is not set +# CONFIG_NFSD_V4 is not set # CONFIG_NFSD_TCP is not set CONFIG_SUNRPC=y CONFIG_LOCKD=y CONFIG_EXPORTFS=y +# CONFIG_CIFS is not set # CONFIG_SMB_FS is not set # CONFIG_NCP_FS is not set # CONFIG_NCPFS_PACKET_SIGNING is not set @@ -342,6 +345,7 @@ # CONFIG_NCPFS_SMALLDOS is not set # CONFIG_NCPFS_NLS is not set # CONFIG_NCPFS_EXTRAS is not set +# CONFIG_AFS_FS is not set # CONFIG_ZISOFS_FS is not set # diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/arch/s390/Kconfig linux.2.5.47-ac6/arch/s390/Kconfig --- linux.2.5.47/arch/s390/Kconfig 2002-11-11 16:39:09.000000000 +0000 +++ linux.2.5.47-ac6/arch/s390/Kconfig 2002-11-11 16:50:46.000000000 +0000 @@ -115,6 +115,12 @@ int "Maximum number of CPUs (2-32)" depends on SMP default "32" + help + This allows you to specify the maximum number of CPUs which this + kernel will support. The maximum supported value is 32 and the + minimum value which makes sense is 2. + This is purely to save memory - each supported CPU adds + approximately eight kilobytes to the kernel image. comment "I/O subsystem configuration" @@ -153,6 +159,15 @@ config PREEMPT bool "Preemptible Kernel" + help + This option reduces the latency of the kernel when reacting to + real-time or interactive events by allowing a low priority process to + be preempted even if it is in kernel mode executing a system call. + This allows applications to run more reliably even when the system is + under load. + + Say Y here if you are building a kernel for a desktop, embedded + or real-time system. Say N if you are unsure. config IPL bool "Builtin IPL record support" diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/arch/s390/lib/uaccess.S linux.2.5.47-ac6/arch/s390/lib/uaccess.S --- linux.2.5.47/arch/s390/lib/uaccess.S 2002-10-31 14:57:35.000000000 +0000 +++ linux.2.5.47-ac6/arch/s390/lib/uaccess.S 2002-11-01 11:32:36.000000000 +0000 @@ -1,9 +1,9 @@ /* * arch/s390/lib/uaccess.S - * fixup routines for copy_{from|to}_user functions. + * __copy_{from|to}_user functions. * * s390 - * Copyright (C) 2000 IBM Deutschland Entwicklung GmbH, IBM Corporation + * Copyright (C) 2000,2002 IBM Deutschland Entwicklung GmbH, IBM Corporation * Authors(s): Martin Schwidefsky (schwidefsky@de.ibm.com) * * These functions have standard call interface @@ -22,17 +22,23 @@ 1: sacf 0 lr %r2,%r5 br %r14 -2: sll %r4,1 - srl %r4,1 - lhi %r3,-4096 - sll %r3,1 - srl %r3,1 - n %r3,__LC_TRANS_EXC_ADDR - sr %r3,%r4 - jm 1b - j 0b +2: lhi %r1,-4096 + lr %r3,%r4 + slr %r3,%r1 # %r3 = %r4 + 4096 + nr %r3,%r1 # %r3 = (%r4 + 4096) & -4096 + slr %r3,%r4 # %r3 = #bytes to next user page boundary + clr %r5,%r3 # copy crosses next page boundary ? + jnh 1b # no, this page fauled + # The page after the current user page might have faulted. + # We cant't find out which page because the program check handler + # might have callled schedule, destroying all lowcore information. + # We retry with the shortened length. +3: mvcle %r2,%r4,0 + jo 3b + j 1b .section __ex_table,"a" .long 0b,2b + .long 3b,1b .previous .align 4 @@ -46,17 +52,23 @@ 1: sacf 0 lr %r2,%r3 br %r14 -2: sll %r4,1 - srl %r4,1 - lhi %r5,-4096 - sll %r5,1 - srl %r5,1 - n %r5,__LC_TRANS_EXC_ADDR - sr %r5,%r4 - jm 1b - j 0b +2: lhi %r1,-4096 + lr %r5,%r4 + slr %r5,%r1 # %r5 = %r4 + 4096 + nr %r5,%r1 # %r5 = (%r4 + 4096) & -4096 + slr %r5,%r4 # %r5 = #bytes to next user page boundary + clr %r3,%r5 # copy crosses next page boundary ? + jnh 1b # no, the current page fauled + # The page after the current user page might have faulted. + # We cant't find out which page because the program check handler + # might have callled schedule, destroying all lowcore information. + # We retry with the shortened length. +3: mvcle %r4,%r2,0 + jo 3b + j 1b .section __ex_table,"a" - .long 0b,2b + .long 0b,2b + .long 3b,1b .previous .align 4 @@ -71,18 +83,26 @@ 0: mvcle %r4,%r2,0 jo 0b 1: sacf 0 - lr %r2,%r3 br %r14 -2: sll %r4,1 - srl %r4,1 - lhi %r5,-4096 - sll %r5,1 - srl %r5,1 - n %r5,__LC_TRANS_EXC_ADDR - sr %r5,%r4 - jm 1b - j 0b +2: lr %r2,%r5 + lhi %r1,-4096 + slr %r5,%r1 # %r5 = %r4 + 4096 + nr %r5,%r1 # %r5 = (%r4 + 4096) & -4096 + slr %r5,%r4 # %r5 = #bytes to next user page boundary + clr %r2,%r5 # copy crosses next page boundary ? + jnh 1b # no, the current page fauled + # The page after the current user page might have faulted. + # We cant't find out which page because the program check handler + # might have callled schedule, destroying all lowcore information. + # We retry with the shortened length. + slr %r2,%r5 +3: mvcle %r4,%r2,0 + jo 3b + j 1b +4: alr %r2,%r5 + j 1b .section __ex_table,"a" - .long 0b,2b + .long 0b,2b + .long 3b,4b .previous diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/arch/s390/Makefile linux.2.5.47-ac6/arch/s390/Makefile --- linux.2.5.47/arch/s390/Makefile 2002-10-31 14:57:35.000000000 +0000 +++ linux.2.5.47-ac6/arch/s390/Makefile 2002-11-01 11:32:36.000000000 +0000 @@ -28,18 +28,14 @@ all: image listing -listing: vmlinux - @$(MAKEBOOT) listing +makeboot = $(call descend,arch/$(ARCH)/boot,$(1)) +BOOTIMAGE= arch/$(ARCH)/boot/image -MAKEBOOT = $(MAKE) -C arch/$(ARCH)/boot - -image: vmlinux - @$(MAKEBOOT) image - -install: vmlinux - @$(MAKEBOOT) BOOTIMAGE=image install +listing install image: vmlinux + +@$(call makeboot,BOOTIMAGE=$(BOOTIMAGE) $@) archclean: + +@$(call makeboot,clean) archmrproper: diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/arch/s390x/boot/Makefile linux.2.5.47-ac6/arch/s390x/boot/Makefile --- linux.2.5.47/arch/s390x/boot/Makefile 2002-10-31 14:57:34.000000000 +0000 +++ linux.2.5.47-ac6/arch/s390x/boot/Makefile 2002-10-31 15:05:57.000000000 +0000 @@ -6,22 +6,22 @@ include $(TOPDIR)/Rules.make -%.lnk: %.o - $(LD) -Ttext 0x0 -o $@ $< +quiet_cmd_listing = OBJDUMP $(echo_target) +cmd_listing = $(OBJDUMP) --disassemble --disassemble-all \ + --disassemble-zeroes --reloc vmlinux > $@ -%.boot: %.lnk - $(OBJCOPY) $(OBJCOPYFLAGS) $< $@ +$(obj)/image: vmlinux + $(call if_changed,objcopy) -image: $(TOPDIR)/vmlinux \ - iplfba.boot ipleckd.boot ipldump.boot - $(OBJCOPY) $(OBJCOPYFLAGS) $< $@ - $(NM) $(TOPDIR)/vmlinux | grep -v '\(compiled\)\|\( [aUw] \)\|\(\.\)\|\(LASH[RL]DI\)' | sort > $(TOPDIR)/System.map +$(obj)/listing: vmlinux + $(call if_changed,listing) -listing: ../../../vmlinux - $(OBJDUMP) --disassemble --disassemble-all --disassemble-zeroes --reloc $(TOPDIR)/vmlinux > listing +image: $(obj)/image + +listing: $(obj)/listing clean: - rm -f image listing iplfba.boot ipleckd.boot ipldump.boot + rm -f $(obj)/image $(obj)/listing install: $(CONFIGURE) $(BOOTIMAGE) - sh -x ./install.sh $(KERNELRELEASE) $(BOOTIMAGE) $(TOPDIR)/System.map $(TOPDIR)/Kerntypes "$(INSTALL_PATH)" + sh -x $(obj)/install.sh $(KERNELRELEASE) $(BOOTIMAGE) System.map Kerntypes "$(INSTALL_PATH)" diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/arch/s390x/defconfig linux.2.5.47-ac6/arch/s390x/defconfig --- linux.2.5.47/arch/s390x/defconfig 2002-10-31 14:57:34.000000000 +0000 +++ linux.2.5.47-ac6/arch/s390x/defconfig 2002-10-31 15:05:57.000000000 +0000 @@ -38,15 +38,15 @@ # Processor type and features # CONFIG_SMP=y +CONFIG_NR_CPUS=64 CONFIG_S390_SUPPORT=y CONFIG_BINFMT_ELF32=y -CONFIG_NR_CPUS=64 # # I/O subsystem configuration # CONFIG_MACHCHK_WARNING=y -CONFIG_QDIO=y +CONFIG_QDIO=m # CONFIG_QDIO_PERF_STATS is not set # @@ -301,7 +301,7 @@ # CONFIG_NTFS_RW is not set # CONFIG_HPFS_FS is not set CONFIG_PROC_FS=y -CONFIG_DEVFS_FS=y +# CONFIG_DEVFS_FS is not set # CONFIG_DEVFS_MOUNT is not set # CONFIG_DEVFS_DEBUG is not set # CONFIG_DEVPTS_FS is not set @@ -325,13 +325,16 @@ # CONFIG_INTERMEZZO_FS is not set CONFIG_NFS_FS=y # CONFIG_NFS_V3 is not set +# CONFIG_NFS_V4 is not set # CONFIG_ROOT_NFS is not set CONFIG_NFSD=y # CONFIG_NFSD_V3 is not set +# CONFIG_NFSD_V4 is not set # CONFIG_NFSD_TCP is not set CONFIG_SUNRPC=y CONFIG_LOCKD=y CONFIG_EXPORTFS=y +# CONFIG_CIFS is not set # CONFIG_SMB_FS is not set # CONFIG_NCP_FS is not set # CONFIG_NCPFS_PACKET_SIGNING is not set @@ -342,6 +345,7 @@ # CONFIG_NCPFS_SMALLDOS is not set # CONFIG_NCPFS_NLS is not set # CONFIG_NCPFS_EXTRAS is not set +# CONFIG_AFS_FS is not set # CONFIG_ZISOFS_FS is not set # diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/arch/s390x/Kconfig linux.2.5.47-ac6/arch/s390x/Kconfig --- linux.2.5.47/arch/s390x/Kconfig 2002-11-11 16:39:09.000000000 +0000 +++ linux.2.5.47-ac6/arch/s390x/Kconfig 2002-11-11 16:50:46.000000000 +0000 @@ -108,6 +108,12 @@ int "Maximum number of CPUs (2-64)" depends on SMP default "64" + This allows you to specify the maximum number of CPUs which this + kernel will support. The maximum supported value is 32 and the + minimum value which makes sense is 2. + + This is purely to save memory - each supported CPU adds + approximately eight kilobytes to the kernel image. config S390_SUPPORT bool "Kernel support for 31 bit emulation" @@ -161,6 +167,15 @@ config PREEMPT bool "Preemptible Kernel" + help + This option reduces the latency of the kernel when reacting to + real-time or interactive events by allowing a low priority process to + be preempted even if it is in kernel mode executing a system call. + This allows applications to run more reliably even when the system is + under load. + + Say Y here if you are building a kernel for a desktop, embedded + or real-time system. Say N if you are unsure. config IPL bool "Builtin IPL record support" diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/arch/s390x/kernel/linux32.c linux.2.5.47-ac6/arch/s390x/kernel/linux32.c --- linux.2.5.47/arch/s390x/kernel/linux32.c 2002-10-31 14:57:34.000000000 +0000 +++ linux.2.5.47-ac6/arch/s390x/kernel/linux32.c 2002-11-02 21:33:06.000000000 +0000 @@ -2492,8 +2492,23 @@ CMSG32_ALIGN(sizeof(struct cmsghdr32))); kcmsg32->cmsg_len = clen32; + switch (kcmsg32->cmsg_type) { + /* + * The timestamp type's data needs to be converted + * from 64-bit time values to 32-bit time values + */ + case SO_TIMESTAMP: { + __kernel_time_t32* ptr_time32 = CMSG32_DATA(kcmsg32); + __kernel_time_t* ptr_time = CMSG_DATA(ucmsg); + get_user(*ptr_time32, ptr_time); + get_user(*(ptr_time32+1), ptr_time+1); + kcmsg32->cmsg_len -= 2*(sizeof(__kernel_time_t) - + sizeof(__kernel_time_t32)); + } + default:; + } ucmsg = (struct cmsghdr *) (((char *)ucmsg) + CMSG_ALIGN(clen64)); - wp = (((char *)kcmsg32) + CMSG32_ALIGN(clen32)); + wp = (((char *)kcmsg32) + CMSG32_ALIGN(kcmsg32->cmsg_len)); } /* Copy back fixed up data, and adjust pointers. */ @@ -2608,6 +2623,9 @@ err = sock->ops->recvmsg(&iocb, sock, &kern_msg, total_len, user_flags, si->scm); + if (err >= 0) + scm_recv32(sock, msg, &iocb, flags, cmsg_ptr); + if (-EIOCBQUEUED == err) err = wait_on_sync_kiocb(&iocb); @@ -2640,7 +2658,7 @@ sockfd_put(sock); } - if(uaddr != NULL && err >= 0) + if(uaddr != NULL && err >= 0 && kern_msg.msg_namelen) err = move_addr_to_user(addr, kern_msg.msg_namelen, uaddr, uaddr_len); if(cmsg_ptr != 0 && err >= 0) { unsigned long ucmsg_ptr = ((unsigned long)kern_msg.msg_control); @@ -2742,6 +2760,32 @@ return err; } +static __inline__ void +scm_recv32(struct socket *sock, struct msghdr *msg, + struct sock_iocb *si, int flags, unsigned long cmsg_ptr) +{ + if(!msg->msg_control) { + if(sock->passcred || si->scm->fp) + msg->msg_flags |= MSG_CTRUNC; + if(si->scm->fp) + __scm_destroy(si->scm); + } else { + /* If recvmsg processing itself placed some + * control messages into user space, it's is + * using 64-bit CMSG processing, so we need + * to fix it up before we tack on more stuff. + */ + if((unsigned long) msg->msg_control != cmsg_ptr) + cmsg32_recvmsg_fixup(msg, cmsg_ptr); + /* Wheee... */ + if(sock->passcred) + put_cmsg32(msg, SOL_SOCKET, SCM_CREDENTIALS, + sizeof(si->scm->creds), &si->scm->creds); + if(si->scm->fp != NULL) + scm_detach_fds32(msg, si->scm); + } +} + /* * BSD recvmsg interface */ @@ -2815,6 +2859,9 @@ err = sock->ops->recvmsg(&iocb, sock, &msg_sys, total_len, flags, si->scm); + if (err >= 0) + scm_recv32(sock, msg, &iocb, flags, cmsg_ptr); + if (-EIOCBQUEUED == err) err = wait_on_sync_kiocb(&iocb); if (err < 0) @@ -2828,27 +2875,13 @@ if (err < 0) goto out_freeiov; } - if(!msg_sys.msg_control) { - if(sock->passcred || si->scm->fp) - msg_sys.msg_flags |= MSG_CTRUNC; - if(si->scm->fp) - __scm_destroy(si->scm); - } else { - /* If recvmsg processing itself placed some - * control messages into user space, it's is - * using 64-bit CMSG processing, so we need - * to fix it up before we tack on more stuff. - */ - if((unsigned long) msg_sys.msg_control != cmsg_ptr) - cmsg32_recvmsg_fixup(&msg_sys, cmsg_ptr); - /* Wheee... */ - if(sock->passcred) - put_cmsg32(&msg_sys, - SOL_SOCKET, SCM_CREDENTIALS, - sizeof(si->scm->creds), &si->scm->creds); - if(si->scm->fp != NULL) - scm_detach_fds32(&msg_sys, si->scm); - } + err = __put_user(msg_sys.msg_flags, &msg->msg_flags); + if (err) + goto out_freeiov; + err = __put_user((__kernel_size_t32) ((unsigned long)msg_sys.msg_control - cmsg_ptr), &msg->msg_controllen); + if (err) + goto out_freeiov; + err = len; out_freeiov: if (iov != iovstack) @@ -2941,6 +2974,20 @@ if (level == SOL_ICMPV6 && optname == ICMPV6_FILTER) return do_set_icmpv6_filter(fd, level, optname, optval, optlen); + if (level == SOL_SOCKET && + (optname == SO_SNDTIMEO || optname == SO_RCVTIMEO)) { + long ret; + struct timeval tmp; + mm_segment_t old_fs; + + if (get_tv32(&tmp, (struct timeval32 *)optval )) + return -EFAULT; + old_fs = get_fs(); + set_fs(KERNEL_DS); + ret = sys_setsockopt(fd, level, optname, (char *) &tmp, sizeof(struct timeval)); + set_fs(old_fs); + return ret; + } return sys_setsockopt(fd, level, optname, optval, optlen); } @@ -4551,26 +4598,19 @@ sys32_futex(void *uaddr, int op, int val, struct timespec32 *timeout32) { - long ret; - struct timespec tmp, *timeout; - - ret = -ENOMEM; - timeout = kmalloc(sizeof(*timeout), GFP_USER); - if (!timeout) - goto out; + struct timespec tmp; + mm_segment_t old_fs; + int ret; - ret = -EINVAL; if (get_user (tmp.tv_sec, &timeout32->tv_sec) || - get_user (tmp.tv_nsec, &timeout32->tv_nsec) || - put_user (tmp.tv_sec, &timeout->tv_sec) || - put_user (tmp.tv_nsec, &timeout->tv_nsec)) - goto out_free; + get_user (tmp.tv_nsec, &timeout32->tv_nsec)) + return -EINVAL; - ret = sys_futex(uaddr, op, val, timeout); + old_fs = get_fs(); + set_fs(KERNEL_DS); + ret = sys_futex(uaddr, op, val, &tmp); + set_fs(old_fs); -out_free: - kfree(timeout); -out: return ret; } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/arch/s390x/lib/uaccess.S linux.2.5.47-ac6/arch/s390x/lib/uaccess.S --- linux.2.5.47/arch/s390x/lib/uaccess.S 2002-10-31 14:57:34.000000000 +0000 +++ linux.2.5.47-ac6/arch/s390x/lib/uaccess.S 2002-10-31 15:05:57.000000000 +0000 @@ -1,9 +1,9 @@ /* * arch/s390x/lib/uaccess.S - * fixup routines for copy_{from|to}_user functions. + * __copy_{from|to}_user functions. * - * S390 - * Copyright (C) 2000 IBM Deutschland Entwicklung GmbH, IBM Corporation + * s390 + * Copyright (C) 2000,2002 IBM Deutschland Entwicklung GmbH, IBM Corporation * Authors(s): Martin Schwidefsky (schwidefsky@de.ibm.com) * * These functions have standard call interface @@ -22,14 +22,23 @@ 1: sacf 0 lgr %r2,%r5 br %r14 -2: lghi %r3,-4096 - ng %r3,__LC_TRANS_EXC_ADDR - sgr %r3,%r4 - jm 1b - j 0b +2: lghi %r1,-4096 + lgr %r3,%r4 + slgr %r3,%r1 # %r3 = %r4 + 4096 + ngr %r3,%r1 # %r3 = (%r4 + 4096) & -4096 + slgr %r3,%r4 # %r3 = #bytes to next user page boundary + clgr %r5,%r3 # copy crosses next page boundary ? + jnh 1b # no, this page fauled + # The page after the current user page might have faulted. + # We cant't find out which page because the program check handler + # might have callled schedule, destroying all lowcore information. + # We retry with the shortened length. +3: mvcle %r2,%r4,0 + jo 3b + j 1b .section __ex_table,"a" - .align 8 .quad 0b,2b + .quad 3b,1b .previous .align 4 @@ -43,14 +52,23 @@ 1: sacf 0 lgr %r2,%r3 br %r14 -2: lghi %r5,-4096 - ng %r5,__LC_TRANS_EXC_ADDR - sgr %r5,%r4 - jm 1b - j 0b +2: lghi %r1,-4096 + lgr %r5,%r4 + slgr %r5,%r1 # %r5 = %r4 + 4096 + ngr %r5,%r1 # %r5 = (%r4 + 4096) & -4096 + slgr %r5,%r4 # %r5 = #bytes to next user page boundary + clgr %r3,%r5 # copy crosses next page boundary ? + jnh 1b # no, the current page fauled + # The page after the current user page might have faulted. + # We cant't find out which page because the program check handler + # might have callled schedule, destroying all lowcore information. + # We retry with the shortened length. +3: mvcle %r4,%r2,0 + jo 3b + j 1b .section __ex_table,"a" - .align 8 - .quad 0b,2b + .quad 0b,2b + .quad 3b,1b .previous .align 4 @@ -65,14 +83,25 @@ 0: mvcle %r4,%r2,0 jo 0b 1: sacf 0 - lgr %r2,%r5 br %r14 -2: lghi %r5,-4096 - ng %r5,__LC_TRANS_EXC_ADDR - sgr %r5,%r4 - jm 1b - j 0b +2: lgr %r2,%r5 + lghi %r1,-4096 + slgr %r5,%r1 # %r5 = %r4 + 4096 + ngr %r5,%r1 # %r5 = (%r4 + 4096) & -4096 + slgr %r5,%r4 # %r5 = #bytes to next user page boundary + clgr %r2,%r5 # copy crosses next page boundary ? + jnh 1b # no, the current page fauled + # The page after the current user page might have faulted. + # We cant't find out which page because the program check handler + # might have callled schedule, destroying all lowcore information. + # We retry with the shortened length. + slgr %r2,%r5 +3: mvcle %r4,%r2,0 + jo 3b + j 1b +4: algr %r2,%r5 + j 1b .section __ex_table,"a" - .align 8 - .quad 0b,2b + .quad 0b,2b + .quad 3b,4b .previous diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/arch/s390x/Makefile linux.2.5.47-ac6/arch/s390x/Makefile --- linux.2.5.47/arch/s390x/Makefile 2002-10-31 14:57:34.000000000 +0000 +++ linux.2.5.47-ac6/arch/s390x/Makefile 2002-10-31 15:05:57.000000000 +0000 @@ -28,18 +28,14 @@ all: image listing -listing: vmlinux - @$(MAKEBOOT) listing +makeboot = $(call descend,arch/$(ARCH)/boot,$(1)) +BOOTIMAGE= arch/$(ARCH)/boot/image -MAKEBOOT = $(MAKE) -C arch/$(ARCH)/boot - -image: vmlinux - @$(MAKEBOOT) image - -install: vmlinux - @$(MAKEBOOT) BOOTIMAGE=image install +listing install image: vmlinux + +@$(call makeboot,BOOTIMAGE=$(BOOTIMAGE) $@) archclean: + +@$(call makeboot,clean) archmrproper: diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/arch/sparc64/defconfig linux.2.5.47-ac6/arch/sparc64/defconfig --- linux.2.5.47/arch/sparc64/defconfig 2002-10-31 15:05:00.000000000 +0000 +++ linux.2.5.47-ac6/arch/sparc64/defconfig 2002-11-05 16:08:04.000000000 +0000 @@ -569,7 +569,6 @@ # CONFIG_BAYCOM_SER_HDX is not set # CONFIG_BAYCOM_PAR is not set # CONFIG_BAYCOM_EPP is not set -# CONFIG_SOUNDMODEM is not set # CONFIG_YAM is not set # diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/arch/um/defconfig linux.2.5.47-ac6/arch/um/defconfig --- linux.2.5.47/arch/um/defconfig 2002-10-31 14:57:35.000000000 +0000 +++ linux.2.5.47-ac6/arch/um/defconfig 2002-10-31 15:05:57.000000000 +0000 @@ -219,13 +219,16 @@ # CONFIG_INTERMEZZO_FS is not set # CONFIG_NFS_FS is not set # CONFIG_NFS_V3 is not set +# CONFIG_NFS_V4 is not set # CONFIG_ROOT_NFS is not set # CONFIG_NFSD is not set # CONFIG_NFSD_V3 is not set +# CONFIG_NFSD_V4 is not set # CONFIG_NFSD_TCP is not set # CONFIG_SUNRPC is not set # CONFIG_LOCKD is not set # CONFIG_EXPORTFS is not set +# CONFIG_CIFS is not set # CONFIG_SMB_FS is not set # CONFIG_NCP_FS is not set # CONFIG_NCPFS_PACKET_SIGNING is not set @@ -236,6 +239,7 @@ # CONFIG_NCPFS_SMALLDOS is not set # CONFIG_NCPFS_NLS is not set # CONFIG_NCPFS_EXTRAS is not set +# CONFIG_AFS_FS is not set # CONFIG_ZISOFS_FS is not set # @@ -332,7 +336,9 @@ CONFIG_MTD=y # CONFIG_MTD_DEBUG is not set # CONFIG_MTD_PARTITIONS is not set +# CONFIG_MTD_CONCAT is not set # CONFIG_MTD_REDBOOT_PARTS is not set +# CONFIG_MTD_CMDLINE_PARTS is not set # # User Modules And Translation Layers @@ -362,6 +368,8 @@ # Mapping drivers for chip access # # CONFIG_MTD_PHYSMAP is not set +# CONFIG_MTD_PCI is not set +# CONFIG_MTD_PCMCIA is not set # # Self-contained MTD device drivers diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/arch/um/drivers/Makefile linux.2.5.47-ac6/arch/um/drivers/Makefile --- linux.2.5.47/arch/um/drivers/Makefile 2002-10-31 14:57:35.000000000 +0000 +++ linux.2.5.47-ac6/arch/um/drivers/Makefile 2002-10-31 15:05:57.000000000 +0000 @@ -15,7 +15,7 @@ # So, what this does is figure out by hand (crudely) what file -lpcap really # is and just use it. -PCAP = $(shell for f in echo {/lib,/usr/lib}/libpcap.{a,so}; do \ +PCAP = $(shell for f in echo {/lib,/usr/lib}/libpcap.a; do \ [ -f $$f ] && echo $$f ; done | head -1) slip-objs := slip_kern.o slip_user.o @@ -47,7 +47,7 @@ obj-$(CONFIG_PORT_CHAN) += port.o obj-$(CONFIG_PTY_CHAN) += pty.o obj-$(CONFIG_TTY_CHAN) += tty.o -obj-$(CONFIG_XTERM_CHAN) += xterm.o +obj-$(CONFIG_XTERM_CHAN) += xterm.o xterm_kern.o obj-$(CONFIG_UML_WATCHDOG) += harddog.o CFLAGS_pcap_user.o = -I/usr/include/pcap diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/arch/um/drivers/mconsole_kern.c linux.2.5.47-ac6/arch/um/drivers/mconsole_kern.c --- linux.2.5.47/arch/um/drivers/mconsole_kern.c 2002-10-31 14:57:35.000000000 +0000 +++ linux.2.5.47-ac6/arch/um/drivers/mconsole_kern.c 2002-10-31 15:05:57.000000000 +0000 @@ -111,6 +111,8 @@ remove - Remove a device from UML sysrq - Performs the SysRq action controlled by the letter cad - invoke the Ctl-Alt-Del handler + stop - pause the UML; it will do nothing until it receives a 'go' + go - continue the UML after a 'stop' " void mconsole_help(struct mc_request *req) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/arch/um/drivers/port_kern.c linux.2.5.47-ac6/arch/um/drivers/port_kern.c --- linux.2.5.47/arch/um/drivers/port_kern.c 2002-10-31 14:57:35.000000000 +0000 +++ linux.2.5.47-ac6/arch/um/drivers/port_kern.c 2002-10-31 15:05:57.000000000 +0000 @@ -20,6 +20,7 @@ struct port_list { struct list_head list; + int has_connection; struct semaphore sem; int port; int fd; @@ -49,28 +50,32 @@ struct connection *conn = data; int fd; - list_del(&conn->list); - fd = os_rcv_fd(conn->socket[0], &conn->helper_pid); if(fd < 0){ + if(fd == -EAGAIN) + return; + printk("os_rcv_fd returned %d\n", -fd); os_close_file(conn->fd); } + + list_del(&conn->list); + conn->fd = fd; list_add(&conn->list, &conn->port->connections); up(&conn->port->sem); } -static void port_interrupt(int irq, void *data, struct pt_regs *regs) +static int port_accept(struct port_list *port) { - struct port_list *port = data; struct connection *conn; - int fd, socket[2], pid; + int fd, socket[2], pid, ret = 0; fd = port_connection(port->fd, socket, &pid); if(fd < 0){ - printk("port_connection returned %d\n", -fd); + if(fd != -EAGAIN) + printk("port_connection returned %d\n", -fd); goto out; } @@ -94,6 +99,7 @@ } list_add(&conn->list, &port->pending); + ret = 1; goto out; out_free: @@ -102,17 +108,45 @@ os_close_file(fd); if(pid != -1) os_kill_process(pid); out: - reactivate_fd(port->fd, ACCEPT_IRQ); + return(ret); } DECLARE_MUTEX(ports_sem); struct list_head ports = LIST_HEAD_INIT(ports); +void port_work_proc(void *unused) +{ + struct port_list *port; + struct list_head *ele; + unsigned long flags; + + local_irq_save(flags); + list_for_each(ele, &ports){ + port = list_entry(ele, struct port_list, list); + if(!port->has_connection) + continue; + reactivate_fd(port->fd, ACCEPT_IRQ); + while(port_accept(port)) ; + port->has_connection = 0; + } + local_irq_restore(flags); +} + +DECLARE_WORK(port_work, port_work_proc, NULL); + +static void port_interrupt(int irq, void *data, struct pt_regs *regs) +{ + struct port_list *port = data; + + port->has_connection = 1; + schedule_work(&port_work); +} + void *port_data(int port_num) { struct list_head *ele; struct port_list *port; - struct port_dev *dev; + struct port_dev *dev = NULL; int fd; down(&ports_sem); @@ -140,13 +174,14 @@ } *port = ((struct port_list) - { list : LIST_HEAD_INIT(port->list), - sem : __SEMAPHORE_INITIALIZER(port->sem, 0), - lock : SPIN_LOCK_UNLOCKED, - port : port_num, - fd : fd, - pending : LIST_HEAD_INIT(port->pending), - connections : LIST_HEAD_INIT(port->connections) }); + { list : LIST_HEAD_INIT(port->list), + has_connection : 0, + sem : __SEMAPHORE_INITIALIZER(port->sem, 0), + lock : SPIN_LOCK_UNLOCKED, + port : port_num, + fd : fd, + pending : LIST_HEAD_INIT(port->pending), + connections : LIST_HEAD_INIT(port->connections) }); list_add(&port->list, &ports); found: @@ -159,8 +194,7 @@ *dev = ((struct port_dev) { port : port, fd : -1, helper_pid : -1 }); - up(&ports_sem); - return(dev); + goto out; out_free: kfree(port); @@ -168,7 +202,7 @@ os_close_file(fd); out: up(&ports_sem); - return(NULL); + return(dev); } void port_remove_dev(void *d) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/arch/um/drivers/ssl.c linux.2.5.47-ac6/arch/um/drivers/ssl.c --- linux.2.5.47/arch/um/drivers/ssl.c 2002-10-31 14:57:35.000000000 +0000 +++ linux.2.5.47-ac6/arch/um/drivers/ssl.c 2002-10-31 15:05:57.000000000 +0000 @@ -44,6 +44,7 @@ xterm_title: "Serial Line #%d", raw: 1, tramp_stack : 0, + in_kernel : 1, }; static struct line_driver driver = { diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/arch/um/drivers/stdio_console.c linux.2.5.47-ac6/arch/um/drivers/stdio_console.c --- linux.2.5.47/arch/um/drivers/stdio_console.c 2002-10-31 14:57:35.000000000 +0000 +++ linux.2.5.47-ac6/arch/um/drivers/stdio_console.c 2002-10-31 15:05:57.000000000 +0000 @@ -75,6 +75,7 @@ xterm_title: "Virtual Console #%d", raw: 1, tramp_stack : 0, + in_kernel : 1, }; static struct line_driver driver = { diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/arch/um/drivers/ubd_kern.c linux.2.5.47-ac6/arch/um/drivers/ubd_kern.c --- linux.2.5.47/arch/um/drivers/ubd_kern.c 2002-10-31 14:57:35.000000000 +0000 +++ linux.2.5.47-ac6/arch/um/drivers/ubd_kern.c 2002-10-31 15:05:57.000000000 +0000 @@ -6,12 +6,15 @@ /* 2001-09-28...2002-04-17 * Partition stuff by James_McMechan@hotmail.com * old style ubd by setting UBD_SHIFT to 0 + * 2002-09-27...2002-10-18 massive tinkering for 2.5 + * partitions have changed in 2.5 */ #define MAJOR_NR UBD_MAJOR #define UBD_SHIFT 4 #include "linux/config.h" +#include "linux/module.h" #include "linux/blk.h" #include "linux/blkdev.h" #include "linux/hdreg.h" @@ -51,15 +54,17 @@ static int ubd_release(struct inode * inode, struct file * file); static int ubd_ioctl(struct inode * inode, struct file * file, unsigned int cmd, unsigned long arg); -static int ubd_revalidate(struct gendisk *disk); #define MAX_DEV (8) +#define MAX_MINOR (MAX_DEV << UBD_SHIFT) + +#define DEVICE_NR(n) (minor(n) >> UBD_SHIFT) static struct block_device_operations ubd_blops = { + .owner = THIS_MODULE, .open = ubd_open, .release = ubd_release, .ioctl = ubd_ioctl, - .revalidate_disk= ubd_revalidate, }; /* Protected by the queue_lock */ @@ -169,8 +174,6 @@ struct proc_dir_entry *dir, *ent; char name[64]; - if(!fake_ide) return; - if(proc_ide_root == NULL) make_proc_ide(); dir = proc_mkdir(dev_name, proc_ide); @@ -415,88 +418,135 @@ return(os_file_size(file, size_out)); } -/* Initialized in an initcall, and unchanged thereafter */ -devfs_handle_t ubd_dir_handle; -devfs_handle_t ubd_fake_dir_handle; +static void ubd_close(struct ubd *dev) +{ + os_close_file(dev->fd); + if(dev->cow.file == NULL) + return; -static int ubd_add(int n) + os_close_file(dev->cow.fd); + vfree(dev->cow.bitmap); + dev->cow.bitmap = NULL; +} + +static int ubd_open_dev(struct ubd *dev) { - devfs_handle_t real, fake; - char name[sizeof("nnnnnn\0")]; - struct ubd *dev = &ubd_dev[n]; - struct gendisk *disk, *fake_disk = NULL; - u64 size; + struct openflags flags; + int err, n, create_cow, *create_ptr; - if (!dev->file) - goto out; + create_cow = 0; + create_ptr = (dev->cow.file != NULL) ? &create_cow : NULL; + dev->fd = open_ubd_file(dev->file, &dev->openflags, &dev->cow.file, + &dev->cow.bitmap_offset, &dev->cow.bitmap_len, + &dev->cow.data_offset, create_ptr); - disk = alloc_disk(1 << UBD_SHIFT); - if (!disk) - return -1; - disk->major = MAJOR_NR; - disk->first_minor = n << UBD_SHIFT; - disk->fops = &ubd_blops; - if (fakehd_set) - sprintf(disk->disk_name, "hd%c", n + 'a'); - else - sprintf(disk->disk_name, "ubd%d", n); - - if (fake_major) { - fake_disk = alloc_disk(1 << UBD_SHIFT); - if (!fake_disk) { - put_disk(disk); - return -1; + if((dev->fd == -ENOENT) && create_cow){ + n = dev - ubd_dev; + dev->fd = create_cow_file(dev->file, dev->cow.file, + dev->openflags, 1 << 9, + &dev->cow.bitmap_offset, + &dev->cow.bitmap_len, + &dev->cow.data_offset); + if(dev->fd >= 0){ + printk(KERN_INFO "Creating \"%s\" as COW file for " + "\"%s\"\n", dev->file, dev->cow.file); } - fake_disk->major = fake_major; - fake_disk->first_minor = n << UBD_SHIFT; - fake_disk->fops = &ubd_blops; - sprintf(fake_disk->disk_name, "ubd%d", n); - fake_gendisk[n] = fake_disk; } - ubd_gendisk[n] = disk; - - if (!dev->is_dir && ubd_file_size(dev, &size) == 0) { - set_capacity(disk, size/512); - if (fake_major) - set_capacity(fake_disk, size/512); - } - - sprintf(name, "%d", n); - real = devfs_register(ubd_dir_handle, name, DEVFS_FL_REMOVABLE, - MAJOR_NR, n << UBD_SHIFT, - S_IFBLK | S_IRUSR | S_IWUSR | S_IRGRP |S_IWGRP, - &ubd_blops, NULL); - if(real == NULL) - goto out; - ubd_dev[n].real = real; - - if (fake_major) { - fake = devfs_register(ubd_fake_dir_handle, name, - DEVFS_FL_REMOVABLE, fake_major, - n << UBD_SHIFT, - S_IFBLK | S_IRUSR | S_IWUSR | S_IRGRP | - S_IWGRP, &ubd_blops, NULL); - if(fake == NULL) - goto out_unregister; - - ubd_dev[n].fake = fake; - fake_disk->private_data = &ubd_dev[n]; - fake_disk->queue = &ubd_queue; - add_disk(fake_disk); + if(dev->fd < 0) return(dev->fd); + + if(dev->cow.file != NULL){ + err = -ENOMEM; + dev->cow.bitmap = (void *) vmalloc(dev->cow.bitmap_len); + if(dev->cow.bitmap == NULL) goto error; + flush_tlb_kernel_vm(); + + err = read_cow_bitmap(dev->fd, dev->cow.bitmap, + dev->cow.bitmap_offset, + dev->cow.bitmap_len); + if(err) goto error; + + flags = dev->openflags; + flags.w = 0; + err = open_ubd_file(dev->cow.file, &flags, NULL, NULL, NULL, + NULL, NULL); + if(err < 0) goto error; + dev->cow.fd = err; } - - disk->private_data = &ubd_dev[n]; + return(0); + error: + os_close_file(dev->fd); + return(err); +} + +static int ubd_new_disk(int major, u64 size, char *name, int unit, + struct gendisk **disk_out, devfs_handle_t dir_handle, + devfs_handle_t *handle_out) +{ + char devfs_name[sizeof("nnnnnn\0")]; + struct gendisk *disk; + int minor = unit << UBD_SHIFT; + + disk = alloc_disk(1 << UBD_SHIFT); + if(disk == NULL) + return(-ENOMEM); + + disk->major = major; + disk->first_minor = minor; + disk->fops = &ubd_blops; + set_capacity(disk, size / 512); + /* needs to be ubd -> /dev/ubd/discX/disc */ + sprintf(disk->disk_name, "ubd"); + *disk_out = disk; + + /* /dev/ubd/N style names */ + sprintf(devfs_name, "%d", unit); + *handle_out = devfs_register(dir_handle, devfs_name, + DEVFS_FL_REMOVABLE, major, minor, + S_IFBLK | S_IRUSR | S_IWUSR | S_IRGRP | + S_IWGRP, &ubd_blops, NULL); + disk->private_data = &ubd_dev[unit]; disk->queue = &ubd_queue; add_disk(disk); - make_ide_entries(disk->disk_name); return(0); +} - out_unregister: - devfs_unregister(real); - ubd_dev[n].real = NULL; - out: - return(-1); +/* Initialized in an initcall, and unchanged thereafter */ +devfs_handle_t ubd_dir_handle; +devfs_handle_t ubd_fake_dir_handle; + +static int ubd_add(int n) +{ + struct ubd *dev = &ubd_dev[n]; + int err; + + if (!dev->file || dev->is_dir) + return(-ENODEV); + + if (ubd_open_dev(dev)) + return(-ENODEV); + + err = ubd_file_size(dev, &dev->size); + if(err) + return(err); + + err = ubd_new_disk(MAJOR_NR, dev->size, "ubd", n, &ubd_gendisk[n], + ubd_dir_handle, &dev->real); + if(err) + return(err); + + if(fake_major) + ubd_new_disk(fake_major, dev->size, "ubd%d", n, + &fake_gendisk[n], ubd_fake_dir_handle, + &dev->fake); + + /* perhaps this should also be under the "if (fake_major)" above */ + /* using the fake_disk->disk_name and also the fakehd_set name */ + if (fake_ide) + make_ide_entries(ubd_gendisk[n]->disk_name); + + ubd_close(dev); + return 0; } static int ubd_config(char *str) @@ -527,34 +577,39 @@ static int ubd_remove(char *str) { struct ubd *dev; - int n, err; + int n, err = -ENODEV; + + if(!isdigit(*str)) + return(err); /* it should be a number 0-7/a-h */ - if(!isdigit(*str)) - return(-1); n = *str - '0'; if(n > MAX_DEV) - return(-1); + return(err); + dev = &ubd_dev[n]; + if(dev->count > 0) + return(-EBUSY); /* you cannot remove a open disk */ err = 0; spin_lock(&ubd_lock); + + if(ubd_gendisk[n] == NULL) + goto out; + del_gendisk(ubd_gendisk[n]); put_disk(ubd_gendisk[n]); ubd_gendisk[n] = NULL; - if (fake_major) { + if(dev->real != NULL) + devfs_unregister(dev->real); + + if(fake_gendisk[n] != NULL){ del_gendisk(fake_gendisk[n]); put_disk(fake_gendisk[n]); fake_gendisk[n] = NULL; + if(dev->fake != NULL) + devfs_unregister(dev->fake); } - if(dev->file == NULL) - goto out; - err = -1; - if(dev->count > 0) - goto out; - if(dev->real != NULL) - devfs_unregister(dev->real); - if(dev->fake != NULL) - devfs_unregister(dev->fake); + *dev = ((struct ubd) DEFAULT_UBD); err = 0; out: @@ -563,9 +618,9 @@ } static struct mc_device ubd_mc = { - name: "ubd", - config: ubd_config, - remove: ubd_remove, + .name = "ubd", + .config = ubd_config, + .remove = ubd_remove, }; static int ubd_mc_init(void) @@ -585,8 +640,10 @@ printk(KERN_ERR "ubd: unable to get major %d\n", MAJOR_NR); return -1; } + blk_init_queue(&ubd_queue, do_ubd_request, &ubd_io_lock); elevator_init(&ubd_queue, &elevator_noop); + if(fake_major != 0){ char name[sizeof("ubd_nnn\0")]; @@ -631,81 +688,23 @@ device_initcall(ubd_driver_init); -static void ubd_close(struct ubd *dev) -{ - os_close_file(dev->fd); - if(dev->cow.file != NULL) { - os_close_file(dev->cow.fd); - vfree(dev->cow.bitmap); - dev->cow.bitmap = NULL; - } -} - -static int ubd_open_dev(struct ubd *dev) -{ - struct openflags flags; - int err, n, create_cow, *create_ptr; - - create_cow = 0; - create_ptr = (dev->cow.file != NULL) ? &create_cow : NULL; - dev->fd = open_ubd_file(dev->file, &dev->openflags, &dev->cow.file, - &dev->cow.bitmap_offset, &dev->cow.bitmap_len, - &dev->cow.data_offset, create_ptr); - - if((dev->fd == -ENOENT) && create_cow){ - n = dev - ubd_dev; - dev->fd = create_cow_file(dev->file, dev->cow.file, - dev->openflags, 1 << 9, - &dev->cow.bitmap_offset, - &dev->cow.bitmap_len, - &dev->cow.data_offset); - if(dev->fd >= 0){ - printk(KERN_INFO "Creating \"%s\" as COW file for " - "\"%s\"\n", dev->file, dev->cow.file); - } - } - - if(dev->fd < 0) return(dev->fd); - - if(dev->cow.file != NULL){ - err = -ENOMEM; - dev->cow.bitmap = (void *) vmalloc(dev->cow.bitmap_len); - if(dev->cow.bitmap == NULL) goto error; - flush_tlb_kernel_vm(); - - err = read_cow_bitmap(dev->fd, dev->cow.bitmap, - dev->cow.bitmap_offset, - dev->cow.bitmap_len); - if(err) goto error; - - flags = dev->openflags; - flags.w = 0; - err = open_ubd_file(dev->cow.file, &flags, NULL, NULL, NULL, - NULL, NULL); - if(err < 0) goto error; - dev->cow.fd = err; - } - return(0); - error: - os_close_file(dev->fd); - return(err); -} - static int ubd_open(struct inode *inode, struct file *filp) { struct gendisk *disk = inode->i_bdev->bd_disk; struct ubd *dev = disk->private_data; - int err; + int err = -EISDIR; + if(dev->is_dir == 1) goto out; + err = 0; if(dev->count == 0){ dev->openflags = dev->boot_openflags; err = ubd_open_dev(dev); if(err){ - printk(KERN_ERR "%s: Can't open \"%s\": " - "errno = %d\n", disk->disk_name, dev->file, -err); + printk(KERN_ERR "%s: Can't open \"%s\": errno = %d\n", + disk->disk_name, dev->file, -err); goto out; } } @@ -722,7 +721,8 @@ { struct gendisk *disk = inode->i_bdev->bd_disk; struct ubd *dev = disk->private_data; - if(dev->count == 0) + + if(--dev->count == 0) ubd_close(dev); return(0); } @@ -772,7 +772,7 @@ __u64 block; int nsect; - if (req->rq_status == RQ_INACTIVE) return(1); + if(req->rq_status == RQ_INACTIVE) return(1); if(dev->is_dir){ strcpy(req->buffer, "HOSTFS:"); @@ -784,7 +784,8 @@ } if((rq_data_dir(req) == WRITE) && !dev->openflags.w){ - printk("Write attempted on readonly ubd device %s\n", disk->disk_name); + printk("Write attempted on readonly ubd device %s\n", + disk->disk_name); spin_lock(&ubd_io_lock); end_request(req, 0); spin_unlock(&ubd_io_lock); @@ -848,7 +849,6 @@ struct hd_geometry *loc = (struct hd_geometry *) arg; struct ubd *dev = inode->i_bdev->bd_disk->private_data; int err; - struct ubd *dev; struct hd_driveid ubd_id = { .cyls = 0, .heads = 128, @@ -868,7 +868,7 @@ case HDIO_SET_UNMASKINTR: if(!capable(CAP_SYS_ADMIN)) return(-EACCES); - if((arg > 1) || inode->i_bdev->bd_contains != inode->i_bdev) + if((arg > 1) || (inode->i_bdev->bd_contains != inode->i_bdev)) return(-EINVAL); return(0); @@ -888,7 +888,7 @@ case HDIO_SET_MULTCOUNT: if(!capable(CAP_SYS_ADMIN)) return(-EACCES); - if (inode->i_bdev->bd_contains != inode->i_bdev) + if(inode->i_bdev->bd_contains != inode->i_bdev) return(-EINVAL); return(0); @@ -913,27 +913,6 @@ return(-EINVAL); } -static int ubd_revalidate(struct gendisk *disk) -{ - __u64 size; - int err; - struct ubd *dev = disk->private_data; - - err = 0; - spin_lock(&ubd_lock); - if(dev->is_dir) - goto out; - - err = ubd_file_size(dev, &size); - if (!err) { - set_capacity(disk, size / 512); - dev->size = size; - } - out: - spin_unlock(&ubd_lock); - return err; -} - /* * Overrides for Emacs so that we follow Linus's tabbing style. * Emacs will notice this stuff at the end of the file and automatically diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/arch/um/drivers/xterm.c linux.2.5.47-ac6/arch/um/drivers/xterm.c --- linux.2.5.47/arch/um/drivers/xterm.c 2002-10-31 14:57:35.000000000 +0000 +++ linux.2.5.47-ac6/arch/um/drivers/xterm.c 2002-10-31 15:05:57.000000000 +0000 @@ -19,6 +19,7 @@ #include "user_util.h" #include "user.h" #include "os.h" +#include "xterm.h" struct xterm_chan { int pid; @@ -28,6 +29,7 @@ int raw; struct termios tt; unsigned long stack; + int direct_rcv; }; void *xterm_init(char *str, int device, struct chan_opts *opts) @@ -40,7 +42,8 @@ device : device, title : opts->xterm_title, raw : opts->raw, - stack : opts->tramp_stack } ); + stack : opts->tramp_stack, + direct_rcv : !opts->in_kernel } ); return(data); } @@ -84,7 +87,7 @@ { struct xterm_chan *data = d; unsigned long stack; - int pid, fd, new; + int pid, fd, new, err; char title[256], file[] = "/tmp/xterm-pipeXXXXXX"; char *argv[] = { terminal_emulator, title_switch, title, exec_switch, "/usr/lib/uml/port-helper", "-uml-socket", @@ -105,21 +108,30 @@ fd = create_unix_socket(file, sizeof(file)); if(fd < 0){ printk("xterm_open : create_unix_socket failed, errno = %d\n", - errno); - return(-errno); + -fd); + return(-fd); } sprintf(title, data->title, data->device); stack = data->stack; pid = run_helper(NULL, NULL, argv, &stack); if(pid < 0){ - printk("xterm_open : run_helper failed\n"); - return(-1); + printk("xterm_open : run_helper failed, errno = %d\n", -pid); + return(pid); } if(data->stack == 0) free_stack(stack, 0); - new = os_rcv_fd(fd, &data->helper_pid); + if(data->direct_rcv) + new = os_rcv_fd(fd, &data->helper_pid); + else { + if((err = os_set_fd_block(fd, 0)) != 0){ + printk("xterm_open : failed to set descriptor " + "non-blocking, errno = %d\n", err); + return(err); + } + new = xterm_fd(fd, &data->helper_pid); + } if(new < 0){ printk("xterm_open : os_rcv_fd failed, errno = %d\n", -new); return(new); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/arch/um/drivers/xterm.h linux.2.5.47-ac6/arch/um/drivers/xterm.h --- linux.2.5.47/arch/um/drivers/xterm.h 1970-01-01 01:00:00.000000000 +0100 +++ linux.2.5.47-ac6/arch/um/drivers/xterm.h 2002-10-31 15:05:57.000000000 +0000 @@ -0,0 +1,22 @@ +/* + * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) + * Licensed under the GPL + */ + +#ifndef __XTERM_H__ +#define __XTERM_H__ + +extern int xterm_fd(int socket, int *pid_out); + +#endif + +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * Emacs will notice this stuff at the end of the file and automatically + * adjust the settings for this buffer only. This must remain at the end + * of the file. + * --------------------------------------------------------------------------- + * Local variables: + * c-file-style: "linux" + * End: + */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/arch/um/drivers/xterm_kern.c linux.2.5.47-ac6/arch/um/drivers/xterm_kern.c --- linux.2.5.47/arch/um/drivers/xterm_kern.c 1970-01-01 01:00:00.000000000 +0100 +++ linux.2.5.47-ac6/arch/um/drivers/xterm_kern.c 2002-10-31 15:05:57.000000000 +0000 @@ -0,0 +1,77 @@ +/* + * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) + * Licensed under the GPL + */ + +#include "linux/errno.h" +#include "linux/slab.h" +#include "asm/semaphore.h" +#include "asm/irq.h" +#include "irq_user.h" +#include "kern_util.h" +#include "os.h" +#include "xterm.h" + +struct xterm_wait { + struct semaphore sem; + int fd; + int pid; + int new_fd; +}; + +static void xterm_interrupt(int irq, void *data, struct pt_regs *regs) +{ + struct xterm_wait *xterm = data; + + xterm->new_fd = os_rcv_fd(xterm->fd, &xterm->pid); + if(xterm->new_fd == -EAGAIN) + return; + + up(&xterm->sem); +} + +int xterm_fd(int socket, int *pid_out) +{ + struct xterm_wait *data; + int err, ret; + + data = kmalloc(sizeof(*data), GFP_KERNEL); + if(data == NULL){ + printk(KERN_ERR "xterm_fd - failed to allocate semaphore\n"); + return(-ENOMEM); + } + *data = ((struct xterm_wait) + { sem : __SEMAPHORE_INITIALIZER(data->sem, 0), + fd : socket, + pid : -1, + new_fd : -1 }); + + err = um_request_irq(XTERM_IRQ, socket, IRQ_READ, xterm_interrupt, + SA_INTERRUPT | SA_SHIRQ | SA_SAMPLE_RANDOM, + "xterm", data); + if(err){ + printk(KERN_ERR "Failed to get IRQ for xterm, err = %d\n", + err); + return(err); + } + down(&data->sem); + + free_irq(XTERM_IRQ, data); + + ret = data->new_fd; + *pid_out = data->pid; + kfree(data); + + return(ret); +} + +/* + * 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-file-style: "linux" + * End: + */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/arch/um/include/chan_user.h linux.2.5.47-ac6/arch/um/include/chan_user.h --- linux.2.5.47/arch/um/include/chan_user.h 2002-10-31 14:57:35.000000000 +0000 +++ linux.2.5.47-ac6/arch/um/include/chan_user.h 2002-10-31 15:05:57.000000000 +0000 @@ -13,6 +13,7 @@ char *xterm_title; int raw; unsigned long tramp_stack; + int in_kernel; }; enum chan_init_pri { INIT_STATIC, INIT_ALL, INIT_ONE }; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/arch/um/include/kern_util.h linux.2.5.47-ac6/arch/um/include/kern_util.h --- linux.2.5.47/arch/um/include/kern_util.h 2002-10-31 14:57:35.000000000 +0000 +++ linux.2.5.47-ac6/arch/um/include/kern_util.h 2002-10-31 15:05:57.000000000 +0000 @@ -6,6 +6,7 @@ #ifndef __KERN_UTIL_H__ #define __KERN_UTIL_H__ +#include "linux/threads.h" #include "sysdep/ptrace.h" extern int ncpus; @@ -14,6 +15,7 @@ extern int kmalloc_ok; extern int timer_irq_inited; extern int jail; +extern struct task_struct *idle_threads[NR_CPUS]; #define ROUND_DOWN(addr) ((void *)(((unsigned long) addr) & PAGE_MASK)) #define ROUND_UP(addr) ROUND_DOWN(((unsigned long) addr) + PAGE_SIZE - 1) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/arch/um/Kconfig linux.2.5.47-ac6/arch/um/Kconfig --- linux.2.5.47/arch/um/Kconfig 2002-11-05 13:54:43.000000000 +0000 +++ linux.2.5.47-ac6/arch/um/Kconfig 2002-11-05 14:51:47.000000000 +0000 @@ -2,7 +2,6 @@ bool default y -# XXX: does UM have a mmu/swap? config MMU bool default y @@ -30,7 +29,6 @@ bool default y - menu "Code maturity level options" config EXPERIMENTAL diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/arch/um/kernel/irq_user.c linux.2.5.47-ac6/arch/um/kernel/irq_user.c --- linux.2.5.47/arch/um/kernel/irq_user.c 2002-10-31 14:57:35.000000000 +0000 +++ linux.2.5.47-ac6/arch/um/kernel/irq_user.c 2002-10-31 15:05:58.000000000 +0000 @@ -209,7 +209,6 @@ out_unlock: irq_unlock(flags); - out_free: kfree(new_fd); out: return(err); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/arch/um/kernel/ksyms.c linux.2.5.47-ac6/arch/um/kernel/ksyms.c --- linux.2.5.47/arch/um/kernel/ksyms.c 2002-10-31 14:57:35.000000000 +0000 +++ linux.2.5.47-ac6/arch/um/kernel/ksyms.c 2002-10-31 15:05:58.000000000 +0000 @@ -1,5 +1,9 @@ +#include "linux/config.h" #include "linux/module.h" #include "linux/string.h" +#include "linux/smp_lock.h" +#include "linux/spinlock.h" +#include #include "asm/current.h" #include "asm/delay.h" #include "asm/processor.h" @@ -36,12 +40,15 @@ EXPORT_SYMBOL(get_signals); EXPORT_SYMBOL(page_to_phys); EXPORT_SYMBOL(phys_to_page); +EXPORT_SYMBOL(high_physmem); EXPORT_SYMBOL(os_open_file); EXPORT_SYMBOL(os_read_file); EXPORT_SYMBOL(os_write_file); EXPORT_SYMBOL(os_seek_file); EXPORT_SYMBOL(os_pipe); +EXPORT_SYMBOL(os_file_type); +EXPORT_SYMBOL(os_close_file); EXPORT_SYMBOL(helper_wait); EXPORT_SYMBOL(os_shutdown_socket); EXPORT_SYMBOL(os_connect_socket); @@ -58,3 +65,23 @@ EXPORT_SYMBOL(sys_read); EXPORT_SYMBOL(sys_wait4); +#ifdef CONFIG_SMP + +/* required for SMP */ + +extern void FASTCALL( __write_lock_failed(rwlock_t *rw)); +EXPORT_SYMBOL_NOVERS(__write_lock_failed); + +extern void FASTCALL( __read_lock_failed(rwlock_t *rw)); +EXPORT_SYMBOL_NOVERS(__read_lock_failed); + +#endif + +#ifdef CONFIG_HIGHMEM +EXPORT_SYMBOL(kmap); +EXPORT_SYMBOL(kunmap); +EXPORT_SYMBOL(kmap_atomic); +EXPORT_SYMBOL(kunmap_atomic); +EXPORT_SYMBOL(kmap_atomic_to_page); +#endif + diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/arch/um/kernel/Makefile linux.2.5.47-ac6/arch/um/kernel/Makefile --- linux.2.5.47/arch/um/kernel/Makefile 2002-10-31 14:57:35.000000000 +0000 +++ linux.2.5.47-ac6/arch/um/kernel/Makefile 2002-10-31 15:05:57.000000000 +0000 @@ -1,4 +1,3 @@ - EXTRA_TARGETS := unmap_fin.o obj-y = config.o exec_kern.o exec_user.o exitcode.o frame_kern.o frame.o \ @@ -51,6 +50,9 @@ arch/um/kernel/unmap_fin.o : arch/um/kernel/unmap.o ld -r -o $@ $< -lc -L/usr/lib +# This has to be separate because it needs be compiled with frame pointers +# regardless of how the rest of the kernel is built. + arch/um/kernel/frame.o: arch/um/kernel/frame.c $(CC) $(CFLAGS_$(notdir $@)) -c -o $@ $< diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/arch/um/kernel/process_kern.c linux.2.5.47-ac6/arch/um/kernel/process_kern.c --- linux.2.5.47/arch/um/kernel/process_kern.c 2002-10-31 14:57:35.000000000 +0000 +++ linux.2.5.47-ac6/arch/um/kernel/process_kern.c 2002-10-31 15:05:58.000000000 +0000 @@ -767,8 +767,8 @@ int smp_sigio_handler(void) { - int cpu = current->thread_info->cpu; #ifdef CONFIG_SMP + int cpu = current->thread_info->cpu; IPI_handler(cpu); if(cpu != 0) return(1); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/arch/um/kernel/reboot.c linux.2.5.47-ac6/arch/um/kernel/reboot.c --- linux.2.5.47/arch/um/kernel/reboot.c 2002-10-31 14:57:35.000000000 +0000 +++ linux.2.5.47-ac6/arch/um/kernel/reboot.c 2002-10-31 15:05:58.000000000 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (C) 2000 Jeff Dike (jdike@karaya.com) + * Copyright (C) 2000, 2002 Jeff Dike (jdike@karaya.com) * Licensed under the GPL */ @@ -9,6 +9,20 @@ #include "kern.h" #include "os.h" +#ifdef CONFIG_SMP +static void kill_idlers(int me) +{ + struct task_struct *p; + int i; + + for(i = 0; i < sizeof(idle_threads)/sizeof(idle_threads[0]); i++){ + p = idle_threads[i]; + if((p != NULL) && (p->thread.extern_pid != me)) + os_kill_process(p->thread.extern_pid); + } +} +#endif + static void kill_off_processes(void) { struct task_struct *p; @@ -21,6 +35,9 @@ } if(init_task.thread.extern_pid != me) os_kill_process(init_task.thread.extern_pid); +#ifdef CONFIG_SMP + kill_idlers(me); +#endif } void uml_cleanup(void) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/arch/um/kernel/signal_user.c linux.2.5.47-ac6/arch/um/kernel/signal_user.c --- linux.2.5.47/arch/um/kernel/signal_user.c 2002-10-31 14:57:35.000000000 +0000 +++ linux.2.5.47-ac6/arch/um/kernel/signal_user.c 2002-10-31 15:05:58.000000000 +0000 @@ -84,13 +84,13 @@ #define SIGIO_BIT 0 #define SIGVTALRM_BIT 1 -static int disable_mask(sigset_t *mask) +static int enable_mask(sigset_t *mask) { int sigs; - sigs = sigismember(mask, SIGIO) ? 1 << SIGIO_BIT : 0; - sigs |= sigismember(mask, SIGVTALRM) ? 1 << SIGVTALRM_BIT : 0; - sigs |= sigismember(mask, SIGALRM) ? 1 << SIGVTALRM_BIT : 0; + sigs = sigismember(mask, SIGIO) ? 0 : 1 << SIGIO_BIT; + sigs |= sigismember(mask, SIGVTALRM) ? 0 : 1 << SIGVTALRM_BIT; + sigs |= sigismember(mask, SIGALRM) ? 0 : 1 << SIGVTALRM_BIT; return(sigs); } @@ -100,30 +100,28 @@ if(sigprocmask(SIG_SETMASK, NULL, &mask) < 0) panic("Failed to get signal mask"); - return(disable_mask(&mask)); + return(enable_mask(&mask)); } -int set_signals(int disable) +int set_signals(int enable) { sigset_t mask; int ret; sigemptyset(&mask); - if(!(disable & (1 << SIGIO_BIT))) + if(enable & (1 << SIGIO_BIT)) sigaddset(&mask, SIGIO); - if(!(disable & (1 << SIGVTALRM_BIT))){ + if(enable & (1 << SIGVTALRM_BIT)){ sigaddset(&mask, SIGVTALRM); sigaddset(&mask, SIGALRM); } if(sigprocmask(SIG_UNBLOCK, &mask, &mask) < 0) panic("Failed to enable signals"); - - ret = disable_mask(&mask); - + ret = enable_mask(&mask); sigemptyset(&mask); - if(disable & (1 << SIGIO_BIT)) + if((enable & (1 << SIGIO_BIT)) == 0) sigaddset(&mask, SIGIO); - if(disable & (1 << SIGVTALRM_BIT)){ + if((enable & (1 << SIGVTALRM_BIT)) == 0){ sigaddset(&mask, SIGVTALRM); sigaddset(&mask, SIGALRM); } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/arch/um/kernel/smp.c linux.2.5.47-ac6/arch/um/kernel/smp.c --- linux.2.5.47/arch/um/kernel/smp.c 2002-10-31 14:57:35.000000000 +0000 +++ linux.2.5.47-ac6/arch/um/kernel/smp.c 2002-10-31 15:05:58.000000000 +0000 @@ -47,6 +47,9 @@ /* Small, random number, never changed */ unsigned long cache_decay_ticks = 5; +/* Not changed after boot */ +struct task_struct *idle_threads[NR_CPUS]; + void smp_send_reschedule(int cpu) { write(cpu_data[cpu].ipi_pipe[1], "R", 1); @@ -142,6 +145,7 @@ cpu_tasks[cpu] = ((struct cpu_task) { .pid = new_task->thread.extern_pid, .task = new_task } ); + idle_threads[cpu] = new_task; write(new_task->thread.switch_pipe[1], &c, sizeof(c)); return(new_task); } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/arch/um/kernel/sys_call_table.c linux.2.5.47-ac6/arch/um/kernel/sys_call_table.c --- linux.2.5.47/arch/um/kernel/sys_call_table.c 2002-10-31 14:57:35.000000000 +0000 +++ linux.2.5.47-ac6/arch/um/kernel/sys_call_table.c 2002-10-31 15:05:58.000000000 +0000 @@ -229,6 +229,7 @@ extern syscall_handler_t sys_io_submit; extern syscall_handler_t sys_io_cancel; extern syscall_handler_t sys_exit_group; +extern syscall_handler_t sys_lookup_dcookie; #if CONFIG_NFSD #define NFSSERVCTL sys_nfsserctl @@ -240,7 +241,7 @@ extern syscall_handler_t um_time; extern syscall_handler_t um_stime; -#define LAST_GENERIC_SYSCALL __NR_exit_group +#define LAST_GENERIC_SYSCALL __NR_lookup_dcookie #if LAST_GENERIC_SYSCALL > LAST_ARCH_SYSCALL #define LAST_SYSCALL LAST_GENERIC_SYSCALL @@ -479,6 +480,7 @@ [ __NR_alloc_hugepages ] = sys_ni_syscall, [ __NR_free_hugepages ] = sys_ni_syscall, [ __NR_exit_group ] = sys_exit_group, + [ __NR_lookup_dcookie ] = sys_lookup_dcookie, ARCH_SYSCALLS [ LAST_SYSCALL + 1 ... NR_syscalls ] = diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/arch/um/kernel/sysrq.c linux.2.5.47-ac6/arch/um/kernel/sysrq.c --- linux.2.5.47/arch/um/kernel/sysrq.c 2002-10-31 14:57:35.000000000 +0000 +++ linux.2.5.47-ac6/arch/um/kernel/sysrq.c 2002-10-31 15:05:58.000000000 +0000 @@ -76,6 +76,16 @@ printk("\n"); } +/* + * The architecture-independent dump_stack generator + */ +void dump_stack(void) +{ + unsigned long stack; + + show_trace(&stack); +} + void show_trace_task(struct task_struct *tsk) { unsigned long esp = PT_REGS_SP(&tsk->thread.regs); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/arch/um/kernel/trap_kern.c linux.2.5.47-ac6/arch/um/kernel/trap_kern.c --- linux.2.5.47/arch/um/kernel/trap_kern.c 2002-10-31 14:57:35.000000000 +0000 +++ linux.2.5.47-ac6/arch/um/kernel/trap_kern.c 2002-10-31 15:05:58.000000000 +0000 @@ -211,6 +211,7 @@ xterm_title : "UML kernel debugger", raw : 0, tramp_stack : 0, + in_kernel : 0, }; /* Accessed by the tracing thread, which automatically serializes access */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/arch/um/kernel/um_arch.c linux.2.5.47-ac6/arch/um/kernel/um_arch.c --- linux.2.5.47/arch/um/kernel/um_arch.c 2002-10-31 14:57:35.000000000 +0000 +++ linux.2.5.47-ac6/arch/um/kernel/um_arch.c 2002-10-31 15:05:58.000000000 +0000 @@ -349,7 +349,7 @@ void *unused2) { #ifdef CONFIG_SYSRQ - handle_sysrq('p', ¤t->thread.regs, NULL, NULL); + handle_sysrq('p', ¤t->thread.regs, NULL); #endif machine_halt(); return(0); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/arch/um/Makefile linux.2.5.47-ac6/arch/um/Makefile --- linux.2.5.47/arch/um/Makefile 2002-10-31 14:57:35.000000000 +0000 +++ linux.2.5.47-ac6/arch/um/Makefile 2002-10-31 15:05:57.000000000 +0000 @@ -1,9 +1,6 @@ ARCH_DIR = arch/um OS := $(shell uname -s) -include $(ARCH_DIR)/Makefile-$(SUBARCH) -include $(ARCH_DIR)/Makefile-os-$(OS) - EXTRAVERSION := $(EXTRAVERSION)-1um include/linux/version.h: arch/$(ARCH)/Makefile @@ -59,6 +56,9 @@ GEN_HEADERS = $(ARCH_DIR)/include/task.h +include $(ARCH_DIR)/Makefile-$(SUBARCH) +include $(ARCH_DIR)/Makefile-os-$(OS) + $(ARCH_DIR)/vmlinux.lds.S : touch $@ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/arch/um/Makefile-i386 linux.2.5.47-ac6/arch/um/Makefile-i386 --- linux.2.5.47/arch/um/Makefile-i386 2002-10-31 14:57:35.000000000 +0000 +++ linux.2.5.47-ac6/arch/um/Makefile-i386 2002-10-31 15:05:57.000000000 +0000 @@ -21,11 +21,14 @@ $(SYS_DIR)/thread.h: $(SYS_UTIL_DIR)/mk_thread $< > $@ -$(SYS_UTIL_DIR)/mk_sc $(SYS_UTIL_DIR)/mk_thread: $(SYS_UTIL_DIR) FORCE ; +$(SYS_UTIL_DIR)/mk_sc: FORCE ; + @$(call descend,$(SYS_UTIL_DIR),$@) + +$(SYS_UTIL_DIR)/mk_thread: $(ARCH_SYMLINKS) FORCE ; + @$(call descend,$(SYS_UTIL_DIR),$@) $(SYS_UTIL_DIR): include/asm FORCE @$(call descend,$@,) sysclean : rm -f $(SYS_HEADERS) - @$(call descend,$(SYS_DIR),clean) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/arch/um/os-Linux/file.c linux.2.5.47-ac6/arch/um/os-Linux/file.c --- linux.2.5.47/arch/um/os-Linux/file.c 2002-10-31 14:57:36.000000000 +0000 +++ linux.2.5.47-ac6/arch/um/os-Linux/file.c 2002-10-31 15:05:58.000000000 +0000 @@ -283,10 +283,9 @@ msg.msg_flags = 0; n = recvmsg(fd, &msg, 0); - if(n < 0){ - printk("rcv_fd : recvmsg failed - errno = %d\n", errno); - return(-1); - } + if(n < 0) + return(-errno); + else if(n != sizeof(iov.iov_len)) *helper_pid_out = -1; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/arch/um/sys-i386/Makefile linux.2.5.47-ac6/arch/um/sys-i386/Makefile --- linux.2.5.47/arch/um/sys-i386/Makefile 2002-10-31 14:57:36.000000000 +0000 +++ linux.2.5.47-ac6/arch/um/sys-i386/Makefile 2002-10-31 15:05:58.000000000 +0000 @@ -1,19 +1,21 @@ -obj-y = bugs.o checksum.o extable.o fault.o ksyms.o ldt.o old-checksum.o \ +obj-y = bugs.o checksum.o extable.o fault.o ksyms.o ldt.o \ ptrace.o ptrace_user.o semaphore.o sigcontext.o syscalls.o sysrq.o +obj-$(CONFIG_HIGHMEM) += highmem.o + export-objs = ksyms.o USER_OBJS := bugs.o ptrace_user.o sigcontext.o fault.o USER_OBJS := $(foreach file,$(USER_OBJS),arch/um/sys-i386/$(file)) -SYMLINKS = semaphore.c old-checksum.c checksum.S extable.c +SYMLINKS = semaphore.c checksum.S extable.c highmem.c include $(TOPDIR)/Rules.make $(USER_OBJS) : %.o: %.c $(CC) $(CFLAGS_$@) $(USER_CFLAGS) -c -o $@ $< -arch/um/sys-i386/checksum.S arch/um/sys-i386/old-checksum.c: +arch/um/sys-i386/checksum.S: -rm -f $@ -ln -s $(TOPDIR)/arch/i386/lib/$(notdir $@) $@ @@ -25,6 +27,9 @@ -rm -f $@ -ln -s $(TOPDIR)/arch/i386/mm/$(notdir $@) $@ +arch/um/sys-i386/highmem.c: + -rm -f $@ + -ln -s $(TOPDIR)/arch/i386/mm/$(notdir $@) $@ clean: $(MAKE) -C util clean diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/arch/um/uml.lds.S linux.2.5.47-ac6/arch/um/uml.lds.S --- linux.2.5.47/arch/um/uml.lds.S 2002-10-31 14:57:35.000000000 +0000 +++ linux.2.5.47-ac6/arch/um/uml.lds.S 2002-10-31 15:05:58.000000000 +0000 @@ -65,7 +65,7 @@ .uml.postsetup.init : { *(.uml.postsetup.init) } __uml_postsetup_end = .; __setup_start = .; - .setup.init : { *(.setup.init) } + .init.setup : { *(.init.setup) } __setup_end = .; __per_cpu_start = . ; .data.percpu : { *(.data.percpu) } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/CREDITS linux.2.5.47-ac6/CREDITS --- linux.2.5.47/CREDITS 2002-11-11 16:39:08.000000000 +0000 +++ linux.2.5.47-ac6/CREDITS 2002-11-11 20:30:22.000000000 +0000 @@ -156,6 +156,14 @@ S: Calgary, Alberta S: Canada +N: Miles Bader +E: miles@gnu.org +D: v850 port (uClinux) +S: NEC Corporation +S: 1753 Shimonumabe, Nakahara-ku +S: Kawasaki 211-8666 +S: Japan + N: Ralf Baechle E: ralf@gnu.org P: 1024/AF7B30C1 CF 97 C2 CC 6D AE A7 FE C8 BA 9C FC 88 DE 32 C3 @@ -2239,6 +2247,15 @@ S: Toronto, Ontario S: Canada +N: Zwane Mwaikambo +E: zwane@linuxpower.ca +W: http://function.linuxpower.ca +D: Various driver hacking +D: Lowlevel x86 kernel hacking +D: General debugging +S: (ask for current address) +S: Tanzania + N: Trond Myklebust E: trond.myklebust@fys.uio.no D: current NFS client hacker. @@ -2713,7 +2730,7 @@ N: Thomas Sailer E: t.sailer@alumni.ethz.ch E: HB9JNX@HB9W.CHE.EU (packet radio) -D: hfmodem, Baycom and sound card radio modem driver +D: Baycom driver S: Markusstrasse 18 S: 8006 Zuerich S: Switzerland @@ -3084,8 +3101,14 @@ S: Germany N: Greg Ungerer -E: gerg@moreton.com.au +E: gerg@snapgear.com +D: uClinux kernel hacker +D: Port uClinux to the Motorola ColdFire CPU D: Author of Stallion multiport serial drivers +S: SnapGear Inc. +S: 825 Stanley St +S: Woolloongabba. QLD. 4102 +S: Australia N: Jeffrey A. Uphoff E: juphoff@transmeta.com diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/Documentation/DriverFixers linux.2.5.47-ac6/Documentation/DriverFixers --- linux.2.5.47/Documentation/DriverFixers 1970-01-01 01:00:00.000000000 +0100 +++ linux.2.5.47-ac6/Documentation/DriverFixers 2002-11-17 00:36:43.000000000 +0000 @@ -0,0 +1,75 @@ +People who fix drivers as a business - ie for money. (No recommendation, +business association or other relationship implied. This for the benefit of +American lawyers is just a list of people who have asked to be listed - nothing +more). + +Companies Who Will Do Small Contract Work +----------------------------------------- + +Company: BitWizard +Contact: Rogier Wolff +E-Mail: R.E.Wolff@BitWizard.nl + +Company: Caederus +Contact: Justin Mitchell +E-Mail: info@caederus.com +Location: Swansea, Wales, UK +URL: http://www.caederus.com/ + +Company: Calsoft Inc +Contact: Anupam Bhide +E-Mail: anupam@calsoftinc.com +URL: http://www.calsoftinc.com +Location: Pune, India + +Company: Hansen Partnership Inc +Contact: James Bottomley +E-Mail: James.Bottomley@HansenPartnership.com +Location: 1, Partridge Square, Oswego, Illinois 60543, USA + +Company: Linking +Contact: Elmer Joandi +E-Mail: elmer@linkingsoft.com + +Company: Penguru Consulting, LLC +Contact: Komron Takmil +E-Mail: komron@penguru.net +Location: Salt Lake City, UT USA + +Company: 7Chips +Contact: Vadim Lebedev +E-Mail: vadim@7chips.com +Location: Paris, France +Notes: Experienced in Linux and uClinux on x86/ARM/Motorola + +Company: Weinigel Ingenjörsbyrå AB +Contact: Christer Weinigel +E-Mail: christer@weinigel.se +Location: Stockholm, Sweden + +Company: WildOpenSource +Contact: Martin Hicks +E-Mail: info@wildopensource.com + + +Companies Only Interested In Larger ($10000+) Jobs +-------------------------------------------------- + + + +Companies Only Interested In Very Large ($100000+) Jobs +------------------------------------------------------- + + +To be added to the list: email giving the +following information + +Company: CompanyName [Required] +Contact: ContactName [Required] +E-Mail: An email address [Required] +URL: Web site [Optional] +Location: Area/Country [Optional] +Telephone: Contact phone number [Optional] +Speciality: Any specific speciality [Optional] +Notes: Any other notes (eg certifications, specialities) + diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/Documentation/kernel-parameters.txt linux.2.5.47-ac6/Documentation/kernel-parameters.txt --- linux.2.5.47/Documentation/kernel-parameters.txt 2002-10-31 14:57:48.000000000 +0000 +++ linux.2.5.47-ac6/Documentation/kernel-parameters.txt 2002-11-05 16:08:04.000000000 +0000 @@ -584,8 +584,6 @@ sound= [SOUND] - soundmodem= [HW,AX25,SOUND] Use sound card as packet radio modem. - specialix= [HW,SERIAL] Specialix multi-serial port adapter. sscape= [HW,SOUND] diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/Documentation/magic-number.txt linux.2.5.47-ac6/Documentation/magic-number.txt --- linux.2.5.47/Documentation/magic-number.txt 2002-10-31 14:57:48.000000000 +0000 +++ linux.2.5.47-ac6/Documentation/magic-number.txt 2002-11-11 20:32:58.000000000 +0000 @@ -43,57 +43,115 @@ 29 Jul 1998 +Updated the magic table to Linux 2.5.45. Right over the feature freeze, +but it is possible that some new magic numbers will sneak into the +kernel before 2.6.x yet. + + Petr Baudis + + 03 Nov 2002 + Magic Name Number Structure File =========================================================================== -PG_MAGIC 'P' pg_{read,write}_hdr include/linux/pg.h +PG_MAGIC 'P' pg_{read,write}_hdr include/linux/pg.h +CMAGIC 0x0111 user include/linux/a.out.h MKISS_DRIVER_MAGIC 0x04bf mkiss_channel drivers/net/mkiss.h RISCOM8_MAGIC 0x0907 riscom_port drivers/char/riscom8.h +SPECIALIX_MAGIC 0x0907 specialix_port drivers/char/specialix_io8.h +AURORA_MAGIC 0x0A18 Aurora_port drivers/sbus/char/aurora.h +HDLC_MAGIC 0x239e n_hdlc drivers/char/n_hdlc.c APM_BIOS_MAGIC 0x4101 apm_user arch/i386/kernel/apm.c CYCLADES_MAGIC 0x4359 cyclades_port include/linux/cyclades.h FASYNC_MAGIC 0x4601 fasync_struct include/linux/fs.h -PTY_MAGIC 0x5001 (none at the moment) - drivers/char/pty.c -PPP_MAGIC 0x5002 ppp include/linux/if_ppp.h +ISICOM_MAGIC 0x4d54 isi_port include/linux/isicom.h +PTY_MAGIC 0x5001 (none at the moment) + drivers/char/pty.c +PPP_MAGIC 0x5002 ppp include/linux/if_pppvar.h SERIAL_MAGIC 0x5301 async_struct include/linux/serial.h SSTATE_MAGIC 0x5302 serial_state include/linux/serial.h SLIP_MAGIC 0x5302 slip drivers/net/slip.h STRIP_MAGIC 0x5303 strip drivers/net/strip.c X25_ASY_MAGIC 0x5303 x25_asy drivers/net/x25_asy.h -SIXPACK_MAGIC 0x5304 sixpack drivers/net/hamradio/6pack.h +SIXPACK_MAGIC 0x5304 sixpack drivers/net/hamradio/6pack.h AX25_MAGIC 0x5316 ax_disp drivers/net/mkiss.h ESP_MAGIC 0x53ee esp_struct drivers/char/esp.h TTY_MAGIC 0x5401 tty_struct include/linux/tty.h +MGSL_MAGIC 0x5401 mgsl_info drivers/char/synclink.c TTY_DRIVER_MAGIC 0x5402 tty_driver include/linux/tty_driver.h +MGSLPC_MAGIC 0x5402 mgslpc_info drivers/char/pcmcia/synclink_cs.c TTY_LDISC_MAGIC 0x5403 tty_ldisc include/linux/tty_ldisc.h -SPECIALIX_MAGIC 0x0907 specialix_port drivers/char/specialix_io8.h -CG_MAGIC 0x090255 ufs_cylinder_group include/linux/ufs_fs.h -RPORT_MAGIC 0x525001 r_port drivers/char/rocket_int.h -GDTIOCTL_MAGIC 0x06030f07 gdth_iowr_str drivers/scsi/gdth_ioctl.h +USB_SERIAL_MAGIC 0x6702 usb_serial drivers/usb/serial/usb-serial.h +USB_BLUETOOTH_MAGIC 0x6d02 usb_bluetooth drivers/usb/class/bluetty.c +RFCOMM_TTY_MAGIC 0x6d02 (note at the moment) + net/bluetooth/rfcomm/tty.c +USB_SERIAL_PORT_MAGIC 0x7301 usb_serial_port drivers/usb/serial/usb-serial.h +CG_MAGIC 0x00090255 ufs_cylinder_group include/linux/ufs_fs.h +A2232_MAGIC 0x000a2232 gs_port drivers/char/ser_a2232.h +SOLARIS_SOCKET_MAGIC 0x000ADDED sol_socket_struct arch/sparc64/solaris/socksys.h +RPORT_MAGIC 0x00525001 r_port drivers/char/rocket_int.h +LSEMAGIC 0x05091998 lse drivers/fc4/fc.c +GDTIOCTL_MAGIC 0x06030f07 gdth_iowr_str drivers/scsi/gdth_ioctl.h +RIO_MAGIC 0x12345678 gs_port drivers/char/rio/rio_linux.c +SX_MAGIC 0x12345678 gs_port drivers/char/sx.h NBD_REQUEST_MAGIC 0x12560953 nbd_request include/linux/nbd.h -SLAB_RED_MAGIC2 0x170fc2a5 (any) mm/slab.c +RED_MAGIC2 0x170fc2a5 (any) mm/slab.c BAYCOM_MAGIC 0x19730510 baycom_state drivers/net/baycom_epp.c ISDN_X25IFACE_MAGIC 0x1e75a2b9 isdn_x25iface_proto_data drivers/isdn/isdn_x25iface.h ECP_MAGIC 0x21504345 cdkecpsig include/linux/cdk.h +LSOMAGIC 0x27091997 lso drivers/fc4/fc.c LSMAGIC 0x2a3b4d2a ls drivers/fc4/fc.c -LSOMAGIC 0x2a3c4e3c lso drivers/fc4/fc.c WANPIPE_MAGIC 0x414C4453 sdla_{dump,exec} include/linux/wanpipe.h -CODA_CNODE_MAGIC 0x47114711 coda_inode_info include/linux/coda_fs_i.h +CS_CARD_MAGIC 0x43525553 cs_card sound/oss/cs46xx.c +LABELCL_MAGIC 0x4857434c labelcl_info_s include/asm/ia64/sn/labelcl.h ISDN_ASYNC_MAGIC 0x49344C01 modem_info include/linux/isdn.h -ISDN_NET_MAGIC 0x49344C02 isdn_net_local_s include/linux/isdn.h +CTC_ASYNC_MAGIC 0x49344C01 ctc_tty_info drivers/s390/net/ctctty.c +ISDN_NET_MAGIC 0x49344C02 isdn_net_local_s drivers/isdn/i4l/isdn_net_lib.h +SAVEKMSG_MAGIC2 0x4B4D5347 savekmsg arch/*/amiga/config.c STLI_BOARDMAGIC 0x4bc6c825 stlibrd include/linux/istallion.h +CS_STATE_MAGIC 0x4c4f4749 cs_state sound/oss/cs46xx.c SLAB_C_MAGIC 0x4f17a36d kmem_cache_s mm/slab.c +COW_MAGIC 0x4f4f4f4d cow_header_v1 arch/um/drivers/ubd_user.c +I810_CARD_MAGIC 0x5072696E i810_card sound/oss/i810_audio.c +TRIDENT_CARD_MAGIC 0x5072696E trident_card sound/oss/trident.c ROUTER_MAGIC 0x524d4157 wan_device include/linux/wanrouter.h -SLAB_RED_MAGIC1 0x5a2cf071 (any) mm/slab.c +SCC_MAGIC 0x52696368 gs_port drivers/char/scc.h +SAVEKMSG_MAGIC1 0x53415645 savekmsg arch/*/amiga/config.c +GDA_MAGIC 0x58464552 gda include/asm-mips64/sn/gda.h +RED_MAGIC1 0x5a2cf071 (any) mm/slab.c STL_PORTMAGIC 0x5a7182c9 stlport include/linux/stallion.h HDLCDRV_MAGIC 0x5ac6e778 hdlcdrv_state include/linux/hdlcdrv.h -EPCA_MAGIC 0x5c6df104 channel include/linux/epca.h +EPCA_MAGIC 0x5c6df104 channel include/linux/epca.h PCXX_MAGIC 0x5c6df104 channel drivers/char/pcxx.h +KV_MAGIC 0x5f4b565f kernel_vars_s include/asm-mips64/sn/klkernvars.h +I810_STATE_MAGIC 0x63657373 i810_state sound/oss/i810_audio.c +TRIDENT_STATE_MAGIC 0x63657373 trient_state sound/oss/trident.c +M3_CARD_MAGIC 0x646e6f50 m3_card sound/oss/maestro3.c +SLOT_MAGIC 0x67267321 slot drivers/hotplug/cpqphp.h +SLOT_MAGIC 0x67267322 slot drivers/hotplug/acpiphp.h LO_MAGIC 0x68797548 nbd_device include/linux/nbd.h +M3_STATE_MAGIC 0x734d724d m3_state sound/oss/maestro3.c STL_PANELMAGIC 0x7ef621a1 stlpanel include/linux/stallion.h +VMALLOC_MAGIC 0x87654320 snd_alloc_track sound/core/memory.c +KMALLOC_MAGIC 0x87654321 snd_alloc_track sound/core/memory.c +PWC_MAGIC 0x89DC10AB pwc_device drivers/usb/media/pwc.h NBD_REPLY_MAGIC 0x96744668 nbd_reply include/linux/nbd.h STL_BOARDMAGIC 0xa2267f52 stlbrd include/linux/stallion.h -SLAB_MAGIC_ALLOC 0xa5c32f2b kmem_slab_s mm/slab.c -SLAB_MAGIC_DESTROYED 0xb2f23c5a kmem_slab_s mm/slab.c +SCI_MAGIC 0xbabeface gs_port drivers/char/sh-sci.h +CODA_MAGIC 0xC0DAC0DA coda_file_info include/linux/coda_fs_i.h STLI_PORTMAGIC 0xe671c7a1 stliport include/linux/istallion.h +YAM_MAGIC 0xF10A7654 yam_port drivers/net/hamradio/yam.c CCB_MAGIC 0xf2691ad2 ccb drivers/scsi/ncr53c8xx.c +HTB_CMAGIC 0xFEFAFEF1 htb_class net/sched/sch_htb.c +NMI_MAGIC 0x48414d4d455201 nmi_s include/asm-mips64/sn/nmi.h + +Note that there are also defined special per-driver magic numbers in sound +memory managment. See include/sound/sndmagic.h for complete list of them. Many +OSS sound drivers have their magic numbers constructed from the soundcard PCI +ID - these are not listed here as well. + +IrDA subsystem also uses large number of own magic numbers, see +include/net/irda/irda.h for a complete list of them. + +HFS is another larger user of magic numbers - you can find them in +fs/hfs/hfs.h. diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/Documentation/networking/00-INDEX linux.2.5.47-ac6/Documentation/networking/00-INDEX --- linux.2.5.47/Documentation/networking/00-INDEX 2002-10-31 14:57:47.000000000 +0000 +++ linux.2.5.47-ac6/Documentation/networking/00-INDEX 2002-11-05 16:08:04.000000000 +0000 @@ -104,8 +104,6 @@ - the driver for SMC's 9000 series of Ethernet cards smctr.txt - SMC TokenCard TokenRing Linux driver info. -soundmodem.txt - - Linux driver for sound cards as AX.25 modems tcp.txt - short blurb on how TCP output takes place. tlan.txt diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/Documentation/networking/soundmodem.txt linux.2.5.47-ac6/Documentation/networking/soundmodem.txt --- linux.2.5.47/Documentation/networking/soundmodem.txt 2002-10-31 14:57:47.000000000 +0000 +++ linux.2.5.47-ac6/Documentation/networking/soundmodem.txt 1970-01-01 01:00:00.000000000 +0100 @@ -1,90 +0,0 @@ - LINUX DRIVER FOR SOUNDCARDS AS AX.25 MODEMS - - Thomas M. Sailer, HB9JNX/AE4WA, - -This driver allows either SoundBlaster (sbc) or Windows Sound System (wss) -compatible soundcards to be used as either 1200 baud AFSK or 9600 baud FSK -AX.25 packet radio modems. Only half duplex operation is supported; an -attempt to include full duplex support failed because the hardware did -not support it (it appeared that the card only provides one DMA channel, -although the codec chip would support two channels). The driver needs -some processing power! A 66 MHz 486 DX2 is a minimum requirement. Otherwise -interactive performance of the computer may become sluggish. This driver -does *not* support telephone modem standards, it is intended for radio -use only. - - -The Interface of the driver - -The driver provides kernel network drivers named sm[0-3]. sethdlc -from the ax25 utilities may be used to set driver states etc. Users -of userland AX.25 stacks may use the net2kiss utility (also available -in the ax25 utilities package) to convert packets of a network interface -to a KISS stream on a pseudo tty. There's also a patch available from -me for WAMPES which allows attaching a kernel network interface directly. - - -Configuring the driver - -Some sound cards need to be initialized before they operate in either -SoundBlaster or WSS compatibility mode. The driver does _NOT_ do this; -you may use the standard linux sound driver to initialize the soundcard; -compile it as a module, and do - insmod sound - rmmod sound -The soundcard should then be initialized correctly. If this does not help, -you'll have to write your own initialization utility. - -Every time the driver is inserted into the kernel, it has to know which -modems it should access at which ports. This can be done with the setbaycom -utility. If you are only using one modem, you can also configure the -driver from the insmod command line (or by means of an option line in -/etc/modules.conf). - -Examples: - insmod soundmodem mode="sbc:afsk1200" iobase=0x220 irq=5 dma=1 - sethdlc -i sm0 -p mode "sbc:afsk1200" io 0x220 irq 5 dma 1 - -Both lines configure the first port to drive a soundblaster card -in 1200 baud AFSK mode. - -The channel access parameters can be set with sethdlc -a or kissparms. -Note that both utilities interpret the values slightly different. - - -Input and output levels - -It is important that the input and output levels are adjusted properly. -There are two utilities, available in the ax25 utilities distribution, -to facilitate this: smmixer and smdiag. smdiag allows you to display -the input signal in an oscilloscope like display or an eye diagram. -smmixer allows you to adjust input/output levels. See the respective -man pages. - - -Transmitter keying - -Since soundcards do not have a DC coupled output; PTT keying options include -the following: -* VOX circuitry -* Serial port pin -* Parallel port pin -* MPU401 MIDI output via a retriggerable monoflop. -Circuit schematics may be found at -http://www.ife.ee.ethz.ch/~sailer/pcf/ptt_circ/ptt.html. - - -Compatibility with the rest of the Linux kernel - -The sound driver and the soundcard modem driver compete for the same -hardware resources. Of course only one driver can access a given -interface at a time. Worse yet, the sound driver grabs the soundcard -at startup time. Therefore the soundcard modem driver subsequently won't -be able to access the soundcard. You might therefore find it necessary to -unload the sound driver before using the soundcard modem driver. - - - -vy 73s de -Tom Sailer, sailer@ife.ee.ethz.ch -hb9jnx @ hb9w.ampr.org diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/Documentation/README.nsp_cs.eng linux.2.5.47-ac6/Documentation/README.nsp_cs.eng --- linux.2.5.47/Documentation/README.nsp_cs.eng 2002-10-31 14:57:48.000000000 +0000 +++ linux.2.5.47-ac6/Documentation/README.nsp_cs.eng 1970-01-01 01:00:00.000000000 +0100 @@ -1,130 +0,0 @@ - - WorkBiT NinjaSCSI-3/32Bi driver for Linux - -1. Comment - This is Workbit corp.'s(http://www.workbit.co.jp/) NinjaSCSI-3 -(http://www.workbit.co.jp/ts/z_nj3r.html) and NinjaSCSI-32Bi -(http://www.workbit.co.jp/ts/z_njsc32bi.html) PCMCIA card driver module -for Linux. - -2. My Linux environment -Linux kernel: 2.4.7 / 2.2.19 -pcmcia-cs: 3.1.27 -gcc: gcc-2.95.4 -PC card: I-O data PCSC-F (NinjaSCSI-3) - I-O data CBSC-II in 16 bit mode (NinjaSCSI-32Bi) -SCSI device: I-O data CDPS-PX24 (CD-ROM drive) - Media Intelligent MMO-640GT (Optical disk drive) - -3. Install -[1] Check your PC card is true "NinjaSCSI-3" card. - If you installed pcmcia-cs already, pcmcia reports your card as UNKNOWN - card, and write ["WBT", "NinjaSCSI-3", "R1.0"] or some other string to - your console or log file. - You can also use "cardctl" program (this program is in pcmcia-cs source - code) to get more info. - -# cat /var/log/messgaes -... -Jan 2 03:45:06 lindberg cardmgr[78]: unsupported card in socket 1 -Jan 2 03:45:06 lindberg cardmgr[78]: product info: "WBT", "NinjaSCSI-3", "R1.0" -... -# cardctl ident -Socket 0: - no product info available -Socket 1: - product info: "IO DATA", "CBSC16 ", "1" - - -[2] Get Linux kernel source, and extract it to /usr/src. - Because NinjaSCSI driver requiers some SCSI header files in Linux kernel - source. - I recomend rebuilding your kernel. This eliminate some versioning problem. -$ cd /usr/src -$ tar -zxvf linux-x.x.x.tar.gz -$ cd linux -$ make config -... - -[3] If you use this driver with Kernel 2.2, Unpack pcmcia-cs in some directory - and make & install. This driver requies pcmcia-cs header file. -$ cd /usr/src -$ tar zxvf cs-pcmcia-cs-3.x.x.tar.gz -... - -[4] Extract this driver's archive somewhere, and edit Makefile, then do make. -$ tar -zxvf nsp_cs-x.x.tar.gz -$ cd nsp_cs-x.x -$ emacs Makefile -... -$ make - -[5] Copy nsp_cs.o to suitable plase, like /lib/modules//pcmcia/ . - -[6] Add these lines to /etc/pcmcia/config . - If you yse pcmcia-cs-3.1.8 or later, we can use "nsp_cs.conf" file. - So, you don't need to edit file. Just copy to /etc/pcmcia/ . - -------------------------------------- -device "nsp_cs" - class "scsi" module "nsp_cs" - -card "WorkBit NinjaSCSI-3" - version "WBT", "NinjaSCSI-3", "R1.0" - bind "nsp_cs" - -card "WorkBit NinjaSCSI-32Bi (16bit)" - version "WORKBIT", "UltraNinja-16", "1" - bind "nsp_cs" - -# OEM -card "WorkBit NinjaSCSI-32Bi (16bit) / IO-DATA" - version "IO DATA", "CBSC16 ", "1" - bind "nsp_cs" - -# OEM -card "WorkBit NinjaSCSI-32Bi (16bit) / KME-1" - version "KME ", "SCSI-CARD-001", "1" - bind "nsp_cs" -card "WorkBit NinjaSCSI-32Bi (16bit) / KME-2" - version "KME ", "SCSI-CARD-002", "1" - bind "nsp_cs" -card "WorkBit NinjaSCSI-32Bi (16bit) / KME-3" - version "KME ", "SCSI-CARD-003", "1" - bind "nsp_cs" -card "WorkBit NinjaSCSI-32Bi (16bit) / KME-4" - version "KME ", "SCSI-CARD-004", "1" - bind "nsp_cs" -------------------------------------- - -[7] Start (or restart) pcmcia-cs. -# /etc/rc.d/rc.pcmcia start (BSD style) -or -# /etc/init.d/pcmcia start (SYSV style) - - -4. History -See README.nin_cs . - -5. Caution - If you eject card when doing some operation for your SCSI device or suspend -your computer, you encount some *BAD* error like disk crash. - It works good when I using this driver right way. But I'm not guarantee -your data. Please backup your data when you use this driver. - -6. Known Bugs - In 2.4 kernel, you can't use 640MB Optical disk. This error comes from -high level SCSI driver. - -7. Testing - Please send me some reports(bug reports etc..) of this software. -When you send report, please tell me these or more. - card name - kernel version - your SCSI device name(hard drive, CD-ROM, etc...) - -8. Copyright - See GPL. - - -2001/08/08 yokota@netlab.is.tsukuba.ac.jp diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/Documentation/sysctl/kernel.txt linux.2.5.47-ac6/Documentation/sysctl/kernel.txt --- linux.2.5.47/Documentation/sysctl/kernel.txt 2002-10-31 14:57:47.000000000 +0000 +++ linux.2.5.47-ac6/Documentation/sysctl/kernel.txt 2002-10-31 15:06:24.000000000 +0000 @@ -17,29 +17,42 @@ Currently, these files might (depending on your configuration) show up in /proc/sys/kernel: - acct +- core_pattern +- core_uses_pid - ctrl-alt-del - dentry-state - domainname - hostname - htab-reclaim [ PPC only ] +- hotplug - java-appletviewer [ binfmt_java, obsolete ] - java-interpreter [ binfmt_java, obsolete ] - l2cr [ PPC only ] - modprobe ==> Documentation/kmod.txt +- msgmax +- msgmnb +- msgmni - osrelease - ostype - overflowgid - overflowuid - panic +- pid_max - powersave-nap [ PPC only ] - printk - real-root-dev ==> Documentation/initrd.txt - reboot-cmd [ SPARC only ] -- rtsig-nr - rtsig-max +- rtsig-nr +- sem - sg-big-buff [ generic SCSI device (sg) ] +- shmall - shmmax [ sysv ipc ] +- shmmni +- stop-a [ SPARC only ] +- sysrq ==> Documentation/sysrq.txt - tainted +- threads-max - version - zero-paged [ PPC only ] @@ -62,6 +75,41 @@ ============================================================== +core_pattern: + +core_pattern is used to specify a core dumpfile pattern name. +. max length 64 characters; default value is "core" +. core_pattern is used as a pattern template for the output filename; + certain string patterns (beginning with '%') are substituted with + their actual values. +. backward compatibility with core_uses_pid: + If core_pattern does not include "%p" (default does not) + and core_uses_pid is set, then .PID will be appended to + the filename. +. corename format specifiers: + % '%' is dropped + %% output one '%' + %p pid + %u uid + %g gid + %s signal number + %t UNIX time of dump + %h hostname + %e executable filename + % both are dropped + +============================================================== + +core_uses_pid: + +The default coredump filename is "core". By setting +core_uses_pid to 1, the coredump filename becomes core.PID. +If core_pattern does not include "%p" (default does not) +and core_uses_pid is set, then .PID will be appended to +the filename. + +============================================================== + ctrl-alt-del: When the value in this file is 0, ctrl-alt-del is trapped and @@ -105,6 +153,13 @@ ============================================================== +hotplug: + +Path for the hotplug policy agent. +Default value is "/sbin/hotplug". + +============================================================== + l2cr: (PPC only) This flag controls the L2 cache of G3 processor boards. If @@ -149,6 +204,14 @@ ============================================================== +pid_max: + +PID allocation wrap value. When the kenrel's next PID value +reaches this value, it wraps back to a minimum PID value. +PIDs of value pid_max or larger are not allocated. + +============================================================== + powersave-nap: (PPC only) If set, Linux-PPC will use the 'nap' mode of powersaving, @@ -195,7 +258,7 @@ of POSIX realtime (queued) signals that can be outstanding in the system. -Rtsig-nr shows the number of RT signals currently queued. +rtsig-nr shows the number of RT signals currently queued. ============================================================== @@ -231,6 +294,7 @@ Set by modutils >= 2.4.9. 2 - A module was force loaded by insmod -f. Set by modutils >= 2.4.9. + 4 - Unsafe SMP processors: SMP with CPUs not designed for SMP. ============================================================== diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/drivers/acorn/net/ether3.c linux.2.5.47-ac6/drivers/acorn/net/ether3.c --- linux.2.5.47/drivers/acorn/net/ether3.c 2002-10-31 14:57:10.000000000 +0000 +++ linux.2.5.47-ac6/drivers/acorn/net/ether3.c 2002-11-13 15:21:49.000000000 +0000 @@ -855,6 +855,7 @@ } priv = (struct dev_priv *) dev->priv; + init_timer(&priv->timer); /* Reset card... */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/drivers/acpi/ac.c linux.2.5.47-ac6/drivers/acpi/ac.c --- linux.2.5.47/drivers/acpi/ac.c 2002-10-31 14:57:01.000000000 +0000 +++ linux.2.5.47-ac6/drivers/acpi/ac.c 2002-11-13 01:18:36.000000000 +0000 @@ -159,12 +159,6 @@ ACPI_FUNCTION_TRACE("acpi_ac_add_fs"); - if (!acpi_ac_dir) { - acpi_ac_dir = proc_mkdir(ACPI_AC_CLASS, acpi_root_dir); - if (!acpi_ac_dir) - return_VALUE(-ENODEV); - } - if (!acpi_device_dir(device)) { acpi_device_dir(device) = proc_mkdir(acpi_device_bid(device), acpi_ac_dir); @@ -194,9 +188,6 @@ { ACPI_FUNCTION_TRACE("acpi_ac_remove_fs"); - if (!acpi_ac_dir) - return_VALUE(-ENODEV); - if (acpi_device_dir(device)) remove_proc_entry(acpi_device_bid(device), acpi_ac_dir); @@ -330,6 +321,10 @@ ACPI_FUNCTION_TRACE("acpi_ac_init"); + acpi_ac_dir = proc_mkdir(ACPI_AC_CLASS, acpi_root_dir); + if (!acpi_ac_dir) + return_VALUE(-ENODEV); + result = acpi_bus_register_driver(&acpi_ac_driver); if (result < 0) { remove_proc_entry(ACPI_AC_CLASS, acpi_root_dir); @@ -343,13 +338,11 @@ void __exit acpi_ac_exit (void) { - int result = 0; - ACPI_FUNCTION_TRACE("acpi_ac_exit"); - result = acpi_bus_unregister_driver(&acpi_ac_driver); - if (!result) - remove_proc_entry(ACPI_AC_CLASS, acpi_root_dir); + acpi_bus_unregister_driver(&acpi_ac_driver); + + remove_proc_entry(ACPI_AC_CLASS, acpi_root_dir); return_VOID; } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/drivers/acpi/battery.c linux.2.5.47-ac6/drivers/acpi/battery.c --- linux.2.5.47/drivers/acpi/battery.c 2002-10-31 14:57:01.000000000 +0000 +++ linux.2.5.47-ac6/drivers/acpi/battery.c 2002-11-13 01:18:36.000000000 +0000 @@ -615,12 +615,6 @@ ACPI_FUNCTION_TRACE("acpi_battery_add_fs"); - if (!acpi_battery_dir) { - acpi_battery_dir = proc_mkdir(ACPI_BATTERY_CLASS, acpi_root_dir); - if (!acpi_battery_dir) - return_VALUE(-ENODEV); - } - if (!acpi_device_dir(device)) { acpi_device_dir(device) = proc_mkdir(acpi_device_bid(device), acpi_battery_dir); @@ -675,9 +669,6 @@ { ACPI_FUNCTION_TRACE("acpi_battery_remove_fs"); - if (!acpi_battery_dir) - return_VALUE(-ENODEV); - if (acpi_device_dir(device)) remove_proc_entry(acpi_device_bid(device), acpi_battery_dir); @@ -812,6 +803,10 @@ ACPI_FUNCTION_TRACE("acpi_battery_init"); + acpi_battery_dir = proc_mkdir(ACPI_BATTERY_CLASS, acpi_root_dir); + if (!acpi_battery_dir) + return_VALUE(-ENODEV); + result = acpi_bus_register_driver(&acpi_battery_driver); if (result < 0) { remove_proc_entry(ACPI_BATTERY_CLASS, acpi_root_dir); @@ -825,13 +820,11 @@ static void __exit acpi_battery_exit (void) { - int result = 0; - ACPI_FUNCTION_TRACE("acpi_battery_exit"); - result = acpi_bus_unregister_driver(&acpi_battery_driver); - if (!result) - remove_proc_entry(ACPI_BATTERY_CLASS, acpi_root_dir); + acpi_bus_unregister_driver(&acpi_battery_driver); + + remove_proc_entry(ACPI_BATTERY_CLASS, acpi_root_dir); return_VOID; } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/drivers/acpi/bus.c linux.2.5.47-ac6/drivers/acpi/bus.c --- linux.2.5.47/drivers/acpi/bus.c 2002-11-05 13:54:43.000000000 +0000 +++ linux.2.5.47-ac6/drivers/acpi/bus.c 2002-11-13 01:18:36.000000000 +0000 @@ -27,6 +27,7 @@ #include #include #include +#include #include #ifdef CONFIG_X86 #include diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/drivers/acpi/button.c linux.2.5.47-ac6/drivers/acpi/button.c --- linux.2.5.47/drivers/acpi/button.c 2002-10-31 14:57:01.000000000 +0000 +++ linux.2.5.47-ac6/drivers/acpi/button.c 2002-11-13 01:18:36.000000000 +0000 @@ -141,12 +141,6 @@ button = acpi_driver_data(device); - if (!acpi_button_dir) { - acpi_button_dir = proc_mkdir(ACPI_BUTTON_CLASS, acpi_root_dir); - if (!acpi_button_dir) - return_VALUE(-ENODEV); - } - switch (button->type) { case ACPI_BUTTON_TYPE_POWER: case ACPI_BUTTON_TYPE_POWERF: @@ -190,9 +184,6 @@ { ACPI_FUNCTION_TRACE("acpi_button_remove_fs"); - if (!acpi_button_dir) - return_VALUE(-ENODEV); - if (acpi_device_dir(device)) remove_proc_entry(acpi_device_bid(device), acpi_button_dir); @@ -446,9 +437,15 @@ ACPI_FUNCTION_TRACE("acpi_button_init"); + acpi_button_dir = proc_mkdir(ACPI_BUTTON_CLASS, acpi_root_dir); + if (!acpi_button_dir) + return_VALUE(-ENODEV); + result = acpi_bus_register_driver(&acpi_button_driver); - if (result < 0) + if (result < 0) { + remove_proc_entry(ACPI_BUTTON_CLASS, acpi_root_dir); return_VALUE(-ENODEV); + } return_VALUE(0); } @@ -461,6 +458,8 @@ acpi_bus_unregister_driver(&acpi_button_driver); + remove_proc_entry(ACPI_BUTTON_CLASS, acpi_root_dir); + return_VOID; } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/drivers/acpi/dispatcher/dsmethod.c linux.2.5.47-ac6/drivers/acpi/dispatcher/dsmethod.c --- linux.2.5.47/drivers/acpi/dispatcher/dsmethod.c 2002-10-31 14:57:01.000000000 +0000 +++ linux.2.5.47-ac6/drivers/acpi/dispatcher/dsmethod.c 2002-11-13 01:18:36.000000000 +0000 @@ -1,7 +1,7 @@ /****************************************************************************** * * Module Name: dsmethod - Parser/Interpreter interface - control method parsing - * $Revision: 88 $ + * $Revision: 89 $ * *****************************************************************************/ @@ -216,7 +216,7 @@ * interpreter if we block */ status = acpi_ex_system_wait_semaphore (obj_desc->method.semaphore, - WAIT_FOREVER); + ACPI_WAIT_FOREVER); } /* diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/drivers/acpi/dispatcher/dswstate.c linux.2.5.47-ac6/drivers/acpi/dispatcher/dswstate.c --- linux.2.5.47/drivers/acpi/dispatcher/dswstate.c 2002-10-31 15:05:00.000000000 +0000 +++ linux.2.5.47-ac6/drivers/acpi/dispatcher/dswstate.c 2002-11-13 01:18:36.000000000 +0000 @@ -1,7 +1,7 @@ /****************************************************************************** * * Module Name: dswstate - Dispatcher parse tree walk management routines - * $Revision: 69 $ + * $Revision: 70 $ * *****************************************************************************/ @@ -345,7 +345,7 @@ * * RETURN: Status * - * DESCRIPTION: + * DESCRIPTION: Push an object onto the Walk_state result stack. * ******************************************************************************/ @@ -381,7 +381,7 @@ * * RETURN: Status * - * DESCRIPTION: + * DESCRIPTION: Pop an object off of the Walk_state result stack. * ******************************************************************************/ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/drivers/acpi/ec.c linux.2.5.47-ac6/drivers/acpi/ec.c --- linux.2.5.47/drivers/acpi/ec.c 2002-10-31 15:05:00.000000000 +0000 +++ linux.2.5.47-ac6/drivers/acpi/ec.c 2002-11-13 01:18:36.000000000 +0000 @@ -477,12 +477,6 @@ ACPI_FUNCTION_TRACE("acpi_ec_add_fs"); - if (!acpi_ec_dir) { - acpi_ec_dir = proc_mkdir(ACPI_EC_CLASS, acpi_root_dir); - if (!acpi_ec_dir) - return_VALUE(-ENODEV); - } - if (!acpi_device_dir(device)) { acpi_device_dir(device) = proc_mkdir(acpi_device_bid(device), acpi_ec_dir); @@ -508,12 +502,6 @@ { ACPI_FUNCTION_TRACE("acpi_ec_remove_fs"); - if (!acpi_ec_dir) - return_VALUE(-ENODEV); - - if (acpi_device_dir(device)) - remove_proc_entry(acpi_device_bid(device), acpi_ec_dir); - return_VALUE(0); } @@ -789,13 +777,24 @@ if (acpi_disabled) return_VALUE(0); + acpi_ec_dir = proc_mkdir(ACPI_EC_CLASS, acpi_root_dir); + if (!acpi_ec_dir) + return_VALUE(-ENODEV); + /* Now register the driver for the EC */ result = acpi_bus_register_driver(&acpi_ec_driver); + if (result < 0) { + remove_proc_entry(ACPI_EC_CLASS, acpi_root_dir); + return_VALUE(-ENODEV); + } + return_VALUE(result); } subsys_initcall(acpi_ec_init); +/* EC driver currently not unloadable */ +#if 0 static void __exit acpi_ec_ecdt_exit (void) { @@ -813,17 +812,15 @@ static void __exit acpi_ec_exit (void) { - int result = 0; - ACPI_FUNCTION_TRACE("acpi_ec_exit"); - result = acpi_bus_unregister_driver(&acpi_ec_driver); - if (!result) - remove_proc_entry(ACPI_EC_CLASS, acpi_root_dir); + acpi_bus_unregister_driver(&acpi_ec_driver); + remove_proc_entry(ACPI_EC_CLASS, acpi_root_dir); acpi_ec_ecdt_exit(); return_VOID; } +#endif /* 0 */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/drivers/acpi/events/evevent.c linux.2.5.47-ac6/drivers/acpi/events/evevent.c --- linux.2.5.47/drivers/acpi/events/evevent.c 2002-10-31 15:05:00.000000000 +0000 +++ linux.2.5.47-ac6/drivers/acpi/events/evevent.c 2002-11-13 01:18:37.000000000 +0000 @@ -1,7 +1,7 @@ /****************************************************************************** * * Module Name: evevent - Fixed and General Purpose Even handling and dispatch - * $Revision: 95 $ + * $Revision: 96 $ * *****************************************************************************/ @@ -503,9 +503,9 @@ ACPI_REPORT_INFO (("GPE Block%d defined as GPE%d to GPE%d\n", (s32) gpe_block, - acpi_gbl_gpe_block_info[gpe_block].block_base_number, - acpi_gbl_gpe_block_info[gpe_block].block_base_number + - ((acpi_gbl_gpe_block_info[gpe_block].register_count * 8) -1))); + (u32) acpi_gbl_gpe_block_info[gpe_block].block_base_number, + (u32) (acpi_gbl_gpe_block_info[gpe_block].block_base_number + + ((acpi_gbl_gpe_block_info[gpe_block].register_count * 8) -1)))); } } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/drivers/acpi/events/evmisc.c linux.2.5.47-ac6/drivers/acpi/events/evmisc.c --- linux.2.5.47/drivers/acpi/events/evmisc.c 2002-10-31 14:57:01.000000000 +0000 +++ linux.2.5.47-ac6/drivers/acpi/events/evmisc.c 2002-11-13 01:18:37.000000000 +0000 @@ -1,7 +1,7 @@ /****************************************************************************** * * Module Name: evmisc - Miscellaneous event manager support functions - * $Revision: 57 $ + * $Revision: 58 $ * *****************************************************************************/ @@ -433,7 +433,7 @@ acpi_status acpi_ev_acquire_global_lock ( - u32 timeout) + u16 timeout) { acpi_status status = AE_OK; u8 acquired = FALSE; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/drivers/acpi/events/evxface.c linux.2.5.47-ac6/drivers/acpi/events/evxface.c --- linux.2.5.47/drivers/acpi/events/evxface.c 2002-10-31 15:05:00.000000000 +0000 +++ linux.2.5.47-ac6/drivers/acpi/events/evxface.c 2002-11-13 01:18:37.000000000 +0000 @@ -1,7 +1,7 @@ /****************************************************************************** * * Module Name: evxface - External interfaces for ACPI events - * $Revision: 131 $ + * $Revision: 132 $ * *****************************************************************************/ @@ -612,7 +612,7 @@ acpi_status acpi_acquire_global_lock ( - u32 timeout, + u16 timeout, u32 *handle) { acpi_status status; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/drivers/acpi/executer/exdump.c linux.2.5.47-ac6/drivers/acpi/executer/exdump.c --- linux.2.5.47/drivers/acpi/executer/exdump.c 2002-10-31 15:05:00.000000000 +0000 +++ linux.2.5.47-ac6/drivers/acpi/executer/exdump.c 2002-11-13 01:18:37.000000000 +0000 @@ -1,7 +1,7 @@ /****************************************************************************** * * Module Name: exdump - Interpreter debug output routines - * $Revision: 162 $ + * $Revision: 163 $ * *****************************************************************************/ @@ -590,6 +590,7 @@ acpi_ex_out_integer ("Length", obj_desc->buffer.length); acpi_ex_out_pointer ("Pointer", obj_desc->buffer.pointer); + ACPI_DUMP_BUFFER (obj_desc->buffer.pointer, obj_desc->buffer.length); break; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/drivers/acpi/executer/exfield.c linux.2.5.47-ac6/drivers/acpi/executer/exfield.c --- linux.2.5.47/drivers/acpi/executer/exfield.c 2002-10-31 14:57:01.000000000 +0000 +++ linux.2.5.47-ac6/drivers/acpi/executer/exfield.c 2002-11-13 01:18:37.000000000 +0000 @@ -1,7 +1,7 @@ /****************************************************************************** * * Module Name: exfield - ACPI AML (p-code) execution - field manipulation - * $Revision: 112 $ + * $Revision: 113 $ * *****************************************************************************/ @@ -27,6 +27,8 @@ #include "acpi.h" #include "acdispat.h" #include "acinterp.h" +#include "acevents.h" +#include "amlcode.h" #define _COMPONENT ACPI_EXECUTER @@ -82,6 +84,45 @@ } } } + else if ((ACPI_GET_OBJECT_TYPE (obj_desc) == ACPI_TYPE_LOCAL_REGION_FIELD) && + (obj_desc->field.region_obj->region.space_id == ACPI_ADR_SPACE_SMBUS)) { + /* + * This is an SMBus read. We must create a buffer to hold the data + * and directly access the region handler. + */ + buffer_desc = acpi_ut_create_internal_object (ACPI_TYPE_BUFFER); + if (!buffer_desc) { + return_ACPI_STATUS (AE_NO_MEMORY); + } + + /* Create the actual read buffer */ + + buffer_desc->buffer.pointer = ACPI_MEM_CALLOCATE (ACPI_SMBUS_BUFFER_SIZE); + if (!buffer_desc->buffer.pointer) { + acpi_ut_remove_reference (buffer_desc); + return_ACPI_STATUS (AE_NO_MEMORY); + } + + /* Complete the buffer object initialization */ + + buffer_desc->common.flags = AOPOBJ_DATA_VALID; + buffer_desc->buffer.length = ACPI_SMBUS_BUFFER_SIZE; + buffer = buffer_desc->buffer.pointer; + + /* Lock entire transaction if requested */ + + locked = acpi_ex_acquire_global_lock (obj_desc->common_field.field_flags); + + /* + * Perform the read. + * Note: Smbus protocol value is passed in upper 16-bits of Function + */ + status = acpi_ex_access_region (obj_desc, 0, + (acpi_integer *) buffer_desc->buffer.pointer, + ACPI_READ | (obj_desc->field.attribute << 16)); + acpi_ex_release_global_lock (locked); + goto exit; + } /* * Allocate a buffer for the contents of the field. @@ -138,17 +179,17 @@ obj_desc->common_field.start_field_bit_offset, obj_desc->common_field.base_byte_offset)); + /* Lock entire transaction if requested */ + locked = acpi_ex_acquire_global_lock (obj_desc->common_field.field_flags); /* Read from the field */ status = acpi_ex_extract_from_field (obj_desc, buffer, length); - - /* - * Release global lock if we acquired it earlier - */ acpi_ex_release_global_lock (locked); + +exit: if (ACPI_FAILURE (status)) { acpi_ut_remove_reference (buffer_desc); } @@ -176,7 +217,8 @@ acpi_status acpi_ex_write_data_to_field ( acpi_operand_object *source_desc, - acpi_operand_object *obj_desc) + acpi_operand_object *obj_desc, + acpi_operand_object **result_desc) { acpi_status status; u32 length; @@ -184,6 +226,7 @@ void *buffer; void *new_buffer; u8 locked; + acpi_operand_object *buffer_desc; ACPI_FUNCTION_TRACE_PTR ("Ex_write_data_to_field", obj_desc); @@ -207,6 +250,64 @@ } } } + else if ((ACPI_GET_OBJECT_TYPE (obj_desc) == ACPI_TYPE_LOCAL_REGION_FIELD) && + (obj_desc->field.region_obj->region.space_id == ACPI_ADR_SPACE_SMBUS)) { + /* + * This is an SMBus write. We will bypass the entire field mechanism + * and handoff the buffer directly to the handler. + * + * Source must be a buffer of sufficient size (ACPI_SMBUS_BUFFER_SIZE). + */ + if (ACPI_GET_OBJECT_TYPE (source_desc) != ACPI_TYPE_BUFFER) { + ACPI_REPORT_ERROR (("SMBus write requires Buffer, found type %s\n", + acpi_ut_get_object_type_name (source_desc))); + return_ACPI_STATUS (AE_AML_OPERAND_TYPE); + } + + if (source_desc->buffer.length < ACPI_SMBUS_BUFFER_SIZE) { + ACPI_REPORT_ERROR (("SMBus write requires Buffer of length %X, found length %X\n", + ACPI_SMBUS_BUFFER_SIZE, source_desc->buffer.length)); + return_ACPI_STATUS (AE_AML_BUFFER_LIMIT); + } + + buffer_desc = acpi_ut_create_internal_object (ACPI_TYPE_BUFFER); + if (!buffer_desc) { + return_ACPI_STATUS (AE_NO_MEMORY); + } + + /* Create the actual read buffer */ + + buffer_desc->buffer.pointer = ACPI_MEM_CALLOCATE (ACPI_SMBUS_BUFFER_SIZE); + if (!buffer_desc->buffer.pointer) { + acpi_ut_remove_reference (buffer_desc); + return_ACPI_STATUS (AE_NO_MEMORY); + } + + /* Complete the buffer object initialization */ + + buffer_desc->common.flags = AOPOBJ_DATA_VALID; + buffer_desc->buffer.length = ACPI_SMBUS_BUFFER_SIZE; + buffer = buffer_desc->buffer.pointer; + + + ACPI_MEMCPY (buffer, source_desc->buffer.pointer, ACPI_SMBUS_BUFFER_SIZE); + + /* Lock entire transaction if requested */ + + locked = acpi_ex_acquire_global_lock (obj_desc->common_field.field_flags); + + /* + * Perform the write (returns status and perhaps data in the same buffer) + * Note: SMBus protocol type is passed in upper 16-bits of Function. + */ + status = acpi_ex_access_region (obj_desc, 0, + (acpi_integer *) buffer, + ACPI_WRITE | (obj_desc->field.attribute << 16)); + acpi_ex_release_global_lock (locked); + + *result_desc = buffer_desc; + return_ACPI_STATUS (status); + } /* * Get a pointer to the data to be written @@ -267,16 +368,13 @@ obj_desc->common_field.start_field_bit_offset, obj_desc->common_field.base_byte_offset)); + /* Lock entire transaction if requested */ + locked = acpi_ex_acquire_global_lock (obj_desc->common_field.field_flags); - /* - * Write to the field - */ - status = acpi_ex_insert_into_field (obj_desc, buffer, length); + /* Write to the field */ - /* - * Release global lock if we acquired it earlier - */ + status = acpi_ex_insert_into_field (obj_desc, buffer, length); acpi_ex_release_global_lock (locked); /* Free temporary buffer if we used one */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/drivers/acpi/executer/exfldio.c linux.2.5.47-ac6/drivers/acpi/executer/exfldio.c --- linux.2.5.47/drivers/acpi/executer/exfldio.c 2002-10-31 15:05:00.000000000 +0000 +++ linux.2.5.47-ac6/drivers/acpi/executer/exfldio.c 2002-11-13 01:18:37.000000000 +0000 @@ -1,7 +1,7 @@ /****************************************************************************** * * Module Name: exfldio - Aml Field I/O - * $Revision: 89 $ + * $Revision: 90 $ * *****************************************************************************/ @@ -64,6 +64,8 @@ rgn_desc = obj_desc->common_field.region_obj; + /* We must have a valid region */ + if (ACPI_GET_OBJECT_TYPE (rgn_desc) != ACPI_TYPE_REGION) { ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Needed Region, found type %X (%s)\n", ACPI_GET_OBJECT_TYPE (rgn_desc), @@ -83,6 +85,12 @@ } } + if (rgn_desc->region.space_id == ACPI_ADR_SPACE_SMBUS) { + /* SMBus has a non-linear address space */ + + return_ACPI_STATUS (AE_OK); + } + /* * Validate the request. The entire request from the byte offset for a * length of one field datum (access width) must fit within the region. @@ -127,8 +135,10 @@ * PARAMETERS: *Obj_desc - Field to be read * Field_datum_byte_offset - Byte offset of this datum within the * parent field - * *Value - Where to store value (must be 32 bits) - * Read_write - Read or Write flag + * *Value - Where to store value (must at least + * the size of acpi_integer) + * Function - Read or Write flag plus other region- + * dependent flags * * RETURN: Status * @@ -141,7 +151,7 @@ acpi_operand_object *obj_desc, u32 field_datum_byte_offset, acpi_integer *value, - u32 read_write) + u32 function) { acpi_status status; acpi_operand_object *rgn_desc; @@ -152,6 +162,15 @@ /* + * Ensure that the region operands are fully evaluated and verify + * the validity of the request + */ + status = acpi_ex_setup_region (obj_desc, field_datum_byte_offset); + if (ACPI_FAILURE (status)) { + return_ACPI_STATUS (status); + } + + /* * The physical address of this field datum is: * * 1) The base of the region, plus @@ -163,7 +182,7 @@ + obj_desc->common_field.base_byte_offset + field_datum_byte_offset; - if (read_write == ACPI_READ) { + if ((function & ACPI_IO_MASK) == ACPI_READ) { ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, "[READ]")); } else { @@ -181,7 +200,7 @@ /* Invoke the appropriate Address_space/Op_region handler */ - status = acpi_ev_address_space_dispatch (rgn_desc, read_write, + status = acpi_ev_address_space_dispatch (rgn_desc, function, address, ACPI_MUL_8 (obj_desc->common_field.access_byte_width), value); if (ACPI_FAILURE (status)) { @@ -191,7 +210,6 @@ acpi_ut_get_region_name (rgn_desc->region.space_id), rgn_desc->region.space_id)); } - else if (status == AE_NOT_EXIST) { ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Region %s(%X) has no handler\n", @@ -371,11 +389,6 @@ * For simple Region_fields, we just directly access the owning * Operation Region. */ - status = acpi_ex_setup_region (obj_desc, field_datum_byte_offset); - if (ACPI_FAILURE (status)) { - return_ACPI_STATUS (status); - } - status = acpi_ex_access_region (obj_desc, field_datum_byte_offset, value, read_write); break; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/drivers/acpi/executer/exoparg1.c linux.2.5.47-ac6/drivers/acpi/executer/exoparg1.c --- linux.2.5.47/drivers/acpi/executer/exoparg1.c 2002-10-31 15:05:00.000000000 +0000 +++ linux.2.5.47-ac6/drivers/acpi/executer/exoparg1.c 2002-11-13 01:18:37.000000000 +0000 @@ -2,7 +2,7 @@ /****************************************************************************** * * Module Name: exoparg1 - AML execution - opcodes with 1 argument - * $Revision: 144 $ + * $Revision: 145 $ * *****************************************************************************/ @@ -389,14 +389,16 @@ return_ACPI_STATUS (status); } - /* - * Normally, we would remove a reference on the Operand[0] parameter; - * But since it is being used as the internal return object - * (meaning we would normally increment it), the two cancel out, - * and we simply don't do anything. - */ - walk_state->result_obj = operand[0]; - walk_state->operands[0] = NULL; /* Prevent deletion */ + if (!walk_state->result_obj) { + /* + * Normally, we would remove a reference on the Operand[0] parameter; + * But since it is being used as the internal return object + * (meaning we would normally increment it), the two cancel out, + * and we simply don't do anything. + */ + walk_state->result_obj = operand[0]; + walk_state->operands[0] = NULL; /* Prevent deletion */ + } return_ACPI_STATUS (status); @@ -461,7 +463,9 @@ cleanup: - walk_state->result_obj = return_desc; + if (!walk_state->result_obj) { + walk_state->result_obj = return_desc; + } /* Delete return object on error */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/drivers/acpi/executer/exoparg2.c linux.2.5.47-ac6/drivers/acpi/executer/exoparg2.c --- linux.2.5.47/drivers/acpi/executer/exoparg2.c 2002-10-31 15:05:00.000000000 +0000 +++ linux.2.5.47-ac6/drivers/acpi/executer/exoparg2.c 2002-11-13 01:18:37.000000000 +0000 @@ -1,7 +1,7 @@ /****************************************************************************** * * Module Name: exoparg2 - AML execution - opcodes with 2 arguments - * $Revision: 113 $ + * $Revision: 114 $ * *****************************************************************************/ @@ -490,7 +490,9 @@ goto cleanup; } - walk_state->result_obj = return_desc; + if (!walk_state->result_obj) { + walk_state->result_obj = return_desc; + } } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/drivers/acpi/executer/exoparg3.c linux.2.5.47-ac6/drivers/acpi/executer/exoparg3.c --- linux.2.5.47/drivers/acpi/executer/exoparg3.c 2002-10-31 14:57:01.000000000 +0000 +++ linux.2.5.47-ac6/drivers/acpi/executer/exoparg3.c 2002-11-13 01:18:37.000000000 +0000 @@ -2,7 +2,7 @@ /****************************************************************************** * * Module Name: exoparg3 - AML execution - opcodes with 3 arguments - * $Revision: 14 $ + * $Revision: 15 $ * *****************************************************************************/ @@ -226,7 +226,9 @@ /* Set the return object and exit */ - walk_state->result_obj = return_desc; + if (!walk_state->result_obj) { + walk_state->result_obj = return_desc; + } return_ACPI_STATUS (status); } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/drivers/acpi/executer/exprep.c linux.2.5.47-ac6/drivers/acpi/executer/exprep.c --- linux.2.5.47/drivers/acpi/executer/exprep.c 2002-10-31 15:05:00.000000000 +0000 +++ linux.2.5.47-ac6/drivers/acpi/executer/exprep.c 2002-11-13 01:18:37.000000000 +0000 @@ -2,7 +2,7 @@ /****************************************************************************** * * Module Name: exprep - ACPI AML (p-code) execution - field prep utilities - * $Revision: 120 $ + * $Revision: 121 $ * *****************************************************************************/ @@ -107,28 +107,24 @@ break; case AML_FIELD_ACCESS_BYTE: + case AML_FIELD_ACCESS_BUFFER: /* ACPI 2.0 (SMBus Buffer) */ byte_alignment = 1; - bit_length = 8; + bit_length = 8; break; case AML_FIELD_ACCESS_WORD: byte_alignment = 2; - bit_length = 16; + bit_length = 16; break; case AML_FIELD_ACCESS_DWORD: byte_alignment = 4; - bit_length = 32; + bit_length = 32; break; - case AML_FIELD_ACCESS_QWORD: /* ACPI 2.0 */ + case AML_FIELD_ACCESS_QWORD: /* ACPI 2.0 */ byte_alignment = 8; - bit_length = 64; - break; - - case AML_FIELD_ACCESS_BUFFER: /* ACPI 2.0 */ - byte_alignment = 8; - bit_length = 8; + bit_length = 64; break; default: diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/drivers/acpi/executer/exstore.c linux.2.5.47-ac6/drivers/acpi/executer/exstore.c --- linux.2.5.47/drivers/acpi/executer/exstore.c 2002-10-31 15:05:00.000000000 +0000 +++ linux.2.5.47-ac6/drivers/acpi/executer/exstore.c 2002-11-13 01:18:37.000000000 +0000 @@ -2,7 +2,7 @@ /****************************************************************************** * * Module Name: exstore - AML Interpreter object store support - * $Revision: 173 $ + * $Revision: 174 $ * *****************************************************************************/ @@ -81,7 +81,7 @@ if (ACPI_GET_DESCRIPTOR_TYPE (dest_desc) == ACPI_DESC_TYPE_NAMED) { /* * Dest is a namespace node, - * Storing an object into a Name "container" + * Storing an object into a Named node. */ status = acpi_ex_store_object_to_node (source_desc, (acpi_namespace_node *) dest_desc, walk_state); @@ -435,7 +435,7 @@ /* * For fields, copy the source data to the target field. */ - status = acpi_ex_write_data_to_field (source_desc, target_desc); + status = acpi_ex_write_data_to_field (source_desc, target_desc, &walk_state->result_obj); break; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/drivers/acpi/executer/exsystem.c linux.2.5.47-ac6/drivers/acpi/executer/exsystem.c --- linux.2.5.47/drivers/acpi/executer/exsystem.c 2002-10-31 14:57:01.000000000 +0000 +++ linux.2.5.47-ac6/drivers/acpi/executer/exsystem.c 2002-11-13 01:18:37.000000000 +0000 @@ -2,7 +2,7 @@ /****************************************************************************** * * Module Name: exsystem - Interface to OS services - * $Revision: 73 $ + * $Revision: 74 $ * *****************************************************************************/ @@ -51,7 +51,7 @@ acpi_status acpi_ex_system_wait_semaphore ( acpi_handle semaphore, - u32 timeout) + u16 timeout) { acpi_status status; acpi_status status2; @@ -201,12 +201,12 @@ * Support for the _GL_ Mutex object -- go get the global lock */ if (obj_desc->mutex.semaphore == acpi_gbl_global_lock_semaphore) { - status = acpi_ev_acquire_global_lock ((u32) time_desc->integer.value); + status = acpi_ev_acquire_global_lock ((u16) time_desc->integer.value); return_ACPI_STATUS (status); } status = acpi_ex_system_wait_semaphore (obj_desc->mutex.semaphore, - (u32) time_desc->integer.value); + (u16) time_desc->integer.value); return_ACPI_STATUS (status); } @@ -312,7 +312,7 @@ if (obj_desc) { status = acpi_ex_system_wait_semaphore (obj_desc->event.semaphore, - (u32) time_desc->integer.value); + (u16) time_desc->integer.value); } return_ACPI_STATUS (status); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/drivers/acpi/executer/exutils.c linux.2.5.47-ac6/drivers/acpi/executer/exutils.c --- linux.2.5.47/drivers/acpi/executer/exutils.c 2002-10-31 15:05:00.000000000 +0000 +++ linux.2.5.47-ac6/drivers/acpi/executer/exutils.c 2002-11-13 01:18:37.000000000 +0000 @@ -2,7 +2,7 @@ /****************************************************************************** * * Module Name: exutils - interpreter/scanner utilities - * $Revision: 105 $ + * $Revision: 106 $ * *****************************************************************************/ @@ -189,7 +189,7 @@ if (field_flags & AML_FIELD_LOCK_RULE_MASK) { /* We should attempt to get the lock, wait forever */ - status = acpi_ev_acquire_global_lock (ACPI_UINT32_MAX); + status = acpi_ev_acquire_global_lock (ACPI_WAIT_FOREVER); if (ACPI_SUCCESS (status)) { locked = TRUE; } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/drivers/acpi/fan.c linux.2.5.47-ac6/drivers/acpi/fan.c --- linux.2.5.47/drivers/acpi/fan.c 2002-10-31 14:57:01.000000000 +0000 +++ linux.2.5.47-ac6/drivers/acpi/fan.c 2002-11-13 01:18:37.000000000 +0000 @@ -151,12 +151,6 @@ if (!device) return_VALUE(-EINVAL); - if (!acpi_fan_dir) { - acpi_fan_dir = proc_mkdir(ACPI_FAN_CLASS, acpi_root_dir); - if (!acpi_fan_dir) - return_VALUE(-ENODEV); - } - if (!acpi_device_dir(device)) { acpi_device_dir(device) = proc_mkdir(acpi_device_bid(device), acpi_fan_dir); @@ -187,9 +181,6 @@ { ACPI_FUNCTION_TRACE("acpi_fan_remove_fs"); - if (!acpi_fan_dir) - return_VALUE(-ENODEV); - if (acpi_device_dir(device)) remove_proc_entry(acpi_device_bid(device), acpi_fan_dir); @@ -276,9 +267,15 @@ ACPI_FUNCTION_TRACE("acpi_fan_init"); + acpi_fan_dir = proc_mkdir(ACPI_FAN_CLASS, acpi_root_dir); + if (!acpi_fan_dir) + return_VALUE(-ENODEV); + result = acpi_bus_register_driver(&acpi_fan_driver); - if (result < 0) + if (result < 0) { + remove_proc_entry(ACPI_FAN_CLASS, acpi_root_dir); return_VALUE(-ENODEV); + } return_VALUE(0); } @@ -287,13 +284,11 @@ void __exit acpi_fan_exit (void) { - int result = 0; - ACPI_FUNCTION_TRACE("acpi_fan_exit"); - result = acpi_bus_unregister_driver(&acpi_fan_driver); - if (!result) - remove_proc_entry(ACPI_FAN_CLASS, acpi_root_dir); + acpi_bus_unregister_driver(&acpi_fan_driver); + + remove_proc_entry(ACPI_FAN_CLASS, acpi_root_dir); return_VOID; } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/drivers/acpi/include/acconfig.h linux.2.5.47-ac6/drivers/acpi/include/acconfig.h --- linux.2.5.47/drivers/acpi/include/acconfig.h 2002-11-05 13:54:43.000000000 +0000 +++ linux.2.5.47-ac6/drivers/acpi/include/acconfig.h 2002-11-13 01:18:37.000000000 +0000 @@ -1,7 +1,7 @@ /****************************************************************************** * * Name: acconfig.h - Global configuration constants - * $Revision: 115 $ + * $Revision: 117 $ * *****************************************************************************/ @@ -54,7 +54,7 @@ /* Version string */ -#define ACPI_CA_VERSION 0x20021101 +#define ACPI_CA_VERSION 0x20021111 /* Version of ACPI supported */ @@ -166,6 +166,10 @@ #define ACPI_RSDP_CHECKSUM_LENGTH 20 #define ACPI_RSDP_XCHECKSUM_LENGTH 36 +/* SMBus bidirectional buffer size */ + +#define ACPI_SMBUS_BUFFER_SIZE 34 + /****************************************************************************** * diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/drivers/acpi/include/acdisasm.h linux.2.5.47-ac6/drivers/acpi/include/acdisasm.h --- linux.2.5.47/drivers/acpi/include/acdisasm.h 2002-10-31 15:05:00.000000000 +0000 +++ linux.2.5.47-ac6/drivers/acpi/include/acdisasm.h 2002-11-13 01:18:37.000000000 +0000 @@ -1,7 +1,7 @@ /****************************************************************************** * * Name: acdisasm.h - AML disassembler - * $Revision: 4 $ + * $Revision: 5 $ * *****************************************************************************/ @@ -239,6 +239,9 @@ acpi_dm_bit_list ( u16 mask); +void +acpi_dm_decode_attribute ( + u8 attribute); /* * dmresrcl diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/drivers/acpi/include/acevents.h linux.2.5.47-ac6/drivers/acpi/include/acevents.h --- linux.2.5.47/drivers/acpi/include/acevents.h 2002-10-31 14:57:01.000000000 +0000 +++ linux.2.5.47-ac6/drivers/acpi/include/acevents.h 2002-11-13 01:18:37.000000000 +0000 @@ -1,7 +1,7 @@ /****************************************************************************** * * Name: acevents.h - Event subcomponent prototypes and defines - * $Revision: 79 $ + * $Revision: 80 $ * *****************************************************************************/ @@ -63,7 +63,7 @@ acpi_status acpi_ev_acquire_global_lock( - u32 timeout); + u16 timeout); acpi_status acpi_ev_release_global_lock( diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/drivers/acpi/include/acinterp.h linux.2.5.47-ac6/drivers/acpi/include/acinterp.h --- linux.2.5.47/drivers/acpi/include/acinterp.h 2002-10-31 15:05:00.000000000 +0000 +++ linux.2.5.47-ac6/drivers/acpi/include/acinterp.h 2002-11-13 01:18:37.000000000 +0000 @@ -1,7 +1,7 @@ /****************************************************************************** * * Name: acinterp.h - Interpreter subcomponent prototypes and defines - * $Revision: 140 $ + * $Revision: 142 $ * *****************************************************************************/ @@ -164,7 +164,8 @@ acpi_status acpi_ex_write_data_to_field ( acpi_operand_object *source_desc, - acpi_operand_object *obj_desc); + acpi_operand_object *obj_desc, + acpi_operand_object **result_desc); /* * exmisc - ACPI AML (p-code) execution - specific opcodes @@ -377,7 +378,7 @@ acpi_status acpi_ex_system_wait_semaphore ( acpi_handle semaphore, - u32 timeout); + u16 timeout); /* diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/drivers/acpi/include/aclocal.h linux.2.5.47-ac6/drivers/acpi/include/aclocal.h --- linux.2.5.47/drivers/acpi/include/aclocal.h 2002-10-31 15:05:00.000000000 +0000 +++ linux.2.5.47-ac6/drivers/acpi/include/aclocal.h 2002-11-13 01:18:37.000000000 +0000 @@ -1,7 +1,7 @@ /****************************************************************************** * * Name: aclocal.h - Internal data types used across the ACPI subsystem - * $Revision: 178 $ + * $Revision: 179 $ * *****************************************************************************/ @@ -27,7 +27,7 @@ #define __ACLOCAL_H__ -#define WAIT_FOREVER ((u32) -1) +#define ACPI_WAIT_FOREVER 0xFFFF /* u16, as per ACPI spec */ typedef void* acpi_mutex; typedef u32 ACPI_MUTEX_HANDLE; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/drivers/acpi/include/acpiosxf.h linux.2.5.47-ac6/drivers/acpi/include/acpiosxf.h --- linux.2.5.47/drivers/acpi/include/acpiosxf.h 2002-10-31 14:57:01.000000000 +0000 +++ linux.2.5.47-ac6/drivers/acpi/include/acpiosxf.h 2002-11-13 01:18:37.000000000 +0000 @@ -117,7 +117,7 @@ acpi_os_wait_semaphore ( acpi_handle handle, u32 units, - u32 timeout); + u16 timeout); acpi_status acpi_os_signal_semaphore ( diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/drivers/acpi/include/acpixf.h linux.2.5.47-ac6/drivers/acpi/include/acpixf.h --- linux.2.5.47/drivers/acpi/include/acpixf.h 2002-10-31 14:57:01.000000000 +0000 +++ linux.2.5.47-ac6/drivers/acpi/include/acpixf.h 2002-11-13 01:18:37.000000000 +0000 @@ -281,7 +281,7 @@ acpi_status acpi_acquire_global_lock ( - u32 timeout, + u16 timeout, u32 *handle); acpi_status diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/drivers/acpi/include/actypes.h linux.2.5.47-ac6/drivers/acpi/include/actypes.h --- linux.2.5.47/drivers/acpi/include/actypes.h 2002-10-31 15:05:00.000000000 +0000 +++ linux.2.5.47-ac6/drivers/acpi/include/actypes.h 2002-11-13 01:18:37.000000000 +0000 @@ -1,7 +1,7 @@ /****************************************************************************** * * Name: actypes.h - Common data types for the entire ACPI subsystem - * $Revision: 240 $ + * $Revision: 241 $ * *****************************************************************************/ @@ -499,6 +499,7 @@ */ #define ACPI_READ 0 #define ACPI_WRITE 1 +#define ACPI_IO_MASK 1 /* diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/drivers/acpi/include/amlcode.h linux.2.5.47-ac6/drivers/acpi/include/amlcode.h --- linux.2.5.47/drivers/acpi/include/amlcode.h 2002-10-31 14:57:01.000000000 +0000 +++ linux.2.5.47-ac6/drivers/acpi/include/amlcode.h 2002-11-13 01:18:37.000000000 +0000 @@ -3,7 +3,7 @@ * Name: amlcode.h - Definitions for AML, as included in "definition blocks" * Declarations and definitions contained herein are derived * directly from the ACPI specification. - * $Revision: 70 $ + * $Revision: 71 $ * *****************************************************************************/ @@ -462,7 +462,8 @@ AML_FIELD_ATTRIB_SMB_BYTE = 0x06, AML_FIELD_ATTRIB_SMB_WORD = 0x08, AML_FIELD_ATTRIB_SMB_BLOCK = 0x0A, - AML_FIELD_ATTRIB_SMB_CALL = 0x0E + AML_FIELD_ATTRIB_SMB_WORD_CALL = 0x0C, + AML_FIELD_ATTRIB_SMB_BLOCK_CALL = 0x0D } AML_ACCESS_ATTRIBUTE; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/drivers/acpi/namespace/nsdump.c linux.2.5.47-ac6/drivers/acpi/namespace/nsdump.c --- linux.2.5.47/drivers/acpi/namespace/nsdump.c 2002-10-31 15:05:00.000000000 +0000 +++ linux.2.5.47-ac6/drivers/acpi/namespace/nsdump.c 2002-11-13 01:18:37.000000000 +0000 @@ -1,7 +1,7 @@ /****************************************************************************** * * Module Name: nsdump - table dumping routines for debug - * $Revision: 145 $ + * $Revision: 146 $ * *****************************************************************************/ @@ -180,7 +180,7 @@ /* Indent the object according to the level */ - acpi_os_printf ("%2d%*s", level - 1, level * 2, " "); + acpi_os_printf ("%2d%*s", (u32) level - 1, (int) level * 2, " "); /* Check the node type and name */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/drivers/acpi/namespace/nsobject.c linux.2.5.47-ac6/drivers/acpi/namespace/nsobject.c --- linux.2.5.47/drivers/acpi/namespace/nsobject.c 2002-10-31 15:05:00.000000000 +0000 +++ linux.2.5.47-ac6/drivers/acpi/namespace/nsobject.c 2002-11-13 01:18:37.000000000 +0000 @@ -2,7 +2,7 @@ * * Module Name: nsobject - Utilities for objects attached to namespace * table entries - * $Revision: 84 $ + * $Revision: 85 $ * ******************************************************************************/ @@ -173,13 +173,13 @@ * * FUNCTION: Acpi_ns_detach_object * - * PARAMETERS: Node - An object whose Value will be deleted + * PARAMETERS: Node - An node whose object will be detached * * RETURN: None. * - * DESCRIPTION: Delete the Value associated with a namespace object. If the - * Value is an allocated object, it is freed. Otherwise, the - * field is simply cleared. + * DESCRIPTION: Detach/delete an object associated with a namespace node. + * if the object is an allocated object, it is freed. + * Otherwise, the field is simply cleared. * ******************************************************************************/ @@ -234,6 +234,8 @@ * RETURN: Current value of the object field from the Node whose * handle is passed * + * DESCRIPTION: Obtain the object attached to a namespace node. + * ******************************************************************************/ acpi_operand_object * @@ -266,7 +268,9 @@ * PARAMETERS: Node - Parent Node to be examined * * RETURN: Current value of the object field from the Node whose - * handle is passed + * handle is passed. + * + * DESCRIPTION: Obtain a secondary object associated with a namespace node. * ******************************************************************************/ @@ -292,11 +296,13 @@ * * FUNCTION: Acpi_ns_attach_data * - * PARAMETERS: + * PARAMETERS: Node - Namespace node + * Handler - Handler to be associated with the data + * Data - Data to be attached * * RETURN: Status * - * DESCRIPTION: + * DESCRIPTION: Low-level attach data. Create and attach a Data object. * ******************************************************************************/ @@ -311,7 +317,8 @@ acpi_operand_object *data_desc; - /* */ + /* We only allow one attachment per handler */ + prev_obj_desc = NULL; obj_desc = node->object; while (obj_desc) { @@ -324,7 +331,6 @@ obj_desc = obj_desc->common.next_object; } - /* Create an internal object for the data */ data_desc = acpi_ut_create_internal_object (ACPI_TYPE_LOCAL_DATA); @@ -335,7 +341,6 @@ data_desc->data.handler = handler; data_desc->data.pointer = data; - /* Install the data object */ if (prev_obj_desc) { @@ -353,11 +358,13 @@ * * FUNCTION: Acpi_ns_detach_data * - * PARAMETERS: + * PARAMETERS: Node - Namespace node + * Handler - Handler associated with the data * * RETURN: Status * - * DESCRIPTION: + * DESCRIPTION: Low-level detach data. Delete the data node, but the caller + * is responsible for the actual data. * ******************************************************************************/ @@ -398,11 +405,14 @@ * * FUNCTION: Acpi_ns_get_attached_data * - * PARAMETERS: + * PARAMETERS: Node - Namespace node + * Handler - Handler associated with the data + * Data - Where the data is returned * * RETURN: Status * - * DESCRIPTION: + * DESCRIPTION: Low level interface to obtain data previously associated with + * a namespace node. * ******************************************************************************/ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/drivers/acpi/namespace/nsutils.c linux.2.5.47-ac6/drivers/acpi/namespace/nsutils.c --- linux.2.5.47/drivers/acpi/namespace/nsutils.c 2002-10-31 15:05:00.000000000 +0000 +++ linux.2.5.47-ac6/drivers/acpi/namespace/nsutils.c 2002-11-13 01:18:37.000000000 +0000 @@ -2,7 +2,7 @@ * * Module Name: nsutils - Utilities for accessing ACPI namespace, accessing * parents and siblings and Scope manipulation - * $Revision: 115 $ + * $Revision: 116 $ * *****************************************************************************/ @@ -45,7 +45,7 @@ * * RETURN: None * - * DESCRIPTION: Print warning message + * DESCRIPTION: Print warning message with full pathname * ******************************************************************************/ @@ -61,12 +61,16 @@ char *name; + /* Convert path to external format */ + status = acpi_ns_externalize_name (ACPI_UINT32_MAX, internal_name, NULL, &name); acpi_os_printf ("%8s-%04d: *** Error: Looking up ", module_name, line_number); - if (name) { + /* Print target name */ + + if (ACPI_SUCCESS (status)) { acpi_os_printf ("[%s]", name); } else { diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/drivers/acpi/namespace/nsxfeval.c linux.2.5.47-ac6/drivers/acpi/namespace/nsxfeval.c --- linux.2.5.47/drivers/acpi/namespace/nsxfeval.c 2002-10-31 15:05:00.000000000 +0000 +++ linux.2.5.47-ac6/drivers/acpi/namespace/nsxfeval.c 2002-11-13 01:18:37.000000000 +0000 @@ -2,7 +2,7 @@ * * Module Name: nsxfeval - Public interfaces to the ACPI subsystem * ACPI Object evaluation interfaces - * $Revision: 3 $ + * $Revision: 4 $ * ******************************************************************************/ @@ -570,11 +570,13 @@ * * FUNCTION: Acpi_attach_data * - * PARAMETERS: + * PARAMETERS: Obj_handle - Namespace node + * Handler - Handler for this attachment + * Data - Pointer to data to be attached * * RETURN: Status * - * DESCRIPTION: + * DESCRIPTION: Attach arbitrary data and handler to a namespace node. * ******************************************************************************/ @@ -621,11 +623,12 @@ * * FUNCTION: Acpi_detach_data * - * PARAMETERS: + * PARAMETERS: Obj_handle - Namespace node handle + * Handler - Handler used in call to Acpi_attach_data * * RETURN: Status * - * DESCRIPTION: + * DESCRIPTION: Remove data that was previously attached to a node. * ******************************************************************************/ @@ -670,11 +673,13 @@ * * FUNCTION: Acpi_get_data * - * PARAMETERS: + * PARAMETERS: Obj_handle - Namespace node + * Handler - Handler used in call to Attach_data + * Data - Where the data is returned * * RETURN: Status * - * DESCRIPTION: + * DESCRIPTION: Retrieve data that was previously attached to a namespace node. * ******************************************************************************/ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/drivers/acpi/osl.c linux.2.5.47-ac6/drivers/acpi/osl.c --- linux.2.5.47/drivers/acpi/osl.c 2002-11-05 13:54:43.000000000 +0000 +++ linux.2.5.47-ac6/drivers/acpi/osl.c 2002-11-13 01:18:37.000000000 +0000 @@ -702,7 +702,7 @@ acpi_os_wait_semaphore( acpi_handle handle, u32 units, - u32 timeout) + u16 timeout) { acpi_status status = AE_OK; struct semaphore *sem = (struct semaphore*)handle; @@ -739,7 +739,7 @@ * Wait Indefinitely: * ------------------ */ - case WAIT_FOREVER: + case ACPI_WAIT_FOREVER: ret = down_interruptible(sem); if (ret < 0) status = AE_ERROR; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/drivers/acpi/power.c linux.2.5.47-ac6/drivers/acpi/power.c --- linux.2.5.47/drivers/acpi/power.c 2002-10-31 15:05:00.000000000 +0000 +++ linux.2.5.47-ac6/drivers/acpi/power.c 2002-11-13 01:18:37.000000000 +0000 @@ -443,12 +443,6 @@ if (!device) return_VALUE(-EINVAL); - if (!acpi_power_dir) { - acpi_power_dir = proc_mkdir(ACPI_POWER_CLASS, acpi_root_dir); - if (!acpi_power_dir) - return_VALUE(-ENODEV); - } - if (!acpi_device_dir(device)) { acpi_device_dir(device) = proc_mkdir(acpi_device_bid(device), acpi_power_dir); @@ -478,9 +472,6 @@ { ACPI_FUNCTION_TRACE("acpi_power_remove_fs"); - if (!acpi_power_dir) - return_VALUE(-ENODEV); - if (acpi_device_dir(device)) remove_proc_entry(acpi_device_bid(device), acpi_power_dir); @@ -591,6 +582,10 @@ INIT_LIST_HEAD(&acpi_power_resource_list); + acpi_power_dir = proc_mkdir(ACPI_POWER_CLASS, acpi_root_dir); + if (!acpi_power_dir) + return_VALUE(-ENODEV); + result = acpi_bus_register_driver(&acpi_power_driver); if (result < 0) { remove_proc_entry(ACPI_POWER_CLASS, acpi_root_dir); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/drivers/acpi/processor.c linux.2.5.47-ac6/drivers/acpi/processor.c --- linux.2.5.47/drivers/acpi/processor.c 2002-11-05 13:54:43.000000000 +0000 +++ linux.2.5.47-ac6/drivers/acpi/processor.c 2002-11-13 01:18:37.000000000 +0000 @@ -2289,13 +2289,6 @@ ACPI_FUNCTION_TRACE("acpi_processor_add_fs"); - if (!acpi_processor_dir) { - acpi_processor_dir = proc_mkdir(ACPI_PROCESSOR_CLASS, - acpi_root_dir); - if (!acpi_processor_dir) - return_VALUE(-ENODEV); - } - if (!acpi_device_dir(device)) { acpi_device_dir(device) = proc_mkdir(acpi_device_bid(device), acpi_processor_dir); @@ -2378,9 +2371,6 @@ { ACPI_FUNCTION_TRACE("acpi_processor_remove_fs"); - if (!acpi_processor_dir) - return_VALUE(-ENODEV); - if (acpi_device_dir(device)) remove_proc_entry(acpi_device_bid(device), acpi_processor_dir); @@ -2640,9 +2630,15 @@ memset(&processors, 0, sizeof(processors)); memset(&errata, 0, sizeof(errata)); + acpi_processor_dir = proc_mkdir(ACPI_PROCESSOR_CLASS, acpi_root_dir); + if (!acpi_processor_dir) + return_VALUE(-ENODEV); + result = acpi_bus_register_driver(&acpi_processor_driver); - if (result < 0) + if (result < 0) { + remove_proc_entry(ACPI_PROCESSOR_CLASS, acpi_root_dir); return_VALUE(-ENODEV); + } return_VALUE(0); } @@ -2651,13 +2647,11 @@ static void __exit acpi_processor_exit (void) { - int result = 0; - ACPI_FUNCTION_TRACE("acpi_processor_exit"); - result = acpi_bus_unregister_driver(&acpi_processor_driver); - if (!result) - remove_proc_entry(ACPI_PROCESSOR_CLASS, acpi_root_dir); + acpi_bus_unregister_driver(&acpi_processor_driver); + + remove_proc_entry(ACPI_PROCESSOR_CLASS, acpi_root_dir); return_VOID; } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/drivers/acpi/scan.c linux.2.5.47-ac6/drivers/acpi/scan.c --- linux.2.5.47/drivers/acpi/scan.c 2002-11-05 13:54:43.000000000 +0000 +++ linux.2.5.47-ac6/drivers/acpi/scan.c 2002-11-13 01:18:37.000000000 +0000 @@ -258,6 +258,8 @@ return_VALUE(result); } + device->driver = driver; + /* * TBD - Configuration Management: Assign resources to device based * upon possible configuration and currently allocated resources. diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/drivers/acpi/tables/tbconvrt.c linux.2.5.47-ac6/drivers/acpi/tables/tbconvrt.c --- linux.2.5.47/drivers/acpi/tables/tbconvrt.c 2002-10-31 15:05:00.000000000 +0000 +++ linux.2.5.47-ac6/drivers/acpi/tables/tbconvrt.c 2002-11-13 01:18:37.000000000 +0000 @@ -1,7 +1,7 @@ /****************************************************************************** * * Module Name: tbconvrt - ACPI Table conversion utilities - * $Revision: 44 $ + * $Revision: 45 $ * *****************************************************************************/ @@ -36,11 +36,13 @@ * * FUNCTION: Acpi_tb_get_table_count * - * PARAMETERS: + * PARAMETERS: RSDP - Pointer to the RSDP + * RSDT - Pointer to the RSDT/XSDT * - * RETURN: + * RETURN: The number of tables pointed to by the RSDT or XSDT. * - * DESCRIPTION: Calculate the number of tables + * DESCRIPTION: Calculate the number of tables. Automatically handles either + * an RSDT or XSDT. * ******************************************************************************/ @@ -80,9 +82,9 @@ * * FUNCTION: Acpi_tb_convert_to_xsdt * - * PARAMETERS: + * PARAMETERS: Table_info - Info about the RSDT * - * RETURN: + * RETURN: Status * * DESCRIPTION: Convert an RSDT to an XSDT (internal common format) * @@ -311,13 +313,11 @@ * * RETURN: Status * - * DESCRIPTION: - * Converts a BIOS supplied ACPI 1.0 FADT to an intermediate - * ACPI 2.0 FADT. If the BIOS supplied a 2.0 FADT then it is simply - * copied to the intermediate FADT. The ACPI CA software uses this - * intermediate FADT. Thus a significant amount of special #ifdef - * type codeing is saved. This intermediate FADT will need to be - * freed at some point. + * DESCRIPTION: Converts a BIOS supplied ACPI 1.0 FADT to a local + * ACPI 2.0 FADT. If the BIOS supplied a 2.0 FADT then it is simply + * copied to the local FADT. The ACPI CA software uses this + * local FADT. Thus a significant amount of special #ifdef + * type codeing is saved. * ******************************************************************************/ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/drivers/acpi/tables/tbxfroot.c linux.2.5.47-ac6/drivers/acpi/tables/tbxfroot.c --- linux.2.5.47/drivers/acpi/tables/tbxfroot.c 2002-10-31 14:57:01.000000000 +0000 +++ linux.2.5.47-ac6/drivers/acpi/tables/tbxfroot.c 2002-11-13 01:18:37.000000000 +0000 @@ -1,7 +1,7 @@ /****************************************************************************** * * Module Name: tbxfroot - Find the root ACPI table (RSDT) - * $Revision: 64 $ + * $Revision: 65 $ * *****************************************************************************/ @@ -302,7 +302,8 @@ status = acpi_tb_find_rsdp (&table_info, flags); if (ACPI_FAILURE (status)) { - ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "RSDP structure not found\n")); + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "RSDP structure not found, %s Flags=%X\n", + acpi_format_exception (status), flags)); return_ACPI_STATUS (AE_NO_ACPI_TABLES); } @@ -406,6 +407,8 @@ status = acpi_os_map_memory ((u64) LO_RSDP_WINDOW_BASE, LO_RSDP_WINDOW_SIZE, (void **) &table_ptr); if (ACPI_FAILURE (status)) { + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Could not map memory at %X for length %X\n", + LO_RSDP_WINDOW_BASE, LO_RSDP_WINDOW_SIZE)); return_ACPI_STATUS (status); } @@ -428,6 +431,8 @@ status = acpi_os_map_memory ((u64) HI_RSDP_WINDOW_BASE, HI_RSDP_WINDOW_SIZE, (void **) &table_ptr); if (ACPI_FAILURE (status)) { + ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Could not map memory at %X for length %X\n", + HI_RSDP_WINDOW_BASE, HI_RSDP_WINDOW_SIZE)); return_ACPI_STATUS (status); } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/drivers/acpi/thermal.c linux.2.5.47-ac6/drivers/acpi/thermal.c --- linux.2.5.47/drivers/acpi/thermal.c 2002-10-31 14:57:01.000000000 +0000 +++ linux.2.5.47-ac6/drivers/acpi/thermal.c 2002-11-13 01:18:37.000000000 +0000 @@ -1060,13 +1060,6 @@ ACPI_FUNCTION_TRACE("acpi_thermal_add_fs"); - if (!acpi_thermal_dir) { - acpi_thermal_dir = proc_mkdir(ACPI_THERMAL_CLASS, - acpi_root_dir); - if (!acpi_thermal_dir) - return_VALUE(-ENODEV); - } - if (!acpi_device_dir(device)) { acpi_device_dir(device) = proc_mkdir(acpi_device_bid(device), acpi_thermal_dir); @@ -1147,9 +1140,6 @@ { ACPI_FUNCTION_TRACE("acpi_thermal_remove_fs"); - if (!acpi_thermal_dir) - return_VALUE(-ENODEV); - if (acpi_device_dir(device)) remove_proc_entry(acpi_device_bid(device), acpi_thermal_dir); @@ -1351,9 +1341,15 @@ ACPI_FUNCTION_TRACE("acpi_thermal_init"); + acpi_thermal_dir = proc_mkdir(ACPI_THERMAL_CLASS, acpi_root_dir); + if (!acpi_thermal_dir) + return_VALUE(-ENODEV); + result = acpi_bus_register_driver(&acpi_thermal_driver); - if (result < 0) + if (result < 0) { + remove_proc_entry(ACPI_THERMAL_CLASS, acpi_root_dir); return_VALUE(-ENODEV); + } return_VALUE(0); } @@ -1362,13 +1358,11 @@ static void __exit acpi_thermal_exit (void) { - int result = 0; - ACPI_FUNCTION_TRACE("acpi_thermal_exit"); - result = acpi_bus_unregister_driver(&acpi_thermal_driver); - if (!result) - remove_proc_entry(ACPI_THERMAL_CLASS, acpi_root_dir); + acpi_bus_unregister_driver(&acpi_thermal_driver); + + remove_proc_entry(ACPI_THERMAL_CLASS, acpi_root_dir); return_VOID; } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/drivers/acpi/utilities/utmisc.c linux.2.5.47-ac6/drivers/acpi/utilities/utmisc.c --- linux.2.5.47/drivers/acpi/utilities/utmisc.c 2002-10-31 15:05:00.000000000 +0000 +++ linux.2.5.47-ac6/drivers/acpi/utilities/utmisc.c 2002-11-13 01:18:37.000000000 +0000 @@ -1,7 +1,7 @@ /******************************************************************************* * * Module Name: utmisc - common utility procedures - * $Revision: 85 $ + * $Revision: 86 $ * ******************************************************************************/ @@ -685,7 +685,7 @@ this_thread_id, acpi_ut_get_mutex_name (mutex_id))); status = acpi_os_wait_semaphore (acpi_gbl_acpi_mutex_info[mutex_id].mutex, - 1, WAIT_FOREVER); + 1, ACPI_WAIT_FOREVER); if (ACPI_SUCCESS (status)) { ACPI_DEBUG_PRINT ((ACPI_DB_MUTEX, "Thread %X acquired Mutex [%s]\n", this_thread_id, acpi_ut_get_mutex_name (mutex_id))); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/drivers/atm/idt77252.c linux.2.5.47-ac6/drivers/atm/idt77252.c --- linux.2.5.47/drivers/atm/idt77252.c 2002-10-31 14:57:18.000000000 +0000 +++ linux.2.5.47-ac6/drivers/atm/idt77252.c 2002-11-13 15:21:49.000000000 +0000 @@ -2148,9 +2148,9 @@ est->interval = 2; /* XXX: make this configurable */ est->ewma_log = 2; /* XXX: make this configurable */ + init_timer(&est->timer); est->timer.data = (unsigned long)vc; est->timer.function = idt77252_est_timer; - init_timer(&est->timer); est->timer.expires = jiffies + ((HZ / 4) << est->interval); add_timer(&est->timer); @@ -3745,9 +3745,9 @@ spin_lock_init(&card->cmd_lock); spin_lock_init(&card->tst_lock); + init_timer(&card->tst_timer); card->tst_timer.data = (unsigned long)card; card->tst_timer.function = tst_timer; - init_timer(&card->tst_timer); /* Do the I/O remapping... */ card->membase = (unsigned long) ioremap(membase, 1024); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/drivers/block/cciss.c linux.2.5.47-ac6/drivers/block/cciss.c --- linux.2.5.47/drivers/block/cciss.c 2002-11-11 16:39:09.000000000 +0000 +++ linux.2.5.47-ac6/drivers/block/cciss.c 2002-11-11 16:51:32.000000000 +0000 @@ -88,6 +88,9 @@ /* How long to wait (in millesconds) for board to go into simple mode */ #define MAX_CONFIG_WAIT 1000 +/*define how many times we will try a command because of bus resets */ +#define MAX_CMD_RETRIES 3 + #define READ_AHEAD 128 #define NR_CMDS 384 /* #commands that can be outstanding */ #define MAX_CTLR 8 @@ -113,6 +116,9 @@ static inline void addQ(CommandList_struct **Qptr, CommandList_struct *c); static void start_io( ctlr_info_t *h); +static int sendcmd( __u8 cmd, int ctlr, void *buff, size_t size, + unsigned int use_unit_num, unsigned int log_unit, __u8 page_code, + unsigned char *scsi3addr); #ifdef CONFIG_PROC_FS static int cciss_proc_get_info(char *buffer, char **start, off_t offset, @@ -352,7 +358,7 @@ * but I'm already using way to many device nodes to claim another one * for "raw controller". */ - if (inode->i_bdev->bd_inode->i_size == 0) { + if (hba[ctlr]->drv[dsk].nr_blocks == 0) { if (minor(inode->i_rdev) != 0) return -ENXIO; if (!capable(CAP_SYS_ADMIN)) @@ -571,6 +577,24 @@ case CCISS_REVALIDVOLS: return( revalidate_allvol(inode->i_rdev)); + case CCISS_GETLUNINFO: { + LogvolInfo_struct luninfo; + struct gendisk *disk = hba[ctlr]->gendisk[dsk]; + drive_info_struct *drv = &hba[ctlr]->drv[dsk]; + int i; + + luninfo.LunID = drv->LunID; + luninfo.num_opens = drv->usage_count; + luninfo.num_parts = 0; + /* count partitions 1 to 15 with sizes > 0 */ + for(i=1; i part[i].nr_sects != 0) + luninfo.num_parts++; + if (copy_to_user((void *) arg, &luninfo, + sizeof(LogvolInfo_struct))) + return -EFAULT; + return(0); + } case CCISS_DEREGDISK: return( deregister_disk(ctlr,dsk)); @@ -808,6 +832,7 @@ /* zero out the disk size info */ h->drv[logvol].nr_blocks = 0; h->drv[logvol].block_size = 0; + h->drv[logvol].cylinders = 0; h->drv[logvol].LunID = 0; return(0); } @@ -918,6 +943,7 @@ c->SG[0].Len = size; c->SG[0].Ext = 0; // we are not chaining } +resend_cmd2: c->waiting = &wait; /* Put the request on the tail of the queue and send it */ @@ -929,10 +955,6 @@ wait_for_completion(&wait); - /* unlock the buffers from DMA */ - pci_unmap_single( h->pdev, (dma_addr_t) buff_dma_handle.val, - size, PCI_DMA_BIDIRECTIONAL); - if(c->err_info->CommandStatus != 0) { /* an error has occurred */ switch(c->err_info->CommandStatus) @@ -986,6 +1008,16 @@ case CMD_UNSOLICITED_ABORT: printk(KERN_WARNING "cciss: cmd %p aborted " "do to an unsolicited abort\n", c); + if (c->retry_count < MAX_CMD_RETRIES) { + printk(KERN_WARNING "retrying cmd\n"); + c->retry_count++; + /* erase the old error information */ + memset(c->err_info, 0, + sizeof(ErrorInfo_struct)); + return_status = IO_OK; + INIT_COMPLETION(wait); + goto resend_cmd2; + } return_status = IO_ERROR; @@ -997,10 +1029,80 @@ return_status = IO_ERROR; } } + /* unlock the buffers from DMA */ + pci_unmap_single( h->pdev, (dma_addr_t) buff_dma_handle.val, + size, PCI_DMA_BIDIRECTIONAL); cmd_free(h, c, 0); return(return_status); } +static void cciss_geometry_inquiry(int ctlr, int logvol, + int withirq, unsigned int total_size, + unsigned int block_size, InquiryData_struct *inq_buff, + drive_info_struct *drv) +{ + int return_code; + memset(inq_buff, 0, sizeof(InquiryData_struct)); + if (withirq) + return_code = sendcmd_withirq(CISS_INQUIRY, ctlr, + inq_buff, sizeof(*inq_buff), 1, logvol ,0xC1); + else + return_code = sendcmd(CISS_INQUIRY, ctlr, inq_buff, + sizeof(*inq_buff), 1, logvol ,0xC1, NULL); + if (return_code == IO_OK) { + if(inq_buff->data_byte[8] == 0xFF) { + printk(KERN_WARNING + "cciss: reading geometry failed, volume " + "does not support reading geometry\n"); + drv->block_size = block_size; + drv->nr_blocks = total_size; + drv->heads = 255; + drv->sectors = 32; // Sectors per track + drv->cylinders = total_size / 255 / 32; + } else { + drv->block_size = block_size; + drv->nr_blocks = total_size; + drv->heads = inq_buff->data_byte[6]; + drv->sectors = inq_buff->data_byte[7]; + drv->cylinders = (inq_buff->data_byte[4] & 0xff) << 8; + drv->cylinders += inq_buff->data_byte[5]; + } + } else { /* Get geometry failed */ + printk(KERN_WARNING "cciss: reading geometry failed, " + "continuing with default geometry\n"); + drv->block_size = block_size; + drv->nr_blocks = total_size; + drv->heads = 255; + drv->sectors = 32; // Sectors per track + drv->cylinders = total_size / 255 / 32; + } + printk(KERN_INFO " heads= %d, sectors= %d, cylinders= %d\n\n", + drv->heads, drv->sectors, drv->cylinders); +} +static void +cciss_read_capacity(int ctlr, int logvol, ReadCapdata_struct *buf, + int withirq, unsigned int *total_size, unsigned int *block_size) +{ + int return_code; + memset(buf, 0, sizeof(*buf)); + if (withirq) + return_code = sendcmd_withirq(CCISS_READ_CAPACITY, + ctlr, buf, sizeof(*buf), 1, logvol, 0 ); + else + return_code = sendcmd(CCISS_READ_CAPACITY, + ctlr, buf, sizeof(*buf), 1, logvol, 0, NULL ); + if (return_code == IO_OK) { + *total_size = be32_to_cpu(*((__u32 *) &buf->total_size[0]))+1; + *block_size = be32_to_cpu(*((__u32 *) &buf->block_size[0])); + } else { /* read capacity command failed */ + printk(KERN_WARNING "cciss: read capacity failed\n"); + *total_size = 0; + *block_size = BLOCK_SIZE; + } + printk(KERN_INFO " blocks= %d block_size= %d\n", + *total_size, *block_size); + return; +} static int register_new_disk(int ctlr) { struct gendisk *disk; @@ -1147,85 +1249,10 @@ /* there could be gaps in lun numbers, track hightest */ if(hba[ctlr]->highest_lun < lunid) hba[ctlr]->highest_lun = logvol; - - memset(size_buff, 0, sizeof(ReadCapdata_struct)); - return_code = sendcmd_withirq(CCISS_READ_CAPACITY, ctlr, size_buff, - sizeof( ReadCapdata_struct), 1, logvol, 0 ); - if (return_code == IO_OK) - { - total_size = (0xff & - (unsigned int)(size_buff->total_size[0])) << 24; - total_size |= (0xff & - (unsigned int)(size_buff->total_size[1])) << 16; - total_size |= (0xff & - (unsigned int)(size_buff->total_size[2])) << 8; - total_size |= (0xff & (unsigned int) - (size_buff->total_size[3])); - total_size++; // command returns highest block address - - block_size = (0xff & - (unsigned int)(size_buff->block_size[0])) << 24; - block_size |= (0xff & - (unsigned int)(size_buff->block_size[1])) << 16; - block_size |= (0xff & - (unsigned int)(size_buff->block_size[2])) << 8; - block_size |= (0xff & - (unsigned int)(size_buff->block_size[3])); - } else /* read capacity command failed */ - { - printk(KERN_WARNING "cciss: read capacity failed\n"); - total_size = 0; - block_size = BLOCK_SIZE; - } - printk(KERN_INFO " blocks= %u block_size= %d\n", - total_size, block_size); - /* Execute the command to read the disk geometry */ - memset(inq_buff, 0, sizeof(InquiryData_struct)); - return_code = sendcmd_withirq(CISS_INQUIRY, ctlr, inq_buff, - sizeof(InquiryData_struct), 1, logvol ,0xC1 ); - if (return_code == IO_OK) - { - if(inq_buff->data_byte[8] == 0xFF) - { - printk(KERN_WARNING "cciss: reading geometry failed, " - "volume does not support reading geometry\n"); - - hba[ctlr]->drv[logvol].block_size = block_size; - hba[ctlr]->drv[logvol].nr_blocks = total_size; - hba[ctlr]->drv[logvol].heads = 255; - hba[ctlr]->drv[logvol].sectors = 32; // Sectors per track - hba[ctlr]->drv[logvol].cylinders = total_size / 255 / 32; - } else - { - - hba[ctlr]->drv[logvol].block_size = block_size; - hba[ctlr]->drv[logvol].nr_blocks = total_size; - hba[ctlr]->drv[logvol].heads = - inq_buff->data_byte[6]; - hba[ctlr]->drv[logvol].sectors = - inq_buff->data_byte[7]; - hba[ctlr]->drv[logvol].cylinders = - (inq_buff->data_byte[4] & 0xff) << 8; - hba[ctlr]->drv[logvol].cylinders += - inq_buff->data_byte[5]; - } - } - else /* Get geometry failed */ - { - - printk(KERN_WARNING "cciss: reading geometry failed, " - "continuing with default geometry\n"); - - hba[ctlr]->drv[logvol].block_size = block_size; - hba[ctlr]->drv[logvol].nr_blocks = total_size; - hba[ctlr]->drv[logvol].heads = 255; - hba[ctlr]->drv[logvol].sectors = 32; // Sectors per track - hba[ctlr]->drv[logvol].cylinders = total_size / 255 / 32; - } - printk(KERN_INFO " heads= %d, sectors= %d, cylinders= %d\n\n", - hba[ctlr]->drv[logvol].heads, - hba[ctlr]->drv[logvol].sectors, - hba[ctlr]->drv[logvol].cylinders); + cciss_read_capacity(ctlr, logvol, size_buff, 1, + &total_size, &block_size); + cciss_geometry_inquiry(ctlr, logvol, 1, total_size, block_size, + inq_buff, &hba[ctlr]->drv[logvol]); hba[ctlr]->drv[logvol].usage_count = 0; ++hba[ctlr]->num_luns; /* setup partitions per disk */ @@ -1241,24 +1268,25 @@ /* * Wait polling for a command to complete. * The memory mapped FIFO is polled for the completion. - * Used only at init time, interrupts disabled. + * Used only at init time, interrupts from the HBA are disabled. */ static unsigned long pollcomplete(int ctlr) { - unsigned long done; - int i; + unsigned long done; + int i; - /* Wait (up to 2 seconds) for a command to complete */ + /* Wait (up to 20 seconds) for a command to complete */ - for (i = 200000; i > 0; i--) { - done = hba[ctlr]->access.command_completed(hba[ctlr]); - if (done == FIFO_EMPTY) { - udelay(10); /* a short fixed delay */ - } else - return (done); - } - /* Invalid address to tell caller we ran out of time */ - return 1; + for (i = 20 * HZ; i > 0; i--) { + done = hba[ctlr]->access.command_completed(hba[ctlr]); + if (done == FIFO_EMPTY) { + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout(1); + } else + return (done); + } + /* Invalid address to tell caller we ran out of time */ + return 1; } /* * Send a command to the controller, and wait for it to complete. @@ -1281,6 +1309,7 @@ unsigned long complete; ctlr_info_t *info_p= hba[ctlr]; u64bit buff_dma_handle; + int status = IO_OK; c = cmd_alloc(info_p, 1); if (c == NULL) @@ -1394,6 +1423,7 @@ c->SG[0].Len = size; c->SG[0].Ext = 0; // we are not chaining } +resend_cmd1: /* * Disable interrupt */ @@ -1426,9 +1456,6 @@ printk(KERN_DEBUG "cciss: command completed\n"); #endif /* CCISS_DEBUG */ - /* unlock the data buffer from DMA */ - pci_unmap_single(info_p->pdev, (dma_addr_t) buff_dma_handle.val, - size, PCI_DMA_BIDIRECTIONAL); if (complete != 1) { if ( (complete & CISS_ERROR_BIT) && (complete & ~CISS_ERROR_BIT) == c->busaddr) @@ -1448,6 +1475,27 @@ complete = c->busaddr; } else { + if (c->err_info->CommandStatus == + CMD_UNSOLICITED_ABORT) { + printk(KERN_WARNING "cciss: " + "cmd %p aborted do " + "to an unsolicited abort \n", c); + if (c->retry_count < MAX_CMD_RETRIES) { + printk(KERN_WARNING + "retrying cmd\n"); + c->retry_count++; + /* erase the old error */ + /* information */ + memset(c->err_info, 0, + sizeof(ErrorInfo_struct)); + goto resend_cmd1; + } else { + printk(KERN_WARNING + "retried to many times\n"); + status = IO_ERROR; + goto cleanup1; + } + } printk(KERN_WARNING "ciss ciss%d: sendcmd" " Error %x \n", ctlr, c->err_info->CommandStatus); @@ -1457,27 +1505,31 @@ c->err_info->MoreErrInfo.Invalid_Cmd.offense_size, c->err_info->MoreErrInfo.Invalid_Cmd.offense_num, c->err_info->MoreErrInfo.Invalid_Cmd.offense_value); - cmd_free(info_p,c, 1); - return(IO_ERROR); + status = IO_ERROR; + goto cleanup1; } } if (complete != c->busaddr) { printk( KERN_WARNING "cciss cciss%d: SendCmd " "Invalid command list address returned! (%lx)\n", ctlr, complete); - cmd_free(info_p, c, 1); - return (IO_ERROR); + status = IO_ERROR; + goto cleanup1; } } else { printk( KERN_WARNING "cciss cciss%d: SendCmd Timeout out, " "No command list address returned!\n", ctlr); - cmd_free(info_p, c, 1); - return (IO_ERROR); + status = IO_ERROR; } + +cleanup1: + /* unlock the data buffer from DMA */ + pci_unmap_single(info_p->pdev, (dma_addr_t) buff_dma_handle.val, + size, PCI_DMA_BIDIRECTIONAL); cmd_free(info_p, c, 1); - return (IO_OK); + return (status); } /* * Map (physical) PCI mem into (virtual) kernel space @@ -1561,27 +1613,35 @@ } } +/* Assumes that CCISS_LOCK(h->ctlr) is held. */ +/* Zeros out the error record and then resends the command back */ +/* to the controller */ +static inline void resend_cciss_cmd( ctlr_info_t *h, CommandList_struct *c) +{ + /* erase the old error information */ + memset(c->err_info, 0, sizeof(ErrorInfo_struct)); + + /* add it to software queue and then send it to the controller */ + addQ(&(h->reqQ),c); + h->Qdepth++; + if(h->Qdepth > h->maxQsinceinit) + h->maxQsinceinit = h->Qdepth; + + start_io(h); +} /* checks the status of the job and calls complete buffers to mark all * buffers for the completed job. */ -static inline void complete_command( CommandList_struct *cmd, int timeout) +static inline void complete_command( ctlr_info_t *h, CommandList_struct *cmd, + int timeout) { int status = 1; int i; + int retry_cmd = 0; u64bit temp64; if (timeout) status = 0; - /* unmap the DMA mapping for all the scatter gather elements */ - for(i=0; iHeader.SGList; i++) - { - temp64.val32.lower = cmd->SG[i].Addr.lower; - temp64.val32.upper = cmd->SG[i].Addr.upper; - pci_unmap_page(hba[cmd->ctlr]->pdev, - temp64.val, cmd->SG[i].Len, - (cmd->Request.Type.Direction == XFER_READ) ? - PCI_DMA_FROMDEVICE : PCI_DMA_TODEVICE); - } if(cmd->err_info->CommandStatus != 0) { /* an error has occurred */ @@ -1655,8 +1715,20 @@ status=0; break; case CMD_UNSOLICITED_ABORT: - printk(KERN_WARNING "cciss: cmd %p aborted " - "do to an unsolicited abort\n", cmd); + printk(KERN_WARNING "cciss: cmd %p aborted do " + "to an unsolicited abort \n", + cmd); + if (cmd->retry_count < MAX_CMD_RETRIES) + { + retry_cmd=1; + printk(KERN_WARNING + "retrying cmd\n"); + cmd->retry_count++; + } else + { + printk(KERN_WARNING + "retried to many times\n"); + } status=0; break; case CMD_TIMEOUT: @@ -1671,7 +1743,21 @@ status=0; } } - + /* We need to return this command */ + if(retry_cmd) { + resend_cciss_cmd(h,cmd); + return; + } + /* command did not need to be retried */ + /* unmap the DMA mapping for all the scatter gather elements */ + for(i=0; iHeader.SGList; i++) { + temp64.val32.lower = cmd->SG[i].Addr.lower; + temp64.val32.upper = cmd->SG[i].Addr.upper; + pci_unmap_page(hba[cmd->ctlr]->pdev, + temp64.val, cmd->SG[i].Len, + (cmd->Request.Type.Direction == XFER_READ) ? + PCI_DMA_FROMDEVICE : PCI_DMA_TODEVICE); + } complete_buffers(cmd->rq->bio, status); #ifdef CCISS_DEBUG @@ -1679,6 +1765,7 @@ #endif /* CCISS_DEBUG */ end_that_request_last(cmd->rq); + cmd_free(h,cmd,1); } /* @@ -1825,8 +1912,7 @@ if (c->busaddr == a) { removeQ(&h->cmpQ, c); if (c->cmd_type == CMD_RWREQ) { - complete_command(c, 0); - cmd_free(h, c, 1); + complete_command(h, c, 0); } else if (c->cmd_type == CMD_IOCTL_PEND) { complete(c->waiting); } @@ -2173,83 +2259,10 @@ ld_buff->LUN[i][0], ld_buff->LUN[i][1],ld_buff->LUN[i][2], ld_buff->LUN[i][3], hba[cntl_num]->drv[i].LunID); #endif /* CCISS_DEBUG */ - - memset(size_buff, 0, sizeof(ReadCapdata_struct)); - return_code = sendcmd(CCISS_READ_CAPACITY, cntl_num, size_buff, - sizeof( ReadCapdata_struct), 1, i, 0, NULL ); - if (return_code == IO_OK) - { - total_size = (0xff & - (unsigned int)(size_buff->total_size[0])) << 24; - total_size |= (0xff & - (unsigned int)(size_buff->total_size[1])) << 16; - total_size |= (0xff & - (unsigned int)(size_buff->total_size[2])) << 8; - total_size |= (0xff & (unsigned int) - (size_buff->total_size[3])); - total_size++; // command returns highest block address - - block_size = (0xff & - (unsigned int)(size_buff->block_size[0])) << 24; - block_size |= (0xff & - (unsigned int)(size_buff->block_size[1])) << 16; - block_size |= (0xff & - (unsigned int)(size_buff->block_size[2])) << 8; - block_size |= (0xff & - (unsigned int)(size_buff->block_size[3])); - } else /* read capacity command failed */ - { - printk(KERN_WARNING "cciss: read capacity failed\n"); - total_size = 0; - block_size = BLOCK_SIZE; - } - printk(KERN_INFO " blocks= %d block_size= %d\n", - total_size, block_size); - - /* Execute the command to read the disk geometry */ - memset(inq_buff, 0, sizeof(InquiryData_struct)); - return_code = sendcmd(CISS_INQUIRY, cntl_num, inq_buff, - sizeof(InquiryData_struct), 1, i ,0xC1, NULL ); - if (return_code == IO_OK) - { - if(inq_buff->data_byte[8] == 0xFF) - { - printk(KERN_WARNING "cciss: reading geometry failed, volume does not support reading geometry\n"); - - hba[cntl_num]->drv[i].block_size = block_size; - hba[cntl_num]->drv[i].nr_blocks = total_size; - hba[cntl_num]->drv[i].heads = 255; - hba[cntl_num]->drv[i].sectors = 32; // Sectors per track - hba[cntl_num]->drv[i].cylinders = total_size / 255 / 32; } else - { - - hba[cntl_num]->drv[i].block_size = block_size; - hba[cntl_num]->drv[i].nr_blocks = total_size; - hba[cntl_num]->drv[i].heads = - inq_buff->data_byte[6]; - hba[cntl_num]->drv[i].sectors = - inq_buff->data_byte[7]; - hba[cntl_num]->drv[i].cylinders = - (inq_buff->data_byte[4] & 0xff) << 8; - hba[cntl_num]->drv[i].cylinders += - inq_buff->data_byte[5]; - } - } - else /* Get geometry failed */ - { - printk(KERN_WARNING "cciss: reading geometry failed, continuing with default geometry\n"); - - hba[cntl_num]->drv[i].block_size = block_size; - hba[cntl_num]->drv[i].nr_blocks = total_size; - hba[cntl_num]->drv[i].heads = 255; - hba[cntl_num]->drv[i].sectors = 32; // Sectors per track - hba[cntl_num]->drv[i].cylinders = total_size / 255 / 32; - } - printk(KERN_INFO " heads= %d, sectors= %d, cylinders= %d\n\n", - hba[cntl_num]->drv[i].heads, - hba[cntl_num]->drv[i].sectors, - hba[cntl_num]->drv[i].cylinders); - + cciss_read_capacity(cntl_num, i, size_buff, 0, + &total_size, &block_size); + cciss_geometry_inquiry(cntl_num, i, 0, total_size, block_size, + inq_buff, &hba[cntl_num]->drv[i]); } kfree(ld_buff); kfree(size_buff); @@ -2407,7 +2420,7 @@ cciss_getgeometry(i); - cciss_find_non_disk_devices(i); /* find our tape drives, if any */ + cciss_scsi_setup(i); /* Turn the interrupts on so we can service requests */ hba[i]->access.set_intr_mask(hba[i], CCISS_INTR_ON); @@ -2445,9 +2458,6 @@ set_capacity(disk, drv->nr_blocks); add_disk(disk); } - - cciss_register_scsi(i, 1); /* hook ourself into SCSI subsystem */ - return(1); } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/drivers/block/cciss_cmd.h linux.2.5.47-ac6/drivers/block/cciss_cmd.h --- linux.2.5.47/drivers/block/cciss_cmd.h 2002-10-31 14:57:17.000000000 +0000 +++ linux.2.5.47-ac6/drivers/block/cciss_cmd.h 2002-10-31 15:05:41.000000000 +0000 @@ -240,6 +240,7 @@ struct _CommandList_struct *next; struct request * rq; struct completion *waiting; + int retry_count; #ifdef CONFIG_CISS_SCSI_TAPE void * scsi_cmd; #endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/drivers/block/cciss_scsi.c linux.2.5.47-ac6/drivers/block/cciss_scsi.c --- linux.2.5.47/drivers/block/cciss_scsi.c 2002-10-31 15:05:00.000000000 +0000 +++ linux.2.5.47-ac6/drivers/block/cciss_scsi.c 2002-10-31 16:48:05.000000000 +0000 @@ -89,8 +89,10 @@ working even with the SCSI system. It's so scsi_unregister_host will differentiate the controllers. When register_scsi_module is called, each host template is - customized (name change) in cciss_register_scsi() - (that's called from cciss.c:cciss_init_one()) */ + customized (name change) in cciss_register_scsi() (that's + called from cciss_engage_scsi, called from + cciss.c:cciss_proc_write(), on "engage scsi" being received + from user space.) */ static Scsi_Host_Template driver_template[MAX_CTLR] = @@ -199,14 +201,12 @@ } static int -scsi_cmd_stack_setup(int ctlr) +scsi_cmd_stack_setup(int ctlr, struct cciss_scsi_adapter_data_t *sa) { int i; - struct cciss_scsi_adapter_data_t *sa; struct cciss_scsi_cmd_stack_t *stk; size_t size; - sa = (struct cciss_scsi_adapter_data_t *) hba[ctlr]->scsi_ctlr; stk = &sa->cmd_stack; size = sizeof(struct cciss_scsi_cmd_stack_elem_t) * CMD_STACK_SIZE; @@ -535,126 +535,24 @@ return -1; } - static void -cciss_find_non_disk_devices(int cntl_num) +cciss_scsi_setup(int cntl_num) { - ReportLunData_struct *ld_buff; - InquiryData_struct *inq_buff; - int return_code; - int i; - int listlength = 0; - int num_luns; - unsigned char scsi3addr[8]; - unsigned long flags; - int reportlunsize = sizeof(*ld_buff) + CISS_MAX_PHYS_LUN * 8; - - hba[cntl_num]->scsi_ctlr = (void *) - kmalloc(sizeof(struct cciss_scsi_adapter_data_t), - GFP_KERNEL); - if (hba[cntl_num]->scsi_ctlr == NULL) - return; + struct cciss_scsi_adapter_data_t * shba; - ((struct cciss_scsi_adapter_data_t *) - hba[cntl_num]->scsi_ctlr)->scsi_host = NULL; - ((struct cciss_scsi_adapter_data_t *) - hba[cntl_num]->scsi_ctlr)->lock = SPIN_LOCK_UNLOCKED; - ((struct cciss_scsi_adapter_data_t *) - hba[cntl_num]->scsi_ctlr)->registered = 0; - - if (scsi_cmd_stack_setup(cntl_num) != 0) { - printk("Trouble, returned non-zero!\n"); - return; - } - - ld_buff = kmalloc(reportlunsize, GFP_KERNEL); - if (ld_buff == NULL) { - printk(KERN_ERR "cciss: out of memory\n"); - return; - } - memset(ld_buff, 0, sizeof(ReportLunData_struct)); - inq_buff = kmalloc(sizeof( InquiryData_struct), GFP_KERNEL); - if (inq_buff == NULL) { - printk(KERN_ERR "cciss: out of memory\n"); - kfree(ld_buff); - return; - } - - /* Get the physical luns */ - return_code = sendcmd(CISS_REPORT_PHYS, cntl_num, ld_buff, - reportlunsize, 0, 0, 0, NULL ); - - if( return_code == IO_OK) { - unsigned char *c = &ld_buff->LUNListLength[0]; - listlength = (c[0] << 24) | (c[1] << 16) | (c[2] << 8) | c[3]; - } - else { /* getting report of physical luns failed */ - printk(KERN_WARNING "cciss: report physical luns" - " command failed\n"); - listlength = 0; - } - - CPQ_TAPE_LOCK(cntl_num, flags); ccissscsi[cntl_num].ndevices = 0; - num_luns = listlength / 8; // 8 bytes pre entry - /* printk("Found %d LUNs\n", num_luns); */ - - if (num_luns > CISS_MAX_PHYS_LUN) - { - printk(KERN_WARNING - "cciss: Maximum physical LUNs (%d) exceeded. " - "%d LUNs ignored.\n", CISS_MAX_PHYS_LUN, - num_luns - CISS_MAX_PHYS_LUN); - num_luns = CISS_MAX_PHYS_LUN; - } - - for(i=0; iLUN[i], 8); /* ugly... */ - return_code = sendcmd(CISS_INQUIRY, cntl_num, inq_buff, - sizeof(InquiryData_struct), 2, 0 ,0, scsi3addr ); - if (return_code == IO_OK) { - if(inq_buff->data_byte[8] == 0xFF) - { - printk(KERN_WARNING "cciss: inquiry failed\n"); - } else { - int devtype; - - /* printk("Inquiry...\n"); - print_bytes((unsigned char *) inq_buff, 36, 1, 1); */ - devtype = (inq_buff->data_byte[0] & 0x1f); - - switch (devtype) - { - case 0x01: /* sequential access, (tape) */ - case 0x08: /* medium changer */ - /* this is the only kind of dev */ - /* we want to expose here. */ - if (cciss_scsi_add_entry(cntl_num, -1, - (unsigned char *) ld_buff->LUN[i], - devtype) != 0) - i=num_luns; // leave loop - break; - default: - break; - } - - } - } - else printk("cciss: inquiry failed.\n"); + shba = (struct cciss_scsi_adapter_data_t *) + kmalloc(sizeof(*shba), GFP_KERNEL); + if (shba == NULL) + return; + shba->scsi_host = NULL; + shba->lock = SPIN_LOCK_UNLOCKED; + shba->registered = 0; + if (scsi_cmd_stack_setup(cntl_num, shba) != 0) { + kfree(shba); + shba = NULL; } -#if 0 - for (i=0;iscsi_ctlr = (void *) shba; return; } @@ -913,7 +811,7 @@ memset(cp->Request.CDB, 0, sizeof(cp->Request.CDB)); memcpy(cp->Request.CDB, cdb, cdblen); - cp->Request.Timeout = 1000; // guarantee completion. + cp->Request.Timeout = 0; cp->Request.CDBLen = cdblen; cp->Request.Type.Type = TYPE_CMD; cp->Request.Type.Attribute = ATTR_SIMPLE; @@ -1262,7 +1160,6 @@ int buflen, datalen; struct Scsi_Host *sh; - int found; ctlr_info_t *ci; int cntl_num; @@ -1428,7 +1325,7 @@ // Fill in the request block... - cp->Request.Timeout = 1000; // guarantee completion + cp->Request.Timeout = 0; memset(cp->Request.CDB, 0, sizeof(cp->Request.CDB)); if (cmd->cmd_len > sizeof(cp->Request.CDB)) BUG(); cp->Request.CDBLen = cmd->cmd_len; @@ -1531,7 +1428,7 @@ } static int -cciss_register_scsi(int ctlr, int this_is_init_time) +cciss_register_scsi(int ctlr) { unsigned long flags; @@ -1541,15 +1438,10 @@ driver_template[ctlr].module = THIS_MODULE;; /* Since this is really a block driver, the SCSI core may not be - initialized yet, in which case, calling scsi_register_host - would hang. instead, we will do it later, via /proc filesystem + initialized at init time, in which case, calling scsi_register_host + would hang. Instead, we do it later, via /proc filesystem and rc scripts, when we know SCSI core is good to go. */ - if (this_is_init_time) { - CPQ_TAPE_UNLOCK(ctlr, flags); - return 0; - } - /* Only register if SCSI devices are detected. */ if (ccissscsi[ctlr].ndevices != 0) { ((struct cciss_scsi_adapter_data_t *) @@ -1583,7 +1475,7 @@ } spin_unlock_irqrestore(CCISS_LOCK(ctlr), flags); cciss_update_non_disk_devices(ctlr, -1); - cciss_register_scsi(ctlr, 0); + cciss_register_scsi(ctlr); return 0; } @@ -1607,9 +1499,9 @@ /* If no tape support, then these become defined out of existence */ -#define cciss_find_non_disk_devices(cntl_num) +#define cciss_scsi_setup(cntl_num) #define cciss_unregister_scsi(ctlr) -#define cciss_register_scsi(ctlr, this_is_init_time) +#define cciss_register_scsi(ctlr) #define cciss_proc_tape_report(ctlr, buffer, pos, len) #endif /* CONFIG_CISS_SCSI_TAPE */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/drivers/block/DAC960.c linux.2.5.47-ac6/drivers/block/DAC960.c --- linux.2.5.47/drivers/block/DAC960.c 2002-11-05 13:54:43.000000000 +0000 +++ linux.2.5.47-ac6/drivers/block/DAC960.c 2002-11-15 15:29:02.000000000 +0000 @@ -19,8 +19,8 @@ */ -#define DAC960_DriverVersion "2.4.11" -#define DAC960_DriverDate "11 October 2001" +#define DAC960_DriverVersion "2.5.47" +#define DAC960_DriverDate "14 November 2002" #include @@ -56,16 +56,6 @@ static int DAC960_ControllerCount = 0; - -/* - DAC960_ActiveControllerCount is the number of active DAC960 Controllers - detected. -*/ - -static int - DAC960_ActiveControllerCount = 0; - - /* DAC960_Controllers is an array of pointers to the DAC960 Controller structures. @@ -82,11 +72,11 @@ */ static struct block_device_operations DAC960_BlockDeviceOperations = { - .owner = THIS_MODULE, - .open = DAC960_Open, - .release = DAC960_Release, - .ioctl = DAC960_IOCTL, - .revalidate_disk= DAC960_revalidate, + .owner =THIS_MODULE, + .open =DAC960_Open, + .release =DAC960_Release, + .ioctl =DAC960_IOCTL, + .revalidate_disk=DAC960_revalidate, }; @@ -99,14 +89,6 @@ /* - DAC960_NotifierBlock is the Notifier Block structure for DAC960 Driver. -*/ - -static NotifierBlock_T - DAC960_NotifierBlock = { DAC960_Notifier, NULL, 0 }; - - -/* DAC960_AnnounceDriver announces the Driver Version and Date, Author's Name, Copyright Notice, and Electronic Mail Address. */ @@ -144,6 +126,54 @@ return false; } +/* + init_dma_loaf() and slice_dma_loaf() are helper functions for + aggregating the dma-mapped memory for a well-known collection of + data structures that are of different lengths. + + These routines don't guarantee any alignment. The caller must + include any space needed for alignment in the sizes of the structures + that are passed in. + */ + +static boolean init_dma_loaf(struct pci_dev *dev, struct dma_loaf *loaf, + size_t len) +{ + void *cpu_addr; + dma_addr_t dma_handle; + + cpu_addr = pci_alloc_consistent(dev, len, &dma_handle); + if (cpu_addr == NULL) + return false; + + loaf->cpu_free = loaf->cpu_base = cpu_addr; + loaf->dma_free =loaf->dma_base = dma_handle; + loaf->length = len; + memset(cpu_addr, 0, len); + return true; +} + +static void *slice_dma_loaf(struct dma_loaf *loaf, size_t len, + dma_addr_t *dma_handle) +{ + void *cpu_end = loaf->cpu_free + len; + void *cpu_addr = loaf->cpu_free; + + if (cpu_end > loaf->cpu_base + loaf->length) + BUG(); + *dma_handle = loaf->dma_free; + loaf->cpu_free = cpu_end; + loaf->dma_free += len; + return cpu_addr; +} + +static void free_dma_loaf(struct pci_dev *dev, struct dma_loaf *loaf_handle) +{ + if (loaf_handle->cpu_base != NULL) + pci_free_consistent(dev, loaf_handle->length, + loaf_handle->cpu_base, loaf_handle->dma_base); +} + /* DAC960_CreateAuxiliaryStructures allocates and initializes the auxiliary @@ -156,15 +186,42 @@ int CommandAllocationLength, CommandAllocationGroupSize; int CommandsRemaining = 0, CommandIdentifier, CommandGroupByteCount; void *AllocationPointer = NULL; + void *ScatterGatherCPU = NULL; + dma_addr_t ScatterGatherDMA; + struct pci_pool *ScatterGatherPool; + void *RequestSenseCPU = NULL; + dma_addr_t RequestSenseDMA; + struct pci_pool *RequestSensePool = NULL; + if (Controller->FirmwareType == DAC960_V1_Controller) { CommandAllocationLength = offsetof(DAC960_Command_T, V1.EndMarker); CommandAllocationGroupSize = DAC960_V1_CommandAllocationGroupSize; + ScatterGatherPool = pci_pool_create("DAC960_V1_ScatterGather", + Controller->PCIDevice, + DAC960_V1_ScatterGatherLimit * sizeof(DAC960_V1_ScatterGatherSegment_T), + sizeof(DAC960_V1_ScatterGatherSegment_T), 0); + if (ScatterGatherPool == NULL) + return DAC960_Failure(Controller, + "AUXILIARY STRUCTURE CREATION (SG)"); + Controller->ScatterGatherPool = ScatterGatherPool; } else { CommandAllocationLength = offsetof(DAC960_Command_T, V2.EndMarker); CommandAllocationGroupSize = DAC960_V2_CommandAllocationGroupSize; + ScatterGatherPool = pci_pool_create("DAC960_V2_ScatterGather", + Controller->PCIDevice, + DAC960_V2_ScatterGatherLimit * sizeof(DAC960_V2_ScatterGatherSegment_T), + sizeof(DAC960_V2_ScatterGatherSegment_T), 0); + RequestSensePool = pci_pool_create("DAC960_V2_RequestSense", + Controller->PCIDevice, sizeof(DAC960_SCSI_RequestSense_T), + sizeof(int), 0); + if (ScatterGatherPool == NULL || RequestSensePool == NULL) + return DAC960_Failure(Controller, + "AUXILIARY STRUCTURE CREATION (SG)"); + Controller->ScatterGatherPool = ScatterGatherPool; + Controller->V2.RequestSensePool = RequestSensePool; } Controller->CommandAllocationGroupSize = CommandAllocationGroupSize; Controller->FreeCommands = NULL; @@ -176,16 +233,17 @@ if (--CommandsRemaining <= 0) { CommandsRemaining = - Controller->DriverQueueDepth - CommandIdentifier + 1; + Controller->DriverQueueDepth - CommandIdentifier + 1; if (CommandsRemaining > CommandAllocationGroupSize) - CommandsRemaining = CommandAllocationGroupSize; + CommandsRemaining = CommandAllocationGroupSize; CommandGroupByteCount = - CommandsRemaining * CommandAllocationLength; + CommandsRemaining * CommandAllocationLength; AllocationPointer = kmalloc(CommandGroupByteCount, GFP_ATOMIC); if (AllocationPointer == NULL) - return DAC960_Failure(Controller, "AUXILIARY STRUCTURE CREATION"); + return DAC960_Failure(Controller, + "AUXILIARY STRUCTURE CREATION"); memset(AllocationPointer, 0, CommandGroupByteCount); - } + } Command = (DAC960_Command_T *) AllocationPointer; AllocationPointer += CommandAllocationLength; Command->CommandIdentifier = CommandIdentifier; @@ -193,6 +251,33 @@ Command->Next = Controller->FreeCommands; Controller->FreeCommands = Command; Controller->Commands[CommandIdentifier-1] = Command; + ScatterGatherCPU = pci_pool_alloc(ScatterGatherPool, SLAB_ATOMIC, + &ScatterGatherDMA); + if (ScatterGatherCPU == NULL) + return DAC960_Failure(Controller, "AUXILIARY STRUCTURE CREATION"); + + if (RequestSensePool != NULL) { + RequestSenseCPU = pci_pool_alloc(RequestSensePool, SLAB_ATOMIC, + &RequestSenseDMA); + if (RequestSenseCPU == NULL) { + pci_pool_free(ScatterGatherPool, ScatterGatherCPU, + ScatterGatherDMA); + return DAC960_Failure(Controller, + "AUXILIARY STRUCTURE CREATION"); + } + } + if (Controller->FirmwareType == DAC960_V1_Controller) { + Command->V1.ScatterGatherList = + (DAC960_V1_ScatterGatherSegment_T *)ScatterGatherCPU; + Command->V1.ScatterGatherListDMA = ScatterGatherDMA; + } else { + Command->V2.ScatterGatherList = + (DAC960_V2_ScatterGatherSegment_T *)ScatterGatherCPU; + Command->V2.ScatterGatherListDMA = ScatterGatherDMA; + Command->V2.RequestSense = + (DAC960_SCSI_RequestSense_T *)RequestSenseCPU; + Command->V2.RequestSenseDMA = RequestSenseDMA; + } } return true; } @@ -206,29 +291,80 @@ static void DAC960_DestroyAuxiliaryStructures(DAC960_Controller_T *Controller) { int i; + struct pci_pool *ScatterGatherPool = Controller->ScatterGatherPool; + struct pci_pool *RequestSensePool = NULL; + void *ScatterGatherCPU; + dma_addr_t ScatterGatherDMA; + void *RequestSenseCPU; + dma_addr_t RequestSenseDMA; + DAC960_Command_T *CommandGroup = NULL; + + + if (Controller->FirmwareType == DAC960_V2_Controller) + RequestSensePool = Controller->V2.RequestSensePool; + Controller->FreeCommands = NULL; for (i = 0; i < Controller->DriverQueueDepth; i++) { DAC960_Command_T *Command = Controller->Commands[i]; - if (Command != NULL && - (Command->CommandIdentifier - % Controller->CommandAllocationGroupSize) == 1) - kfree(Command); + + if (Command == NULL) + continue; + + if (Controller->FirmwareType == DAC960_V1_Controller) { + ScatterGatherCPU = (void *)Command->V1.ScatterGatherList; + ScatterGatherDMA = Command->V1.ScatterGatherListDMA; + RequestSenseCPU = NULL; + RequestSenseDMA = (dma_addr_t)0; + } else { + ScatterGatherCPU = (void *)Command->V2.ScatterGatherList; + ScatterGatherDMA = Command->V2.ScatterGatherListDMA; + RequestSenseCPU = (void *)Command->V2.RequestSense; + RequestSenseDMA = Command->V2.RequestSenseDMA; + } + if (ScatterGatherCPU != NULL) + pci_pool_free(ScatterGatherPool, ScatterGatherCPU, ScatterGatherDMA); + if (RequestSenseCPU != NULL) + pci_pool_free(RequestSensePool, RequestSenseCPU, RequestSenseDMA); + + if ((Command->CommandIdentifier + % Controller->CommandAllocationGroupSize) == 1) { + /* + * We can't free the group of commands until all of the + * request sense and scatter gather dma structures are free. + * Remember the beginning of the group, but don't free it + * until we've reached the beginning of the next group. + */ + if (CommandGroup != NULL) + kfree(CommandGroup); + CommandGroup = Command; + } Controller->Commands[i] = NULL; } + if (CommandGroup != NULL) + kfree(CommandGroup); + if (Controller->CombinedStatusBuffer != NULL) { kfree(Controller->CombinedStatusBuffer); Controller->CombinedStatusBuffer = NULL; Controller->CurrentStatusBuffer = NULL; } + + if (ScatterGatherPool != NULL) + pci_pool_destroy(ScatterGatherPool); if (Controller->FirmwareType == DAC960_V1_Controller) return; + + if (RequestSensePool != NULL) + pci_pool_destroy(RequestSensePool); + for (i = 0; i < DAC960_MaxLogicalDrives; i++) if (Controller->V2.LogicalDeviceInformation[i] != NULL) { kfree(Controller->V2.LogicalDeviceInformation[i]); Controller->V2.LogicalDeviceInformation[i] = NULL; } + for (i = 0; i < DAC960_V2_MaxPhysicalDevices; i++) { if (Controller->V2.PhysicalDeviceInformation[i] != NULL) @@ -297,6 +433,8 @@ static inline void DAC960_DeallocateCommand(DAC960_Command_T *Command) { DAC960_Controller_T *Controller = Command->Controller; + + Command->Request = NULL; Command->Next = Controller->FreeCommands; Controller->FreeCommands = Command; } @@ -308,9 +446,9 @@ static void DAC960_WaitForCommand(DAC960_Controller_T *Controller) { - spin_unlock_irq(Controller->RequestQueue.queue_lock); + spin_unlock_irq(&Controller->queue_lock); __wait_event(Controller->CommandWaitQueue, Controller->FreeCommands); - spin_lock_irq(Controller->RequestQueue.queue_lock); + spin_lock_irq(&Controller->queue_lock); } @@ -557,7 +695,7 @@ static boolean DAC960_V1_ExecuteType3(DAC960_Controller_T *Controller, DAC960_V1_CommandOpcode_T CommandOpcode, - void *DataPointer) + dma_addr_t DataDMA) { DAC960_Command_T *Command = DAC960_AllocateCommand(Controller); DAC960_V1_CommandMailbox_T *CommandMailbox = &Command->V1.CommandMailbox; @@ -565,7 +703,7 @@ DAC960_V1_ClearCommand(Command); Command->CommandType = DAC960_ImmediateCommand; CommandMailbox->Type3.CommandOpcode = CommandOpcode; - CommandMailbox->Type3.BusAddress = Virtual_to_Bus32(DataPointer); + CommandMailbox->Type3.BusAddress = DataDMA; DAC960_ExecuteCommand(Command); CommandStatus = Command->V1.CommandStatus; DAC960_DeallocateCommand(Command); @@ -582,7 +720,7 @@ static boolean DAC960_V1_ExecuteType3B(DAC960_Controller_T *Controller, DAC960_V1_CommandOpcode_T CommandOpcode, unsigned char CommandOpcode2, - void *DataPointer) + dma_addr_t DataDMA) { DAC960_Command_T *Command = DAC960_AllocateCommand(Controller); DAC960_V1_CommandMailbox_T *CommandMailbox = &Command->V1.CommandMailbox; @@ -591,7 +729,7 @@ Command->CommandType = DAC960_ImmediateCommand; CommandMailbox->Type3B.CommandOpcode = CommandOpcode; CommandMailbox->Type3B.CommandOpcode2 = CommandOpcode2; - CommandMailbox->Type3B.BusAddress = Virtual_to_Bus32(DataPointer); + CommandMailbox->Type3B.BusAddress = DataDMA; DAC960_ExecuteCommand(Command); CommandStatus = Command->V1.CommandStatus; DAC960_DeallocateCommand(Command); @@ -609,7 +747,7 @@ DAC960_V1_CommandOpcode_T CommandOpcode, unsigned char Channel, unsigned char TargetID, - void *DataPointer) + dma_addr_t DataDMA) { DAC960_Command_T *Command = DAC960_AllocateCommand(Controller); DAC960_V1_CommandMailbox_T *CommandMailbox = &Command->V1.CommandMailbox; @@ -619,7 +757,7 @@ CommandMailbox->Type3D.CommandOpcode = CommandOpcode; CommandMailbox->Type3D.Channel = Channel; CommandMailbox->Type3D.TargetID = TargetID; - CommandMailbox->Type3D.BusAddress = Virtual_to_Bus32(DataPointer); + CommandMailbox->Type3D.BusAddress = DataDMA; DAC960_ExecuteCommand(Command); CommandStatus = Command->V1.CommandStatus; DAC960_DeallocateCommand(Command); @@ -631,12 +769,11 @@ DAC960_V2_GeneralInfo executes a DAC960 V2 Firmware General Information Reading IOCTL Command and waits for completion. It returns true on success and false on failure. + + Return data in The controller's HealthStatusBuffer, which is dma-able memory */ -static boolean DAC960_V2_GeneralInfo(DAC960_Controller_T *Controller, - DAC960_V2_IOCTL_Opcode_T IOCTL_Opcode, - void *DataPointer, - unsigned int DataByteCount) +static boolean DAC960_V2_GeneralInfo(DAC960_Controller_T *Controller) { DAC960_Command_T *Command = DAC960_AllocateCommand(Controller); DAC960_V2_CommandMailbox_T *CommandMailbox = &Command->V2.CommandMailbox; @@ -648,12 +785,12 @@ .DataTransferControllerToHost = true; CommandMailbox->Common.CommandControlBits .NoAutoRequestSense = true; - CommandMailbox->Common.DataTransferSize = DataByteCount; - CommandMailbox->Common.IOCTL_Opcode = IOCTL_Opcode; + CommandMailbox->Common.DataTransferSize = sizeof(DAC960_V2_HealthStatusBuffer_T); + CommandMailbox->Common.IOCTL_Opcode = DAC960_V2_GetHealthStatus; CommandMailbox->Common.DataTransferMemoryAddress .ScatterGatherSegments[0] .SegmentDataPointer = - Virtual_to_Bus64(DataPointer); + Controller->V2.HealthStatusBufferDMA; CommandMailbox->Common.DataTransferMemoryAddress .ScatterGatherSegments[0] .SegmentByteCount = @@ -669,12 +806,12 @@ DAC960_V2_ControllerInfo executes a DAC960 V2 Firmware Controller Information Reading IOCTL Command and waits for completion. It returns true on success and false on failure. + + Data is returned in the controller's V2.NewControllerInformation dma-able + memory buffer. */ -static boolean DAC960_V2_ControllerInfo(DAC960_Controller_T *Controller, - DAC960_V2_IOCTL_Opcode_T IOCTL_Opcode, - void *DataPointer, - unsigned int DataByteCount) +static boolean DAC960_V2_NewControllerInfo(DAC960_Controller_T *Controller) { DAC960_Command_T *Command = DAC960_AllocateCommand(Controller); DAC960_V2_CommandMailbox_T *CommandMailbox = &Command->V2.CommandMailbox; @@ -686,13 +823,13 @@ .DataTransferControllerToHost = true; CommandMailbox->ControllerInfo.CommandControlBits .NoAutoRequestSense = true; - CommandMailbox->ControllerInfo.DataTransferSize = DataByteCount; + CommandMailbox->ControllerInfo.DataTransferSize = sizeof(DAC960_V2_ControllerInfo_T); CommandMailbox->ControllerInfo.ControllerNumber = 0; - CommandMailbox->ControllerInfo.IOCTL_Opcode = IOCTL_Opcode; + CommandMailbox->ControllerInfo.IOCTL_Opcode = DAC960_V2_GetControllerInfo; CommandMailbox->ControllerInfo.DataTransferMemoryAddress .ScatterGatherSegments[0] .SegmentDataPointer = - Virtual_to_Bus64(DataPointer); + Controller->V2.NewControllerInformationDMA; CommandMailbox->ControllerInfo.DataTransferMemoryAddress .ScatterGatherSegments[0] .SegmentByteCount = @@ -708,34 +845,34 @@ DAC960_V2_LogicalDeviceInfo executes a DAC960 V2 Firmware Controller Logical Device Information Reading IOCTL Command and waits for completion. It returns true on success and false on failure. + + Data is returned in the controller's V2.NewLogicalDeviceInformation */ -static boolean DAC960_V2_LogicalDeviceInfo(DAC960_Controller_T *Controller, - DAC960_V2_IOCTL_Opcode_T - IOCTL_Opcode, - unsigned short - LogicalDeviceNumber, - void *DataPointer, - unsigned int DataByteCount) +static boolean DAC960_V2_NewLogicalDeviceInfo(DAC960_Controller_T *Controller, + unsigned short LogicalDeviceNumber) { DAC960_Command_T *Command = DAC960_AllocateCommand(Controller); DAC960_V2_CommandMailbox_T *CommandMailbox = &Command->V2.CommandMailbox; DAC960_V2_CommandStatus_T CommandStatus; + DAC960_V2_ClearCommand(Command); Command->CommandType = DAC960_ImmediateCommand; - CommandMailbox->LogicalDeviceInfo.CommandOpcode = DAC960_V2_IOCTL; + CommandMailbox->LogicalDeviceInfo.CommandOpcode = + DAC960_V2_IOCTL; CommandMailbox->LogicalDeviceInfo.CommandControlBits .DataTransferControllerToHost = true; CommandMailbox->LogicalDeviceInfo.CommandControlBits .NoAutoRequestSense = true; - CommandMailbox->LogicalDeviceInfo.DataTransferSize = DataByteCount; + CommandMailbox->LogicalDeviceInfo.DataTransferSize = + sizeof(DAC960_V2_LogicalDeviceInfo_T); CommandMailbox->LogicalDeviceInfo.LogicalDevice.LogicalDeviceNumber = LogicalDeviceNumber; - CommandMailbox->LogicalDeviceInfo.IOCTL_Opcode = IOCTL_Opcode; + CommandMailbox->LogicalDeviceInfo.IOCTL_Opcode = DAC960_V2_GetLogicalDeviceInfoValid; CommandMailbox->LogicalDeviceInfo.DataTransferMemoryAddress .ScatterGatherSegments[0] .SegmentDataPointer = - Virtual_to_Bus64(DataPointer); + Controller->V2.NewLogicalDeviceInformationDMA; CommandMailbox->LogicalDeviceInfo.DataTransferMemoryAddress .ScatterGatherSegments[0] .SegmentByteCount = @@ -748,23 +885,30 @@ /* - DAC960_V2_PhysicalDeviceInfo executes a DAC960 V2 Firmware Controller Physical - Device Information Reading IOCTL Command and waits for completion. It + DAC960_V2_PhysicalDeviceInfo executes a DAC960 V2 Firmware Controller "Read + Physical Device Information" IOCTL Command and waits for completion. It returns true on success and false on failure. + + The Channel, TargetID, LogicalUnit arguments should be 0 the first time + this function is called for a given controller. This will return data + for the "first" device on that controller. The returned data includes a + Channel, TargetID, LogicalUnit that can be passed in to this routine to + get data for the NEXT device on that controller. + + Data is stored in the controller's V2.NewPhysicalDeviceInfo dma-able + memory buffer. + */ -static boolean DAC960_V2_PhysicalDeviceInfo(DAC960_Controller_T *Controller, - DAC960_V2_IOCTL_Opcode_T - IOCTL_Opcode, +static boolean DAC960_V2_NewPhysicalDeviceInfo(DAC960_Controller_T *Controller, unsigned char Channel, unsigned char TargetID, - unsigned char LogicalUnit, - void *DataPointer, - unsigned int DataByteCount) + unsigned char LogicalUnit) { DAC960_Command_T *Command = DAC960_AllocateCommand(Controller); DAC960_V2_CommandMailbox_T *CommandMailbox = &Command->V2.CommandMailbox; DAC960_V2_CommandStatus_T CommandStatus; + DAC960_V2_ClearCommand(Command); Command->CommandType = DAC960_ImmediateCommand; CommandMailbox->PhysicalDeviceInfo.CommandOpcode = DAC960_V2_IOCTL; @@ -772,15 +916,17 @@ .DataTransferControllerToHost = true; CommandMailbox->PhysicalDeviceInfo.CommandControlBits .NoAutoRequestSense = true; - CommandMailbox->PhysicalDeviceInfo.DataTransferSize = DataByteCount; + CommandMailbox->PhysicalDeviceInfo.DataTransferSize = + sizeof(DAC960_V2_PhysicalDeviceInfo_T); CommandMailbox->PhysicalDeviceInfo.PhysicalDevice.LogicalUnit = LogicalUnit; CommandMailbox->PhysicalDeviceInfo.PhysicalDevice.TargetID = TargetID; CommandMailbox->PhysicalDeviceInfo.PhysicalDevice.Channel = Channel; - CommandMailbox->PhysicalDeviceInfo.IOCTL_Opcode = IOCTL_Opcode; + CommandMailbox->PhysicalDeviceInfo.IOCTL_Opcode = + DAC960_V2_GetPhysicalDeviceInfoValid; CommandMailbox->PhysicalDeviceInfo.DataTransferMemoryAddress .ScatterGatherSegments[0] .SegmentDataPointer = - Virtual_to_Bus64(DataPointer); + Controller->V2.NewPhysicalDeviceInformationDMA; CommandMailbox->PhysicalDeviceInfo.DataTransferMemoryAddress .ScatterGatherSegments[0] .SegmentByteCount = @@ -792,6 +938,75 @@ } +static void DAC960_V2_ConstructNewUnitSerialNumber( + DAC960_Controller_T *Controller, + DAC960_V2_CommandMailbox_T *CommandMailbox, int Channel, int TargetID, + int LogicalUnit) +{ + CommandMailbox->SCSI_10.CommandOpcode = DAC960_V2_SCSI_10_Passthru; + CommandMailbox->SCSI_10.CommandControlBits + .DataTransferControllerToHost = true; + CommandMailbox->SCSI_10.CommandControlBits + .NoAutoRequestSense = true; + CommandMailbox->SCSI_10.DataTransferSize = + sizeof(DAC960_SCSI_Inquiry_UnitSerialNumber_T); + CommandMailbox->SCSI_10.PhysicalDevice.LogicalUnit = LogicalUnit; + CommandMailbox->SCSI_10.PhysicalDevice.TargetID = TargetID; + CommandMailbox->SCSI_10.PhysicalDevice.Channel = Channel; + CommandMailbox->SCSI_10.CDBLength = 6; + CommandMailbox->SCSI_10.SCSI_CDB[0] = 0x12; /* INQUIRY */ + CommandMailbox->SCSI_10.SCSI_CDB[1] = 1; /* EVPD = 1 */ + CommandMailbox->SCSI_10.SCSI_CDB[2] = 0x80; /* Page Code */ + CommandMailbox->SCSI_10.SCSI_CDB[3] = 0; /* Reserved */ + CommandMailbox->SCSI_10.SCSI_CDB[4] = + sizeof(DAC960_SCSI_Inquiry_UnitSerialNumber_T); + CommandMailbox->SCSI_10.SCSI_CDB[5] = 0; /* Control */ + CommandMailbox->SCSI_10.DataTransferMemoryAddress + .ScatterGatherSegments[0] + .SegmentDataPointer = + Controller->V2.NewInquiryUnitSerialNumberDMA; + CommandMailbox->SCSI_10.DataTransferMemoryAddress + .ScatterGatherSegments[0] + .SegmentByteCount = + CommandMailbox->SCSI_10.DataTransferSize; +} + + +/* + DAC960_V2_NewUnitSerialNumber executes an SCSI pass-through + Inquiry command to a SCSI device identified by Channel number, + Target id, Logical Unit Number. This function Waits for completion + of the command. + + The return data includes Unit Serial Number information for the + specified device. + + Data is stored in the controller's V2.NewPhysicalDeviceInfo dma-able + memory buffer. +*/ + +static boolean DAC960_V2_NewInquiryUnitSerialNumber(DAC960_Controller_T *Controller, + int Channel, int TargetID, int LogicalUnit) +{ + DAC960_Command_T *Command; + DAC960_V2_CommandMailbox_T *CommandMailbox; + DAC960_V2_CommandStatus_T CommandStatus; + + Command = DAC960_AllocateCommand(Controller); + CommandMailbox = &Command->V2.CommandMailbox; + DAC960_V2_ClearCommand(Command); + Command->CommandType = DAC960_ImmediateCommand; + + DAC960_V2_ConstructNewUnitSerialNumber(Controller, CommandMailbox, + Channel, TargetID, LogicalUnit); + + DAC960_ExecuteCommand(Command); + CommandStatus = Command->V2.CommandStatus; + DAC960_DeallocateCommand(Command); + return (CommandStatus == DAC960_V2_NormalCompletion); +} + + /* DAC960_V2_DeviceOperation executes a DAC960 V2 Firmware Controller Device Operation IOCTL Command and waits for completion. It returns true on @@ -825,84 +1040,144 @@ /* DAC960_V1_EnableMemoryMailboxInterface enables the Memory Mailbox Interface for DAC960 V1 Firmware Controllers. + + PD and P controller types have no memory mailbox, but still need the + other dma mapped memory. */ static boolean DAC960_V1_EnableMemoryMailboxInterface(DAC960_Controller_T *Controller) { void *ControllerBaseAddress = Controller->BaseAddress; + DAC960_HardwareType_T hw_type = Controller->HardwareType; + PCI_Device_T *PCI_Device = Controller->PCIDevice; + struct dma_loaf *DmaPages = &Controller->DmaPages; + size_t DmaPagesSize; + size_t CommandMailboxesSize; + size_t StatusMailboxesSize; + DAC960_V1_CommandMailbox_T *CommandMailboxesMemory; + dma_addr_t CommandMailboxesMemoryDMA; + DAC960_V1_StatusMailbox_T *StatusMailboxesMemory; + dma_addr_t StatusMailboxesMemoryDMA; + DAC960_V1_CommandMailbox_T CommandMailbox; DAC960_V1_CommandStatus_T CommandStatus; - unsigned long MemoryMailboxPagesAddress; - unsigned long MemoryMailboxPagesOrder; - unsigned long MemoryMailboxPagesSize; - void *SavedMemoryMailboxesAddress = NULL; - short NextCommandMailboxIndex = 0; - short NextStatusMailboxIndex = 0; - int TimeoutCounter = 1000000, i; - MemoryMailboxPagesOrder = 0; - MemoryMailboxPagesSize = - DAC960_V1_CommandMailboxCount * sizeof(DAC960_V1_CommandMailbox_T) + - DAC960_V1_StatusMailboxCount * sizeof(DAC960_V1_StatusMailbox_T); - while (MemoryMailboxPagesSize > PAGE_SIZE << MemoryMailboxPagesOrder) - MemoryMailboxPagesOrder++; - if (Controller->HardwareType == DAC960_LA_Controller) - DAC960_LA_RestoreMemoryMailboxInfo(Controller, - &SavedMemoryMailboxesAddress, - &NextCommandMailboxIndex, - &NextStatusMailboxIndex); - else DAC960_PG_RestoreMemoryMailboxInfo(Controller, - &SavedMemoryMailboxesAddress, - &NextCommandMailboxIndex, - &NextStatusMailboxIndex); - if (SavedMemoryMailboxesAddress == NULL) - { - MemoryMailboxPagesAddress = - __get_free_pages(GFP_KERNEL, MemoryMailboxPagesOrder); - Controller->MemoryMailboxPagesAddress = MemoryMailboxPagesAddress; - CommandMailboxesMemory = - (DAC960_V1_CommandMailbox_T *) MemoryMailboxPagesAddress; - } - else CommandMailboxesMemory = SavedMemoryMailboxesAddress; - if (CommandMailboxesMemory == NULL) return false; - Controller->MemoryMailboxPagesOrder = MemoryMailboxPagesOrder; - memset(CommandMailboxesMemory, 0, MemoryMailboxPagesSize); + int TimeoutCounter; + int i; + + + if (pci_set_dma_mask(Controller->PCIDevice, DAC690_V1_PciDmaMask)) + return DAC960_Failure(Controller, "DMA mask out of range"); + + if ((hw_type == DAC960_PD_Controller) || (hw_type == DAC960_P_Controller)) { + CommandMailboxesSize = 0; + StatusMailboxesSize = 0; + } else { + CommandMailboxesSize = DAC960_V1_CommandMailboxCount * sizeof(DAC960_V1_CommandMailbox_T); + StatusMailboxesSize = DAC960_V1_StatusMailboxCount * sizeof(DAC960_V1_StatusMailbox_T); + } + DmaPagesSize = CommandMailboxesSize + StatusMailboxesSize + + sizeof(DAC960_V1_DCDB_T) + sizeof(DAC960_V1_Enquiry_T) + + sizeof(DAC960_V1_ErrorTable_T) + sizeof(DAC960_V1_EventLogEntry_T) + + sizeof(DAC960_V1_RebuildProgress_T) + + sizeof(DAC960_V1_LogicalDriveInformationArray_T) + + sizeof(DAC960_V1_BackgroundInitializationStatus_T) + + sizeof(DAC960_V1_DeviceState_T) + sizeof(DAC960_SCSI_Inquiry_T) + + sizeof(DAC960_SCSI_Inquiry_UnitSerialNumber_T); + + if (!init_dma_loaf(PCI_Device, DmaPages, DmaPagesSize)) + return false; + + + if ((hw_type == DAC960_PD_Controller) || (hw_type == DAC960_P_Controller)) + goto skip_mailboxes; + + CommandMailboxesMemory = slice_dma_loaf(DmaPages, + CommandMailboxesSize, &CommandMailboxesMemoryDMA); + + /* These are the base addresses for the command memory mailbox array */ Controller->V1.FirstCommandMailbox = CommandMailboxesMemory; + Controller->V1.FirstCommandMailboxDMA = CommandMailboxesMemoryDMA; + CommandMailboxesMemory += DAC960_V1_CommandMailboxCount - 1; Controller->V1.LastCommandMailbox = CommandMailboxesMemory; - Controller->V1.NextCommandMailbox = - &Controller->V1.FirstCommandMailbox[NextCommandMailboxIndex]; - if (--NextCommandMailboxIndex < 0) - NextCommandMailboxIndex = DAC960_V1_CommandMailboxCount - 1; - Controller->V1.PreviousCommandMailbox1 = - &Controller->V1.FirstCommandMailbox[NextCommandMailboxIndex]; - if (--NextCommandMailboxIndex < 0) - NextCommandMailboxIndex = DAC960_V1_CommandMailboxCount - 1; + Controller->V1.NextCommandMailbox = Controller->V1.FirstCommandMailbox; + Controller->V1.PreviousCommandMailbox1 = Controller->V1.LastCommandMailbox; Controller->V1.PreviousCommandMailbox2 = - &Controller->V1.FirstCommandMailbox[NextCommandMailboxIndex]; - StatusMailboxesMemory = - (DAC960_V1_StatusMailbox_T *) (CommandMailboxesMemory + 1); + Controller->V1.LastCommandMailbox - 1; + + /* These are the base addresses for the status memory mailbox array */ + StatusMailboxesMemory = slice_dma_loaf(DmaPages, + StatusMailboxesSize, &StatusMailboxesMemoryDMA); + Controller->V1.FirstStatusMailbox = StatusMailboxesMemory; + Controller->V1.FirstStatusMailboxDMA = StatusMailboxesMemoryDMA; StatusMailboxesMemory += DAC960_V1_StatusMailboxCount - 1; Controller->V1.LastStatusMailbox = StatusMailboxesMemory; - Controller->V1.NextStatusMailbox = - &Controller->V1.FirstStatusMailbox[NextStatusMailboxIndex]; - if (SavedMemoryMailboxesAddress != NULL) return true; + Controller->V1.NextStatusMailbox = Controller->V1.FirstStatusMailbox; + +skip_mailboxes: + Controller->V1.MonitoringDCDB = slice_dma_loaf(DmaPages, + sizeof(DAC960_V1_DCDB_T), + &Controller->V1.MonitoringDCDB_DMA); + + Controller->V1.NewEnquiry = slice_dma_loaf(DmaPages, + sizeof(DAC960_V1_Enquiry_T), + &Controller->V1.NewEnquiryDMA); + + Controller->V1.NewErrorTable = slice_dma_loaf(DmaPages, + sizeof(DAC960_V1_ErrorTable_T), + &Controller->V1.NewErrorTableDMA); + + Controller->V1.EventLogEntry = slice_dma_loaf(DmaPages, + sizeof(DAC960_V1_EventLogEntry_T), + &Controller->V1.EventLogEntryDMA); + + Controller->V1.RebuildProgress = slice_dma_loaf(DmaPages, + sizeof(DAC960_V1_RebuildProgress_T), + &Controller->V1.RebuildProgressDMA); + + Controller->V1.NewLogicalDriveInformation = slice_dma_loaf(DmaPages, + sizeof(DAC960_V1_LogicalDriveInformationArray_T), + &Controller->V1.NewLogicalDriveInformationDMA); + + Controller->V1.BackgroundInitializationStatus = slice_dma_loaf(DmaPages, + sizeof(DAC960_V1_BackgroundInitializationStatus_T), + &Controller->V1.BackgroundInitializationStatusDMA); + + Controller->V1.NewDeviceState = slice_dma_loaf(DmaPages, + sizeof(DAC960_V1_DeviceState_T), + &Controller->V1.NewDeviceStateDMA); + + Controller->V1.NewInquiryStandardData = slice_dma_loaf(DmaPages, + sizeof(DAC960_SCSI_Inquiry_T), + &Controller->V1.NewInquiryStandardDataDMA); + + Controller->V1.NewInquiryUnitSerialNumber = slice_dma_loaf(DmaPages, + sizeof(DAC960_SCSI_Inquiry_UnitSerialNumber_T), + &Controller->V1.NewInquiryUnitSerialNumberDMA); + + if ((hw_type == DAC960_PD_Controller) || (hw_type == DAC960_P_Controller)) + return true; + /* Enable the Memory Mailbox Interface. */ Controller->V1.DualModeMemoryMailboxInterface = true; CommandMailbox.TypeX.CommandOpcode = 0x2B; CommandMailbox.TypeX.CommandIdentifier = 0; CommandMailbox.TypeX.CommandOpcode2 = 0x14; CommandMailbox.TypeX.CommandMailboxesBusAddress = - Virtual_to_Bus32(Controller->V1.FirstCommandMailbox); + Controller->V1.FirstCommandMailboxDMA; CommandMailbox.TypeX.StatusMailboxesBusAddress = - Virtual_to_Bus32(Controller->V1.FirstStatusMailbox); + Controller->V1.FirstStatusMailboxDMA; +#define TIMEOUT_COUNT 1000000 + for (i = 0; i < 2; i++) switch (Controller->HardwareType) { case DAC960_LA_Controller: + TimeoutCounter = TIMEOUT_COUNT; while (--TimeoutCounter >= 0) { if (!DAC960_LA_HardwareMailboxFullP(ControllerBaseAddress)) @@ -912,6 +1187,7 @@ if (TimeoutCounter < 0) return false; DAC960_LA_WriteHardwareMailbox(ControllerBaseAddress, &CommandMailbox); DAC960_LA_HardwareMailboxNewCommand(ControllerBaseAddress); + TimeoutCounter = TIMEOUT_COUNT; while (--TimeoutCounter >= 0) { if (DAC960_LA_HardwareMailboxStatusAvailableP( @@ -928,6 +1204,7 @@ CommandMailbox.TypeX.CommandOpcode2 = 0x10; break; case DAC960_PG_Controller: + TimeoutCounter = TIMEOUT_COUNT; while (--TimeoutCounter >= 0) { if (!DAC960_PG_HardwareMailboxFullP(ControllerBaseAddress)) @@ -937,6 +1214,8 @@ if (TimeoutCounter < 0) return false; DAC960_PG_WriteHardwareMailbox(ControllerBaseAddress, &CommandMailbox); DAC960_PG_HardwareMailboxNewCommand(ControllerBaseAddress); + + TimeoutCounter = TIMEOUT_COUNT; while (--TimeoutCounter >= 0) { if (DAC960_PG_HardwareMailboxStatusAvailableP( @@ -953,6 +1232,7 @@ CommandMailbox.TypeX.CommandOpcode2 = 0x10; break; default: + DAC960_Failure(Controller, "Unknown Controller Type\n"); break; } return false; @@ -962,75 +1242,146 @@ /* DAC960_V2_EnableMemoryMailboxInterface enables the Memory Mailbox Interface for DAC960 V2 Firmware Controllers. + + Aggregate the space needed for the controller's memory mailbox and + the other data structures that will be targets of dma transfers with + the controller. Allocate a dma-mapped region of memory to hold these + structures. Then, save CPU pointers and dma_addr_t values to reference + the structures that are contained in that region. */ static boolean DAC960_V2_EnableMemoryMailboxInterface(DAC960_Controller_T *Controller) { void *ControllerBaseAddress = Controller->BaseAddress; + PCI_Device_T *PCI_Device = Controller->PCIDevice; + struct dma_loaf *DmaPages = &Controller->DmaPages; + size_t DmaPagesSize; + size_t CommandMailboxesSize; + size_t StatusMailboxesSize; + DAC960_V2_CommandMailbox_T *CommandMailboxesMemory; + dma_addr_t CommandMailboxesMemoryDMA; + DAC960_V2_StatusMailbox_T *StatusMailboxesMemory; - DAC960_V2_CommandMailbox_T CommandMailbox; - DAC960_V2_CommandStatus_T CommandStatus = 0; - unsigned long MemoryMailboxPagesAddress; - unsigned long MemoryMailboxPagesOrder; - unsigned long MemoryMailboxPagesSize; - MemoryMailboxPagesOrder = 0; - MemoryMailboxPagesSize = - DAC960_V2_CommandMailboxCount * sizeof(DAC960_V2_CommandMailbox_T) + - DAC960_V2_StatusMailboxCount * sizeof(DAC960_V2_StatusMailbox_T) + - sizeof(DAC960_V2_HealthStatusBuffer_T); - while (MemoryMailboxPagesSize > PAGE_SIZE << MemoryMailboxPagesOrder) - MemoryMailboxPagesOrder++; - MemoryMailboxPagesAddress = - __get_free_pages(GFP_KERNEL, MemoryMailboxPagesOrder); - Controller->MemoryMailboxPagesAddress = MemoryMailboxPagesAddress; - CommandMailboxesMemory = - (DAC960_V2_CommandMailbox_T *) MemoryMailboxPagesAddress; - if (CommandMailboxesMemory == NULL) return false; - Controller->MemoryMailboxPagesOrder = MemoryMailboxPagesOrder; - memset(CommandMailboxesMemory, 0, MemoryMailboxPagesSize); + dma_addr_t StatusMailboxesMemoryDMA; + + DAC960_V2_CommandMailbox_T *CommandMailbox; + dma_addr_t CommandMailboxDMA; + DAC960_V2_CommandStatus_T CommandStatus; + + if (pci_set_dma_mask(Controller->PCIDevice, DAC690_V2_PciDmaMask)) + return DAC960_Failure(Controller, "DMA mask out of range"); + + /* This is a temporary dma mapping, used only in the scope of this function */ + CommandMailbox = + (DAC960_V2_CommandMailbox_T *)pci_alloc_consistent( PCI_Device, + sizeof(DAC960_V2_CommandMailbox_T), &CommandMailboxDMA); + if (CommandMailbox == NULL) + return false; + + CommandMailboxesSize = DAC960_V2_CommandMailboxCount * sizeof(DAC960_V2_CommandMailbox_T); + StatusMailboxesSize = DAC960_V2_StatusMailboxCount * sizeof(DAC960_V2_StatusMailbox_T); + DmaPagesSize = + CommandMailboxesSize + StatusMailboxesSize + + sizeof(DAC960_V2_HealthStatusBuffer_T) + + sizeof(DAC960_V2_ControllerInfo_T) + + sizeof(DAC960_V2_LogicalDeviceInfo_T) + + sizeof(DAC960_V2_PhysicalDeviceInfo_T) + + sizeof(DAC960_SCSI_Inquiry_UnitSerialNumber_T) + + sizeof(DAC960_V2_Event_T) + + sizeof(DAC960_V2_PhysicalToLogicalDevice_T); + + if (!init_dma_loaf(PCI_Device, DmaPages, DmaPagesSize)) { + pci_free_consistent(PCI_Device, sizeof(DAC960_V2_CommandMailbox_T), + CommandMailbox, CommandMailboxDMA); + return false; + } + + CommandMailboxesMemory = slice_dma_loaf(DmaPages, + CommandMailboxesSize, &CommandMailboxesMemoryDMA); + + /* These are the base addresses for the command memory mailbox array */ Controller->V2.FirstCommandMailbox = CommandMailboxesMemory; + Controller->V2.FirstCommandMailboxDMA = CommandMailboxesMemoryDMA; + CommandMailboxesMemory += DAC960_V2_CommandMailboxCount - 1; Controller->V2.LastCommandMailbox = CommandMailboxesMemory; Controller->V2.NextCommandMailbox = Controller->V2.FirstCommandMailbox; Controller->V2.PreviousCommandMailbox1 = Controller->V2.LastCommandMailbox; Controller->V2.PreviousCommandMailbox2 = - Controller->V2.LastCommandMailbox - 1; - StatusMailboxesMemory = - (DAC960_V2_StatusMailbox_T *) (CommandMailboxesMemory + 1); + Controller->V2.LastCommandMailbox - 1; + + /* These are the base addresses for the status memory mailbox array */ + StatusMailboxesMemory = slice_dma_loaf(DmaPages, + StatusMailboxesSize, &StatusMailboxesMemoryDMA); + Controller->V2.FirstStatusMailbox = StatusMailboxesMemory; + Controller->V2.FirstStatusMailboxDMA = StatusMailboxesMemoryDMA; StatusMailboxesMemory += DAC960_V2_StatusMailboxCount - 1; Controller->V2.LastStatusMailbox = StatusMailboxesMemory; Controller->V2.NextStatusMailbox = Controller->V2.FirstStatusMailbox; - Controller->V2.HealthStatusBuffer = - (DAC960_V2_HealthStatusBuffer_T *) (StatusMailboxesMemory + 1); - /* Enable the Memory Mailbox Interface. */ - memset(&CommandMailbox, 0, sizeof(DAC960_V2_CommandMailbox_T)); - CommandMailbox.SetMemoryMailbox.CommandIdentifier = 1; - CommandMailbox.SetMemoryMailbox.CommandOpcode = DAC960_V2_IOCTL; - CommandMailbox.SetMemoryMailbox.CommandControlBits.NoAutoRequestSense = true; - CommandMailbox.SetMemoryMailbox.FirstCommandMailboxSizeKB = + + Controller->V2.HealthStatusBuffer = slice_dma_loaf(DmaPages, + sizeof(DAC960_V2_HealthStatusBuffer_T), + &Controller->V2.HealthStatusBufferDMA); + + Controller->V2.NewControllerInformation = slice_dma_loaf(DmaPages, + sizeof(DAC960_V2_ControllerInfo_T), + &Controller->V2.NewControllerInformationDMA); + + Controller->V2.NewLogicalDeviceInformation = slice_dma_loaf(DmaPages, + sizeof(DAC960_V2_LogicalDeviceInfo_T), + &Controller->V2.NewLogicalDeviceInformationDMA); + + Controller->V2.NewPhysicalDeviceInformation = slice_dma_loaf(DmaPages, + sizeof(DAC960_V2_PhysicalDeviceInfo_T), + &Controller->V2.NewPhysicalDeviceInformationDMA); + + Controller->V2.NewInquiryUnitSerialNumber = slice_dma_loaf(DmaPages, + sizeof(DAC960_SCSI_Inquiry_UnitSerialNumber_T), + &Controller->V2.NewInquiryUnitSerialNumberDMA); + + Controller->V2.Event = slice_dma_loaf(DmaPages, + sizeof(DAC960_V2_Event_T), + &Controller->V2.EventDMA); + + Controller->V2.PhysicalToLogicalDevice = slice_dma_loaf(DmaPages, + sizeof(DAC960_V2_PhysicalToLogicalDevice_T), + &Controller->V2.PhysicalToLogicalDeviceDMA); + + /* + Enable the Memory Mailbox Interface. + + I don't know why we can't just use one of the memory mailboxes + we just allocated to do this, instead of using this temporary one. + Try this change later. + */ + memset(CommandMailbox, 0, sizeof(DAC960_V2_CommandMailbox_T)); + CommandMailbox->SetMemoryMailbox.CommandIdentifier = 1; + CommandMailbox->SetMemoryMailbox.CommandOpcode = DAC960_V2_IOCTL; + CommandMailbox->SetMemoryMailbox.CommandControlBits.NoAutoRequestSense = true; + CommandMailbox->SetMemoryMailbox.FirstCommandMailboxSizeKB = (DAC960_V2_CommandMailboxCount * sizeof(DAC960_V2_CommandMailbox_T)) >> 10; - CommandMailbox.SetMemoryMailbox.FirstStatusMailboxSizeKB = + CommandMailbox->SetMemoryMailbox.FirstStatusMailboxSizeKB = (DAC960_V2_StatusMailboxCount * sizeof(DAC960_V2_StatusMailbox_T)) >> 10; - CommandMailbox.SetMemoryMailbox.SecondCommandMailboxSizeKB = 0; - CommandMailbox.SetMemoryMailbox.SecondStatusMailboxSizeKB = 0; - CommandMailbox.SetMemoryMailbox.RequestSenseSize = 0; - CommandMailbox.SetMemoryMailbox.IOCTL_Opcode = DAC960_V2_SetMemoryMailbox; - CommandMailbox.SetMemoryMailbox.HealthStatusBufferSizeKB = 1; - CommandMailbox.SetMemoryMailbox.HealthStatusBufferBusAddress = - Virtual_to_Bus64(Controller->V2.HealthStatusBuffer); - CommandMailbox.SetMemoryMailbox.FirstCommandMailboxBusAddress = - Virtual_to_Bus64(Controller->V2.FirstCommandMailbox); - CommandMailbox.SetMemoryMailbox.FirstStatusMailboxBusAddress = - Virtual_to_Bus64(Controller->V2.FirstStatusMailbox); + CommandMailbox->SetMemoryMailbox.SecondCommandMailboxSizeKB = 0; + CommandMailbox->SetMemoryMailbox.SecondStatusMailboxSizeKB = 0; + CommandMailbox->SetMemoryMailbox.RequestSenseSize = 0; + CommandMailbox->SetMemoryMailbox.IOCTL_Opcode = DAC960_V2_SetMemoryMailbox; + CommandMailbox->SetMemoryMailbox.HealthStatusBufferSizeKB = 1; + CommandMailbox->SetMemoryMailbox.HealthStatusBufferBusAddress = + Controller->V2.HealthStatusBufferDMA; + CommandMailbox->SetMemoryMailbox.FirstCommandMailboxBusAddress = + Controller->V2.FirstCommandMailboxDMA; + CommandMailbox->SetMemoryMailbox.FirstStatusMailboxBusAddress = + Controller->V2.FirstStatusMailboxDMA; switch (Controller->HardwareType) { case DAC960_BA_Controller: while (DAC960_BA_HardwareMailboxFullP(ControllerBaseAddress)) udelay(1); - DAC960_BA_WriteHardwareMailbox(ControllerBaseAddress, &CommandMailbox); + DAC960_BA_WriteHardwareMailbox(ControllerBaseAddress, CommandMailboxDMA); DAC960_BA_HardwareMailboxNewCommand(ControllerBaseAddress); while (!DAC960_BA_HardwareMailboxStatusAvailableP(ControllerBaseAddress)) udelay(1); @@ -1041,7 +1392,7 @@ case DAC960_LP_Controller: while (DAC960_LP_HardwareMailboxFullP(ControllerBaseAddress)) udelay(1); - DAC960_LP_WriteHardwareMailbox(ControllerBaseAddress, &CommandMailbox); + DAC960_LP_WriteHardwareMailbox(ControllerBaseAddress, CommandMailboxDMA); DAC960_LP_HardwareMailboxNewCommand(ControllerBaseAddress); while (!DAC960_LP_HardwareMailboxStatusAvailableP(ControllerBaseAddress)) udelay(1); @@ -1050,8 +1401,12 @@ DAC960_LP_AcknowledgeHardwareMailboxStatus(ControllerBaseAddress); break; default: + DAC960_Failure(Controller, "Unknown Controller Type\n"); + CommandStatus = DAC960_V2_AbormalCompletion; break; } + pci_free_consistent(PCI_Device, sizeof(DAC960_V2_CommandMailbox_T), + CommandMailbox, CommandMailboxDMA); return (CommandStatus == DAC960_V2_NormalCompletion); } @@ -1064,33 +1419,65 @@ static boolean DAC960_V1_ReadControllerConfiguration(DAC960_Controller_T *Controller) { - DAC960_V1_Enquiry2_T Enquiry2; - DAC960_V1_Config2_T Config2; + DAC960_V1_Enquiry2_T *Enquiry2; + dma_addr_t Enquiry2DMA; + DAC960_V1_Config2_T *Config2; + dma_addr_t Config2DMA; int LogicalDriveNumber, Channel, TargetID; + struct dma_loaf local_dma; + + if (!init_dma_loaf(Controller->PCIDevice, &local_dma, + sizeof(DAC960_V1_Enquiry2_T) + sizeof(DAC960_V1_Config2_T))) + return DAC960_Failure(Controller, "LOGICAL DEVICE ALLOCATION"); + + Enquiry2 = slice_dma_loaf(&local_dma, sizeof(DAC960_V1_Enquiry2_T), &Enquiry2DMA); + Config2 = slice_dma_loaf(&local_dma, sizeof(DAC960_V1_Config2_T), &Config2DMA); + if (!DAC960_V1_ExecuteType3(Controller, DAC960_V1_Enquiry, - &Controller->V1.Enquiry)) + Controller->V1.NewEnquiryDMA)) { + free_dma_loaf(Controller->PCIDevice, &local_dma); return DAC960_Failure(Controller, "ENQUIRY"); - if (!DAC960_V1_ExecuteType3(Controller, DAC960_V1_Enquiry2, &Enquiry2)) + } + memcpy(&Controller->V1.Enquiry, Controller->V1.NewEnquiry, + sizeof(DAC960_V1_Enquiry_T)); + + if (!DAC960_V1_ExecuteType3(Controller, DAC960_V1_Enquiry2, Enquiry2DMA)) { + free_dma_loaf(Controller->PCIDevice, &local_dma); return DAC960_Failure(Controller, "ENQUIRY2"); - if (!DAC960_V1_ExecuteType3(Controller, DAC960_V1_ReadConfig2, &Config2)) + } + + if (!DAC960_V1_ExecuteType3(Controller, DAC960_V1_ReadConfig2, Config2DMA)) { + free_dma_loaf(Controller->PCIDevice, &local_dma); return DAC960_Failure(Controller, "READ CONFIG2"); + } + if (!DAC960_V1_ExecuteType3(Controller, DAC960_V1_GetLogicalDriveInformation, - &Controller->V1.LogicalDriveInformation)) + Controller->V1.NewLogicalDriveInformationDMA)) { + free_dma_loaf(Controller->PCIDevice, &local_dma); return DAC960_Failure(Controller, "GET LOGICAL DRIVE INFORMATION"); - for (Channel = 0; Channel < Enquiry2.ActualChannels; Channel++) - for (TargetID = 0; TargetID < Enquiry2.MaxTargets; TargetID++) + } + memcpy(&Controller->V1.LogicalDriveInformation, + Controller->V1.NewLogicalDriveInformation, + sizeof(DAC960_V1_LogicalDriveInformationArray_T)); + + for (Channel = 0; Channel < Enquiry2->ActualChannels; Channel++) + for (TargetID = 0; TargetID < Enquiry2->MaxTargets; TargetID++) { if (!DAC960_V1_ExecuteType3D(Controller, DAC960_V1_GetDeviceState, Channel, TargetID, - &Controller->V1.DeviceState - [Channel][TargetID])) - return DAC960_Failure(Controller, "GET DEVICE STATE"); + Controller->V1.NewDeviceStateDMA)) { + free_dma_loaf(Controller->PCIDevice, &local_dma); + return DAC960_Failure(Controller, "GET DEVICE STATE"); + } + memcpy(&Controller->V1.DeviceState[Channel][TargetID], + Controller->V1.NewDeviceState, sizeof(DAC960_V1_DeviceState_T)); + } /* Initialize the Controller Model Name and Full Model Name fields. */ - switch (Enquiry2.HardwareID.SubModel) + switch (Enquiry2->HardwareID.SubModel) { case DAC960_V1_P_PD_PU: - if (Enquiry2.SCSICapability.BusSpeed == DAC960_V1_Ultra) + if (Enquiry2->SCSICapability.BusSpeed == DAC960_V1_Ultra) strcpy(Controller->ModelName, "DAC960PU"); else strcpy(Controller->ModelName, "DAC960PD"); break; @@ -1122,6 +1509,7 @@ strcpy(Controller->ModelName, "DAC1164P"); break; default: + free_dma_loaf(Controller->PCIDevice, &local_dma); return DAC960_Failure(Controller, "MODEL VERIFICATION"); } strcpy(Controller->FullModelName, "Mylex "); @@ -1135,18 +1523,18 @@ DAC960PU/PD/PL 3.51 and above DAC960PU/PD/PL/P 2.73 and above */ - if (Enquiry2.FirmwareID.MajorVersion == 0) + if (Enquiry2->FirmwareID.MajorVersion == 0) { - Enquiry2.FirmwareID.MajorVersion = + Enquiry2->FirmwareID.MajorVersion = Controller->V1.Enquiry.MajorFirmwareVersion; - Enquiry2.FirmwareID.MinorVersion = + Enquiry2->FirmwareID.MinorVersion = Controller->V1.Enquiry.MinorFirmwareVersion; - Enquiry2.FirmwareID.FirmwareType = '0'; - Enquiry2.FirmwareID.TurnID = 0; + Enquiry2->FirmwareID.FirmwareType = '0'; + Enquiry2->FirmwareID.TurnID = 0; } sprintf(Controller->FirmwareVersion, "%d.%02d-%c-%02d", - Enquiry2.FirmwareID.MajorVersion, Enquiry2.FirmwareID.MinorVersion, - Enquiry2.FirmwareID.FirmwareType, Enquiry2.FirmwareID.TurnID); + Enquiry2->FirmwareID.MajorVersion, Enquiry2->FirmwareID.MinorVersion, + Enquiry2->FirmwareID.FirmwareType, Enquiry2->FirmwareID.TurnID); if (!((Controller->FirmwareVersion[0] == '5' && strcmp(Controller->FirmwareVersion, "5.06") >= 0) || (Controller->FirmwareVersion[0] == '4' && @@ -1159,17 +1547,18 @@ DAC960_Failure(Controller, "FIRMWARE VERSION VERIFICATION"); DAC960_Error("Firmware Version = '%s'\n", Controller, Controller->FirmwareVersion); + free_dma_loaf(Controller->PCIDevice, &local_dma); return false; } /* Initialize the Controller Channels, Targets, Memory Size, and SAF-TE Enclosure Management Enabled fields. */ - Controller->Channels = Enquiry2.ActualChannels; - Controller->Targets = Enquiry2.MaxTargets; - Controller->MemorySize = Enquiry2.MemorySize >> 20; + Controller->Channels = Enquiry2->ActualChannels; + Controller->Targets = Enquiry2->MaxTargets; + Controller->MemorySize = Enquiry2->MemorySize >> 20; Controller->V1.SAFTE_EnclosureManagementEnabled = - (Enquiry2.FaultManagementType == DAC960_V1_SAFTE); + (Enquiry2->FaultManagementType == DAC960_V1_SAFTE); /* Initialize the Controller Queue Depth, Driver Queue Depth, Logical Drive Count, Maximum Blocks per Command, Controller Scatter/Gather Limit, and @@ -1183,8 +1572,8 @@ Controller->DriverQueueDepth = DAC960_MaxDriverQueueDepth; Controller->LogicalDriveCount = Controller->V1.Enquiry.NumberOfLogicalDrives; - Controller->MaxBlocksPerCommand = Enquiry2.MaxBlocksPerCommand; - Controller->ControllerScatterGatherLimit = Enquiry2.MaxScatterGatherEntries; + Controller->MaxBlocksPerCommand = Enquiry2->MaxBlocksPerCommand; + Controller->ControllerScatterGatherLimit = Enquiry2->MaxScatterGatherEntries; Controller->DriverScatterGatherLimit = Controller->ControllerScatterGatherLimit; if (Controller->DriverScatterGatherLimit > DAC960_V1_ScatterGatherLimit) @@ -1192,11 +1581,11 @@ /* Initialize the Stripe Size, Segment Size, and Geometry Translation. */ - Controller->V1.StripeSize = Config2.BlocksPerStripe * Config2.BlockFactor + Controller->V1.StripeSize = Config2->BlocksPerStripe * Config2->BlockFactor >> (10 - DAC960_BlockSizeBits); - Controller->V1.SegmentSize = Config2.BlocksPerCacheLine * Config2.BlockFactor + Controller->V1.SegmentSize = Config2->BlocksPerCacheLine * Config2->BlockFactor >> (10 - DAC960_BlockSizeBits); - switch (Config2.DriveGeometry) + switch (Config2->DriveGeometry) { case DAC960_V1_Geometry_128_32: Controller->V1.GeometryTranslationHeads = 128; @@ -1207,6 +1596,7 @@ Controller->V1.GeometryTranslationSectors = 63; break; default: + free_dma_loaf(Controller->PCIDevice, &local_dma); return DAC960_Failure(Controller, "CONFIG2 DRIVE GEOMETRY"); } /* @@ -1220,8 +1610,11 @@ Controller->V1.BackgroundInitializationStatusSupported = true; DAC960_V1_ExecuteType3B(Controller, DAC960_V1_BackgroundInitializationControl, 0x20, - &Controller-> - V1.LastBackgroundInitializationStatus); + Controller-> + V1.BackgroundInitializationStatusDMA); + memcpy(&Controller->V1.LastBackgroundInitializationStatus, + Controller->V1.BackgroundInitializationStatus, + sizeof(DAC960_V1_BackgroundInitializationStatus_T)); } /* Initialize the Logical Drive Initially Accessible flag. @@ -1234,6 +1627,7 @@ DAC960_V1_LogicalDrive_Offline) Controller->LogicalDriveInitiallyAccessible[LogicalDriveNumber] = true; Controller->V1.LastRebuildStatus = DAC960_V1_NoRebuildOrCheckInProgress; + free_dma_loaf(Controller->PCIDevice, &local_dma); return true; } @@ -1247,17 +1641,20 @@ *Controller) { DAC960_V2_ControllerInfo_T *ControllerInfo = - &Controller->V2.ControllerInformation; + &Controller->V2.ControllerInformation; unsigned short LogicalDeviceNumber = 0; int ModelNameLength; - if (!DAC960_V2_ControllerInfo(Controller, DAC960_V2_GetControllerInfo, - ControllerInfo, - sizeof(DAC960_V2_ControllerInfo_T))) + + /* Get data into dma-able area, then copy into permanant location */ + if (!DAC960_V2_NewControllerInfo(Controller)) return DAC960_Failure(Controller, "GET CONTROLLER INFO"); - if (!DAC960_V2_GeneralInfo(Controller, DAC960_V2_GetHealthStatus, - Controller->V2.HealthStatusBuffer, - sizeof(DAC960_V2_HealthStatusBuffer_T))) + memcpy(ControllerInfo, Controller->V2.NewControllerInformation, + sizeof(DAC960_V2_ControllerInfo_T)); + + + if (!DAC960_V2_GeneralInfo(Controller)) return DAC960_Failure(Controller, "GET HEALTH STATUS"); + /* Initialize the Controller Model Name and Full Model Name fields. */ @@ -1325,14 +1722,11 @@ while (true) { DAC960_V2_LogicalDeviceInfo_T *NewLogicalDeviceInfo = - &Controller->V2.NewLogicalDeviceInformation; + Controller->V2.NewLogicalDeviceInformation; DAC960_V2_LogicalDeviceInfo_T *LogicalDeviceInfo; DAC960_V2_PhysicalDevice_T PhysicalDevice; - if (!DAC960_V2_LogicalDeviceInfo(Controller, - DAC960_V2_GetLogicalDeviceInfoValid, - LogicalDeviceNumber, - NewLogicalDeviceInfo, - sizeof(DAC960_V2_LogicalDeviceInfo_T))) + + if (!DAC960_V2_NewLogicalDeviceInfo(Controller, LogicalDeviceNumber)) break; LogicalDeviceNumber = NewLogicalDeviceInfo->LogicalDeviceNumber; if (LogicalDeviceNumber > DAC960_MaxLogicalDrives) @@ -1421,26 +1815,61 @@ static boolean DAC960_V1_ReadDeviceConfiguration(DAC960_Controller_T *Controller) { - DAC960_V1_DCDB_T DCDBs[DAC960_V1_MaxChannels], *DCDB; - Completion_T Completions[DAC960_V1_MaxChannels], *Completion; + struct dma_loaf local_dma; + + dma_addr_t DCDBs_dma[DAC960_V1_MaxChannels]; + DAC960_V1_DCDB_T *DCDBs_cpu[DAC960_V1_MaxChannels]; + + dma_addr_t SCSI_Inquiry_dma[DAC960_V1_MaxChannels]; + DAC960_SCSI_Inquiry_T *SCSI_Inquiry_cpu[DAC960_V1_MaxChannels]; + + dma_addr_t SCSI_NewInquiryUnitSerialNumberDMA[DAC960_V1_MaxChannels]; + DAC960_SCSI_Inquiry_UnitSerialNumber_T *SCSI_NewInquiryUnitSerialNumberCPU[DAC960_V1_MaxChannels]; + + Completion_T Completions[DAC960_V1_MaxChannels]; unsigned long ProcessorFlags; int Channel, TargetID; + + if (!init_dma_loaf(Controller->PCIDevice, &local_dma, + DAC960_V1_MaxChannels*(sizeof(DAC960_V1_DCDB_T) + + sizeof(DAC960_SCSI_Inquiry_T) + + sizeof(DAC960_SCSI_Inquiry_UnitSerialNumber_T)))) + return DAC960_Failure(Controller, + "DMA ALLOCATION FAILED IN ReadDeviceConfiguration"); + + for (Channel = 0; Channel < Controller->Channels; Channel++) { + DCDBs_cpu[Channel] = slice_dma_loaf(&local_dma, + sizeof(DAC960_V1_DCDB_T), DCDBs_dma + Channel); + SCSI_Inquiry_cpu[Channel] = slice_dma_loaf(&local_dma, + sizeof(DAC960_SCSI_Inquiry_T), + SCSI_Inquiry_dma + Channel); + SCSI_NewInquiryUnitSerialNumberCPU[Channel] = slice_dma_loaf(&local_dma, + sizeof(DAC960_SCSI_Inquiry_UnitSerialNumber_T), + SCSI_NewInquiryUnitSerialNumberDMA + Channel); + } + for (TargetID = 0; TargetID < Controller->Targets; TargetID++) { + /* + * For each channel, submit a probe for a device on that channel. + * The timeout interval for a device that is present is 10 seconds. + * With this approach, the timeout periods can elapse in parallel + * on each channel. + */ for (Channel = 0; Channel < Controller->Channels; Channel++) { + dma_addr_t NewInquiryStandardDataDMA = SCSI_Inquiry_dma[Channel]; + DAC960_V1_DCDB_T *DCDB = DCDBs_cpu[Channel]; + dma_addr_t DCDB_dma = DCDBs_dma[Channel]; DAC960_Command_T *Command = Controller->Commands[Channel]; - DAC960_SCSI_Inquiry_T *InquiryStandardData = - &Controller->V1.InquiryStandardData[Channel][TargetID]; - InquiryStandardData->PeripheralDeviceType = 0x1F; - Completion = &Completions[Channel]; + Completion_T *Completion = &Completions[Channel]; + init_completion(Completion); - DCDB = &DCDBs[Channel]; DAC960_V1_ClearCommand(Command); Command->CommandType = DAC960_ImmediateCommand; Command->Completion = Completion; Command->V1.CommandMailbox.Type3.CommandOpcode = DAC960_V1_DCDB; - Command->V1.CommandMailbox.Type3.BusAddress = Virtual_to_Bus32(DCDB); + Command->V1.CommandMailbox.Type3.BusAddress = DCDB_dma; DCDB->Channel = Channel; DCDB->TargetID = TargetID; DCDB->Direction = DAC960_V1_DCDB_DataTransferDeviceToSystem; @@ -1449,7 +1878,7 @@ DCDB->NoAutomaticRequestSense = false; DCDB->DisconnectPermitted = true; DCDB->TransferLength = sizeof(DAC960_SCSI_Inquiry_T); - DCDB->BusAddress = Virtual_to_Bus32(InquiryStandardData); + DCDB->BusAddress = NewInquiryStandardDataDMA; DCDB->CDBLength = 6; DCDB->TransferLengthHigh4 = 0; DCDB->SenseLength = sizeof(DCDB->SenseData); @@ -1463,20 +1892,39 @@ DAC960_QueueCommand(Command); DAC960_ReleaseControllerLock(Controller, &ProcessorFlags); } + /* + * Wait for the problems submitted in the previous loop + * to complete. On the probes that are successful, + * get the serial number of the device that was found. + */ for (Channel = 0; Channel < Controller->Channels; Channel++) { - DAC960_Command_T *Command = Controller->Commands[Channel]; + DAC960_SCSI_Inquiry_T *InquiryStandardData = + &Controller->V1.InquiryStandardData[Channel][TargetID]; + DAC960_SCSI_Inquiry_T *NewInquiryStandardData = SCSI_Inquiry_cpu[Channel]; + dma_addr_t NewInquiryUnitSerialNumberDMA = + SCSI_NewInquiryUnitSerialNumberDMA[Channel]; + DAC960_SCSI_Inquiry_UnitSerialNumber_T *NewInquiryUnitSerialNumber = + SCSI_NewInquiryUnitSerialNumberCPU[Channel]; DAC960_SCSI_Inquiry_UnitSerialNumber_T *InquiryUnitSerialNumber = &Controller->V1.InquiryUnitSerialNumber[Channel][TargetID]; - InquiryUnitSerialNumber->PeripheralDeviceType = 0x1F; - Completion = &Completions[Channel]; + DAC960_Command_T *Command = Controller->Commands[Channel]; + DAC960_V1_DCDB_T *DCDB = DCDBs_cpu[Channel]; + Completion_T *Completion = &Completions[Channel]; + wait_for_completion(Completion); - if (Command->V1.CommandStatus != DAC960_V1_NormalCompletion) + + if (Command->V1.CommandStatus != DAC960_V1_NormalCompletion) { + memset(InquiryStandardData, 0, sizeof(DAC960_SCSI_Inquiry_T)); + InquiryStandardData->PeripheralDeviceType = 0x1F; continue; + } else + memcpy(InquiryStandardData, NewInquiryStandardData, sizeof(DAC960_SCSI_Inquiry_T)); + + /* Preserve Channel and TargetID values from the previous loop */ Command->Completion = Completion; - DCDB = &DCDBs[Channel]; DCDB->TransferLength = sizeof(DAC960_SCSI_Inquiry_UnitSerialNumber_T); - DCDB->BusAddress = Virtual_to_Bus32(InquiryUnitSerialNumber); + DCDB->BusAddress = NewInquiryUnitSerialNumberDMA; DCDB->SenseLength = sizeof(DCDB->SenseData); DCDB->CDB[0] = 0x12; /* INQUIRY */ DCDB->CDB[1] = 1; /* EVPD = 1 */ @@ -1488,8 +1936,17 @@ DAC960_QueueCommand(Command); DAC960_ReleaseControllerLock(Controller, &ProcessorFlags); wait_for_completion(Completion); + + if (Command->V1.CommandStatus != DAC960_V1_NormalCompletion) { + memset(InquiryUnitSerialNumber, 0, + sizeof(DAC960_SCSI_Inquiry_UnitSerialNumber_T)); + InquiryUnitSerialNumber->PeripheralDeviceType = 0x1F; + } else + memcpy(InquiryUnitSerialNumber, NewInquiryUnitSerialNumber, + sizeof(DAC960_SCSI_Inquiry_UnitSerialNumber_T)); } } + free_dma_loaf(Controller->PCIDevice, &local_dma); return true; } @@ -1506,74 +1963,55 @@ { unsigned char Channel = 0, TargetID = 0, LogicalUnit = 0; unsigned short PhysicalDeviceIndex = 0; + while (true) { DAC960_V2_PhysicalDeviceInfo_T *NewPhysicalDeviceInfo = - &Controller->V2.NewPhysicalDeviceInformation; + Controller->V2.NewPhysicalDeviceInformation; DAC960_V2_PhysicalDeviceInfo_T *PhysicalDeviceInfo; + DAC960_SCSI_Inquiry_UnitSerialNumber_T *NewInquiryUnitSerialNumber = + Controller->V2.NewInquiryUnitSerialNumber; DAC960_SCSI_Inquiry_UnitSerialNumber_T *InquiryUnitSerialNumber; - DAC960_Command_T *Command; - DAC960_V2_CommandMailbox_T *CommandMailbox; - if (!DAC960_V2_PhysicalDeviceInfo(Controller, - DAC960_V2_GetPhysicalDeviceInfoValid, - Channel, - TargetID, - LogicalUnit, - NewPhysicalDeviceInfo, - sizeof(DAC960_V2_PhysicalDeviceInfo_T))) + + if (!DAC960_V2_NewPhysicalDeviceInfo(Controller, Channel, TargetID, LogicalUnit)) break; - Channel = NewPhysicalDeviceInfo->Channel; - TargetID = NewPhysicalDeviceInfo->TargetID; - LogicalUnit = NewPhysicalDeviceInfo->LogicalUnit; + PhysicalDeviceInfo = (DAC960_V2_PhysicalDeviceInfo_T *) - kmalloc(sizeof(DAC960_V2_PhysicalDeviceInfo_T), GFP_ATOMIC); + kmalloc(sizeof(DAC960_V2_PhysicalDeviceInfo_T), GFP_ATOMIC); if (PhysicalDeviceInfo == NULL) - return DAC960_Failure(Controller, "PHYSICAL DEVICE ALLOCATION"); + return DAC960_Failure(Controller, "PHYSICAL DEVICE ALLOCATION"); Controller->V2.PhysicalDeviceInformation[PhysicalDeviceIndex] = - PhysicalDeviceInfo; + PhysicalDeviceInfo; memcpy(PhysicalDeviceInfo, NewPhysicalDeviceInfo, - sizeof(DAC960_V2_PhysicalDeviceInfo_T)); + sizeof(DAC960_V2_PhysicalDeviceInfo_T)); + InquiryUnitSerialNumber = (DAC960_SCSI_Inquiry_UnitSerialNumber_T *) kmalloc(sizeof(DAC960_SCSI_Inquiry_UnitSerialNumber_T), GFP_ATOMIC); - if (InquiryUnitSerialNumber == NULL) + if (InquiryUnitSerialNumber == NULL) { + kfree(PhysicalDeviceInfo); return DAC960_Failure(Controller, "SERIAL NUMBER ALLOCATION"); + } Controller->V2.InquiryUnitSerialNumber[PhysicalDeviceIndex] = - InquiryUnitSerialNumber; - memset(InquiryUnitSerialNumber, 0, - sizeof(DAC960_SCSI_Inquiry_UnitSerialNumber_T)); - InquiryUnitSerialNumber->PeripheralDeviceType = 0x1F; - Command = DAC960_AllocateCommand(Controller); - CommandMailbox = &Command->V2.CommandMailbox; - DAC960_V2_ClearCommand(Command); - Command->CommandType = DAC960_ImmediateCommand; - CommandMailbox->SCSI_10.CommandOpcode = DAC960_V2_SCSI_10_Passthru; - CommandMailbox->SCSI_10.CommandControlBits - .DataTransferControllerToHost = true; - CommandMailbox->SCSI_10.CommandControlBits - .NoAutoRequestSense = true; - CommandMailbox->SCSI_10.DataTransferSize = - sizeof(DAC960_SCSI_Inquiry_UnitSerialNumber_T); - CommandMailbox->SCSI_10.PhysicalDevice.LogicalUnit = LogicalUnit; - CommandMailbox->SCSI_10.PhysicalDevice.TargetID = TargetID; - CommandMailbox->SCSI_10.PhysicalDevice.Channel = Channel; - CommandMailbox->SCSI_10.CDBLength = 6; - CommandMailbox->SCSI_10.SCSI_CDB[0] = 0x12; /* INQUIRY */ - CommandMailbox->SCSI_10.SCSI_CDB[1] = 1; /* EVPD = 1 */ - CommandMailbox->SCSI_10.SCSI_CDB[2] = 0x80; /* Page Code */ - CommandMailbox->SCSI_10.SCSI_CDB[3] = 0; /* Reserved */ - CommandMailbox->SCSI_10.SCSI_CDB[4] = - sizeof(DAC960_SCSI_Inquiry_UnitSerialNumber_T); - CommandMailbox->SCSI_10.SCSI_CDB[5] = 0; /* Control */ - CommandMailbox->SCSI_10.DataTransferMemoryAddress - .ScatterGatherSegments[0] - .SegmentDataPointer = - Virtual_to_Bus64(InquiryUnitSerialNumber); - CommandMailbox->SCSI_10.DataTransferMemoryAddress - .ScatterGatherSegments[0] - .SegmentByteCount = - CommandMailbox->SCSI_10.DataTransferSize; - DAC960_ExecuteCommand(Command); - DAC960_DeallocateCommand(Command); + InquiryUnitSerialNumber; + + Channel = NewPhysicalDeviceInfo->Channel; + TargetID = NewPhysicalDeviceInfo->TargetID; + LogicalUnit = NewPhysicalDeviceInfo->LogicalUnit; + + /* + Some devices do NOT have Unit Serial Numbers. + This command fails for them. But, we still want to + remember those devices are there. Construct a + UnitSerialNumber structure for the failure case. + */ + if (!DAC960_V2_NewInquiryUnitSerialNumber(Controller, Channel, TargetID, LogicalUnit)) { + memset(InquiryUnitSerialNumber, 0, + sizeof(DAC960_SCSI_Inquiry_UnitSerialNumber_T)); + InquiryUnitSerialNumber->PeripheralDeviceType = 0x1F; + } else + memcpy(InquiryUnitSerialNumber, NewInquiryUnitSerialNumber, + sizeof(DAC960_SCSI_Inquiry_UnitSerialNumber_T)); + PhysicalDeviceIndex++; LogicalUnit++; } @@ -1947,12 +2385,12 @@ Initialize the I/O Request Queue. */ RequestQueue = &Controller->RequestQueue; - Controller->queue_lock = SPIN_LOCK_UNLOCKED; blk_init_queue(RequestQueue, DAC960_RequestFunction, &Controller->queue_lock); RequestQueue->queuedata = Controller; blk_queue_max_hw_segments(RequestQueue, Controller->DriverScatterGatherLimit); - blk_queue_max_phys_segments(RequestQueue, ~0); + blk_queue_max_phys_segments(RequestQueue, + Controller->DriverScatterGatherLimit); blk_queue_max_sectors(RequestQueue, Controller->MaxBlocksPerCommand); for (n = 0; n < DAC960_MaxLogicalDrives; n++) { @@ -1978,8 +2416,10 @@ { int MajorNumber = DAC960_MAJOR + Controller->ControllerNumber; int disk; + for (disk = 0; disk < DAC960_MaxLogicalDrives; disk++) del_gendisk(Controller->disks[disk]); + /* Unregister the Block Device Major Number for this DAC960 Controller. */ @@ -2082,159 +2522,155 @@ /* - DAC960_DetectControllers detects Mylex DAC960/AcceleRAID/eXtremeRAID + * DAC960_DetectCleanup releases the resources that were allocated + * during DAC960_DetectController(). DAC960_DetectController can + * has several internal failure points, so not ALL resources may + * have been allocated. It's important to free only + * resources that HAVE been allocated. The code below always + * tests that the resource has been allocated before attempting to + * free it. + */ +static void DAC960_DetectCleanup(DAC960_Controller_T *Controller) +{ + int i; + + /* Free the memory mailbox, status, and related structures */ + free_dma_loaf(Controller->PCIDevice, &Controller->DmaPages); + if (Controller->MemoryMappedAddress) { + switch(Controller->HardwareType) + { + case DAC960_BA_Controller: + DAC960_BA_DisableInterrupts(Controller->BaseAddress); + break; + case DAC960_LP_Controller: + DAC960_LP_DisableInterrupts(Controller->BaseAddress); + break; + case DAC960_LA_Controller: + DAC960_LA_DisableInterrupts(Controller->BaseAddress); + break; + case DAC960_PG_Controller: + DAC960_PG_DisableInterrupts(Controller->BaseAddress); + break; + case DAC960_PD_Controller: + DAC960_PD_DisableInterrupts(Controller->BaseAddress); + break; + case DAC960_P_Controller: + DAC960_PD_DisableInterrupts(Controller->BaseAddress); + break; + } + iounmap(Controller->MemoryMappedAddress); + } + if (Controller->IRQ_Channel) + free_irq(Controller->IRQ_Channel, Controller); + if (Controller->IO_Address) + release_region(Controller->IO_Address, 0x80); + pci_disable_device(Controller->PCIDevice); + for (i = 0; (i < DAC960_MaxLogicalDrives) && Controller->disks[i]; i++) + put_disk(Controller->disks[i]); + DAC960_Controllers[Controller->ControllerNumber] = NULL; + kfree(Controller); +} + + +/* + DAC960_DetectController detects Mylex DAC960/AcceleRAID/eXtremeRAID PCI RAID Controllers by interrogating the PCI Configuration Space for Controller Type. */ -static void DAC960_DetectControllers(DAC960_HardwareType_T HardwareType) -{ - void (*InterruptHandler)(int, void *, Registers_T *) = NULL; +static DAC960_Controller_T * +DAC960_DetectController(PCI_Device_T *PCI_Device, + const struct pci_device_id *entry) +{ + struct DAC960_privdata *privdata = (struct DAC960_privdata *)entry->driver_data; + void (*InterruptHandler)(int, void *, Registers_T *) = privdata->InterruptHandler; + unsigned int MemoryWindowSize = privdata->MemoryWindowSize; DAC960_Controller_T *Controller = NULL; - DAC960_FirmwareType_T FirmwareType = 0; - unsigned short VendorID = 0, DeviceID = 0; - unsigned int MemoryWindowSize = 0; - PCI_Device_T *PCI_Device = NULL; + unsigned char DeviceFunction = PCI_Device->devfn; + unsigned char ErrorStatus, Parameter0, Parameter1; + unsigned int IRQ_Channel = PCI_Device->irq; + void *BaseAddress; int i; - switch (HardwareType) - { - case DAC960_BA_Controller: - VendorID = PCI_VENDOR_ID_MYLEX; - DeviceID = PCI_DEVICE_ID_MYLEX_DAC960_BA; - FirmwareType = DAC960_V2_Controller; - InterruptHandler = DAC960_BA_InterruptHandler; - MemoryWindowSize = DAC960_BA_RegisterWindowSize; - break; - case DAC960_LP_Controller: - VendorID = PCI_VENDOR_ID_MYLEX; - DeviceID = PCI_DEVICE_ID_MYLEX_DAC960_LP; - FirmwareType = DAC960_LP_Controller; - InterruptHandler = DAC960_LP_InterruptHandler; - MemoryWindowSize = DAC960_LP_RegisterWindowSize; - break; - case DAC960_LA_Controller: - VendorID = PCI_VENDOR_ID_DEC; - DeviceID = PCI_DEVICE_ID_DEC_21285; - FirmwareType = DAC960_V1_Controller; - InterruptHandler = DAC960_LA_InterruptHandler; - MemoryWindowSize = DAC960_LA_RegisterWindowSize; - break; - case DAC960_PG_Controller: - VendorID = PCI_VENDOR_ID_MYLEX; - DeviceID = PCI_DEVICE_ID_MYLEX_DAC960_PG; - FirmwareType = DAC960_V1_Controller; - InterruptHandler = DAC960_PG_InterruptHandler; - MemoryWindowSize = DAC960_PG_RegisterWindowSize; - break; - case DAC960_PD_Controller: - VendorID = PCI_VENDOR_ID_MYLEX; - DeviceID = PCI_DEVICE_ID_MYLEX_DAC960_PD; - FirmwareType = DAC960_V1_Controller; - InterruptHandler = DAC960_PD_InterruptHandler; - MemoryWindowSize = DAC960_PD_RegisterWindowSize; - break; - case DAC960_P_Controller: - VendorID = PCI_VENDOR_ID_MYLEX; - DeviceID = PCI_DEVICE_ID_MYLEX_DAC960_P; - FirmwareType = DAC960_V1_Controller; - InterruptHandler = DAC960_P_InterruptHandler; - MemoryWindowSize = DAC960_PD_RegisterWindowSize; - break; - } - while ((PCI_Device = pci_find_device(VendorID, DeviceID, PCI_Device)) != NULL) - { - DAC960_IO_Address_T IO_Address = 0; - DAC960_PCI_Address_T PCI_Address = 0; - unsigned char Bus = PCI_Device->bus->number; - unsigned char DeviceFunction = PCI_Device->devfn; - unsigned char Device = DeviceFunction >> 3; - unsigned char Function = DeviceFunction & 0x7; - unsigned char ErrorStatus, Parameter0, Parameter1; - unsigned int IRQ_Channel = PCI_Device->irq; - void *BaseAddress; - Controller = NULL; - if (pci_enable_device(PCI_Device) != 0) continue; - switch (HardwareType) - { + + Controller = (DAC960_Controller_T *) + kmalloc(sizeof(DAC960_Controller_T), GFP_ATOMIC); + if (Controller == NULL) { + DAC960_Error("Unable to allocate Controller structure for " + "Controller at\n", NULL); + return NULL; + } + memset(Controller, 0, sizeof(DAC960_Controller_T)); + Controller->ControllerNumber = DAC960_ControllerCount; + DAC960_Controllers[DAC960_ControllerCount++] = Controller; + Controller->Bus = PCI_Device->bus->number; + Controller->FirmwareType = privdata->FirmwareType; + Controller->HardwareType = privdata->HardwareType; + Controller->Device = DeviceFunction >> 3; + Controller->Function = DeviceFunction & 0x7; + Controller->PCIDevice = PCI_Device; + strcpy(Controller->FullModelName, "DAC960"); + + if (pci_enable_device(PCI_Device)) { + kfree(Controller); + goto Failure; + } + + switch (Controller->HardwareType) + { case DAC960_BA_Controller: - PCI_Address = pci_resource_start(PCI_Device, 0); + Controller->PCI_Address = pci_resource_start(PCI_Device, 0); break; case DAC960_LP_Controller: - PCI_Address = pci_resource_start(PCI_Device, 0); + Controller->PCI_Address = pci_resource_start(PCI_Device, 0); break; case DAC960_LA_Controller: - if (!(PCI_Device->subsystem_vendor == PCI_VENDOR_ID_MYLEX && - PCI_Device->subsystem_device == PCI_DEVICE_ID_MYLEX_DAC960_LA)) - continue; - PCI_Address = pci_resource_start(PCI_Device, 0); + Controller->PCI_Address = pci_resource_start(PCI_Device, 0); break; case DAC960_PG_Controller: - PCI_Address = pci_resource_start(PCI_Device, 0); + Controller->PCI_Address = pci_resource_start(PCI_Device, 0); break; case DAC960_PD_Controller: - IO_Address = pci_resource_start(PCI_Device, 0); - PCI_Address = pci_resource_start(PCI_Device, 1); + Controller->IO_Address = pci_resource_start(PCI_Device, 0); + Controller->PCI_Address = pci_resource_start(PCI_Device, 1); break; case DAC960_P_Controller: - IO_Address = pci_resource_start(PCI_Device, 0); - PCI_Address = pci_resource_start(PCI_Device, 1); + Controller->IO_Address = pci_resource_start(PCI_Device, 0); + Controller->PCI_Address = pci_resource_start(PCI_Device, 1); break; - } - if (DAC960_ControllerCount == DAC960_MaxControllers) - { - DAC960_Error("More than %d DAC960 Controllers detected - " - "ignoring from Controller at\n", - NULL, DAC960_MaxControllers); - goto Failure; - } - Controller = (DAC960_Controller_T *) - kmalloc(sizeof(DAC960_Controller_T), GFP_ATOMIC); - if (Controller == NULL) - { - DAC960_Error("Unable to allocate Controller structure for " - "Controller at\n", NULL); - goto Failure; - } - memset(Controller, 0, sizeof(DAC960_Controller_T)); - for (i = 0; i < DAC960_MaxLogicalDrives; i++) { - Controller->disks[i] = alloc_disk(1<disks[i]) - goto Enomem; - Controller->disks[i]->private_data = (void*)i; - Controller->disks[i]->queue = &Controller->RequestQueue; - } - Controller->ControllerNumber = DAC960_ControllerCount; - init_waitqueue_head(&Controller->CommandWaitQueue); - init_waitqueue_head(&Controller->HealthStatusWaitQueue); - DAC960_Controllers[DAC960_ControllerCount++] = Controller; - DAC960_AnnounceDriver(Controller); - Controller->FirmwareType = FirmwareType; - Controller->HardwareType = HardwareType; - Controller->IO_Address = IO_Address; - Controller->PCI_Address = PCI_Address; - Controller->Bus = Bus; - Controller->Device = Device; - Controller->Function = Function; - /* - Map the Controller Register Window. - */ - if (MemoryWindowSize < PAGE_SIZE) + } + + pci_set_drvdata(PCI_Device, (void *)((int)Controller->ControllerNumber)); + for (i = 0; i < DAC960_MaxLogicalDrives; i++) { + Controller->disks[i] = alloc_disk(1<disks[i]) + goto Failure; + Controller->disks[i]->private_data = (void *)i; + Controller->disks[i]->queue = &Controller->RequestQueue; + } + init_waitqueue_head(&Controller->CommandWaitQueue); + init_waitqueue_head(&Controller->HealthStatusWaitQueue); + Controller->queue_lock = SPIN_LOCK_UNLOCKED; + DAC960_AnnounceDriver(Controller); + /* + Map the Controller Register Window. + */ + if (MemoryWindowSize < PAGE_SIZE) MemoryWindowSize = PAGE_SIZE; - Controller->MemoryMappedAddress = - ioremap_nocache(PCI_Address & PAGE_MASK, MemoryWindowSize); - Controller->BaseAddress = - Controller->MemoryMappedAddress + (PCI_Address & ~PAGE_MASK); - if (Controller->MemoryMappedAddress == NULL) - { + Controller->MemoryMappedAddress = + ioremap_nocache(Controller->PCI_Address & PAGE_MASK, MemoryWindowSize); + Controller->BaseAddress = + Controller->MemoryMappedAddress + (Controller->PCI_Address & ~PAGE_MASK); + if (Controller->MemoryMappedAddress == NULL) + { DAC960_Error("Unable to map Controller Register Window for " "Controller at\n", Controller); goto Failure; - } - BaseAddress = Controller->BaseAddress; - switch (HardwareType) - { + } + BaseAddress = Controller->BaseAddress; + switch (Controller->HardwareType) + { case DAC960_BA_Controller: - DAC960_BA_DisableInterrupts(Controller->BaseAddress); + DAC960_BA_DisableInterrupts(BaseAddress); DAC960_BA_AcknowledgeHardwareMailboxStatus(BaseAddress); udelay(1000); while (DAC960_BA_InitializationInProgressP(BaseAddress)) @@ -2252,7 +2688,7 @@ "for Controller at\n", Controller); goto Failure; } - DAC960_BA_EnableInterrupts(Controller->BaseAddress); + DAC960_BA_EnableInterrupts(BaseAddress); Controller->QueueCommand = DAC960_BA_QueueCommand; Controller->ReadControllerConfiguration = DAC960_V2_ReadControllerConfiguration; @@ -2264,7 +2700,7 @@ DAC960_V2_QueueReadWriteCommand; break; case DAC960_LP_Controller: - DAC960_LP_DisableInterrupts(Controller->BaseAddress); + DAC960_LP_DisableInterrupts(BaseAddress); DAC960_LP_AcknowledgeHardwareMailboxStatus(BaseAddress); udelay(1000); while (DAC960_LP_InitializationInProgressP(BaseAddress)) @@ -2282,7 +2718,7 @@ "for Controller at\n", Controller); goto Failure; } - DAC960_LP_EnableInterrupts(Controller->BaseAddress); + DAC960_LP_EnableInterrupts(BaseAddress); Controller->QueueCommand = DAC960_LP_QueueCommand; Controller->ReadControllerConfiguration = DAC960_V2_ReadControllerConfiguration; @@ -2294,7 +2730,7 @@ DAC960_V2_QueueReadWriteCommand; break; case DAC960_LA_Controller: - DAC960_LA_DisableInterrupts(Controller->BaseAddress); + DAC960_LA_DisableInterrupts(BaseAddress); DAC960_LA_AcknowledgeHardwareMailboxStatus(BaseAddress); udelay(1000); while (DAC960_LA_InitializationInProgressP(BaseAddress)) @@ -2312,7 +2748,7 @@ "for Controller at\n", Controller); goto Failure; } - DAC960_LA_EnableInterrupts(Controller->BaseAddress); + DAC960_LA_EnableInterrupts(BaseAddress); if (Controller->V1.DualModeMemoryMailboxInterface) Controller->QueueCommand = DAC960_LA_QueueCommandDualMode; else Controller->QueueCommand = DAC960_LA_QueueCommandSingleMode; @@ -2326,7 +2762,7 @@ DAC960_V1_QueueReadWriteCommand; break; case DAC960_PG_Controller: - DAC960_PG_DisableInterrupts(Controller->BaseAddress); + DAC960_PG_DisableInterrupts(BaseAddress); DAC960_PG_AcknowledgeHardwareMailboxStatus(BaseAddress); udelay(1000); while (DAC960_PG_InitializationInProgressP(BaseAddress)) @@ -2344,7 +2780,7 @@ "for Controller at\n", Controller); goto Failure; } - DAC960_PG_EnableInterrupts(Controller->BaseAddress); + DAC960_PG_EnableInterrupts(BaseAddress); if (Controller->V1.DualModeMemoryMailboxInterface) Controller->QueueCommand = DAC960_PG_QueueCommandDualMode; else Controller->QueueCommand = DAC960_PG_QueueCommandSingleMode; @@ -2373,10 +2809,16 @@ &Parameter0, &Parameter1) && DAC960_ReportErrorStatus(Controller, ErrorStatus, Parameter0, Parameter1)) - goto Failure1; + goto Failure; udelay(10); } - DAC960_PD_EnableInterrupts(Controller->BaseAddress); + if (!DAC960_V1_EnableMemoryMailboxInterface(Controller)) + { + DAC960_Error("Unable to allocate DMA mapped memory " + "for Controller at\n", Controller); + goto Failure; + } + DAC960_PD_EnableInterrupts(BaseAddress); Controller->QueueCommand = DAC960_PD_QueueCommand; Controller->ReadControllerConfiguration = DAC960_V1_ReadControllerConfiguration; @@ -2403,10 +2845,16 @@ &Parameter0, &Parameter1) && DAC960_ReportErrorStatus(Controller, ErrorStatus, Parameter0, Parameter1)) - goto Failure1; + goto Failure; udelay(10); } - DAC960_PD_EnableInterrupts(Controller->BaseAddress); + if (!DAC960_V1_EnableMemoryMailboxInterface(Controller)) + { + DAC960_Error("Unable to allocate DMA mapped memory" + "for Controller at\n", Controller); + goto Failure; + } + DAC960_PD_EnableInterrupts(BaseAddress); Controller->QueueCommand = DAC960_P_QueueCommand; Controller->ReadControllerConfiguration = DAC960_V1_ReadControllerConfiguration; @@ -2417,107 +2865,47 @@ Controller->QueueReadWriteCommand = DAC960_V1_QueueReadWriteCommand; break; - } - /* - Acquire shared access to the IRQ Channel. - */ - if (IRQ_Channel == 0) - { - DAC960_Error("IRQ Channel %d illegal for Controller at\n", - Controller, IRQ_Channel); - goto Failure1; - } - strcpy(Controller->FullModelName, "DAC960"); - if (request_irq(IRQ_Channel, InterruptHandler, SA_SHIRQ, + } + /* + Acquire shared access to the IRQ Channel. + */ + if (request_irq(IRQ_Channel, InterruptHandler, SA_SHIRQ, Controller->FullModelName, Controller) < 0) - { - DAC960_Error("Unable to acquire IRQ Channel %d for Controller at\n", - Controller, IRQ_Channel); - goto Failure1; - } - Controller->IRQ_Channel = IRQ_Channel; - DAC960_ActiveControllerCount++; - Controller->InitialCommand.CommandIdentifier = 1; - Controller->InitialCommand.Controller = Controller; - Controller->Commands[0] = &Controller->InitialCommand; - Controller->FreeCommands = &Controller->InitialCommand; - Controller->ControllerDetectionSuccessful = true; - continue; - Failure1: - if (Controller->IO_Address) release_region(Controller->IO_Address, 0x80); - Failure: - if (IO_Address == 0) + { + DAC960_Error("Unable to acquire IRQ Channel %d for Controller at\n", + Controller, Controller->IRQ_Channel); + goto Failure; + } + Controller->IRQ_Channel = IRQ_Channel; + Controller->InitialCommand.CommandIdentifier = 1; + Controller->InitialCommand.Controller = Controller; + Controller->Commands[0] = &Controller->InitialCommand; + Controller->FreeCommands = &Controller->InitialCommand; + return Controller; + +Failure: + if (Controller->IO_Address == 0) DAC960_Error("PCI Bus %d Device %d Function %d I/O Address N/A " "PCI Address 0x%X\n", Controller, - Bus, Device, Function, PCI_Address); - else DAC960_Error("PCI Bus %d Device %d Function %d I/O Address " + Controller->Bus, Controller->Device, + Controller->Function, Controller->PCI_Address); + else + DAC960_Error("PCI Bus %d Device %d Function %d I/O Address " "0x%X PCI Address 0x%X\n", Controller, - Bus, Device, Function, IO_Address, PCI_Address); - if (Controller == NULL) break; - if (Controller->MemoryMappedAddress != NULL) - iounmap(Controller->MemoryMappedAddress); - if (Controller->IRQ_Channel > 0) - free_irq(IRQ_Channel, Controller); - } - return; -Enomem: - while (i--) - put_disk(Controller->disks[i]); - kfree(Controller); - goto Failure; -} - - -/* - DAC960_SortControllers sorts the Controllers by PCI Bus and Device Number. -*/ - -static void DAC960_SortControllers(void) -{ - int ControllerNumber, LastInterchange, Bound, j; - LastInterchange = DAC960_ControllerCount-1; - while (LastInterchange > 0) - { - Bound = LastInterchange; - LastInterchange = 0; - for (j = 0; j < Bound; j++) - { - DAC960_Controller_T *Controller1 = DAC960_Controllers[j]; - DAC960_Controller_T *Controller2 = DAC960_Controllers[j+1]; - if (Controller1->Bus > Controller2->Bus || - (Controller1->Bus == Controller2->Bus && - (Controller1->Device > Controller2->Device))) - { - Controller2->ControllerNumber = j; - DAC960_Controllers[j] = Controller2; - Controller1->ControllerNumber = j+1; - DAC960_Controllers[j+1] = Controller1; - LastInterchange = j; - } - } - } - for (ControllerNumber = 0; - ControllerNumber < DAC960_ControllerCount; - ControllerNumber++) - { - DAC960_Controller_T *Controller = DAC960_Controllers[ControllerNumber]; - if (!Controller->ControllerDetectionSuccessful) - { - int i; - DAC960_Controllers[ControllerNumber] = NULL; - for (i = 0; i < DAC960_MaxLogicalDrives; i++) - put_disk(Controller->disks[i]); - kfree(Controller); - } - } + Controller->Bus, Controller->Device, + Controller->Function, Controller->IO_Address, + Controller->PCI_Address); + DAC960_DetectCleanup(Controller); + DAC960_ControllerCount--; + return NULL; } - /* DAC960_InitializeController initializes Controller. */ -static void DAC960_InitializeController(DAC960_Controller_T *Controller) +static boolean +DAC960_InitializeController(DAC960_Controller_T *Controller) { if (DAC960_ReadControllerConfiguration(Controller) && DAC960_ReportControllerConfiguration(Controller) && @@ -2536,8 +2924,9 @@ Controller->MonitoringTimer.function = DAC960_MonitoringTimerFunction; add_timer(&Controller->MonitoringTimer); Controller->ControllerInitialized = true; + return true; } - else DAC960_FinalizeController(Controller); + return false; } @@ -2547,35 +2936,38 @@ static void DAC960_FinalizeController(DAC960_Controller_T *Controller) { - int i; if (Controller->ControllerInitialized) { - del_timer(&Controller->MonitoringTimer); + unsigned long ProcessorFlags; + + /* + * Acquiring and releasing lock here eliminates + * a very low probability race. + * + * The code below allocates controller command structures + * from the free list without holding the controller lock. + * This is safe assuming there is no other activity on + * the controller at the time. + * + * But, there might be a monitoring command still + * in progress. Setting the Shutdown flag while holding + * the lock ensures that there is no monitoring command + * in the interrupt handler currently, and any monitoring + * commands that complete from this time on will NOT return + * their command structure to the free list. + */ + DAC960_AcquireControllerLock(Controller, &ProcessorFlags); + Controller->ShutdownMonitoringTimer = 1; + DAC960_ReleaseControllerLock(Controller, &ProcessorFlags); + del_timer_sync(&Controller->MonitoringTimer); if (Controller->FirmwareType == DAC960_V1_Controller) { DAC960_Notice("Flushing Cache...", Controller); - DAC960_V1_ExecuteType3(Controller, DAC960_V1_Flush, NULL); + DAC960_V1_ExecuteType3(Controller, DAC960_V1_Flush, 0); DAC960_Notice("done\n", Controller); - switch (Controller->HardwareType) - { - case DAC960_LA_Controller: - if (Controller->V1.DualModeMemoryMailboxInterface) - free_pages(Controller->MemoryMailboxPagesAddress, - Controller->MemoryMailboxPagesOrder); - else DAC960_LA_SaveMemoryMailboxInfo(Controller); - break; - case DAC960_PG_Controller: - if (Controller->V1.DualModeMemoryMailboxInterface) - free_pages(Controller->MemoryMailboxPagesAddress, - Controller->MemoryMailboxPagesOrder); - else DAC960_PG_SaveMemoryMailboxInfo(Controller); - break; - case DAC960_PD_Controller: + + if (Controller->HardwareType == DAC960_PD_Controller) release_region(Controller->IO_Address, 0x80); - break; - default: - break; - } } else { @@ -2583,51 +2975,48 @@ DAC960_V2_DeviceOperation(Controller, DAC960_V2_PauseDevice, DAC960_V2_RAID_Controller); DAC960_Notice("done\n", Controller); - free_pages(Controller->MemoryMailboxPagesAddress, - Controller->MemoryMailboxPagesOrder); } } - free_irq(Controller->IRQ_Channel, Controller); - iounmap(Controller->MemoryMappedAddress); DAC960_UnregisterBlockDevice(Controller); DAC960_DestroyAuxiliaryStructures(Controller); - DAC960_Controllers[Controller->ControllerNumber] = NULL; - for (i = 0; i < DAC960_MaxLogicalDrives; i++) - put_disk(Controller->disks[i]); - kfree(Controller); + DAC960_DestroyProcEntries(Controller); + DAC960_DetectCleanup(Controller); } /* - DAC960_Initialize initializes the DAC960 Driver. + DAC960_Probe verifies controller's existence and + initializes the DAC960 Driver for that controller. */ -static int DAC960_Initialize(void) +static int +DAC960_Probe(struct pci_dev *dev, const struct pci_device_id *entry) { - int ControllerNumber; - DAC960_DetectControllers(DAC960_BA_Controller); - DAC960_DetectControllers(DAC960_LP_Controller); - DAC960_DetectControllers(DAC960_LA_Controller); - DAC960_DetectControllers(DAC960_PG_Controller); - DAC960_DetectControllers(DAC960_PD_Controller); - DAC960_DetectControllers(DAC960_P_Controller); - DAC960_SortControllers(); - if (DAC960_ActiveControllerCount == 0) return -ENODEV; - for (ControllerNumber = 0; - ControllerNumber < DAC960_ControllerCount; - ControllerNumber++) - { - DAC960_Controller_T *Controller = DAC960_Controllers[ControllerNumber]; - int disk; - if (Controller == NULL) continue; - DAC960_InitializeController(Controller); - for (disk = 0; disk < DAC960_MaxLogicalDrives; disk++) { - set_capacity(Controller->disks[disk], disk_size(Controller, disk)); - add_disk(Controller->disks[disk]); - } - } - DAC960_CreateProcEntries(); - register_reboot_notifier(&DAC960_NotifierBlock); + int disk; + DAC960_Controller_T *Controller; + + if (DAC960_ControllerCount == DAC960_MaxControllers) + { + DAC960_Error("More than %d DAC960 Controllers detected - " + "ignoring from Controller at\n", + NULL, DAC960_MaxControllers); + return -ENODEV; + } + + Controller = DAC960_DetectController(dev, entry); + if (!Controller) + return -ENODEV; + + if (!DAC960_InitializeController(Controller)) { + DAC960_FinalizeController(Controller); + return -ENODEV; + } + + for (disk = 0; disk < DAC960_MaxLogicalDrives; disk++) { + set_capacity(Controller->disks[disk], disk_size(Controller, disk)); + add_disk(Controller->disks[disk]); + } + DAC960_CreateProcEntries(Controller); return 0; } @@ -2636,32 +3025,12 @@ DAC960_Finalize finalizes the DAC960 Driver. */ -static void DAC960_Finalize(void) -{ - int ControllerNumber; - if (DAC960_ActiveControllerCount == 0) return; - for (ControllerNumber = 0; - ControllerNumber < DAC960_ControllerCount; - ControllerNumber++) - if (DAC960_Controllers[ControllerNumber] != NULL) - DAC960_FinalizeController(DAC960_Controllers[ControllerNumber]); - DAC960_DestroyProcEntries(); - unregister_reboot_notifier(&DAC960_NotifierBlock); -} - - -/* - DAC960_Notifier is the notifier for the DAC960 Driver. -*/ - -static int DAC960_Notifier(NotifierBlock_T *NotifierBlock, - unsigned long Event, - void *Buffer) +static void DAC960_Remove(PCI_Device_T *PCI_Device) { - if (!(Event == SYS_RESTART || Event == SYS_HALT || Event == SYS_POWER_OFF)) - return NOTIFY_DONE; - DAC960_Finalize(); - return NOTIFY_OK; + int Controller_Number = (int)pci_get_drvdata(PCI_Device); + DAC960_Controller_T *Controller = DAC960_Controllers[Controller_Number]; + if (Controller != NULL) + DAC960_FinalizeController(Controller); } @@ -2674,57 +3043,60 @@ { DAC960_Controller_T *Controller = Command->Controller; DAC960_V1_CommandMailbox_T *CommandMailbox = &Command->V1.CommandMailbox; + DAC960_V1_ScatterGatherSegment_T *ScatterGatherList = + Command->V1.ScatterGatherList; + struct scatterlist *ScatterList = Command->V1.ScatterList; + int DmaDirection, SegCount; + DAC960_V1_ClearCommand(Command); - if (Command->SegmentCount == 1) + + if (Command->CommandType == DAC960_ReadCommand) + DmaDirection = PCI_DMA_FROMDEVICE; + else + DmaDirection = PCI_DMA_TODEVICE; + + SegCount = blk_rq_map_sg(&Controller->RequestQueue, Command->Request, + ScatterList); + /* pci_map_sg MAY change the value of SegCount */ + SegCount = pci_map_sg(Command->PciDevice, ScatterList, SegCount, + DmaDirection); + Command->SegmentCount = SegCount; + + if (SegCount == 1) { if (Command->CommandType == DAC960_ReadCommand) CommandMailbox->Type5.CommandOpcode = DAC960_V1_Read; - else CommandMailbox->Type5.CommandOpcode = DAC960_V1_Write; + else + CommandMailbox->Type5.CommandOpcode = DAC960_V1_Write; + CommandMailbox->Type5.LD.TransferLength = Command->BlockCount; CommandMailbox->Type5.LD.LogicalDriveNumber = Command->LogicalDriveNumber; CommandMailbox->Type5.LogicalBlockAddress = Command->BlockNumber; CommandMailbox->Type5.BusAddress = - Virtual_to_Bus32(Command->RequestBuffer); + (DAC960_BusAddress32_T)sg_dma_address(ScatterList); } else { - DAC960_V1_ScatterGatherSegment_T - *ScatterGatherList = Command->V1.ScatterGatherList; - BufferHeader_T *BufferHeader = Command->BufferHeader; - char *LastDataEndPointer = NULL; - int SegmentNumber = 0; + int i; + if (Command->CommandType == DAC960_ReadCommand) CommandMailbox->Type5.CommandOpcode = DAC960_V1_ReadWithScatterGather; else CommandMailbox->Type5.CommandOpcode = DAC960_V1_WriteWithScatterGather; + CommandMailbox->Type5.LD.TransferLength = Command->BlockCount; CommandMailbox->Type5.LD.LogicalDriveNumber = Command->LogicalDriveNumber; CommandMailbox->Type5.LogicalBlockAddress = Command->BlockNumber; - CommandMailbox->Type5.BusAddress = Virtual_to_Bus32(ScatterGatherList); - CommandMailbox->Type5.ScatterGatherCount = Command->SegmentCount; - while (BufferHeader != NULL) - { - if (bio_data(BufferHeader) == LastDataEndPointer) - { - ScatterGatherList[SegmentNumber-1].SegmentByteCount += - BufferHeader->bi_size; - LastDataEndPointer += BufferHeader->bi_size; - } - else - { - ScatterGatherList[SegmentNumber].SegmentDataPointer = - Virtual_to_Bus32(bio_data(BufferHeader)); - ScatterGatherList[SegmentNumber].SegmentByteCount = - BufferHeader->bi_size; - LastDataEndPointer = bio_data(BufferHeader) + - BufferHeader->bi_size; - if (SegmentNumber++ > Controller->DriverScatterGatherLimit) - panic("DAC960: Scatter/Gather Segment Overflow\n"); - } - BufferHeader = BufferHeader->bi_next; - } - if (SegmentNumber != Command->SegmentCount) - panic("DAC960: SegmentNumber != SegmentCount\n"); + CommandMailbox->Type5.BusAddress = Command->V1.ScatterGatherListDMA; + + CommandMailbox->Type5.ScatterGatherCount = SegCount; + + for (i = 0; i < SegCount; i++, ScatterList++, ScatterGatherList++) { + ScatterGatherList->SegmentDataPointer = + (DAC960_BusAddress32_T)sg_dma_address(ScatterList); + ScatterGatherList->SegmentByteCount = + (DAC960_ByteCount32_T)sg_dma_len(ScatterList); + } } DAC960_QueueCommand(Command); } @@ -2739,18 +3111,32 @@ { DAC960_Controller_T *Controller = Command->Controller; DAC960_V2_CommandMailbox_T *CommandMailbox = &Command->V2.CommandMailbox; + struct scatterlist *ScatterList = Command->V2.ScatterList; + int DmaDirection, SegCount; + DAC960_V2_ClearCommand(Command); + + if (Command->CommandType == DAC960_ReadCommand) + DmaDirection = PCI_DMA_FROMDEVICE; + else + DmaDirection = PCI_DMA_TODEVICE; + + SegCount = blk_rq_map_sg(&Controller->RequestQueue, Command->Request, + ScatterList); + /* pci_map_sg MAY change the value of SegCount */ + SegCount = pci_map_sg(Command->PciDevice, ScatterList, SegCount, + DmaDirection); + Command->SegmentCount = SegCount; + CommandMailbox->SCSI_10.CommandOpcode = DAC960_V2_SCSI_10; CommandMailbox->SCSI_10.CommandControlBits.DataTransferControllerToHost = (Command->CommandType == DAC960_ReadCommand); CommandMailbox->SCSI_10.DataTransferSize = Command->BlockCount << DAC960_BlockSizeBits; - CommandMailbox->SCSI_10.RequestSenseBusAddress = - Virtual_to_Bus64(&Command->V2.RequestSense); + CommandMailbox->SCSI_10.RequestSenseBusAddress = Command->V2.RequestSenseDMA; CommandMailbox->SCSI_10.PhysicalDevice = Controller->V2.LogicalDriveToVirtualDevice[Command->LogicalDriveNumber]; - CommandMailbox->SCSI_10.RequestSenseSize = - sizeof(DAC960_SCSI_RequestSense_T); + CommandMailbox->SCSI_10.RequestSenseSize = sizeof(DAC960_SCSI_RequestSense_T); CommandMailbox->SCSI_10.CDBLength = 10; CommandMailbox->SCSI_10.SCSI_CDB[0] = (Command->CommandType == DAC960_ReadCommand ? 0x28 : 0x2A); @@ -2760,12 +3146,13 @@ CommandMailbox->SCSI_10.SCSI_CDB[5] = Command->BlockNumber; CommandMailbox->SCSI_10.SCSI_CDB[7] = Command->BlockCount >> 8; CommandMailbox->SCSI_10.SCSI_CDB[8] = Command->BlockCount; - if (Command->SegmentCount == 1) + + if (SegCount == 1) { CommandMailbox->SCSI_10.DataTransferMemoryAddress .ScatterGatherSegments[0] .SegmentDataPointer = - Virtual_to_Bus64(Command->RequestBuffer); + (DAC960_BusAddress64_T)sg_dma_address(ScatterList); CommandMailbox->SCSI_10.DataTransferMemoryAddress .ScatterGatherSegments[0] .SegmentByteCount = @@ -2773,49 +3160,30 @@ } else { - DAC960_V2_ScatterGatherSegment_T - *ScatterGatherList = Command->V2.ScatterGatherList; - BufferHeader_T *BufferHeader = Command->BufferHeader; - char *LastDataEndPointer = NULL; - int SegmentNumber = 0; - if (Command->SegmentCount > 2) + DAC960_V2_ScatterGatherSegment_T *ScatterGatherList; + int i; + + if (SegCount > 2) { + ScatterGatherList = Command->V2.ScatterGatherList; CommandMailbox->SCSI_10.CommandControlBits .AdditionalScatterGatherListMemory = true; CommandMailbox->SCSI_10.DataTransferMemoryAddress - .ExtendedScatterGather.ScatterGatherList0Length = - Command->SegmentCount; + .ExtendedScatterGather.ScatterGatherList0Length = SegCount; CommandMailbox->SCSI_10.DataTransferMemoryAddress .ExtendedScatterGather.ScatterGatherList0Address = - Virtual_to_Bus64(ScatterGatherList); + Command->V2.ScatterGatherListDMA; } else - ScatterGatherList = - CommandMailbox->SCSI_10.DataTransferMemoryAddress + ScatterGatherList = CommandMailbox->SCSI_10.DataTransferMemoryAddress .ScatterGatherSegments; - while (BufferHeader != NULL) - { - if (bio_data(BufferHeader) == LastDataEndPointer) - { - ScatterGatherList[SegmentNumber-1].SegmentByteCount += - BufferHeader->bi_size; - LastDataEndPointer += BufferHeader->bi_size; - } - else - { - ScatterGatherList[SegmentNumber].SegmentDataPointer = - Virtual_to_Bus64(bio_data(BufferHeader)); - ScatterGatherList[SegmentNumber].SegmentByteCount = - BufferHeader->bi_size; - LastDataEndPointer = bio_data(BufferHeader) + - BufferHeader->bi_size; - if (SegmentNumber++ > Controller->DriverScatterGatherLimit) - panic("DAC960: Scatter/Gather Segment Overflow\n"); - } - BufferHeader = BufferHeader->bi_next; - } - if (SegmentNumber != Command->SegmentCount) - panic("DAC960: SegmentNumber != SegmentCount\n"); + + for (i = 0; i < SegCount; i++, ScatterList++, ScatterGatherList++) { + ScatterGatherList->SegmentDataPointer = + (DAC960_BusAddress64_T)sg_dma_address(ScatterList); + ScatterGatherList->SegmentByteCount = + (DAC960_ByteCount64_T)sg_dma_len(ScatterList); + } } DAC960_QueueCommand(Command); } @@ -2832,32 +3200,36 @@ boolean WaitForCommand) { RequestQueue_T *RequestQueue = &Controller->RequestQueue; - ListHead_T *RequestQueueHead; IO_Request_T *Request; DAC960_Command_T *Command; - if (RequestQueue == NULL) return false; - RequestQueueHead = &RequestQueue->queue_head; - while (true) - { - if (list_empty(RequestQueueHead)) return false; + + if (!Controller->ControllerInitialized) + return false; + + while (true) { + if (blk_queue_empty(RequestQueue)) + return false; + Request = elv_next_request(RequestQueue); Command = DAC960_AllocateCommand(Controller); - if (Command != NULL) break; - if (!WaitForCommand) return false; + if (Command != NULL) + break; + + if (!WaitForCommand) + return false; + DAC960_WaitForCommand(Controller); - } - if (Request->cmd == READ) + } + if (rq_data_dir(Request) == READ) Command->CommandType = DAC960_ReadCommand; - else Command->CommandType = DAC960_WriteCommand; + else + Command->CommandType = DAC960_WriteCommand; Command->Completion = Request->waiting; Command->LogicalDriveNumber = (int)Request->rq_disk->private_data; Command->BlockNumber = Request->sector; Command->BlockCount = Request->nr_sectors; - Command->SegmentCount = Request->nr_phys_segments; - Command->BufferHeader = Request->bio; - Command->RequestBuffer = Request->buffer; + Command->Request = Request; blkdev_dequeue_request(Request); - blk_put_request(Request); DAC960_QueueReadWriteCommand(Command); return true; } @@ -2904,16 +3276,43 @@ individual Buffer. */ -static inline void DAC960_ProcessCompletedBuffer(BufferHeader_T *BufferHeader, +static inline void DAC960_ProcessCompletedRequest(DAC960_Command_T *Command, boolean SuccessfulIO) { - bio_endio(BufferHeader, BufferHeader->bi_size, SuccessfulIO ? 0 : -EIO); - blk_finished_io(bio_sectors(BufferHeader)); -} + DAC960_CommandType_T CommandType = Command->CommandType; + IO_Request_T *Request = Command->Request; + int DmaDirection, UpToDate; + + UpToDate = 0; + if (SuccessfulIO) + UpToDate = 1; + + /* + * We could save DmaDirection in the command structure + * and just reuse that information here. + */ + if (CommandType == DAC960_ReadCommand || + CommandType == DAC960_ReadRetryCommand) + DmaDirection = PCI_DMA_FROMDEVICE; + else + DmaDirection = PCI_DMA_TODEVICE; -static inline int DAC960_PartitionByCommand(DAC960_Command_T *Command) -{ - return DAC960_PartitionNumber(to_kdev_t(Command->BufferHeader->bi_bdev->bd_dev)); + pci_unmap_sg(Command->PciDevice, Command->V1.ScatterList, + Command->SegmentCount, DmaDirection); + /* + * BlockCount is redundant with nr_sectors in the request + * structure. Consider eliminating BlockCount from the + * command structure now that Command includes a pointer to + * the request. + */ + while (end_that_request_first(Request, UpToDate, Command->BlockCount)) + ; + end_that_request_last(Request); + + if (Command->Completion) { + complete(Command->Completion); + Command->Completion = NULL; + } } /* @@ -2966,13 +3365,6 @@ Controller, Controller->ControllerNumber, Command->LogicalDriveNumber, Command->BlockNumber, Command->BlockNumber + Command->BlockCount - 1); - if (DAC960_PartitionByCommand(Command) > 0) - DAC960_Error(" /dev/rd/c%dd%dp%d: relative blocks %u..%u\n", - Controller, Controller->ControllerNumber, - Command->LogicalDriveNumber, - DAC960_PartitionByCommand(Command), - Command->BufferHeader->bi_sector, - Command->BufferHeader->bi_sector + Command->BlockCount - 1); } @@ -2988,129 +3380,60 @@ DAC960_V1_CommandOpcode_T CommandOpcode = Command->V1.CommandMailbox.Common.CommandOpcode; DAC960_V1_CommandStatus_T CommandStatus = Command->V1.CommandStatus; - BufferHeader_T *BufferHeader = Command->BufferHeader; + if (CommandType == DAC960_ReadCommand || CommandType == DAC960_WriteCommand) { if (CommandStatus == DAC960_V1_NormalCompletion) + + DAC960_ProcessCompletedRequest(Command, true); + + else if (CommandStatus == DAC960_V1_IrrecoverableDataError || + CommandStatus == DAC960_V1_BadDataEncountered) { + /* - Perform completion processing for all buffers in this I/O Request. - */ - while (BufferHeader != NULL) - { - BufferHeader_T *NextBufferHeader = BufferHeader->bi_next; - BufferHeader->bi_next = NULL; - DAC960_ProcessCompletedBuffer(BufferHeader, true); - BufferHeader = NextBufferHeader; - } - if (Command->Completion != NULL) - { - complete(Command->Completion); - Command->Completion = NULL; - } - add_disk_randomness(Controller->disks[Command->LogicalDriveNumber]); - } - else if ((CommandStatus == DAC960_V1_IrrecoverableDataError || - CommandStatus == DAC960_V1_BadDataEncountered) && - BufferHeader != NULL && - BufferHeader->bi_next != NULL) - { - DAC960_V1_CommandMailbox_T *CommandMailbox = - &Command->V1.CommandMailbox; - if (CommandType == DAC960_ReadCommand) - { - Command->CommandType = DAC960_ReadRetryCommand; - CommandMailbox->Type5.CommandOpcode = DAC960_V1_Read; - } - else - { - Command->CommandType = DAC960_WriteRetryCommand; - CommandMailbox->Type5.CommandOpcode = DAC960_V1_Write; - } - Command->BlockCount = BufferHeader->bi_size >> DAC960_BlockSizeBits; - CommandMailbox->Type5.LD.TransferLength = Command->BlockCount; - CommandMailbox->Type5.BusAddress = - Virtual_to_Bus32(bio_data(BufferHeader)); - DAC960_QueueCommand(Command); - return; + * Finish this later. + * + * We should call "complete_that_request_first()" + * to remove the first part of the request. Then, if there + * is still more I/O to be done, resubmit the request. + * + * We want to recalculate scatter/gather list, + * and requeue the command. + * + * For now, print a message on the console, and clone + * the code for "normal" completion. + */ + printk("V1_ProcessCompletedCommand: I/O error on read/write\n"); + + DAC960_ProcessCompletedRequest(Command, false); } else { if (CommandStatus != DAC960_V1_LogicalDriveNonexistentOrOffline) DAC960_V1_ReadWriteError(Command); - /* - Perform completion processing for all buffers in this I/O Request. - */ - while (BufferHeader != NULL) - { - BufferHeader_T *NextBufferHeader = BufferHeader->bi_next; - BufferHeader->bi_next = NULL; - DAC960_ProcessCompletedBuffer(BufferHeader, false); - BufferHeader = NextBufferHeader; - } - if (Command->Completion != NULL) - { - complete(Command->Completion); - Command->Completion = NULL; - } + + DAC960_ProcessCompletedRequest(Command, false); } } else if (CommandType == DAC960_ReadRetryCommand || CommandType == DAC960_WriteRetryCommand) { - BufferHeader_T *NextBufferHeader = BufferHeader->bi_next; - BufferHeader->bi_next = NULL; - /* - Perform completion processing for this single buffer. - */ - if (CommandStatus == DAC960_V1_NormalCompletion) - DAC960_ProcessCompletedBuffer(BufferHeader, true); - else - { - if (CommandStatus != DAC960_V1_LogicalDriveNonexistentOrOffline) - DAC960_V1_ReadWriteError(Command); - DAC960_ProcessCompletedBuffer(BufferHeader, false); - } - if (NextBufferHeader != NULL) - { - DAC960_V1_CommandMailbox_T *CommandMailbox = - &Command->V1.CommandMailbox; - Command->BlockNumber += - BufferHeader->bi_size >> DAC960_BlockSizeBits; - Command->BlockCount = - NextBufferHeader->bi_size >> DAC960_BlockSizeBits; - Command->BufferHeader = NextBufferHeader; - CommandMailbox->Type5.LD.TransferLength = Command->BlockCount; - CommandMailbox->Type5.LogicalBlockAddress = Command->BlockNumber; - CommandMailbox->Type5.BusAddress = - Virtual_to_Bus32(bio_data(NextBufferHeader)); - DAC960_QueueCommand(Command); - return; - } + /* + * We're not doing retry commands yet. + */ + printk("DAC960_ProcessCompletedCommand: RetryCommand not done yet\n"); } - else if (CommandType == DAC960_MonitoringCommand || - CommandOpcode == DAC960_V1_Enquiry || - CommandOpcode == DAC960_V1_GetRebuildProgress) - { - if (CommandType != DAC960_MonitoringCommand) - { - if (CommandOpcode == DAC960_V1_Enquiry) - memcpy(&Controller->V1.NewEnquiry, - Bus32_to_Virtual(Command->V1.CommandMailbox - .Type3.BusAddress), - sizeof(DAC960_V1_Enquiry_T)); - else if (CommandOpcode == DAC960_V1_GetRebuildProgress) - memcpy(&Controller->V1.RebuildProgress, - Bus32_to_Virtual(Command->V1.CommandMailbox - .Type3.BusAddress), - sizeof(DAC960_V1_RebuildProgress_T)); - } - if (CommandOpcode == DAC960_V1_Enquiry && - Controller->ControllerInitialized) + + else if (CommandType == DAC960_MonitoringCommand) + { + if (Controller->ShutdownMonitoringTimer) + return; + if (CommandOpcode == DAC960_V1_Enquiry) { DAC960_V1_Enquiry_T *OldEnquiry = &Controller->V1.Enquiry; - DAC960_V1_Enquiry_T *NewEnquiry = &Controller->V1.NewEnquiry; + DAC960_V1_Enquiry_T *NewEnquiry = Controller->V1.NewEnquiry; unsigned int OldCriticalLogicalDriveCount = OldEnquiry->CriticalLogicalDriveCount; unsigned int NewCriticalLogicalDriveCount = @@ -3220,17 +3543,7 @@ (NewEnquiry->CriticalLogicalDriveCount > 0 || NewEnquiry->OfflineLogicalDriveCount > 0 || NewEnquiry->DeadDriveCount > 0); - if (CommandType != DAC960_MonitoringCommand && - Controller->V1.RebuildFlagPending) - { - DAC960_V1_Enquiry_T *Enquiry = (DAC960_V1_Enquiry_T *) - Bus32_to_Virtual(Command->V1.CommandMailbox.Type3.BusAddress); - Enquiry->RebuildFlag = Controller->V1.PendingRebuildFlag; - Controller->V1.RebuildFlagPending = false; - } - else if (CommandType == DAC960_MonitoringCommand && - NewEnquiry->RebuildFlag > - DAC960_V1_BackgroundCheckInProgress) + if (NewEnquiry->RebuildFlag > DAC960_V1_BackgroundCheckInProgress) { Controller->V1.PendingRebuildFlag = NewEnquiry->RebuildFlag; Controller->V1.RebuildFlagPending = true; @@ -3256,7 +3569,7 @@ "killed due to SCSI phase sequence error", "killed due to unknown status" }; DAC960_V1_EventLogEntry_T *EventLogEntry = - &Controller->V1.EventLogEntry; + Controller->V1.EventLogEntry; if (EventLogEntry->SequenceNumber == Controller->V1.OldEventLogSequenceNumber) { @@ -3316,7 +3629,7 @@ else if (CommandOpcode == DAC960_V1_GetErrorTable) { DAC960_V1_ErrorTable_T *OldErrorTable = &Controller->V1.ErrorTable; - DAC960_V1_ErrorTable_T *NewErrorTable = &Controller->V1.NewErrorTable; + DAC960_V1_ErrorTable_T *NewErrorTable = Controller->V1.NewErrorTable; int Channel, TargetID; for (Channel = 0; Channel < Controller->Channels; Channel++) for (TargetID = 0; TargetID < Controller->Targets; TargetID++) @@ -3342,7 +3655,7 @@ NewErrorEntry->HardErrorCount, NewErrorEntry->MiscErrorCount); } - memcpy(&Controller->V1.ErrorTable, &Controller->V1.NewErrorTable, + memcpy(&Controller->V1.ErrorTable, Controller->V1.NewErrorTable, sizeof(DAC960_V1_ErrorTable_T)); } else if (CommandOpcode == DAC960_V1_GetDeviceState) @@ -3351,7 +3664,7 @@ &Controller->V1.DeviceState[Controller->V1.DeviceStateChannel] [Controller->V1.DeviceStateTargetID]; DAC960_V1_DeviceState_T *NewDeviceState = - &Controller->V1.NewDeviceState; + Controller->V1.NewDeviceState; if (NewDeviceState->DeviceState != OldDeviceState->DeviceState) DAC960_Critical("Physical Device %d:%d is now %s\n", Controller, Controller->V1.DeviceStateChannel, @@ -3387,7 +3700,7 @@ DAC960_V1_LogicalDriveInformation_T *OldLogicalDriveInformation = &Controller->V1.LogicalDriveInformation[LogicalDriveNumber]; DAC960_V1_LogicalDriveInformation_T *NewLogicalDriveInformation = - &Controller->V1.NewLogicalDriveInformation[LogicalDriveNumber]; + &(*Controller->V1.NewLogicalDriveInformation)[LogicalDriveNumber]; if (NewLogicalDriveInformation->LogicalDriveState != OldLogicalDriveInformation->LogicalDriveState) DAC960_Critical("Logical Drive %d (/dev/rd/c%dd%d) " @@ -3412,17 +3725,17 @@ ? "WRITE BACK" : "WRITE THRU")); } memcpy(&Controller->V1.LogicalDriveInformation, - &Controller->V1.NewLogicalDriveInformation, + Controller->V1.NewLogicalDriveInformation, sizeof(DAC960_V1_LogicalDriveInformationArray_T)); } else if (CommandOpcode == DAC960_V1_GetRebuildProgress) { unsigned int LogicalDriveNumber = - Controller->V1.RebuildProgress.LogicalDriveNumber; + Controller->V1.RebuildProgress->LogicalDriveNumber; unsigned int LogicalDriveSize = - Controller->V1.RebuildProgress.LogicalDriveSize; + Controller->V1.RebuildProgress->LogicalDriveSize; unsigned int BlocksCompleted = - LogicalDriveSize - Controller->V1.RebuildProgress.RemainingBlocks; + LogicalDriveSize - Controller->V1.RebuildProgress->RemainingBlocks; if (CommandStatus == DAC960_V1_NoRebuildOrCheckInProgress && Controller->V1.LastRebuildStatus == DAC960_V1_NormalCompletion) CommandStatus = DAC960_V1_RebuildSuccessful; @@ -3479,11 +3792,11 @@ else if (CommandOpcode == DAC960_V1_RebuildStat) { unsigned int LogicalDriveNumber = - Controller->V1.RebuildProgress.LogicalDriveNumber; + Controller->V1.RebuildProgress->LogicalDriveNumber; unsigned int LogicalDriveSize = - Controller->V1.RebuildProgress.LogicalDriveSize; + Controller->V1.RebuildProgress->LogicalDriveSize; unsigned int BlocksCompleted = - LogicalDriveSize - Controller->V1.RebuildProgress.RemainingBlocks; + LogicalDriveSize - Controller->V1.RebuildProgress->RemainingBlocks; if (CommandStatus == DAC960_V1_NormalCompletion) { Controller->EphemeralProgressMessage = true; @@ -3501,15 +3814,15 @@ else if (CommandOpcode == DAC960_V1_BackgroundInitializationControl) { unsigned int LogicalDriveNumber = - Controller->V1.BackgroundInitializationStatus.LogicalDriveNumber; + Controller->V1.BackgroundInitializationStatus->LogicalDriveNumber; unsigned int LogicalDriveSize = - Controller->V1.BackgroundInitializationStatus.LogicalDriveSize; + Controller->V1.BackgroundInitializationStatus->LogicalDriveSize; unsigned int BlocksCompleted = - Controller->V1.BackgroundInitializationStatus.BlocksCompleted; + Controller->V1.BackgroundInitializationStatus->BlocksCompleted; switch (CommandStatus) { case DAC960_V1_NormalCompletion: - switch (Controller->V1.BackgroundInitializationStatus.Status) + switch (Controller->V1.BackgroundInitializationStatus->Status) { case DAC960_V1_BackgroundInitializationInvalid: break; @@ -3519,11 +3832,11 @@ break; case DAC960_V1_BackgroundInitializationInProgress: if (BlocksCompleted == - Controller->V1.LastBackgroundInitializationStatus - .BlocksCompleted && + Controller->V1.LastBackgroundInitializationStatus. + BlocksCompleted && LogicalDriveNumber == - Controller->V1.LastBackgroundInitializationStatus - .LogicalDriveNumber) + Controller->V1.LastBackgroundInitializationStatus. + LogicalDriveNumber) break; Controller->EphemeralProgressMessage = true; DAC960_Progress("Background Initialization in Progress: " @@ -3546,32 +3859,84 @@ break; } memcpy(&Controller->V1.LastBackgroundInitializationStatus, - &Controller->V1.BackgroundInitializationStatus, + Controller->V1.BackgroundInitializationStatus, sizeof(DAC960_V1_BackgroundInitializationStatus_T)); break; case DAC960_V1_BackgroundInitSuccessful: - if (Controller->V1.BackgroundInitializationStatus.Status == + if (Controller->V1.BackgroundInitializationStatus->Status == DAC960_V1_BackgroundInitializationInProgress) DAC960_Progress("Background Initialization " "Completed Successfully\n", Controller); - Controller->V1.BackgroundInitializationStatus.Status = + Controller->V1.BackgroundInitializationStatus->Status = DAC960_V1_BackgroundInitializationInvalid; break; case DAC960_V1_BackgroundInitAborted: - if (Controller->V1.BackgroundInitializationStatus.Status == + if (Controller->V1.BackgroundInitializationStatus->Status == DAC960_V1_BackgroundInitializationInProgress) DAC960_Progress("Background Initialization Aborted\n", Controller); - Controller->V1.BackgroundInitializationStatus.Status = + Controller->V1.BackgroundInitializationStatus->Status = DAC960_V1_BackgroundInitializationInvalid; break; case DAC960_V1_NoBackgroundInitInProgress: break; } + } + else if (CommandOpcode == DAC960_V1_DCDB) + { + /* + This is a bit ugly. + + The InquiryStandardData and + the InquiryUntitSerialNumber information + retrieval operations BOTH use the DAC960_V1_DCDB + commands. the test above can't distinguish between + these two cases. + + Instead, we rely on the order of code later in this + function to ensure that DeviceInquiryInformation commands + are submitted before DeviceSerialNumber commands. + */ + if (Controller->V1.NeedDeviceInquiryInformation) + { + DAC960_SCSI_Inquiry_T *InquiryStandardData = + &Controller->V1.InquiryStandardData + [Controller->V1.DeviceStateChannel] + [Controller->V1.DeviceStateTargetID]; + if (CommandStatus != DAC960_V1_NormalCompletion) + { + memset(InquiryStandardData, 0, + sizeof(DAC960_SCSI_Inquiry_T)); + InquiryStandardData->PeripheralDeviceType = 0x1F; + } + else + memcpy(InquiryStandardData, + Controller->V1.NewInquiryStandardData, + sizeof(DAC960_SCSI_Inquiry_T)); + Controller->V1.NeedDeviceInquiryInformation = false; + } + else if (Controller->V1.NeedDeviceSerialNumberInformation) + { + DAC960_SCSI_Inquiry_UnitSerialNumber_T *InquiryUnitSerialNumber = + &Controller->V1.InquiryUnitSerialNumber + [Controller->V1.DeviceStateChannel] + [Controller->V1.DeviceStateTargetID]; + if (CommandStatus != DAC960_V1_NormalCompletion) + { + memset(InquiryUnitSerialNumber, 0, + sizeof(DAC960_SCSI_Inquiry_UnitSerialNumber_T)); + InquiryUnitSerialNumber->PeripheralDeviceType = 0x1F; + } + else + memcpy(InquiryUnitSerialNumber, + Controller->V1.NewInquiryUnitSerialNumber, + sizeof(DAC960_SCSI_Inquiry_UnitSerialNumber_T)); + Controller->V1.NeedDeviceSerialNumberInformation = false; + } } - } - if (CommandType == DAC960_MonitoringCommand) - { + /* + Begin submitting new monitoring commands. + */ if (Controller->V1.NewEventLogSequenceNumber - Controller->V1.OldEventLogSequenceNumber > 0) { @@ -3583,7 +3948,7 @@ Command->V1.CommandMailbox.Type3E.SequenceNumber = Controller->V1.OldEventLogSequenceNumber; Command->V1.CommandMailbox.Type3E.BusAddress = - Virtual_to_Bus32(&Controller->V1.EventLogEntry); + Controller->V1.EventLogEntryDMA; DAC960_QueueCommand(Command); return; } @@ -3593,7 +3958,7 @@ Command->V1.CommandMailbox.Type3.CommandOpcode = DAC960_V1_GetErrorTable; Command->V1.CommandMailbox.Type3.BusAddress = - Virtual_to_Bus32(&Controller->V1.NewErrorTable); + Controller->V1.NewErrorTableDMA; DAC960_QueueCommand(Command); return; } @@ -3604,7 +3969,7 @@ Command->V1.CommandMailbox.Type3.CommandOpcode = DAC960_V1_GetRebuildProgress; Command->V1.CommandMailbox.Type3.BusAddress = - Virtual_to_Bus32(&Controller->V1.RebuildProgress); + Controller->V1.RebuildProgressDMA; DAC960_QueueCommand(Command); return; } @@ -3612,15 +3977,14 @@ { if (Controller->V1.NeedDeviceInquiryInformation) { - DAC960_V1_DCDB_T *DCDB = &Controller->V1.MonitoringDCDB; - DAC960_SCSI_Inquiry_T *InquiryStandardData = - &Controller->V1.InquiryStandardData - [Controller->V1.DeviceStateChannel] - [Controller->V1.DeviceStateTargetID]; - InquiryStandardData->PeripheralDeviceType = 0x1F; + DAC960_V1_DCDB_T *DCDB = Controller->V1.MonitoringDCDB; + dma_addr_t DCDB_DMA = Controller->V1.MonitoringDCDB_DMA; + + dma_addr_t NewInquiryStandardDataDMA = + Controller->V1.NewInquiryStandardDataDMA; + Command->V1.CommandMailbox.Type3.CommandOpcode = DAC960_V1_DCDB; - Command->V1.CommandMailbox.Type3.BusAddress = - Virtual_to_Bus32(DCDB); + Command->V1.CommandMailbox.Type3.BusAddress = DCDB_DMA; DCDB->Channel = Controller->V1.DeviceStateChannel; DCDB->TargetID = Controller->V1.DeviceStateTargetID; DCDB->Direction = DAC960_V1_DCDB_DataTransferDeviceToSystem; @@ -3629,7 +3993,7 @@ DCDB->NoAutomaticRequestSense = false; DCDB->DisconnectPermitted = true; DCDB->TransferLength = sizeof(DAC960_SCSI_Inquiry_T); - DCDB->BusAddress = Virtual_to_Bus32(InquiryStandardData); + DCDB->BusAddress = NewInquiryStandardDataDMA; DCDB->CDBLength = 6; DCDB->TransferLengthHigh4 = 0; DCDB->SenseLength = sizeof(DCDB->SenseData); @@ -3640,20 +4004,17 @@ DCDB->CDB[4] = sizeof(DAC960_SCSI_Inquiry_T); DCDB->CDB[5] = 0; /* Control */ DAC960_QueueCommand(Command); - Controller->V1.NeedDeviceInquiryInformation = false; return; } if (Controller->V1.NeedDeviceSerialNumberInformation) { - DAC960_V1_DCDB_T *DCDB = &Controller->V1.MonitoringDCDB; - DAC960_SCSI_Inquiry_UnitSerialNumber_T *InquiryUnitSerialNumber = - &Controller->V1.InquiryUnitSerialNumber - [Controller->V1.DeviceStateChannel] - [Controller->V1.DeviceStateTargetID]; - InquiryUnitSerialNumber->PeripheralDeviceType = 0x1F; + DAC960_V1_DCDB_T *DCDB = Controller->V1.MonitoringDCDB; + dma_addr_t DCDB_DMA = Controller->V1.MonitoringDCDB_DMA; + dma_addr_t NewInquiryUnitSerialNumberDMA = + Controller->V1.NewInquiryUnitSerialNumberDMA; + Command->V1.CommandMailbox.Type3.CommandOpcode = DAC960_V1_DCDB; - Command->V1.CommandMailbox.Type3.BusAddress = - Virtual_to_Bus32(DCDB); + Command->V1.CommandMailbox.Type3.BusAddress = DCDB_DMA; DCDB->Channel = Controller->V1.DeviceStateChannel; DCDB->TargetID = Controller->V1.DeviceStateTargetID; DCDB->Direction = DAC960_V1_DCDB_DataTransferDeviceToSystem; @@ -3663,7 +4024,7 @@ DCDB->DisconnectPermitted = true; DCDB->TransferLength = sizeof(DAC960_SCSI_Inquiry_UnitSerialNumber_T); - DCDB->BusAddress = Virtual_to_Bus32(InquiryUnitSerialNumber); + DCDB->BusAddress = NewInquiryUnitSerialNumberDMA; DCDB->CDBLength = 6; DCDB->TransferLengthHigh4 = 0; DCDB->SenseLength = sizeof(DCDB->SenseData); @@ -3674,7 +4035,6 @@ DCDB->CDB[4] = sizeof(DAC960_SCSI_Inquiry_UnitSerialNumber_T); DCDB->CDB[5] = 0; /* Control */ DAC960_QueueCommand(Command); - Controller->V1.NeedDeviceSerialNumberInformation = false; return; } if (Controller->V1.StartDeviceStateScan) @@ -3690,7 +4050,7 @@ } if (Controller->V1.DeviceStateChannel < Controller->Channels) { - Controller->V1.NewDeviceState.DeviceState = + Controller->V1.NewDeviceState->DeviceState = DAC960_V1_Device_Dead; Command->V1.CommandMailbox.Type3D.CommandOpcode = DAC960_V1_GetDeviceState; @@ -3699,7 +4059,7 @@ Command->V1.CommandMailbox.Type3D.TargetID = Controller->V1.DeviceStateTargetID; Command->V1.CommandMailbox.Type3D.BusAddress = - Virtual_to_Bus32(&Controller->V1.NewDeviceState); + Controller->V1.NewDeviceStateDMA; DAC960_QueueCommand(Command); return; } @@ -3711,7 +4071,7 @@ Command->V1.CommandMailbox.Type3.CommandOpcode = DAC960_V1_GetLogicalDriveInformation; Command->V1.CommandMailbox.Type3.BusAddress = - Virtual_to_Bus32(&Controller->V1.NewLogicalDriveInformation); + Controller->V1.NewLogicalDriveInformationDMA; DAC960_QueueCommand(Command); return; } @@ -3721,7 +4081,7 @@ Command->V1.CommandMailbox.Type3.CommandOpcode = DAC960_V1_GetRebuildProgress; Command->V1.CommandMailbox.Type3.BusAddress = - Virtual_to_Bus32(&Controller->V1.RebuildProgress); + Controller->V1.RebuildProgressDMA; DAC960_QueueCommand(Command); return; } @@ -3731,7 +4091,7 @@ Command->V1.CommandMailbox.Type3.CommandOpcode = DAC960_V1_RebuildStat; Command->V1.CommandMailbox.Type3.BusAddress = - Virtual_to_Bus32(&Controller->V1.RebuildProgress); + Controller->V1.RebuildProgressDMA; DAC960_QueueCommand(Command); return; } @@ -3742,14 +4102,14 @@ DAC960_V1_BackgroundInitializationControl; Command->V1.CommandMailbox.Type3B.CommandOpcode2 = 0x20; Command->V1.CommandMailbox.Type3B.BusAddress = - Virtual_to_Bus32(&Controller->V1.BackgroundInitializationStatus); + Controller->V1.BackgroundInitializationStatusDMA; DAC960_QueueCommand(Command); return; } Controller->MonitoringTimerCount++; Controller->MonitoringTimer.expires = jiffies + DAC960_MonitoringTimerInterval; - add_timer(&Controller->MonitoringTimer); + add_timer(&Controller->MonitoringTimer); } if (CommandType == DAC960_ImmediateCommand) { @@ -3825,18 +4185,11 @@ break; } DAC960_Error("Error Condition %s on %s:\n", Controller, - SenseErrors[Command->V2.RequestSense.SenseKey], CommandName); + SenseErrors[Command->V2.RequestSense->SenseKey], CommandName); DAC960_Error(" /dev/rd/c%dd%d: absolute blocks %u..%u\n", Controller, Controller->ControllerNumber, Command->LogicalDriveNumber, Command->BlockNumber, Command->BlockNumber + Command->BlockCount - 1); - if (DAC960_PartitionByCommand(Command) > 0) - DAC960_Error(" /dev/rd/c%dd%dp%d: relative blocks %u..%u\n", - Controller, Controller->ControllerNumber, - Command->LogicalDriveNumber, - DAC960_PartitionByCommand(Command), - Command->BufferHeader->bi_sector, - Command->BufferHeader->bi_sector + Command->BlockCount - 1); } @@ -4094,123 +4447,51 @@ DAC960_V2_CommandMailbox_T *CommandMailbox = &Command->V2.CommandMailbox; DAC960_V2_IOCTL_Opcode_T CommandOpcode = CommandMailbox->Common.IOCTL_Opcode; DAC960_V2_CommandStatus_T CommandStatus = Command->V2.CommandStatus; - BufferHeader_T *BufferHeader = Command->BufferHeader; + if (CommandType == DAC960_ReadCommand || CommandType == DAC960_WriteCommand) { if (CommandStatus == DAC960_V2_NormalCompletion) + + DAC960_ProcessCompletedRequest(Command, true); + + else if (Command->V2.RequestSense->SenseKey == DAC960_SenseKey_MediumError) { + /* - Perform completion processing for all buffers in this I/O Request. - */ - while (BufferHeader != NULL) - { - BufferHeader_T *NextBufferHeader = BufferHeader->bi_next; - BufferHeader->bi_next = NULL; - DAC960_ProcessCompletedBuffer(BufferHeader, true); - BufferHeader = NextBufferHeader; - } - if (Command->Completion != NULL) - { - complete(Command->Completion); - Command->Completion = NULL; - } - add_disk_randomness(Controller->disks[Command->LogicalDriveNumber]); - } - else if (Command->V2.RequestSense.SenseKey - == DAC960_SenseKey_MediumError && - BufferHeader != NULL && - BufferHeader->bi_next != NULL) - { - if (CommandType == DAC960_ReadCommand) - Command->CommandType = DAC960_ReadRetryCommand; - else Command->CommandType = DAC960_WriteRetryCommand; - Command->BlockCount = BufferHeader->bi_size >> DAC960_BlockSizeBits; - CommandMailbox->SCSI_10.CommandControlBits - .AdditionalScatterGatherListMemory = false; - CommandMailbox->SCSI_10.DataTransferSize = - Command->BlockCount << DAC960_BlockSizeBits; - CommandMailbox->SCSI_10.DataTransferMemoryAddress - .ScatterGatherSegments[0].SegmentDataPointer = - Virtual_to_Bus64(bio_data(BufferHeader)); - CommandMailbox->SCSI_10.DataTransferMemoryAddress - .ScatterGatherSegments[0].SegmentByteCount = - CommandMailbox->SCSI_10.DataTransferSize; - CommandMailbox->SCSI_10.SCSI_CDB[7] = Command->BlockCount >> 8; - CommandMailbox->SCSI_10.SCSI_CDB[8] = Command->BlockCount; - DAC960_QueueCommand(Command); - return; + * Don't know yet how to handle this case. + * See comments in DAC960_V1_ProcessCompletedCommand() + * + * For now, print a message on the console, and clone + * the code for "normal" completion. + */ + printk("V1_ProcessCompletedCommand: I/O error on read/write\n"); + + DAC960_ProcessCompletedRequest(Command, false); } else { - if (Command->V2.RequestSense.SenseKey != DAC960_SenseKey_NotReady) + if (Command->V2.RequestSense->SenseKey != DAC960_SenseKey_NotReady) DAC960_V2_ReadWriteError(Command); /* Perform completion processing for all buffers in this I/O Request. */ - while (BufferHeader != NULL) - { - BufferHeader_T *NextBufferHeader = BufferHeader->bi_next; - BufferHeader->bi_next = NULL; - DAC960_ProcessCompletedBuffer(BufferHeader, false); - BufferHeader = NextBufferHeader; - } - if (Command->Completion != NULL) - { - complete(Command->Completion); - Command->Completion = NULL; - } + DAC960_ProcessCompletedRequest(Command, false); } } else if (CommandType == DAC960_ReadRetryCommand || CommandType == DAC960_WriteRetryCommand) { - BufferHeader_T *NextBufferHeader = BufferHeader->bi_next; - BufferHeader->bi_next = NULL; - /* - Perform completion processing for this single buffer. - */ - if (CommandStatus == DAC960_V2_NormalCompletion) - DAC960_ProcessCompletedBuffer(BufferHeader, true); - else - { - if (Command->V2.RequestSense.SenseKey != DAC960_SenseKey_NotReady) - DAC960_V2_ReadWriteError(Command); - DAC960_ProcessCompletedBuffer(BufferHeader, false); - } - if (NextBufferHeader != NULL) - { - Command->BlockNumber += - BufferHeader->bi_size >> DAC960_BlockSizeBits; - Command->BlockCount = - NextBufferHeader->bi_size >> DAC960_BlockSizeBits; - Command->BufferHeader = NextBufferHeader; - CommandMailbox->SCSI_10.DataTransferSize = - Command->BlockCount << DAC960_BlockSizeBits; - CommandMailbox->SCSI_10.DataTransferMemoryAddress - .ScatterGatherSegments[0] - .SegmentDataPointer = - Virtual_to_Bus64(bio_data(NextBufferHeader)); - CommandMailbox->SCSI_10.DataTransferMemoryAddress - .ScatterGatherSegments[0] - .SegmentByteCount = - CommandMailbox->SCSI_10.DataTransferSize; - CommandMailbox->SCSI_10.SCSI_CDB[2] = Command->BlockNumber >> 24; - CommandMailbox->SCSI_10.SCSI_CDB[3] = Command->BlockNumber >> 16; - CommandMailbox->SCSI_10.SCSI_CDB[4] = Command->BlockNumber >> 8; - CommandMailbox->SCSI_10.SCSI_CDB[5] = Command->BlockNumber; - CommandMailbox->SCSI_10.SCSI_CDB[7] = Command->BlockCount >> 8; - CommandMailbox->SCSI_10.SCSI_CDB[8] = Command->BlockCount; - DAC960_QueueCommand(Command); - return; - } + printk("DAC960_V2_ProcessCompletedCommand: retries not coded yet\n"); } else if (CommandType == DAC960_MonitoringCommand) { + if (Controller->ShutdownMonitoringTimer) + return; if (CommandOpcode == DAC960_V2_GetControllerInfo) { DAC960_V2_ControllerInfo_T *NewControllerInfo = - &Controller->V2.NewControllerInformation; + Controller->V2.NewControllerInformation; DAC960_V2_ControllerInfo_T *ControllerInfo = &Controller->V2.ControllerInformation; Controller->LogicalDriveCount = @@ -4229,15 +4510,16 @@ } else if (CommandOpcode == DAC960_V2_GetEvent) { - if (CommandStatus == DAC960_V2_NormalCompletion) - DAC960_V2_ReportEvent(Controller, &Controller->V2.Event); + if (CommandStatus == DAC960_V2_NormalCompletion) { + DAC960_V2_ReportEvent(Controller, Controller->V2.Event); + } Controller->V2.NextEventSequenceNumber++; } else if (CommandOpcode == DAC960_V2_GetPhysicalDeviceInfoValid && CommandStatus == DAC960_V2_NormalCompletion) { DAC960_V2_PhysicalDeviceInfo_T *NewPhysicalDeviceInfo = - &Controller->V2.NewPhysicalDeviceInformation; + Controller->V2.NewPhysicalDeviceInformation; unsigned int PhysicalDeviceIndex = Controller->V2.PhysicalDeviceIndex; DAC960_V2_PhysicalDeviceInfo_T *PhysicalDeviceInfo = Controller->V2.PhysicalDeviceInformation[PhysicalDeviceIndex]; @@ -4448,7 +4730,7 @@ CommandStatus == DAC960_V2_NormalCompletion) { DAC960_V2_LogicalDeviceInfo_T *NewLogicalDeviceInfo = - &Controller->V2.NewLogicalDeviceInformation; + Controller->V2.NewLogicalDeviceInformation; unsigned short LogicalDeviceNumber = NewLogicalDeviceInfo->LogicalDeviceNumber; DAC960_V2_LogicalDeviceInfo_T *LogicalDeviceInfo = @@ -4598,6 +4880,23 @@ } Controller->V2.NeedLogicalDeviceInformation = false; } + else if (CommandOpcode == DAC960_V2_SCSI_10_Passthru) + { + DAC960_SCSI_Inquiry_UnitSerialNumber_T *InquiryUnitSerialNumber = + Controller->V2.InquiryUnitSerialNumber[Controller->V2.PhysicalDeviceIndex - 1]; + + if (CommandStatus != DAC960_V2_NormalCompletion) { + memset(InquiryUnitSerialNumber, + 0, sizeof(DAC960_SCSI_Inquiry_UnitSerialNumber_T)); + InquiryUnitSerialNumber->PeripheralDeviceType = 0x1F; + } else + memcpy(InquiryUnitSerialNumber, + Controller->V2.NewInquiryUnitSerialNumber, + sizeof(DAC960_SCSI_Inquiry_UnitSerialNumber_T)); + + Controller->V2.NeedDeviceSerialNumberInformation = false; + } + if (Controller->V2.HealthStatusBuffer->NextEventSequenceNumber - Controller->V2.NextEventSequenceNumber > 0) { @@ -4613,7 +4912,7 @@ CommandMailbox->GetEvent.DataTransferMemoryAddress .ScatterGatherSegments[0] .SegmentDataPointer = - Virtual_to_Bus64(&Controller->V2.Event); + Controller->V2.EventDMA; CommandMailbox->GetEvent.DataTransferMemoryAddress .ScatterGatherSegments[0] .SegmentByteCount = @@ -4626,62 +4925,41 @@ if (Controller->V2.NeedDeviceSerialNumberInformation) { DAC960_SCSI_Inquiry_UnitSerialNumber_T *InquiryUnitSerialNumber = - Controller->V2.InquiryUnitSerialNumber - [Controller->V2.PhysicalDeviceIndex - 1]; + Controller->V2.NewInquiryUnitSerialNumber; InquiryUnitSerialNumber->PeripheralDeviceType = 0x1F; - CommandMailbox->SCSI_10.CommandOpcode = - DAC960_V2_SCSI_10_Passthru; - CommandMailbox->SCSI_10.DataTransferSize = - sizeof(DAC960_SCSI_Inquiry_UnitSerialNumber_T); - CommandMailbox->SCSI_10.PhysicalDevice.LogicalUnit = - Controller->V2.NewPhysicalDeviceInformation.LogicalUnit - 1; - CommandMailbox->SCSI_10.PhysicalDevice.TargetID = - Controller->V2.NewPhysicalDeviceInformation.TargetID; - CommandMailbox->SCSI_10.PhysicalDevice.Channel = - Controller->V2.NewPhysicalDeviceInformation.Channel; - CommandMailbox->SCSI_10.CDBLength = 6; - CommandMailbox->SCSI_10.SCSI_CDB[0] = 0x12; /* INQUIRY */ - CommandMailbox->SCSI_10.SCSI_CDB[1] = 1; /* EVPD = 1 */ - CommandMailbox->SCSI_10.SCSI_CDB[2] = 0x80; /* Page Code */ - CommandMailbox->SCSI_10.SCSI_CDB[3] = 0; /* Reserved */ - CommandMailbox->SCSI_10.SCSI_CDB[4] = - sizeof(DAC960_SCSI_Inquiry_UnitSerialNumber_T); - CommandMailbox->SCSI_10.SCSI_CDB[5] = 0; /* Control */ - CommandMailbox->SCSI_10.DataTransferMemoryAddress - .ScatterGatherSegments[0] - .SegmentDataPointer = - Virtual_to_Bus64(InquiryUnitSerialNumber); - CommandMailbox->SCSI_10.DataTransferMemoryAddress - .ScatterGatherSegments[0] - .SegmentByteCount = - CommandMailbox->SCSI_10.DataTransferSize; + + DAC960_V2_ConstructNewUnitSerialNumber(Controller, CommandMailbox, + Controller->V2.NewPhysicalDeviceInformation->Channel, + Controller->V2.NewPhysicalDeviceInformation->TargetID, + Controller->V2.NewPhysicalDeviceInformation->LogicalUnit - 1); + + DAC960_QueueCommand(Command); - Controller->V2.NeedDeviceSerialNumberInformation = false; return; } if (Controller->V2.StartPhysicalDeviceInformationScan) { Controller->V2.PhysicalDeviceIndex = 0; - Controller->V2.NewPhysicalDeviceInformation.Channel = 0; - Controller->V2.NewPhysicalDeviceInformation.TargetID = 0; - Controller->V2.NewPhysicalDeviceInformation.LogicalUnit = 0; + Controller->V2.NewPhysicalDeviceInformation->Channel = 0; + Controller->V2.NewPhysicalDeviceInformation->TargetID = 0; + Controller->V2.NewPhysicalDeviceInformation->LogicalUnit = 0; Controller->V2.StartPhysicalDeviceInformationScan = false; } CommandMailbox->PhysicalDeviceInfo.CommandOpcode = DAC960_V2_IOCTL; CommandMailbox->PhysicalDeviceInfo.DataTransferSize = sizeof(DAC960_V2_PhysicalDeviceInfo_T); CommandMailbox->PhysicalDeviceInfo.PhysicalDevice.LogicalUnit = - Controller->V2.NewPhysicalDeviceInformation.LogicalUnit; + Controller->V2.NewPhysicalDeviceInformation->LogicalUnit; CommandMailbox->PhysicalDeviceInfo.PhysicalDevice.TargetID = - Controller->V2.NewPhysicalDeviceInformation.TargetID; + Controller->V2.NewPhysicalDeviceInformation->TargetID; CommandMailbox->PhysicalDeviceInfo.PhysicalDevice.Channel = - Controller->V2.NewPhysicalDeviceInformation.Channel; + Controller->V2.NewPhysicalDeviceInformation->Channel; CommandMailbox->PhysicalDeviceInfo.IOCTL_Opcode = DAC960_V2_GetPhysicalDeviceInfoValid; CommandMailbox->PhysicalDeviceInfo.DataTransferMemoryAddress .ScatterGatherSegments[0] .SegmentDataPointer = - Virtual_to_Bus64(&Controller->V2.NewPhysicalDeviceInformation); + Controller->V2.NewPhysicalDeviceInformationDMA; CommandMailbox->PhysicalDeviceInfo.DataTransferMemoryAddress .ScatterGatherSegments[0] .SegmentByteCount = @@ -4699,21 +4977,20 @@ LogicalDriveNumber++) Controller->V2.LogicalDriveFoundDuringScan [LogicalDriveNumber] = false; - Controller->V2.NewLogicalDeviceInformation - .LogicalDeviceNumber = 0; + Controller->V2.NewLogicalDeviceInformation->LogicalDeviceNumber = 0; Controller->V2.StartLogicalDeviceInformationScan = false; } CommandMailbox->LogicalDeviceInfo.CommandOpcode = DAC960_V2_IOCTL; CommandMailbox->LogicalDeviceInfo.DataTransferSize = sizeof(DAC960_V2_LogicalDeviceInfo_T); CommandMailbox->LogicalDeviceInfo.LogicalDevice.LogicalDeviceNumber = - Controller->V2.NewLogicalDeviceInformation.LogicalDeviceNumber; + Controller->V2.NewLogicalDeviceInformation->LogicalDeviceNumber; CommandMailbox->LogicalDeviceInfo.IOCTL_Opcode = DAC960_V2_GetLogicalDeviceInfoValid; CommandMailbox->LogicalDeviceInfo.DataTransferMemoryAddress .ScatterGatherSegments[0] .SegmentDataPointer = - Virtual_to_Bus64(&Controller->V2.NewLogicalDeviceInformation); + Controller->V2.NewLogicalDeviceInformationDMA; CommandMailbox->LogicalDeviceInfo.DataTransferMemoryAddress .ScatterGatherSegments[0] .SegmentByteCount = @@ -4724,7 +5001,7 @@ Controller->MonitoringTimerCount++; Controller->MonitoringTimer.expires = jiffies + DAC960_HealthStatusMonitoringInterval; - add_timer(&Controller->MonitoringTimer); + add_timer(&Controller->MonitoringTimer); } if (CommandType == DAC960_ImmediateCommand) { @@ -5002,6 +5279,10 @@ /* DAC960_P_InterruptHandler handles hardware interrupts from DAC960 P Series Controllers. + + Translations of DAC960_V1_Enquiry and DAC960_V1_GetDeviceState rely + on the data having been placed into DAC960_Controller_T, rather than + an arbitrary buffer. */ static void DAC960_P_InterruptHandler(int IRQ_Channel, @@ -5034,14 +5315,12 @@ { case DAC960_V1_Enquiry_Old: Command->V1.CommandMailbox.Common.CommandOpcode = DAC960_V1_Enquiry; - DAC960_P_To_PD_TranslateEnquiry( - Bus32_to_Virtual(CommandMailbox->Type3.BusAddress)); + DAC960_P_To_PD_TranslateEnquiry(Controller->V1.NewEnquiry); break; case DAC960_V1_GetDeviceState_Old: Command->V1.CommandMailbox.Common.CommandOpcode = - DAC960_V1_GetDeviceState; - DAC960_P_To_PD_TranslateDeviceState( - Bus32_to_Virtual(CommandMailbox->Type3.BusAddress)); + DAC960_V1_GetDeviceState; + DAC960_P_To_PD_TranslateDeviceState(Controller->V1.NewDeviceState); break; case DAC960_V1_Read_Old: Command->V1.CommandMailbox.Common.CommandOpcode = DAC960_V1_Read; @@ -5090,8 +5369,7 @@ DAC960_V1_ClearCommand(Command); Command->CommandType = DAC960_MonitoringCommand; CommandMailbox->Type3.CommandOpcode = DAC960_V1_Enquiry; - CommandMailbox->Type3.BusAddress = - Virtual_to_Bus32(&Controller->V1.NewEnquiry); + CommandMailbox->Type3.BusAddress = Controller->V1.NewEnquiryDMA; DAC960_QueueCommand(Command); } @@ -5119,7 +5397,7 @@ CommandMailbox->ControllerInfo.DataTransferMemoryAddress .ScatterGatherSegments[0] .SegmentDataPointer = - Virtual_to_Bus64(&Controller->V2.NewControllerInformation); + Controller->V2.NewControllerInformationDMA; CommandMailbox->ControllerInfo.DataTransferMemoryAddress .ScatterGatherSegments[0] .SegmentByteCount = @@ -5198,7 +5476,7 @@ { Controller->MonitoringTimer.expires = jiffies + DAC960_HealthStatusMonitoringInterval; - add_timer(&Controller->MonitoringTimer); + add_timer(&Controller->MonitoringTimer); return; } Controller->V2.StatusChangeCounter = StatusChangeCounter; @@ -5225,6 +5503,7 @@ } } + /* DAC960_Open is the Device Open Function for the DAC960 Driver. */ @@ -5423,14 +5702,17 @@ DAC960_V1_CommandOpcode_T CommandOpcode; DAC960_V1_CommandStatus_T CommandStatus; DAC960_V1_DCDB_T DCDB; + DAC960_V1_DCDB_T *DCDB_IOBUF = NULL; + dma_addr_t DCDB_IOBUFDMA; ProcessorFlags_T ProcessorFlags; int ControllerNumber, DataTransferLength; unsigned char *DataTransferBuffer = NULL; + dma_addr_t DataTransferBufferDMA; if (UserSpaceUserCommand == NULL) return -EINVAL; if (copy_from_user(&UserCommand, UserSpaceUserCommand, sizeof(DAC960_V1_UserCommand_T))) { ErrorCode = -EFAULT; - goto Failure1; + goto Failure1a; } ControllerNumber = UserCommand.ControllerNumber; if (ControllerNumber < 0 || @@ -5447,7 +5729,7 @@ if (copy_from_user(&DCDB, UserCommand.DCDB, sizeof(DAC960_V1_DCDB_T))) { ErrorCode = -EFAULT; - goto Failure1; + goto Failure1a; } if (DCDB.Channel >= DAC960_V1_MaxChannels) return -EINVAL; if (!((DataTransferLength == 0 && @@ -5463,17 +5745,29 @@ if (((DCDB.TransferLengthHigh4 << 16) | DCDB.TransferLength) != abs(DataTransferLength)) return -EINVAL; + DCDB_IOBUF = pci_alloc_consistent(Controller->PCIDevice, + sizeof(DAC960_V1_DCDB_T), &DCDB_IOBUFDMA); + if (DCDB_IOBUF == NULL) + return -ENOMEM; } if (DataTransferLength > 0) { - DataTransferBuffer = kmalloc(DataTransferLength, GFP_KERNEL); - if (DataTransferBuffer == NULL) return -ENOMEM; + DataTransferBuffer = pci_alloc_consistent(Controller->PCIDevice, + DataTransferLength, &DataTransferBufferDMA); + if (DataTransferBuffer == NULL) { + ErrorCode = -ENOMEM; + goto Failure1; + } memset(DataTransferBuffer, 0, DataTransferLength); } else if (DataTransferLength < 0) { - DataTransferBuffer = kmalloc(-DataTransferLength, GFP_KERNEL); - if (DataTransferBuffer == NULL) return -ENOMEM; + DataTransferBuffer = pci_alloc_consistent(Controller->PCIDevice, + -DataTransferLength, &DataTransferBufferDMA); + if (DataTransferBuffer == NULL) { + ErrorCode = -ENOMEM; + goto Failure1; + } if (copy_from_user(DataTransferBuffer, UserCommand.DataTransferBuffer, -DataTransferLength)) { @@ -5489,11 +5783,11 @@ while (Controller->V1.DirectCommandActive[DCDB.Channel] [DCDB.TargetID]) { - spin_unlock_irq(Controller->RequestQueue.queue_lock); + spin_unlock_irq(&Controller->queue_lock); __wait_event(Controller->CommandWaitQueue, !Controller->V1.DirectCommandActive [DCDB.Channel][DCDB.TargetID]); - spin_lock_irq(Controller->RequestQueue.queue_lock); + spin_lock_irq(&Controller->queue_lock); } Controller->V1.DirectCommandActive[DCDB.Channel] [DCDB.TargetID] = true; @@ -5502,9 +5796,9 @@ Command->CommandType = DAC960_ImmediateCommand; memcpy(&Command->V1.CommandMailbox, &UserCommand.CommandMailbox, sizeof(DAC960_V1_CommandMailbox_T)); - Command->V1.CommandMailbox.Type3.BusAddress = - Virtual_to_Bus32(&DCDB); - DCDB.BusAddress = Virtual_to_Bus32(DataTransferBuffer); + Command->V1.CommandMailbox.Type3.BusAddress = DCDB_IOBUFDMA; + DCDB.BusAddress = DataTransferBufferDMA; + memcpy(DCDB_IOBUF, &DCDB, sizeof(DAC960_V1_DCDB_T)); } else { @@ -5518,7 +5812,7 @@ sizeof(DAC960_V1_CommandMailbox_T)); if (DataTransferBuffer != NULL) Command->V1.CommandMailbox.Type3.BusAddress = - Virtual_to_Bus32(DataTransferBuffer); + DataTransferBufferDMA; } DAC960_ExecuteCommand(Command); CommandStatus = Command->V1.CommandStatus; @@ -5528,15 +5822,20 @@ if (DataTransferLength > 0) { if (copy_to_user(UserCommand.DataTransferBuffer, - DataTransferBuffer, DataTransferLength)) + DataTransferBuffer, DataTransferLength)) { ErrorCode = -EFAULT; goto Failure1; + } } if (CommandOpcode == DAC960_V1_DCDB) { + /* + I don't believe Target or Channel in the DCDB_IOBUF + should be any different from the contents of DCDB. + */ Controller->V1.DirectCommandActive[DCDB.Channel] [DCDB.TargetID] = false; - if (copy_to_user(UserCommand.DCDB, &DCDB, + if (copy_to_user(UserCommand.DCDB, DCDB_IOBUF, sizeof(DAC960_V1_DCDB_T))) { ErrorCode = -EFAULT; goto Failure1; @@ -5545,7 +5844,12 @@ ErrorCode = CommandStatus; Failure1: if (DataTransferBuffer != NULL) - kfree(DataTransferBuffer); + pci_free_consistent(Controller->PCIDevice, abs(DataTransferLength), + DataTransferBuffer, DataTransferBufferDMA); + if (DCDB_IOBUF != NULL) + pci_free_consistent(Controller->PCIDevice, sizeof(DAC960_V1_DCDB_T), + DCDB_IOBUF, DCDB_IOBUFDMA); + Failure1a: return ErrorCode; } case DAC960_IOCTL_V2_EXECUTE_COMMAND: @@ -5561,12 +5865,14 @@ int ControllerNumber, DataTransferLength; int DataTransferResidue, RequestSenseLength; unsigned char *DataTransferBuffer = NULL; + dma_addr_t DataTransferBufferDMA; unsigned char *RequestSenseBuffer = NULL; + dma_addr_t RequestSenseBufferDMA; if (UserSpaceUserCommand == NULL) return -EINVAL; if (copy_from_user(&UserCommand, UserSpaceUserCommand, sizeof(DAC960_V2_UserCommand_T))) { ErrorCode = -EFAULT; - goto Failure2; + goto Failure2a; } ControllerNumber = UserCommand.ControllerNumber; if (ControllerNumber < 0 || @@ -5578,13 +5884,15 @@ DataTransferLength = UserCommand.DataTransferLength; if (DataTransferLength > 0) { - DataTransferBuffer = kmalloc(DataTransferLength, GFP_KERNEL); + DataTransferBuffer = pci_alloc_consistent(Controller->PCIDevice, + DataTransferLength, &DataTransferBufferDMA); if (DataTransferBuffer == NULL) return -ENOMEM; memset(DataTransferBuffer, 0, DataTransferLength); } else if (DataTransferLength < 0) { - DataTransferBuffer = kmalloc(-DataTransferLength, GFP_KERNEL); + DataTransferBuffer = pci_alloc_consistent(Controller->PCIDevice, + -DataTransferLength, &DataTransferBufferDMA); if (DataTransferBuffer == NULL) return -ENOMEM; if (copy_from_user(DataTransferBuffer, UserCommand.DataTransferBuffer, @@ -5596,7 +5904,8 @@ RequestSenseLength = UserCommand.RequestSenseLength; if (RequestSenseLength > 0) { - RequestSenseBuffer = kmalloc(RequestSenseLength, GFP_KERNEL); + RequestSenseBuffer = pci_alloc_consistent(Controller->PCIDevice, + RequestSenseLength, &RequestSenseBufferDMA); if (RequestSenseBuffer == NULL) { ErrorCode = -ENOMEM; @@ -5637,8 +5946,7 @@ } CommandMailbox->Common.DataTransferMemoryAddress .ScatterGatherSegments[0] - .SegmentDataPointer = - Virtual_to_Bus64(DataTransferBuffer); + .SegmentDataPointer = DataTransferBufferDMA; CommandMailbox->Common.DataTransferMemoryAddress .ScatterGatherSegments[0] .SegmentByteCount = @@ -5650,7 +5958,7 @@ .NoAutoRequestSense = false; CommandMailbox->Common.RequestSenseSize = RequestSenseLength; CommandMailbox->Common.RequestSenseBusAddress = - Virtual_to_Bus64(RequestSenseBuffer); + RequestSenseBufferDMA; } DAC960_ExecuteCommand(Command); CommandStatus = Command->V2.CommandStatus; @@ -5690,10 +5998,12 @@ } ErrorCode = CommandStatus; Failure2: - if (DataTransferBuffer != NULL) - kfree(DataTransferBuffer); + pci_free_consistent(Controller->PCIDevice, abs(DataTransferLength), + DataTransferBuffer, DataTransferBufferDMA); if (RequestSenseBuffer != NULL) - kfree(RequestSenseBuffer); + pci_free_consistent(Controller->PCIDevice, RequestSenseLength, + RequestSenseBuffer, RequestSenseBufferDMA); + Failure2a: return ErrorCode; } case DAC960_IOCTL_V2_GET_HEALTH_STATUS: @@ -5740,226 +6050,6 @@ /* - DAC960_KernelIOCTL is the Kernel IOCTL Function for the DAC960 Driver. -*/ - -int DAC960_KernelIOCTL(unsigned int Request, void *Argument) -{ - switch (Request) - { - case DAC960_IOCTL_GET_CONTROLLER_COUNT: - return DAC960_ControllerCount; - case DAC960_IOCTL_GET_CONTROLLER_INFO: - { - DAC960_ControllerInfo_T *ControllerInfo = - (DAC960_ControllerInfo_T *) Argument; - DAC960_Controller_T *Controller; - int ControllerNumber; - if (ControllerInfo == NULL) return -EINVAL; - ControllerNumber = ControllerInfo->ControllerNumber; - if (ControllerNumber < 0 || - ControllerNumber > DAC960_ControllerCount - 1) - return -ENXIO; - Controller = DAC960_Controllers[ControllerNumber]; - if (Controller == NULL) return -ENXIO; - memset(ControllerInfo, 0, sizeof(DAC960_ControllerInfo_T)); - ControllerInfo->ControllerNumber = ControllerNumber; - ControllerInfo->FirmwareType = Controller->FirmwareType; - ControllerInfo->Channels = Controller->Channels; - ControllerInfo->Targets = Controller->Targets; - ControllerInfo->PCI_Bus = Controller->Bus; - ControllerInfo->PCI_Device = Controller->Device; - ControllerInfo->PCI_Function = Controller->Function; - ControllerInfo->IRQ_Channel = Controller->IRQ_Channel; - ControllerInfo->PCI_Address = Controller->PCI_Address; - strcpy(ControllerInfo->ModelName, Controller->ModelName); - strcpy(ControllerInfo->FirmwareVersion, Controller->FirmwareVersion); - return 0; - } - case DAC960_IOCTL_V1_EXECUTE_COMMAND: - { - DAC960_V1_KernelCommand_T *KernelCommand = - (DAC960_V1_KernelCommand_T *) Argument; - DAC960_Controller_T *Controller; - DAC960_Command_T *Command = NULL; - DAC960_V1_CommandOpcode_T CommandOpcode; - DAC960_V1_DCDB_T *DCDB = NULL; - ProcessorFlags_T ProcessorFlags; - int ControllerNumber, DataTransferLength; - unsigned char *DataTransferBuffer = NULL; - if (KernelCommand == NULL) return -EINVAL; - ControllerNumber = KernelCommand->ControllerNumber; - if (ControllerNumber < 0 || - ControllerNumber > DAC960_ControllerCount - 1) - return -ENXIO; - Controller = DAC960_Controllers[ControllerNumber]; - if (Controller == NULL) return -ENXIO; - if (Controller->FirmwareType != DAC960_V1_Controller) return -EINVAL; - CommandOpcode = KernelCommand->CommandMailbox.Common.CommandOpcode; - DataTransferLength = KernelCommand->DataTransferLength; - DataTransferBuffer = KernelCommand->DataTransferBuffer; - if (CommandOpcode & 0x80) return -EINVAL; - if (CommandOpcode == DAC960_V1_DCDB) - { - DCDB = KernelCommand->DCDB; - if (DCDB->Channel >= DAC960_V1_MaxChannels) return -EINVAL; - if (!((DataTransferLength == 0 && - DCDB->Direction == DAC960_V1_DCDB_NoDataTransfer) || - (DataTransferLength > 0 && - DCDB->Direction - == DAC960_V1_DCDB_DataTransferDeviceToSystem) || - (DataTransferLength < 0 && - DCDB->Direction - == DAC960_V1_DCDB_DataTransferSystemToDevice))) - return -EINVAL; - if (((DCDB->TransferLengthHigh4 << 16) | DCDB->TransferLength) - != abs(DataTransferLength)) - return -EINVAL; - } - if (DataTransferLength != 0 && DataTransferBuffer == NULL) - return -EINVAL; - if (DataTransferLength > 0) - memset(DataTransferBuffer, 0, DataTransferLength); - if (CommandOpcode == DAC960_V1_DCDB) - { - DAC960_AcquireControllerLock(Controller, &ProcessorFlags); - if (!Controller->V1.DirectCommandActive[DCDB->Channel] - [DCDB->TargetID]) - Command = DAC960_AllocateCommand(Controller); - if (Command == NULL) - { - DAC960_ReleaseControllerLock(Controller, &ProcessorFlags); - return -EBUSY; - } - else Controller->V1.DirectCommandActive[DCDB->Channel] - [DCDB->TargetID] = true; - DAC960_V1_ClearCommand(Command); - Command->CommandType = DAC960_QueuedCommand; - memcpy(&Command->V1.CommandMailbox, &KernelCommand->CommandMailbox, - sizeof(DAC960_V1_CommandMailbox_T)); - Command->V1.CommandMailbox.Type3.BusAddress = - Virtual_to_Bus32(DCDB); - Command->V1.KernelCommand = KernelCommand; - DCDB->BusAddress = Virtual_to_Bus32(DataTransferBuffer); - DAC960_QueueCommand(Command); - DAC960_ReleaseControllerLock(Controller, &ProcessorFlags); - } - else - { - DAC960_AcquireControllerLock(Controller, &ProcessorFlags); - Command = DAC960_AllocateCommand(Controller); - if (Command == NULL) - { - DAC960_ReleaseControllerLock(Controller, &ProcessorFlags); - return -EBUSY; - } - DAC960_V1_ClearCommand(Command); - Command->CommandType = DAC960_QueuedCommand; - memcpy(&Command->V1.CommandMailbox, &KernelCommand->CommandMailbox, - sizeof(DAC960_V1_CommandMailbox_T)); - if (DataTransferBuffer != NULL) - Command->V1.CommandMailbox.Type3.BusAddress = - Virtual_to_Bus32(DataTransferBuffer); - Command->V1.KernelCommand = KernelCommand; - DAC960_QueueCommand(Command); - DAC960_ReleaseControllerLock(Controller, &ProcessorFlags); - } - return 0; - } - case DAC960_IOCTL_V2_EXECUTE_COMMAND: - { - DAC960_V2_KernelCommand_T *KernelCommand = - (DAC960_V2_KernelCommand_T *) Argument; - DAC960_Controller_T *Controller; - DAC960_Command_T *Command = NULL; - DAC960_V2_CommandMailbox_T *CommandMailbox; - ProcessorFlags_T ProcessorFlags; - int ControllerNumber, DataTransferLength, RequestSenseLength; - unsigned char *DataTransferBuffer = NULL; - unsigned char *RequestSenseBuffer = NULL; - if (KernelCommand == NULL) return -EINVAL; - ControllerNumber = KernelCommand->ControllerNumber; - if (ControllerNumber < 0 || - ControllerNumber > DAC960_ControllerCount - 1) - return -ENXIO; - Controller = DAC960_Controllers[ControllerNumber]; - if (Controller == NULL) return -ENXIO; - if (Controller->FirmwareType != DAC960_V2_Controller) return -EINVAL; - DataTransferLength = KernelCommand->DataTransferLength; - RequestSenseLength = KernelCommand->RequestSenseLength; - DataTransferBuffer = KernelCommand->DataTransferBuffer; - RequestSenseBuffer = KernelCommand->RequestSenseBuffer; - if (DataTransferLength != 0 && DataTransferBuffer == NULL) - return -EINVAL; - if (RequestSenseLength < 0) - return -EINVAL; - if (RequestSenseLength > 0 && RequestSenseBuffer == NULL) - return -EINVAL; - if (DataTransferLength > 0) - memset(DataTransferBuffer, 0, DataTransferLength); - if (RequestSenseLength > 0) - memset(RequestSenseBuffer, 0, RequestSenseLength); - DAC960_AcquireControllerLock(Controller, &ProcessorFlags); - Command = DAC960_AllocateCommand(Controller); - if (Command == NULL) - { - DAC960_ReleaseControllerLock(Controller, &ProcessorFlags); - return -EBUSY; - } - DAC960_V2_ClearCommand(Command); - Command->CommandType = DAC960_QueuedCommand; - CommandMailbox = &Command->V2.CommandMailbox; - memcpy(CommandMailbox, &KernelCommand->CommandMailbox, - sizeof(DAC960_V2_CommandMailbox_T)); - CommandMailbox->Common.CommandControlBits - .AdditionalScatterGatherListMemory = false; - CommandMailbox->Common.CommandControlBits - .NoAutoRequestSense = true; - CommandMailbox->Common.DataTransferSize = 0; - CommandMailbox->Common.DataTransferPageNumber = 0; - memset(&CommandMailbox->Common.DataTransferMemoryAddress, 0, - sizeof(DAC960_V2_DataTransferMemoryAddress_T)); - if (DataTransferLength != 0) - { - if (DataTransferLength > 0) - { - CommandMailbox->Common.CommandControlBits - .DataTransferControllerToHost = true; - CommandMailbox->Common.DataTransferSize = DataTransferLength; - } - else - { - CommandMailbox->Common.CommandControlBits - .DataTransferControllerToHost = false; - CommandMailbox->Common.DataTransferSize = -DataTransferLength; - } - CommandMailbox->Common.DataTransferMemoryAddress - .ScatterGatherSegments[0] - .SegmentDataPointer = - Virtual_to_Bus64(DataTransferBuffer); - CommandMailbox->Common.DataTransferMemoryAddress - .ScatterGatherSegments[0] - .SegmentByteCount = - CommandMailbox->Common.DataTransferSize; - } - if (RequestSenseLength > 0) - { - CommandMailbox->Common.CommandControlBits - .NoAutoRequestSense = false; - CommandMailbox->Common.RequestSenseBusAddress = - Virtual_to_Bus64(RequestSenseBuffer); - } - Command->V2.KernelCommand = KernelCommand; - DAC960_QueueCommand(Command); - DAC960_ReleaseControllerLock(Controller, &ProcessorFlags); - return 0; - } - } - return -EINVAL; -} - - -/* DAC960_CheckStatusBuffer verifies that there is room to hold ByteCount additional bytes in the Combined Status Buffer and grows the buffer if necessary. It returns true if there is enough room and false otherwise. @@ -6381,11 +6471,25 @@ else if (strcmp(UserCommand, "cancel-rebuild") == 0 || strcmp(UserCommand, "cancel-consistency-check") == 0) { - unsigned char OldRebuildRateConstant; + /* + the OldRebuildRateConstant is never actually used + once its value is retrieved from the controller. + */ + unsigned char *OldRebuildRateConstant; + dma_addr_t OldRebuildRateConstantDMA; + + OldRebuildRateConstant = pci_alloc_consistent( Controller->PCIDevice, + sizeof(char), &OldRebuildRateConstantDMA); + if (OldRebuildRateConstant == NULL) { + DAC960_UserCritical("Cancellation of Rebuild or " + "Consistency Check Failed - " + "Out of Memory", + Controller); + goto failure; + } CommandMailbox->Type3R.CommandOpcode = DAC960_V1_RebuildControl; CommandMailbox->Type3R.RebuildRateConstant = 0xFF; - CommandMailbox->Type3R.BusAddress = - Virtual_to_Bus32(&OldRebuildRateConstant); + CommandMailbox->Type3R.BusAddress = OldRebuildRateConstantDMA; DAC960_ExecuteCommand(Command); switch (Command->V1.CommandStatus) { @@ -6400,6 +6504,9 @@ Controller, Command->V1.CommandStatus); break; } +failure: + pci_free_consistent(Controller->PCIDevice, sizeof(char), + OldRebuildRateConstant, OldRebuildRateConstantDMA); } else DAC960_UserCritical("Illegal User Command: '%s'\n", Controller, UserCommand); @@ -6423,10 +6530,12 @@ *LogicalDeviceNumber) { DAC960_V2_CommandMailbox_T SavedCommandMailbox, *CommandMailbox; - DAC960_V2_PhysicalToLogicalDevice_T PhysicalToLogicalDevice; + DAC960_Controller_T *Controller = Command->Controller; + CommandMailbox = &Command->V2.CommandMailbox; memcpy(&SavedCommandMailbox, CommandMailbox, sizeof(DAC960_V2_CommandMailbox_T)); + CommandMailbox->PhysicalDeviceInfo.CommandOpcode = DAC960_V2_IOCTL; CommandMailbox->PhysicalDeviceInfo.CommandControlBits .DataTransferControllerToHost = true; @@ -6441,15 +6550,17 @@ CommandMailbox->Common.DataTransferMemoryAddress .ScatterGatherSegments[0] .SegmentDataPointer = - Virtual_to_Bus64(&PhysicalToLogicalDevice); + Controller->V2.PhysicalToLogicalDeviceDMA; CommandMailbox->Common.DataTransferMemoryAddress .ScatterGatherSegments[0] .SegmentByteCount = - CommandMailbox->Common.DataTransferSize; + CommandMailbox->Common.DataTransferSize; + DAC960_ExecuteCommand(Command); + *LogicalDeviceNumber = Controller->V2.PhysicalToLogicalDevice->LogicalDeviceNumber; + memcpy(CommandMailbox, &SavedCommandMailbox, sizeof(DAC960_V2_CommandMailbox_T)); - *LogicalDeviceNumber = PhysicalToLogicalDevice.LogicalDeviceNumber; return (Command->V2.CommandStatus == DAC960_V2_NormalCompletion); } @@ -6635,16 +6746,20 @@ CommandMailbox->ControllerInfo.ControllerNumber = 0; CommandMailbox->ControllerInfo.IOCTL_Opcode = DAC960_V2_GetControllerInfo; + /* + * How does this NOT race with the queued Monitoring + * usage of this structure? + */ CommandMailbox->ControllerInfo.DataTransferMemoryAddress .ScatterGatherSegments[0] .SegmentDataPointer = - Virtual_to_Bus64(&Controller->V2.NewControllerInformation); + Controller->V2.NewControllerInformationDMA; CommandMailbox->ControllerInfo.DataTransferMemoryAddress .ScatterGatherSegments[0] .SegmentByteCount = CommandMailbox->ControllerInfo.DataTransferSize; DAC960_ExecuteCommand(Command); - while (Controller->V2.NewControllerInformation.PhysicalScanActive) + while (Controller->V2.NewControllerInformation->PhysicalScanActive) { DAC960_ExecuteCommand(Command); sleep_on_timeout(&Controller->CommandWaitQueue, HZ); @@ -6817,22 +6932,19 @@ DAC960 Driver. */ -static void DAC960_CreateProcEntries(void) +static void DAC960_CreateProcEntries(DAC960_Controller_T *Controller) { - PROC_DirectoryEntry_T *StatusProcEntry; - int ControllerNumber; - DAC960_ProcDirectoryEntry = proc_mkdir("rd", NULL); - StatusProcEntry = create_proc_read_entry("status", 0, + PROC_DirectoryEntry_T *StatusProcEntry; + PROC_DirectoryEntry_T *ControllerProcEntry; + PROC_DirectoryEntry_T *UserCommandProcEntry; + + if (DAC960_ProcDirectoryEntry == NULL) { + DAC960_ProcDirectoryEntry = proc_mkdir("rd", NULL); + StatusProcEntry = create_proc_read_entry("status", 0, DAC960_ProcDirectoryEntry, DAC960_ProcReadStatus, NULL); - for (ControllerNumber = 0; - ControllerNumber < DAC960_ControllerCount; - ControllerNumber++) - { - DAC960_Controller_T *Controller = DAC960_Controllers[ControllerNumber]; - PROC_DirectoryEntry_T *ControllerProcEntry; - PROC_DirectoryEntry_T *UserCommandProcEntry; - if (Controller == NULL) continue; + } + sprintf(Controller->ControllerName, "c%d", Controller->ControllerNumber); ControllerProcEntry = proc_mkdir(Controller->ControllerName, DAC960_ProcDirectoryEntry); @@ -6846,7 +6958,6 @@ Controller); UserCommandProcEntry->write_proc = DAC960_ProcWriteUserCommand; Controller->ControllerProcEntry = ControllerProcEntry; - } } @@ -6855,26 +6966,138 @@ DAC960 Driver. */ -static void DAC960_DestroyProcEntries(void) +static void DAC960_DestroyProcEntries(DAC960_Controller_T *Controller) { - int ControllerNumber; - for (ControllerNumber = 0; - ControllerNumber < DAC960_ControllerCount; - ControllerNumber++) - { - DAC960_Controller_T *Controller = DAC960_Controllers[ControllerNumber]; - if (Controller == NULL) continue; + if (Controller->ControllerProcEntry == NULL) + return; remove_proc_entry("initial_status", Controller->ControllerProcEntry); remove_proc_entry("current_status", Controller->ControllerProcEntry); remove_proc_entry("user_command", Controller->ControllerProcEntry); remove_proc_entry(Controller->ControllerName, DAC960_ProcDirectoryEntry); - } - remove_proc_entry("rd/status", NULL); - remove_proc_entry("rd", NULL); + Controller->ControllerProcEntry = NULL; +} + +static struct DAC960_privdata DAC960_BA_privdata = { + .HardwareType = DAC960_BA_Controller, + .FirmwareType = DAC960_V2_Controller, + .InterruptHandler = DAC960_BA_InterruptHandler, + .MemoryWindowSize = DAC960_BA_RegisterWindowSize, +}; + +static struct DAC960_privdata DAC960_LP_privdata = { + .HardwareType = DAC960_LP_Controller, + .FirmwareType = DAC960_LP_Controller, + .InterruptHandler = DAC960_LP_InterruptHandler, + .MemoryWindowSize = DAC960_LP_RegisterWindowSize, +}; + +static struct DAC960_privdata DAC960_LA_privdata = { + .HardwareType = DAC960_LA_Controller, + .FirmwareType = DAC960_V1_Controller, + .InterruptHandler = DAC960_LA_InterruptHandler, + .MemoryWindowSize = DAC960_LA_RegisterWindowSize, +}; + +static struct DAC960_privdata DAC960_PG_privdata = { + .HardwareType = DAC960_PG_Controller, + .FirmwareType = DAC960_V1_Controller, + .InterruptHandler = DAC960_PG_InterruptHandler, + .MemoryWindowSize = DAC960_PG_RegisterWindowSize, +}; + +static struct DAC960_privdata DAC960_PD_privdata = { + .HardwareType = DAC960_PD_Controller, + .FirmwareType = DAC960_V1_Controller, + .InterruptHandler = DAC960_PD_InterruptHandler, + .MemoryWindowSize = DAC960_PD_RegisterWindowSize, +}; + +static struct DAC960_privdata DAC960_P_privdata = { + .HardwareType = DAC960_P_Controller, + .FirmwareType = DAC960_V1_Controller, + .InterruptHandler = DAC960_P_InterruptHandler, + .MemoryWindowSize = DAC960_PD_RegisterWindowSize, +}; + +static struct pci_device_id DAC960_id_table[] = { + { + .vendor = PCI_VENDOR_ID_MYLEX, + .device = PCI_DEVICE_ID_MYLEX_DAC960_BA, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .driver_data = (unsigned long) &DAC960_BA_privdata, + }, + { + .vendor = PCI_VENDOR_ID_MYLEX, + .device = PCI_DEVICE_ID_MYLEX_DAC960_LP, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .driver_data = (unsigned long) &DAC960_LP_privdata, + }, + { + .vendor = PCI_VENDOR_ID_DEC, + .device = PCI_DEVICE_ID_DEC_21285, + .subvendor = PCI_VENDOR_ID_MYLEX, + .subdevice = PCI_DEVICE_ID_MYLEX_DAC960_LA, + .driver_data = (unsigned long) &DAC960_LA_privdata, + }, + { + .vendor = PCI_VENDOR_ID_MYLEX, + .device = PCI_DEVICE_ID_MYLEX_DAC960_PG, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .driver_data = (unsigned long) &DAC960_PG_privdata, + }, + { + .vendor = PCI_VENDOR_ID_MYLEX, + .device = PCI_DEVICE_ID_MYLEX_DAC960_PD, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .driver_data = (unsigned long) &DAC960_PD_privdata, + }, + { + .vendor = PCI_VENDOR_ID_MYLEX, + .device = PCI_DEVICE_ID_MYLEX_DAC960_P, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .driver_data = (unsigned long) &DAC960_P_privdata, + }, + {0, }, +}; + +MODULE_DEVICE_TABLE(pci, DAC960_id_table); + +static struct pci_driver DAC960_pci_driver = { + .name = "DAC960", + .id_table = DAC960_id_table, + .probe = DAC960_Probe, + .remove = DAC960_Remove, +}; + +static int DAC960_init_module(void) +{ + return pci_module_init(&DAC960_pci_driver); } +static void DAC960_cleanup_module(void) +{ + int i; + + for (i = 0; i < DAC960_ControllerCount; i++) { + DAC960_Controller_T *Controller = DAC960_Controllers[i]; + if (Controller == NULL) + continue; + DAC960_FinalizeController(Controller); + } + if (DAC960_ProcDirectoryEntry != NULL) { + remove_proc_entry("rd/status", NULL); + remove_proc_entry("rd", NULL); + } + DAC960_ControllerCount = 0; + pci_unregister_driver(&DAC960_pci_driver); +} -module_init(DAC960_Initialize); -module_exit(DAC960_Finalize); +module_init(DAC960_init_module); +module_exit(DAC960_cleanup_module); MODULE_LICENSE("GPL"); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/drivers/block/DAC960.h linux.2.5.47-ac6/drivers/block/DAC960.h --- linux.2.5.47/drivers/block/DAC960.h 2002-10-31 14:57:17.000000000 +0000 +++ linux.2.5.47-ac6/drivers/block/DAC960.h 2002-11-15 15:29:02.000000000 +0000 @@ -60,6 +60,17 @@ #define DAC960_V1_MaxPhysicalDevices 45 #define DAC960_V2_MaxPhysicalDevices 272 +/* + Define the pci dma mask supported by DAC960 V1 and V2 Firmware Controlers + + For now set the V2 mask to only 32 bits. The controller IS capable + of doing 64 bit dma. But I have yet to find out whether this needs to + be explicitely enabled in the controller, or of the controller adapts + automatically. + */ + +#define DAC690_V1_PciDmaMask 0xffffffff +#define DAC690_V2_PciDmaMask 0xffffffffffffffff /* Define a Boolean data type. @@ -111,6 +122,20 @@ /* + dma_loaf is used by helper routines to divide a region of + dma mapped memory into smaller pieces, where those pieces + are not of uniform size. + */ + +struct dma_loaf { + void *cpu_base; + dma_addr_t dma_base; + size_t length; + void *cpu_free; + dma_addr_t dma_free; +}; + +/* Define the SCSI INQUIRY Standard Data structure. */ @@ -2059,9 +2084,6 @@ #define DAC960_LogicalDriveNumber(Device) \ (minor(Device) >> DAC960_MaxPartitionsBits) -#define DAC960_PartitionNumber(Device) \ - (minor(Device) & (DAC960_MaxPartitions - 1)) - #define DAC960_MajorNumber(ControllerNumber) \ (DAC960_MAJOR + (ControllerNumber)) @@ -2191,7 +2213,6 @@ of the Linux Kernel and I/O Subsystem. */ -typedef struct bio BufferHeader_T; typedef struct file File_T; typedef struct block_device_operations BlockDeviceOperations_T; typedef struct completion Completion_T; @@ -2200,7 +2221,6 @@ typedef struct inode_operations InodeOperations_T; typedef kdev_t KernelDevice_T; typedef struct list_head ListHead_T; -typedef struct notifier_block NotifierBlock_T; typedef struct pci_dev PCI_Device_T; typedef struct proc_dir_entry PROC_DirectoryEntry_T; typedef unsigned long ProcessorFlags_T; @@ -2211,6 +2231,13 @@ typedef struct timer_list Timer_T; typedef wait_queue_head_t WaitQueue_T; +struct DAC960_privdata { + DAC960_HardwareType_T HardwareType; + DAC960_FirmwareType_T FirmwareType; + void (*InterruptHandler)(int, void *, Registers_T *); + unsigned int MemoryWindowSize; +}; + /* Define the DAC960 V1 Firmware Controller Status Mailbox structure. @@ -2278,16 +2305,16 @@ unsigned int BlockNumber; unsigned int BlockCount; unsigned int SegmentCount; - BufferHeader_T *BufferHeader; - void *RequestBuffer; + IO_Request_T *Request; + struct pci_dev *PciDevice; union { struct { DAC960_V1_CommandMailbox_T CommandMailbox; DAC960_V1_KernelCommand_T *KernelCommand; DAC960_V1_CommandStatus_T CommandStatus; - DAC960_V1_ScatterGatherSegment_T - ScatterGatherList[DAC960_V1_ScatterGatherLimit] - __attribute__ ((aligned (sizeof(DAC960_V1_ScatterGatherSegment_T)))); + DAC960_V1_ScatterGatherSegment_T *ScatterGatherList; + dma_addr_t ScatterGatherListDMA; + struct scatterlist ScatterList[DAC960_V1_ScatterGatherLimit]; unsigned int EndMarker[0]; } V1; struct { @@ -2296,11 +2323,11 @@ DAC960_V2_CommandStatus_T CommandStatus; unsigned char RequestSenseLength; int DataTransferResidue; - DAC960_V2_ScatterGatherSegment_T - ScatterGatherList[DAC960_V2_ScatterGatherLimit] - __attribute__ ((aligned (sizeof(DAC960_V2_ScatterGatherSegment_T)))); - DAC960_SCSI_RequestSense_T RequestSense - __attribute__ ((aligned (sizeof(int)))); + DAC960_V2_ScatterGatherSegment_T *ScatterGatherList; + dma_addr_t ScatterGatherListDMA; + DAC960_SCSI_RequestSense_T *RequestSense; + dma_addr_t RequestSenseDMA; + struct scatterlist ScatterList[DAC960_V2_ScatterGatherLimit]; unsigned int EndMarker[0]; } V2; } FW; @@ -2320,6 +2347,7 @@ DAC960_HardwareType_T HardwareType; DAC960_IO_Address_T IO_Address; DAC960_PCI_Address_T PCI_Address; + PCI_Device_T *PCIDevice; unsigned char ControllerNumber; unsigned char ControllerName[4]; unsigned char ModelName[20]; @@ -2345,14 +2373,13 @@ unsigned int CurrentStatusLength; unsigned int ProgressBufferLength; unsigned int UserStatusLength; - unsigned long MemoryMailboxPagesAddress; - unsigned long MemoryMailboxPagesOrder; + struct dma_loaf DmaPages; unsigned long MonitoringTimerCount; unsigned long PrimaryMonitoringTime; unsigned long SecondaryMonitoringTime; + unsigned long ShutdownMonitoringTimer; unsigned long LastProgressReportTime; unsigned long LastCurrentStatusTime; - boolean ControllerDetectionSuccessful; boolean ControllerInitialized; boolean MonitoringCommandDeferred; boolean EphemeralProgressMessage; @@ -2361,6 +2388,7 @@ boolean SuppressEnclosureMessages; Timer_T MonitoringTimer; struct gendisk *disks[DAC960_MaxLogicalDrives]; + struct pci_pool *ScatterGatherPool; DAC960_Command_T *FreeCommands; unsigned char *CombinedStatusBuffer; unsigned char *CurrentStatusBuffer; @@ -2404,36 +2432,63 @@ boolean RebuildProgressFirst; boolean RebuildFlagPending; boolean RebuildStatusPending; + + dma_addr_t FirstCommandMailboxDMA; DAC960_V1_CommandMailbox_T *FirstCommandMailbox; DAC960_V1_CommandMailbox_T *LastCommandMailbox; DAC960_V1_CommandMailbox_T *NextCommandMailbox; DAC960_V1_CommandMailbox_T *PreviousCommandMailbox1; DAC960_V1_CommandMailbox_T *PreviousCommandMailbox2; + + dma_addr_t FirstStatusMailboxDMA; DAC960_V1_StatusMailbox_T *FirstStatusMailbox; DAC960_V1_StatusMailbox_T *LastStatusMailbox; DAC960_V1_StatusMailbox_T *NextStatusMailbox; - DAC960_V1_DCDB_T MonitoringDCDB; + + DAC960_V1_DCDB_T *MonitoringDCDB; + dma_addr_t MonitoringDCDB_DMA; + DAC960_V1_Enquiry_T Enquiry; - DAC960_V1_Enquiry_T NewEnquiry; + DAC960_V1_Enquiry_T *NewEnquiry; + dma_addr_t NewEnquiryDMA; + DAC960_V1_ErrorTable_T ErrorTable; - DAC960_V1_ErrorTable_T NewErrorTable; - DAC960_V1_EventLogEntry_T EventLogEntry; - DAC960_V1_RebuildProgress_T RebuildProgress; + DAC960_V1_ErrorTable_T *NewErrorTable; + dma_addr_t NewErrorTableDMA; + + DAC960_V1_EventLogEntry_T *EventLogEntry; + dma_addr_t EventLogEntryDMA; + + DAC960_V1_RebuildProgress_T *RebuildProgress; + dma_addr_t RebuildProgressDMA; DAC960_V1_CommandStatus_T LastRebuildStatus; DAC960_V1_CommandStatus_T PendingRebuildStatus; + DAC960_V1_LogicalDriveInformationArray_T LogicalDriveInformation; - DAC960_V1_LogicalDriveInformationArray_T NewLogicalDriveInformation; + DAC960_V1_LogicalDriveInformationArray_T *NewLogicalDriveInformation; + dma_addr_t NewLogicalDriveInformationDMA; + DAC960_V1_BackgroundInitializationStatus_T - BackgroundInitializationStatus; + *BackgroundInitializationStatus; + dma_addr_t BackgroundInitializationStatusDMA; DAC960_V1_BackgroundInitializationStatus_T - LastBackgroundInitializationStatus; + LastBackgroundInitializationStatus; + DAC960_V1_DeviceState_T DeviceState[DAC960_V1_MaxChannels][DAC960_V1_MaxTargets]; - DAC960_V1_DeviceState_T NewDeviceState; + DAC960_V1_DeviceState_T *NewDeviceState; + dma_addr_t NewDeviceStateDMA; + DAC960_SCSI_Inquiry_T InquiryStandardData[DAC960_V1_MaxChannels][DAC960_V1_MaxTargets]; + DAC960_SCSI_Inquiry_T *NewInquiryStandardData; + dma_addr_t NewInquiryStandardDataDMA; + DAC960_SCSI_Inquiry_UnitSerialNumber_T InquiryUnitSerialNumber[DAC960_V1_MaxChannels][DAC960_V1_MaxTargets]; + DAC960_SCSI_Inquiry_UnitSerialNumber_T *NewInquiryUnitSerialNumber; + dma_addr_t NewInquiryUnitSerialNumberDMA; + int DeviceResetCount[DAC960_V1_MaxChannels][DAC960_V1_MaxTargets]; boolean DirectCommandActive[DAC960_V1_MaxChannels][DAC960_V1_MaxTargets]; } V1; @@ -2446,28 +2501,50 @@ boolean NeedDeviceSerialNumberInformation; boolean StartLogicalDeviceInformationScan; boolean StartPhysicalDeviceInformationScan; + struct pci_pool *RequestSensePool; + + dma_addr_t FirstCommandMailboxDMA; DAC960_V2_CommandMailbox_T *FirstCommandMailbox; DAC960_V2_CommandMailbox_T *LastCommandMailbox; DAC960_V2_CommandMailbox_T *NextCommandMailbox; DAC960_V2_CommandMailbox_T *PreviousCommandMailbox1; DAC960_V2_CommandMailbox_T *PreviousCommandMailbox2; + + dma_addr_t FirstStatusMailboxDMA; DAC960_V2_StatusMailbox_T *FirstStatusMailbox; DAC960_V2_StatusMailbox_T *LastStatusMailbox; DAC960_V2_StatusMailbox_T *NextStatusMailbox; + + dma_addr_t HealthStatusBufferDMA; DAC960_V2_HealthStatusBuffer_T *HealthStatusBuffer; + DAC960_V2_ControllerInfo_T ControllerInformation; - DAC960_V2_ControllerInfo_T NewControllerInformation; + DAC960_V2_ControllerInfo_T *NewControllerInformation; + dma_addr_t NewControllerInformationDMA; + DAC960_V2_LogicalDeviceInfo_T *LogicalDeviceInformation[DAC960_MaxLogicalDrives]; - DAC960_V2_LogicalDeviceInfo_T NewLogicalDeviceInformation; + DAC960_V2_LogicalDeviceInfo_T *NewLogicalDeviceInformation; + dma_addr_t NewLogicalDeviceInformationDMA; + DAC960_V2_PhysicalDeviceInfo_T *PhysicalDeviceInformation[DAC960_V2_MaxPhysicalDevices]; - DAC960_V2_PhysicalDeviceInfo_T NewPhysicalDeviceInformation; + DAC960_V2_PhysicalDeviceInfo_T *NewPhysicalDeviceInformation; + dma_addr_t NewPhysicalDeviceInformationDMA; + + DAC960_SCSI_Inquiry_UnitSerialNumber_T *NewInquiryUnitSerialNumber; + dma_addr_t NewInquiryUnitSerialNumberDMA; DAC960_SCSI_Inquiry_UnitSerialNumber_T *InquiryUnitSerialNumber[DAC960_V2_MaxPhysicalDevices]; + + DAC960_V2_Event_T *Event; + dma_addr_t EventDMA; + + DAC960_V2_PhysicalToLogicalDevice_T *PhysicalToLogicalDevice; + dma_addr_t PhysicalToLogicalDeviceDMA; + DAC960_V2_PhysicalDevice_T LogicalDriveToVirtualDevice[DAC960_MaxLogicalDrives]; - DAC960_V2_Event_T Event; boolean LogicalDriveFoundDuringScan[DAC960_MaxLogicalDrives]; } V2; } FW; @@ -2495,16 +2572,47 @@ #define DAC960_QueueReadWriteCommand(Command) \ (Controller->QueueReadWriteCommand)(Command) +/* + * dma_addr_writeql is provided to write dma_addr_t types + * to a 64-bit pci address space register. The controller + * will accept having the register written as two 32-bit + * values. + * + * In HIGHMEM kernels, dma_addr_t is a 64-bit value. + * without HIGHMEM, dma_addr_t is a 32-bit value. + * + * The compiler should always fix up the assignment + * to u.wq appropriately, depending upon the size of + * dma_addr_t. + */ +static inline +void dma_addr_writeql(dma_addr_t addr, void *write_address) +{ + union { + u64 wq; + uint wl[2]; + } u; + + u.wq = addr; + + writel(u.wl[0], write_address); + writel(u.wl[1], write_address + 4); +} /* DAC960_AcquireControllerLock acquires exclusive access to Controller. + Reference the queue_lock through the controller structure, + rather than through the request queue. These macros are + used to mutex on the controller structure during initialization, + BEFORE the request queue is allocated and initialized in + DAC960_RegisterBlockDevice(). */ static inline void DAC960_AcquireControllerLock(DAC960_Controller_T *Controller, ProcessorFlags_T *ProcessorFlags) { - spin_lock_irqsave(Controller->RequestQueue.queue_lock, *ProcessorFlags); + spin_lock_irqsave(&Controller->queue_lock, *ProcessorFlags); } @@ -2516,7 +2624,7 @@ void DAC960_ReleaseControllerLock(DAC960_Controller_T *Controller, ProcessorFlags_T *ProcessorFlags) { - spin_unlock_irqrestore(Controller->RequestQueue.queue_lock, *ProcessorFlags); + spin_unlock_irqrestore(&Controller->queue_lock, *ProcessorFlags); } @@ -2553,7 +2661,7 @@ void DAC960_AcquireControllerLockIH(DAC960_Controller_T *Controller, ProcessorFlags_T *ProcessorFlags) { - spin_lock_irqsave(Controller->RequestQueue.queue_lock, *ProcessorFlags); + spin_lock_irqsave(&Controller->queue_lock, *ProcessorFlags); } @@ -2566,10 +2674,9 @@ void DAC960_ReleaseControllerLockIH(DAC960_Controller_T *Controller, ProcessorFlags_T *ProcessorFlags) { - spin_unlock_irqrestore(Controller->RequestQueue.queue_lock, *ProcessorFlags); + spin_unlock_irqrestore(&Controller->queue_lock, *ProcessorFlags); } -#error I am a non-portable driver, please convert me to use the Documentation/DMA-mapping.txt interfaces /* Define the DAC960 BA Series Controller Interface Register Offsets. @@ -2834,17 +2941,14 @@ mb(); } + static inline void DAC960_BA_WriteHardwareMailbox(void *ControllerBaseAddress, - DAC960_V2_CommandMailbox_T *CommandMailbox) + dma_addr_t CommandMailboxDMA) { -#ifdef __ia64__ - writeq(Virtual_to_Bus64(CommandMailbox), - ControllerBaseAddress + DAC960_BA_CommandMailboxBusAddressOffset); -#else - writel(Virtual_to_Bus32(CommandMailbox), - ControllerBaseAddress + DAC960_BA_CommandMailboxBusAddressOffset); -#endif + dma_addr_writeql(CommandMailboxDMA, + ControllerBaseAddress + + DAC960_BA_CommandMailboxBusAddressOffset); } static inline DAC960_V2_CommandIdentifier_T @@ -3142,15 +3246,11 @@ static inline void DAC960_LP_WriteHardwareMailbox(void *ControllerBaseAddress, - DAC960_V2_CommandMailbox_T *CommandMailbox) + dma_addr_t CommandMailboxDMA) { -#ifdef __ia64__ - writeq(Virtual_to_Bus64(CommandMailbox), - ControllerBaseAddress + DAC960_LP_CommandMailboxBusAddressOffset); -#else - writel(Virtual_to_Bus32(CommandMailbox), - ControllerBaseAddress + DAC960_LP_CommandMailboxBusAddressOffset); -#endif + dma_addr_writeql(CommandMailboxDMA, + ControllerBaseAddress + + DAC960_LP_CommandMailboxBusAddressOffset); } static inline DAC960_V2_CommandIdentifier_T @@ -3506,43 +3606,6 @@ return true; } -static inline -void DAC960_LA_SaveMemoryMailboxInfo(DAC960_Controller_T *Controller) -{ -#ifdef __i386__ - void *ControllerBaseAddress = Controller->BaseAddress; - writel(0x743C485E, - ControllerBaseAddress + DAC960_LA_CommandOpcodeRegisterOffset); - writel((unsigned long) Controller->V1.FirstCommandMailbox, - ControllerBaseAddress + DAC960_LA_MailboxRegister4Offset); - writew(Controller->V1.NextCommandMailbox - Controller->V1.FirstCommandMailbox, - ControllerBaseAddress + DAC960_LA_MailboxRegister8Offset); - writew(Controller->V1.NextStatusMailbox - Controller->V1.FirstStatusMailbox, - ControllerBaseAddress + DAC960_LA_MailboxRegister10Offset); -#endif -} - -static inline -void DAC960_LA_RestoreMemoryMailboxInfo(DAC960_Controller_T *Controller, - void **MemoryMailboxAddress, - short *NextCommandMailboxIndex, - short *NextStatusMailboxIndex) -{ -#ifdef __i386__ - void *ControllerBaseAddress = Controller->BaseAddress; - if (readl(ControllerBaseAddress - + DAC960_LA_CommandOpcodeRegisterOffset) != 0x743C485E) - return; - *MemoryMailboxAddress = - (void *) readl(ControllerBaseAddress + DAC960_LA_MailboxRegister4Offset); - *NextCommandMailboxIndex = - readw(ControllerBaseAddress + DAC960_LA_MailboxRegister8Offset); - *NextStatusMailboxIndex = - readw(ControllerBaseAddress + DAC960_LA_MailboxRegister10Offset); -#endif -} - - /* Define the DAC960 PG Series Controller Interface Register Offsets. */ @@ -3868,43 +3931,6 @@ return true; } -static inline -void DAC960_PG_SaveMemoryMailboxInfo(DAC960_Controller_T *Controller) -{ -#ifdef __i386__ - void *ControllerBaseAddress = Controller->BaseAddress; - writel(0x743C485E, - ControllerBaseAddress + DAC960_PG_CommandOpcodeRegisterOffset); - writel((unsigned long) Controller->V1.FirstCommandMailbox, - ControllerBaseAddress + DAC960_PG_MailboxRegister4Offset); - writew(Controller->V1.NextCommandMailbox - Controller->V1.FirstCommandMailbox, - ControllerBaseAddress + DAC960_PG_MailboxRegister8Offset); - writew(Controller->V1.NextStatusMailbox - Controller->V1.FirstStatusMailbox, - ControllerBaseAddress + DAC960_PG_MailboxRegister10Offset); -#endif -} - -static inline -void DAC960_PG_RestoreMemoryMailboxInfo(DAC960_Controller_T *Controller, - void **MemoryMailboxAddress, - short *NextCommandMailboxIndex, - short *NextStatusMailboxIndex) -{ -#ifdef __i386__ - void *ControllerBaseAddress = Controller->BaseAddress; - if (readl(ControllerBaseAddress - + DAC960_PG_CommandOpcodeRegisterOffset) != 0x743C485E) - return; - *MemoryMailboxAddress = - (void *) readl(ControllerBaseAddress + DAC960_PG_MailboxRegister4Offset); - *NextCommandMailboxIndex = - readw(ControllerBaseAddress + DAC960_PG_MailboxRegister8Offset); - *NextStatusMailboxIndex = - readw(ControllerBaseAddress + DAC960_PG_MailboxRegister10Offset); -#endif -} - - /* Define the DAC960 PD Series Controller Interface Register Offsets. */ @@ -4206,9 +4232,8 @@ */ static void DAC960_FinalizeController(DAC960_Controller_T *); -static int DAC960_Notifier(NotifierBlock_T *, unsigned long, void *); static void DAC960_V1_QueueReadWriteCommand(DAC960_Command_T *); -static void DAC960_V2_QueueReadWriteCommand(DAC960_Command_T *); +static void DAC960_V2_QueueReadWriteCommand(DAC960_Command_T *); static void DAC960_RequestFunction(RequestQueue_T *); static void DAC960_BA_InterruptHandler(int, void *, Registers_T *); static void DAC960_LP_InterruptHandler(int, void *, Registers_T *); @@ -4225,7 +4250,7 @@ static int DAC960_UserIOCTL(Inode_T *, File_T *, unsigned int, unsigned long); static void DAC960_Message(DAC960_MessageLevel_T, unsigned char *, DAC960_Controller_T *, ...); -static void DAC960_CreateProcEntries(void); -static void DAC960_DestroyProcEntries(void); +static void DAC960_CreateProcEntries(DAC960_Controller_T *); +static void DAC960_DestroyProcEntries(DAC960_Controller_T *); #endif /* DAC960_DriverVersion */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/drivers/block/floppy98.c linux.2.5.47-ac6/drivers/block/floppy98.c --- linux.2.5.47/drivers/block/floppy98.c 1970-01-01 01:00:00.000000000 +0100 +++ linux.2.5.47-ac6/drivers/block/floppy98.c 2002-11-15 15:32:53.000000000 +0000 @@ -0,0 +1,4650 @@ +/* + * linux/drivers/block/floppy.c + * + * Copyright (C) 1991, 1992 Linus Torvalds + * Copyright (C) 1993, 1994 Alain Knaff + * Copyright (C) 1998 Alan Cox + */ +/* + * 02.12.91 - Changed to static variables to indicate need for reset + * and recalibrate. This makes some things easier (output_byte reset + * checking etc), and means less interrupt jumping in case of errors, + * so the code is hopefully easier to understand. + */ + +/* + * This file is certainly a mess. I've tried my best to get it working, + * but I don't like programming floppies, and I have only one anyway. + * Urgel. I should check for more errors, and do more graceful error + * recovery. Seems there are problems with several drives. I've tried to + * correct them. No promises. + */ + +/* + * As with hd.c, all routines within this file can (and will) be called + * by interrupts, so extreme caution is needed. A hardware interrupt + * handler may not sleep, or a kernel panic will happen. Thus I cannot + * call "floppy-on" directly, but have to set a special timer interrupt + * etc. + */ + +/* + * 28.02.92 - made track-buffering routines, based on the routines written + * by entropy@wintermute.wpi.edu (Lawrence Foard). Linus. + */ + +/* + * Automatic floppy-detection and formatting written by Werner Almesberger + * (almesber@nessie.cs.id.ethz.ch), who also corrected some problems with + * the floppy-change signal detection. + */ + +/* + * 1992/7/22 -- Hennus Bergman: Added better error reporting, fixed + * FDC data overrun bug, added some preliminary stuff for vertical + * recording support. + * + * 1992/9/17: Added DMA allocation & DMA functions. -- hhb. + * + * TODO: Errors are still not counted properly. + */ + +/* 1992/9/20 + * Modifications for ``Sector Shifting'' by Rob Hooft (hooft@chem.ruu.nl) + * modeled after the freeware MS-DOS program fdformat/88 V1.8 by + * Christoph H. Hochst\"atter. + * I have fixed the shift values to the ones I always use. Maybe a new + * ioctl() should be created to be able to modify them. + * There is a bug in the driver that makes it impossible to format a + * floppy as the first thing after bootup. + */ + +/* + * 1993/4/29 -- Linus -- cleaned up the timer handling in the kernel, and + * this helped the floppy driver as well. Much cleaner, and still seems to + * work. + */ + +/* 1994/6/24 --bbroad-- added the floppy table entries and made + * minor modifications to allow 2.88 floppies to be run. + */ + +/* 1994/7/13 -- Paul Vojta -- modified the probing code to allow three or more + * disk types. + */ + +/* + * 1994/8/8 -- Alain Knaff -- Switched to fdpatch driver: Support for bigger + * format bug fixes, but unfortunately some new bugs too... + */ + +/* 1994/9/17 -- Koen Holtman -- added logging of physical floppy write + * errors to allow safe writing by specialized programs. + */ + +/* 1995/4/24 -- Dan Fandrich -- added support for Commodore 1581 3.5" disks + * by defining bit 1 of the "stretch" parameter to mean put sectors on the + * opposite side of the disk, leaving the sector IDs alone (i.e. Commodore's + * drives are "upside-down"). + */ + +/* + * 1995/8/26 -- Andreas Busse -- added Mips support. + */ + +/* + * 1995/10/18 -- Ralf Baechle -- Portability cleanup; move machine dependent + * features to asm/floppy.h. + */ + +/* + * 1998/05/07 -- Russell King -- More portability cleanups; moved definition of + * interrupt and dma channel to asm/floppy.h. Cleaned up some formatting & + * use of '0' for NULL. + */ + +/* + * 1998/06/07 -- Alan Cox -- Merged the 2.0.34 fixes for resource allocation + * failures. + */ + +/* + * 1998/09/20 -- David Weinehall -- Added slow-down code for buggy PS/2-drives. + */ + +/* + * 1999/01/19 -- N.Fujita & Linux/98 Project -- Added code for NEC PC-9800 + * series. + */ + +/* + * 1999/08/13 -- Paul Slootman -- floppy stopped working on Alpha after 24 + * days, 6 hours, 32 minutes and 32 seconds (i.e. MAXINT jiffies; ints were + * being used to store jiffies, which are unsigned longs). + */ + +/* + * 2000/08/28 -- Arnaldo Carvalho de Melo + * - get rid of check_region + * - s/suser/capable/ + */ + +/* + * 2001/08/26 -- Paul Gortmaker - fix insmod oops on machines with no + * floppy controller (lingering task on list after module is gone... boom.) + */ + +/* + * 2002/02/07 -- Anton Altaparmakov - Fix io ports reservation to correct range + * (0x3f2-0x3f5, 0x3f7). This fix is a bit of a hack but the proper fix + * requires many non-obvious changes in arch dependent code. + */ + +/* + * 2002/10/12 -- Osamu Tomita + * split code from floppy.c + * support NEC PC-9800 only + */ + +#define FLOPPY_SANITY_CHECK +#undef FLOPPY_SILENT_DCL_CLEAR + +/* +#define PC9800_DEBUG_FLOPPY +#define PC9800_DEBUG_FLOPPY2 +*/ + +#define REALLY_SLOW_IO + +#define DEBUGT 2 +#define DCL_DEBUG /* debug disk change line */ + +/* do print messages for unexpected interrupts */ +static int print_unex=1; +#include +#include +#include +#include +#include +#include +#define FDPATCHES +#include + +/* + * 1998/1/21 -- Richard Gooch -- devfs support + */ + + +#include +#define FLOPPY98_MOTOR_MASK 0x08 + +#define FDPATCHES +#include +#define FD98_STATUS (0 + FD_IOPORT ) +#define FD98_DATA (2 + FD_IOPORT ) +#define FD_MODE (4 + FD_IOPORT ) +#define FD_MODE_CHANGE 0xbe +#define FD_EMODE_CHANGE 0x4be + +#include +#include +#include +#include +#include +#include +#include +#include /* CMOS defines */ +#include +#include +#include +#include +#include +#include /* for invalidate_buffers() */ + +/* + * PS/2 floppies have much slower step rates than regular floppies. + * It's been recommended that take about 1/4 of the default speed + * in some more extreme cases. + */ +static int slow_floppy; + +#include +#include +#include +#include +#include + +#ifndef DEFAULT_FLOPPY_IRQ +# define DEFAULT_FLOPPY_IRQ 11 +#endif +#ifndef DEFAULT_FLOPPY_DMA +# define DEFAULT_FLOPPY_DMA 2 +#endif + +static int FLOPPY_IRQ=DEFAULT_FLOPPY_IRQ; +static int FLOPPY_DMA=DEFAULT_FLOPPY_DMA; +static int can_use_virtual_dma=2; +static int auto_detect_mode = 0; +static int retry_auto_detect = 0; +#define FD_AFTER_RESET_DELAY 1000 + +/* ======= + * can use virtual DMA: + * 0 = use of virtual DMA disallowed by config + * 1 = use of virtual DMA prescribed by config + * 2 = no virtual DMA preference configured. By default try hard DMA, + * but fall back on virtual DMA when not enough memory available + */ + +static int use_virtual_dma; +/* ======= + * use virtual DMA + * 0 using hard DMA + * 1 using virtual DMA + * This variable is set to virtual when a DMA mem problem arises, and + * reset back in floppy_grab_irq_and_dma. + * It is not safe to reset it in other circumstances, because the floppy + * driver may have several buffers in use at once, and we do currently not + * record each buffers capabilities + */ + +static spinlock_t floppy_lock = SPIN_LOCK_UNLOCKED; + +static unsigned short virtual_dma_port=0x3f0; +void floppy_interrupt(int irq, void *dev_id, struct pt_regs * regs); +static int set_mode(char mask, char data); +static void register_devfs_entries (int drive) __init; +static devfs_handle_t devfs_handle; + +#define K_64 0x10000 /* 64KB */ + +/* the following is the mask of allowed drives. By default units 2 and + * 3 of both floppy controllers are disabled, because switching on the + * motor of these drives causes system hangs on some PCI computers. drive + * 0 is the low bit (0x1), and drive 7 is the high bit (0x80). Bits are on if + * a drive is allowed. + * + * NOTE: This must come before we include the arch floppy header because + * some ports reference this variable from there. -DaveM + */ + +static int allowed_drive_mask = 0x0f; + +#include + +static int irqdma_allocated; + +#define LOCAL_END_REQUEST +#define MAJOR_NR FLOPPY_MAJOR +#define DEVICE_NAME "floppy" +#define DEVICE_NR(device) ( (minor(device) & 3) | ((minor(device) & 0x80 ) >> 5 )) +#include +#include +#include /* for the compatibility eject ioctl */ +#include + +static struct request *current_req; +static struct request_queue floppy_queue; + +#ifndef fd_get_dma_residue +#define fd_get_dma_residue() get_dma_residue(FLOPPY_DMA) +#endif + +/* Dma Memory related stuff */ + +#ifndef fd_dma_mem_free +#define fd_dma_mem_free(addr, size) free_pages(addr, get_order(size)) +#endif + +#ifndef fd_dma_mem_alloc +#define fd_dma_mem_alloc(size) __get_dma_pages(GFP_KERNEL,get_order(size)) +#endif + +static inline void fallback_on_nodma_alloc(char **addr, size_t l) +{ +#ifdef FLOPPY_CAN_FALLBACK_ON_NODMA + if (*addr) + return; /* we have the memory */ + if (can_use_virtual_dma != 2) + return; /* no fallback allowed */ + printk("DMA memory shortage. Temporarily falling back on virtual DMA\n"); + *addr = (char *) nodma_mem_alloc(l); +#else + return; +#endif +} + +/* End dma memory related stuff */ + +static unsigned long fake_change; +static int initialising=1; + +static inline int TYPE(kdev_t x) { + return (minor(x)>>2) & 0x1f; +} +static inline int DRIVE(kdev_t x) { + return (minor(x)&0x03) | ((minor(x)&0x80) >> 5); +} +#define ITYPE(x) (((x)>>2) & 0x1f) +#define TOMINOR(x) ((x & 3) | ((x & 4) << 5)) +#define UNIT(x) ((x) & 0x03) /* drive on fdc */ +#define FDC(x) (((x) & 0x04) >> 2) /* fdc of drive */ +#define REVDRIVE(fdc, unit) ((unit) + ((fdc) << 2)) + /* reverse mapping from unit and fdc to drive */ +#define DP (&drive_params[current_drive]) +#define DRS (&drive_state[current_drive]) +#define DRWE (&write_errors[current_drive]) +#define FDCS (&fdc_state[fdc]) +#define CLEARF(x) (clear_bit(x##_BIT, &DRS->flags)) +#define SETF(x) (set_bit(x##_BIT, &DRS->flags)) +#define TESTF(x) (test_bit(x##_BIT, &DRS->flags)) + +#define UDP (&drive_params[drive]) +#define UDRS (&drive_state[drive]) +#define UDRWE (&write_errors[drive]) +#define UFDCS (&fdc_state[FDC(drive)]) +#define UCLEARF(x) (clear_bit(x##_BIT, &UDRS->flags)) +#define USETF(x) (set_bit(x##_BIT, &UDRS->flags)) +#define UTESTF(x) (test_bit(x##_BIT, &UDRS->flags)) + +#define DPRINT(format, args...) printk(DEVICE_NAME "%d: " format, current_drive , ## args) + +#define PH_HEAD(floppy,head) (((((floppy)->stretch & 2) >>1) ^ head) << 2) +#define STRETCH(floppy) ((floppy)->stretch & FD_STRETCH) + +#define CLEARSTRUCT(x) memset((x), 0, sizeof(*(x))) + +/* read/write */ +#define COMMAND raw_cmd->cmd[0] +#define DR_SELECT raw_cmd->cmd[1] +#define TRACK raw_cmd->cmd[2] +#define HEAD raw_cmd->cmd[3] +#define SECTOR raw_cmd->cmd[4] +#define SIZECODE raw_cmd->cmd[5] +#define SECT_PER_TRACK raw_cmd->cmd[6] +#define GAP raw_cmd->cmd[7] +#define SIZECODE2 raw_cmd->cmd[8] +#define NR_RW 9 + +/* format */ +#define F_SIZECODE raw_cmd->cmd[2] +#define F_SECT_PER_TRACK raw_cmd->cmd[3] +#define F_GAP raw_cmd->cmd[4] +#define F_FILL raw_cmd->cmd[5] +#define NR_F 6 + +/* + * Maximum disk size (in kilobytes). This default is used whenever the + * current disk size is unknown. + * [Now it is rather a minimum] + */ +#define MAX_DISK_SIZE 4 /* 3984*/ + + +/* + * globals used by 'result()' + */ +#define MAX_REPLIES 16 +static unsigned char reply_buffer[MAX_REPLIES]; +static int inr; /* size of reply buffer, when called from interrupt */ +#define ST0 (reply_buffer[0]) +#define ST1 (reply_buffer[1]) +#define ST2 (reply_buffer[2]) +#define ST3 (reply_buffer[0]) /* result of GETSTATUS */ +#define R_TRACK (reply_buffer[3]) +#define R_HEAD (reply_buffer[4]) +#define R_SECTOR (reply_buffer[5]) +#define R_SIZECODE (reply_buffer[6]) + +#define SEL_DLY (2*HZ/100) + +/* + * this struct defines the different floppy drive types. + */ +static struct { + struct floppy_drive_params params; + const char *name; /* name printed while booting */ +} default_drive_params[]= { +/* NOTE: the time values in jiffies should be in msec! + CMOS drive type + | Maximum data rate supported by drive type + | | Head load time, msec + | | | Head unload time, msec (not used) + | | | | Step rate interval, usec + | | | | | Time needed for spinup time (jiffies) + | | | | | | Timeout for spinning down (jiffies) + | | | | | | | Spindown offset (where disk stops) + | | | | | | | | Select delay + | | | | | | | | | RPS + | | | | | | | | | | Max number of tracks + | | | | | | | | | | | Interrupt timeout + | | | | | | | | | | | | Max nonintlv. sectors + | | | | | | | | | | | | | -Max Errors- flags */ +{{0, 500, 16, 16, 8000, 1*HZ, 3*HZ, 0, SEL_DLY, 5, 80, 3*HZ, 20, {3,1,2,0,2}, 0, + 0, { 7, 4, 8, 2, 1, 5, 3,10}, 3*HZ/2, 0 }, "unknown" }, + +{{1, 300, 16, 16, 8000, 1*HZ, 3*HZ, 0, SEL_DLY, 5, 40, 3*HZ, 17, {3,1,2,0,2}, 0, + 0, { 1, 0, 0, 0, 0, 0, 0, 0}, 3*HZ/2, 1 }, "360K PC" }, /*5 1/4 360 KB PC*/ + +{{2, 500, 16, 16, 6000, 4*HZ/10, 3*HZ, 14, SEL_DLY, 6, 83, 3*HZ, 17, {3,1,2,0,2}, 0, + 0, { 2, 6, 4, 0, 0, 0, 0, 0}, 3*HZ/2, 2 }, "1.2M" }, /*5 1/4 HD AT*/ + +{{3, 250, 16, 16, 3000, 1*HZ, 3*HZ, 0, SEL_DLY, 5, 83, 3*HZ, 20, {3,1,2,0,2}, 0, + 0, { 4, 6, 0, 0, 0, 0, 0, 0}, 3*HZ/2, 4 }, "720k" }, /*3 1/2 DD*/ + +{{4, 500, 16, 16, 4000, 4*HZ/10, 3*HZ, 10, SEL_DLY, 5, 83, 3*HZ, 20, {3,1,2,0,2}, 0, + 0, { 7,10, 2, 4, 6, 0, 0, 0}, 3*HZ/2, 7 }, "1.44M" }, /*3 1/2 HD*/ + +{{5, 1000, 15, 8, 3000, 4*HZ/10, 3*HZ, 10, SEL_DLY, 5, 83, 3*HZ, 40, {3,1,2,0,2}, 0, + 0, { 7, 8, 4,25,28,22,31,21}, 3*HZ/2, 8 }, "2.88M AMI BIOS" }, /*3 1/2 ED*/ + +{{6, 1000, 15, 8, 3000, 4*HZ/10, 3*HZ, 10, SEL_DLY, 5, 83, 3*HZ, 40, {3,1,2,0,2}, 0, + 0, { 7, 8, 4,25,28,22,31,21}, 3*HZ/2, 8 }, "2.88M" } /*3 1/2 ED*/ +/* | --autodetected formats--- | | | + * read_track | | Name printed when booting + * | Native format + * Frequency of disk change checks */ +}; + +static struct floppy_drive_params drive_params[N_DRIVE]; +static struct floppy_drive_struct drive_state[N_DRIVE]; +static struct floppy_write_errors write_errors[N_DRIVE]; +static struct timer_list motor_off_timer[N_DRIVE]; +static struct gendisk *disks[N_DRIVE]; +static struct floppy_raw_cmd *raw_cmd, default_raw_cmd; + +/* + * This struct defines the different floppy types. + * + * Bit 0 of 'stretch' tells if the tracks need to be doubled for some + * types (e.g. 360kB diskette in 1.2MB drive, etc.). Bit 1 of 'stretch' + * tells if the disk is in Commodore 1581 format, which means side 0 sectors + * are located on side 1 of the disk but with a side 0 ID, and vice-versa. + * This is the same as the Sharp MZ-80 5.25" CP/M disk format, except that the + * 1581's logical side 0 is on physical side 1, whereas the Sharp's logical + * side 0 is on physical side 0 (but with the misnamed sector IDs). + * 'stretch' should probably be renamed to something more general, like + * 'options'. Other parameters should be self-explanatory (see also + * setfdprm(8)). + */ +/* + Size + | Sectors per track + | | Head + | | | Tracks + | | | | Stretch + | | | | | Gap 1 size + | | | | | | Data rate, | 0x40 for perp + | | | | | | | Spec1 (stepping rate, head unload + | | | | | | | | /fmt gap (gap2) */ +static struct floppy_struct floppy_type[32] = { + { 0, 0,0, 0,0,0x00,0x00,0x00,0x00,NULL }, /* 0 no testing */ +#if 0 + { 720, 9,2,40,0,0x2A,0x02,0xDF,0x50,"d360" }, /* 1 360KB PC */ +#else + { 2464,16,2,77,0,0x35,0x48,0xDF,0x74,"d360" }, /* 1 1.25MB 98 */ +#endif + { 2400,15,2,80,0,0x1B,0x00,0xDF,0x54,"h1200" }, /* 2 1.2MB AT */ + { 720, 9,1,80,0,0x2A,0x02,0xDF,0x50,"D360" }, /* 3 360KB SS 3.5" */ + { 1440, 9,2,80,0,0x2A,0x02,0xDF,0x50,"D720" }, /* 4 720KB 3.5" */ + { 720, 9,2,40,1,0x23,0x01,0xDF,0x50,"h360" }, /* 5 360KB AT */ + { 1440, 9,2,80,0,0x23,0x01,0xDF,0x50,"h720" }, /* 6 720KB AT */ + { 2880,18,2,80,0,0x1B,0x00,0xCF,0x6C,"H1440" }, /* 7 1.44MB 3.5" */ + { 5760,36,2,80,0,0x1B,0x43,0xAF,0x54,"E2880" }, /* 8 2.88MB 3.5" */ + { 6240,39,2,80,0,0x1B,0x43,0xAF,0x28,"E3120" }, /* 9 3.12MB 3.5" */ + + { 2880,18,2,80,0,0x25,0x00,0xDF,0x02,"h1440" }, /* 10 1.44MB 5.25" */ + { 3360,21,2,80,0,0x1C,0x00,0xCF,0x0C,"H1680" }, /* 11 1.68MB 3.5" */ + { 820,10,2,41,1,0x25,0x01,0xDF,0x2E,"h410" }, /* 12 410KB 5.25" */ + { 1640,10,2,82,0,0x25,0x02,0xDF,0x2E,"H820" }, /* 13 820KB 3.5" */ + { 2952,18,2,82,0,0x25,0x00,0xDF,0x02,"h1476" }, /* 14 1.48MB 5.25" */ + { 3444,21,2,82,0,0x25,0x00,0xDF,0x0C,"H1722" }, /* 15 1.72MB 3.5" */ + { 840,10,2,42,1,0x25,0x01,0xDF,0x2E,"h420" }, /* 16 420KB 5.25" */ + { 1660,10,2,83,0,0x25,0x02,0xDF,0x2E,"H830" }, /* 17 830KB 3.5" */ + { 2988,18,2,83,0,0x25,0x00,0xDF,0x02,"h1494" }, /* 18 1.49MB 5.25" */ + { 3486,21,2,83,0,0x25,0x00,0xDF,0x0C,"H1743" }, /* 19 1.74 MB 3.5" */ + + { 1760,11,2,80,0,0x1C,0x09,0xCF,0x00,"h880" }, /* 20 880KB 5.25" */ + { 2080,13,2,80,0,0x1C,0x01,0xCF,0x00,"D1040" }, /* 21 1.04MB 3.5" */ + { 2240,14,2,80,0,0x1C,0x19,0xCF,0x00,"D1120" }, /* 22 1.12MB 3.5" */ + { 3200,20,2,80,0,0x1C,0x20,0xCF,0x2C,"h1600" }, /* 23 1.6MB 5.25" */ + { 3520,22,2,80,0,0x1C,0x08,0xCF,0x2e,"H1760" }, /* 24 1.76MB 3.5" */ + { 3840,24,2,80,0,0x1C,0x20,0xCF,0x00,"H1920" }, /* 25 1.92MB 3.5" */ + { 6400,40,2,80,0,0x25,0x5B,0xCF,0x00,"E3200" }, /* 26 3.20MB 3.5" */ + { 7040,44,2,80,0,0x25,0x5B,0xCF,0x00,"E3520" }, /* 27 3.52MB 3.5" */ + { 7680,48,2,80,0,0x25,0x63,0xCF,0x00,"E3840" }, /* 28 3.84MB 3.5" */ + + { 3680,23,2,80,0,0x1C,0x10,0xCF,0x00,"H1840" }, /* 29 1.84MB 3.5" */ + { 1600,10,2,80,0,0x25,0x02,0xDF,0x2E,"D800" }, /* 30 800KB 3.5" */ + { 3200,20,2,80,0,0x1C,0x00,0xCF,0x2C,"H1600" }, /* 31 1.6MB 3.5" */ +}; + +#define NUMBER(x) (sizeof(x) / sizeof(*(x))) +#define SECTSIZE (_FD_SECTSIZE(*floppy)) + +/* Auto-detection: Disk type used until the next media change occurs. */ +static struct floppy_struct *current_type[N_DRIVE]; + +/* + * User-provided type information. current_type points to + * the respective entry of this array. + */ +static struct floppy_struct user_params[N_DRIVE]; + +static sector_t floppy_sizes[256]; + +/* + * The driver is trying to determine the correct media format + * while probing is set. rw_interrupt() clears it after a + * successful access. + */ +static int probing; + +/* Synchronization of FDC access. */ +#define FD_COMMAND_NONE -1 +#define FD_COMMAND_ERROR 2 +#define FD_COMMAND_OKAY 3 + +static volatile int command_status = FD_COMMAND_NONE; +static unsigned long fdc_busy; +static DECLARE_WAIT_QUEUE_HEAD(fdc_wait); +static DECLARE_WAIT_QUEUE_HEAD(command_done); + +#define NO_SIGNAL (!interruptible || !signal_pending(current)) +#define CALL(x) if ((x) == -EINTR) return -EINTR +#define ECALL(x) if ((ret = (x))) return ret; +#define _WAIT(x,i) CALL(ret=wait_til_done((x),i)) +#define WAIT(x) _WAIT((x),interruptible) +#define IWAIT(x) _WAIT((x),1) + +/* Errors during formatting are counted here. */ +static int format_errors; + +/* Format request descriptor. */ +static struct format_descr format_req; + +/* + * Rate is 0 for 500kb/s, 1 for 300kbps, 2 for 250kbps + * Spec1 is 0xSH, where S is stepping rate (F=1ms, E=2ms, D=3ms etc), + * H is head unload time (1=16ms, 2=32ms, etc) + */ + +/* + * Track buffer + * Because these are written to by the DMA controller, they must + * not contain a 64k byte boundary crossing, or data will be + * corrupted/lost. + */ +static char *floppy_track_buffer; +static int max_buffer_sectors; + +static int *errors; +typedef void (*done_f)(int); +static struct cont_t { + void (*interrupt)(void); /* this is called after the interrupt of the + * main command */ + void (*redo)(void); /* this is called to retry the operation */ + void (*error)(void); /* this is called to tally an error */ + done_f done; /* this is called to say if the operation has + * succeeded/failed */ +} *cont; + +static void floppy_ready(void); +static void floppy_start(void); +static void process_fd_request(void); +static void recalibrate_floppy(void); +static void floppy_shutdown(unsigned long); + +static int floppy_grab_irq_and_dma(void); +static void floppy_release_irq_and_dma(void); + +/* + * The "reset" variable should be tested whenever an interrupt is scheduled, + * after the commands have been sent. This is to ensure that the driver doesn't + * get wedged when the interrupt doesn't come because of a failed command. + * reset doesn't need to be tested before sending commands, because + * output_byte is automatically disabled when reset is set. + */ +#define CHECK_RESET { if (FDCS->reset){ reset_fdc(); return; } } +static void reset_fdc(void); + +/* + * These are global variables, as that's the easiest way to give + * information to interrupts. They are the data used for the current + * request. + */ +#define NO_TRACK -1 +#define NEED_1_RECAL -2 +#define NEED_2_RECAL -3 + +static int usage_count; + +/* buffer related variables */ +static int buffer_track = -1; +static int buffer_drive = -1; +static int buffer_min = -1; +static int buffer_max = -1; + +/* fdc related variables, should end up in a struct */ +static struct floppy_fdc_state fdc_state[N_FDC]; +static int fdc; /* current fdc */ + +static struct floppy_struct *_floppy = floppy_type; +static unsigned char current_drive; +static long current_count_sectors; +static unsigned char fsector_t; /* sector in track */ +static unsigned char in_sector_offset; /* offset within physical sector, + * expressed in units of 512 bytes */ + +#ifndef fd_eject +static inline int fd_eject(int drive) +{ + return -EINVAL; +} +#endif + +#ifdef DEBUGT +static long unsigned debugtimer; +#endif + +/* + * Debugging + * ========= + */ +static inline void set_debugt(void) +{ +#ifdef DEBUGT + debugtimer = jiffies; +#endif +} + +static inline void debugt(const char *message) +{ +#ifdef DEBUGT + if (DP->flags & DEBUGT) + printk("%s dtime=%lu\n", message, jiffies-debugtimer); +#endif +} + +typedef void (*timeout_fn)(unsigned long); +static struct timer_list fd_timeout = TIMER_INITIALIZER(floppy_shutdown, 0, 0); + +static const char *timeout_message; + +#ifdef FLOPPY_SANITY_CHECK +static void is_alive(const char *message) +{ + /* this routine checks whether the floppy driver is "alive" */ + if (fdc_busy && command_status < 2 && !timer_pending(&fd_timeout)){ + DPRINT("timeout handler died: %s\n",message); + } +} +#endif + +static void (*do_floppy)(void) = NULL; + +#ifdef FLOPPY_SANITY_CHECK + +#define OLOGSIZE 20 + +static void (*lasthandler)(void); +static unsigned long interruptjiffies; +static unsigned long resultjiffies; +static int resultsize; +static unsigned long lastredo; + +static struct output_log { + unsigned char data; + unsigned char status; + unsigned long jiffies; +} output_log[OLOGSIZE]; + +static int output_log_pos; +#endif + +#define current_reqD -1 +#define MAXTIMEOUT -2 + +static void reschedule_timeout(int drive, const char *message, int marg) +{ + if (drive == current_reqD) + drive = current_drive; + del_timer(&fd_timeout); + if (drive < 0 || drive > N_DRIVE) { + fd_timeout.expires = jiffies + 20UL*HZ; + drive=0; + } else + fd_timeout.expires = jiffies + UDP->timeout; + add_timer(&fd_timeout); + if (UDP->flags & FD_DEBUG){ + DPRINT("reschedule timeout "); + printk(message, marg); + printk("\n"); + } + timeout_message = message; +} + +static int maximum(int a, int b) +{ + if (a > b) + return a; + else + return b; +} +#define INFBOUND(a,b) (a)=maximum((a),(b)); + +static int minimum(int a, int b) +{ + if (a < b) + return a; + else + return b; +} +#define SUPBOUND(a,b) (a)=minimum((a),(b)); + + +/* + * Bottom half floppy driver. + * ========================== + * + * This part of the file contains the code talking directly to the hardware, + * and also the main service loop (seek-configure-spinup-command) + */ + +/* + * disk change. + * This routine is responsible for maintaining the FD_DISK_CHANGE flag, + * and the last_checked date. + * + * last_checked is the date of the last check which showed 'no disk change' + * FD_DISK_CHANGE is set under two conditions: + * 1. The floppy has been changed after some i/o to that floppy already + * took place. + * 2. No floppy disk is in the drive. This is done in order to ensure that + * requests are quickly flushed in case there is no disk in the drive. It + * follows that FD_DISK_CHANGE can only be cleared if there is a disk in + * the drive. + * + * For 1., maxblock is observed. Maxblock is 0 if no i/o has taken place yet. + * For 2., FD_DISK_NEWCHANGE is watched. FD_DISK_NEWCHANGE is cleared on + * each seek. If a disk is present, the disk change line should also be + * cleared on each seek. Thus, if FD_DISK_NEWCHANGE is clear, but the disk + * change line is set, this means either that no disk is in the drive, or + * that it has been removed since the last seek. + * + * This means that we really have a third possibility too: + * The floppy has been changed after the last seek. + */ + +static int disk_change(int drive) +{ + return UTESTF(FD_DISK_CHANGED); +} + +static int set_mode(char mask, char data) +{ + register unsigned char newdor, olddor; + + olddor = FDCS->dor; + newdor = (olddor & mask) | data; + if (newdor != olddor) { + FDCS->dor = newdor; + fd_outb(newdor, FD_MODE); + } + + if (newdor & FLOPPY98_MOTOR_MASK) + floppy_grab_irq_and_dma(); + + if (olddor & FLOPPY98_MOTOR_MASK) + floppy_release_irq_and_dma(); + + return olddor; +} + +static void twaddle(void) +{ + if (DP->select_delay) + return; + + fd_outb(FDCS->dor & 0xf7, FD_MODE); + fd_outb(FDCS->dor, FD_MODE); + DRS->select_date = jiffies; +} + +/* reset all driver information about the current fdc. This is needed after + * a reset, and after a raw command. */ +static void reset_fdc_info(int mode) +{ + int drive; + + FDCS->spec1 = FDCS->spec2 = -1; + FDCS->need_configure = 1; + FDCS->perp_mode = 1; + FDCS->rawcmd = 0; + for (drive = 0; drive < N_DRIVE; drive++) + if (FDC(drive) == fdc && + (mode || UDRS->track != NEED_1_RECAL)) + UDRS->track = NEED_2_RECAL; +} + +/* selects the fdc and drive, and enables the fdc's input/dma. */ +static void set_fdc(int drive) +{ + fdc = 0; + current_drive = drive; + set_mode(~0, 0x10); + if (FDCS->rawcmd == 2) + reset_fdc_info(1); + + if (fd_inb(FD98_STATUS) != STATUS_READY) + FDCS->reset = 1; +} + +/* locks the driver */ +static int _lock_fdc(int drive, int interruptible, int line) +{ + if (!usage_count){ + printk(KERN_ERR "Trying to lock fdc while usage count=0 at line %d\n", line); + return -1; + } + if(floppy_grab_irq_and_dma()==-1) + return -EBUSY; + + if (test_and_set_bit(0, &fdc_busy)) { + DECLARE_WAITQUEUE(wait, current); + add_wait_queue(&fdc_wait, &wait); + + for (;;) { + set_current_state(TASK_INTERRUPTIBLE); + + if (!test_and_set_bit(0, &fdc_busy)) + break; + + schedule(); + + if (!NO_SIGNAL) { + remove_wait_queue(&fdc_wait, &wait); + return -EINTR; + } + } + + set_current_state(TASK_RUNNING); + remove_wait_queue(&fdc_wait, &wait); + } + command_status = FD_COMMAND_NONE; + + reschedule_timeout(drive, "lock fdc", 0); + set_fdc(drive); + return 0; +} + +#define lock_fdc(drive,interruptible) _lock_fdc(drive,interruptible, __LINE__) + +#define LOCK_FDC(drive,interruptible) \ +if (lock_fdc(drive,interruptible)) return -EINTR; + + +/* unlocks the driver */ +static inline void unlock_fdc(void) +{ + raw_cmd = 0; + if (!fdc_busy) + DPRINT("FDC access conflict!\n"); + + if (do_floppy) + DPRINT("device interrupt still active at FDC release: %p!\n", + do_floppy); + command_status = FD_COMMAND_NONE; + del_timer(&fd_timeout); + cont = NULL; + clear_bit(0, &fdc_busy); + floppy_release_irq_and_dma(); + wake_up(&fdc_wait); +} + +#ifndef CONFIG_PC9800_MOTOR_OFF /* tomita */ + +/* switches the motor off after a given timeout */ +static void motor_off_callback(unsigned long nr) +{ + printk(KERN_DEBUG "fdc%lu: turn off motor\n", nr); +} + +/* schedules motor off */ +static void floppy_off(unsigned int drive) +{ +} + +#else /* CONFIG_PC9800_MOTOR_OFF */ + +/* switches the motor off after a given timeout */ +static void motor_off_callback(unsigned long fdc) +{ + printk(KERN_DEBUG "fdc%u: turn off motor\n", (unsigned int) fdc); + + fd_outb(0, FD_MODE); /* MTON = 0 */ +} + +static struct timer_list motor_off_timer[N_FDC] = { + { data: 0, function: motor_off_callback }, +#if N_FDC > 1 + { data: 1, function: motor_off_callback }, +#endif +#if N_FDC > 2 +# error "N_FDC > 2; please fix initializer for motor_off_timer[]" +#endif +}; + +/* schedules motor off */ +static void floppy_off(unsigned int drive) +{ + unsigned long volatile delta; + register int fdc = FDC(drive); + + if (!(FDCS->dor & (0x10 << UNIT(drive)))) + return; + + del_timer(motor_off_timer + fdc); + +#if 0 + /* make spindle stop in a position which minimizes spinup time + * next time */ + if (UDP->rps){ + delta = jiffies - UDRS->first_read_date + HZ - + UDP->spindown_offset; + delta = ((delta * UDP->rps) % HZ) / UDP->rps; + motor_off_timer[drive].expires = jiffies + UDP->spindown - delta; + } +#else + if (UDP->rps) + motor_off_timer[drive].expires = jiffies + UDP->spindown; +#endif + + add_timer(motor_off_timer + fdc); +} + +#endif /* CONFIG_PC9800_MOTOR_OFF */ + +/* + * cycle through all N_DRIVE floppy drives, for disk change testing. + * stopping at current drive. This is done before any long operation, to + * be sure to have up to date disk change information. + */ +static void scandrives(void) +{ + int i, drive, saved_drive; + + if (DP->select_delay) + return; + + saved_drive = current_drive; + for (i=0; i < N_DRIVE; i++){ + drive = (saved_drive + i + 1) % N_DRIVE; + if (UDRS->fd_ref == 0 || UDP->select_delay != 0) + continue; /* skip closed drives */ + set_fdc(drive); + } + set_fdc(saved_drive); +} + +static void empty(void) +{ +} + +static DECLARE_WORK(floppy_work, NULL, NULL); + +static void schedule_bh( void (*handler)(void*) ) +{ + PREPARE_WORK(&floppy_work, handler, NULL); + schedule_work(&floppy_work); +} + +static struct timer_list fd_timer = TIMER_INITIALIZER(NULL, 0, 0); + +static void cancel_activity(void) +{ + do_floppy = NULL; + PREPARE_WORK(&floppy_work, (void*)(void*)empty, NULL); + del_timer(&fd_timer); +} + +/* this function makes sure that the disk stays in the drive during the + * transfer */ +static void fd_watchdog(void) +{ +#ifdef DCL_DEBUG + if (DP->flags & FD_DEBUG){ + DPRINT("calling disk change from watchdog\n"); + } +#endif + + if (disk_change(current_drive)){ + DPRINT("disk removed during i/o\n"); + cancel_activity(); + cont->done(0); + reset_fdc(); + } else { + del_timer(&fd_timer); + fd_timer.function = (timeout_fn) fd_watchdog; + fd_timer.expires = jiffies + HZ / 10; + add_timer(&fd_timer); + } +} + +static void main_command_interrupt(void) +{ + del_timer(&fd_timer); + cont->interrupt(); +} + +/* waits for a delay (spinup or select) to pass */ +static int fd_wait_for_completion(unsigned long delay, timeout_fn function) +{ + if (FDCS->reset){ + reset_fdc(); /* do the reset during sleep to win time + * if we don't need to sleep, it's a good + * occasion anyways */ + return 1; + } + + if ((signed) (jiffies - delay) < 0){ + del_timer(&fd_timer); + fd_timer.function = function; + fd_timer.expires = delay; + add_timer(&fd_timer); + return 1; + } + return 0; +} + +static spinlock_t floppy_hlt_lock = SPIN_LOCK_UNLOCKED; +static int hlt_disabled; +static void floppy_disable_hlt(void) +{ + unsigned long flags; + + spin_lock_irqsave(&floppy_hlt_lock, flags); + if (!hlt_disabled) { + hlt_disabled=1; +#ifdef HAVE_DISABLE_HLT + disable_hlt(); +#endif + } + spin_unlock_irqrestore(&floppy_hlt_lock, flags); +} + +static void floppy_enable_hlt(void) +{ + unsigned long flags; + + spin_lock_irqsave(&floppy_hlt_lock, flags); + if (hlt_disabled){ + hlt_disabled=0; +#ifdef HAVE_DISABLE_HLT + enable_hlt(); +#endif + } + spin_unlock_irqrestore(&floppy_hlt_lock, flags); +} + + +static void setup_DMA(void) +{ + unsigned long f; + +#ifdef FLOPPY_SANITY_CHECK + if (raw_cmd->length == 0){ + int i; + + printk("zero dma transfer size:"); + for (i=0; i < raw_cmd->cmd_count; i++) + printk("%x,", raw_cmd->cmd[i]); + printk("\n"); + cont->done(0); + FDCS->reset = 1; + return; + } + if (((unsigned long) raw_cmd->kernel_data) % 512){ + printk("non aligned address: %p\n", raw_cmd->kernel_data); + cont->done(0); + FDCS->reset=1; + return; + } +#endif + f=claim_dma_lock(); + fd_disable_dma(); +#ifdef fd_dma_setup + if (fd_dma_setup(raw_cmd->kernel_data, raw_cmd->length, + (raw_cmd->flags & FD_RAW_READ)? + DMA_MODE_READ : DMA_MODE_WRITE, + FDCS->address) < 0) { + release_dma_lock(f); + cont->done(0); + FDCS->reset=1; + return; + } + release_dma_lock(f); +#else + fd_clear_dma_ff(); + fd_cacheflush(raw_cmd->kernel_data, raw_cmd->length); + fd_set_dma_mode((raw_cmd->flags & FD_RAW_READ)? + DMA_MODE_READ : DMA_MODE_WRITE); + fd_set_dma_addr(raw_cmd->kernel_data); + fd_set_dma_count(raw_cmd->length); + virtual_dma_port = FDCS->address; + fd_enable_dma(); + release_dma_lock(f); +#endif + floppy_disable_hlt(); +} + +static void show_floppy(void); + +/* waits until the fdc becomes ready */ + +#ifdef PC9800_DEBUG_FLOPPY +#define READY_DELAY 10000000 +#else +#define READY_DELAY 100000 +#endif + +static int wait_til_ready(void) +{ + int counter, status; + if (FDCS->reset) + return -1; + for (counter = 0; counter < READY_DELAY; counter++) { + status = fd_inb(FD98_STATUS); + if (status & STATUS_READY) + return status; + } + if (!initialising) { + DPRINT("Getstatus times out (%x) on fdc %d\n", + status, fdc); + show_floppy(); + } + FDCS->reset = 1; + return -1; +} + +/* sends a command byte to the fdc */ +static int output_byte(char byte) +{ + int status; + + if ((status = wait_til_ready()) < 0) + return -1; + if ((status & (STATUS_READY|STATUS_DIR|STATUS_DMA)) == STATUS_READY){ + fd_outb(byte,FD98_DATA); +#ifdef FLOPPY_SANITY_CHECK + output_log[output_log_pos].data = byte; + output_log[output_log_pos].status = status; + output_log[output_log_pos].jiffies = jiffies; + output_log_pos = (output_log_pos + 1) % OLOGSIZE; +#endif + return 0; + } + FDCS->reset = 1; + if (!initialising) { + DPRINT("Unable to send byte %x to FDC. Fdc=%x Status=%x\n", + byte, fdc, status); + show_floppy(); + } + return -1; +} +#define LAST_OUT(x) if (output_byte(x)<0){ reset_fdc();return;} + +/* gets the response from the fdc */ +static int result(void) +{ + int i, status=0; + + for(i=0; i < MAX_REPLIES; i++) { + if ((status = wait_til_ready()) < 0) + break; + status &= STATUS_DIR|STATUS_READY|STATUS_BUSY|STATUS_DMA; + if ((status & ~STATUS_BUSY) == STATUS_READY){ +#ifdef FLOPPY_SANITY_CHECK + resultjiffies = jiffies; + resultsize = i; +#endif + return i; + } + if (status == (STATUS_DIR|STATUS_READY|STATUS_BUSY)) + reply_buffer[i] = fd_inb(FD98_DATA); + else + break; + } + if (!initialising) { + DPRINT("get result error. Fdc=%d Last status=%x Read bytes=%d\n", + fdc, status, i); + show_floppy(); + } + FDCS->reset = 1; + return -1; +} + +static int fifo_depth = 0xa; +static int no_fifo; + +#define NOMINAL_DTR 500 + +/* Issue a "SPECIFY" command to set the step rate time, head unload time, + * head load time, and DMA disable flag to values needed by floppy. + * + * The value "dtr" is the data transfer rate in Kbps. It is needed + * to account for the data rate-based scaling done by the 82072 and 82077 + * FDC types. This parameter is ignored for other types of FDCs (i.e. + * 8272a). + * + * Note that changing the data transfer rate has a (probably deleterious) + * effect on the parameters subject to scaling for 82072/82077 FDCs, so + * fdc_specify is called again after each data transfer rate + * change. + * + * srt: 1000 to 16000 in microseconds + * hut: 16 to 240 milliseconds + * hlt: 2 to 254 milliseconds + * + * These values are rounded up to the next highest available delay time. + */ +static void fdc_specify(void) +{ + output_byte(FD_SPECIFY); + output_byte(FDCS->spec1 = 0xdf); + output_byte(FDCS->spec2 = 0x24); +} + +static void tell_sector(void) +{ + printk(": track %d, head %d, sector %d, size %d", + R_TRACK, R_HEAD, R_SECTOR, R_SIZECODE); +} /* tell_sector */ + +static int auto_detect_mode_pc9800(void) +{ +#ifdef PC9800_DEBUG_FLOPPY + printk("auto_detect_mode_pc9800: retry_auto_detect=%d\n", + retry_auto_detect); +#endif + if (retry_auto_detect > 4) { + retry_auto_detect = 0; + return 1; + } + + switch ((int)(_floppy - floppy_type)) { + case 2: + _floppy = floppy_type + 4; + break; + + case 4: + case 6: + _floppy = floppy_type + 7; + break; + + case 7: + case 10: + _floppy = floppy_type + 2; + break; + + default: + _floppy = floppy_type + 7; + } + + retry_auto_detect++; + return 0; +} + +static void access_mode_change_pc9800(void); + +/* + * OK, this error interpreting routine is called after a + * DMA read/write has succeeded + * or failed, so we check the results, and copy any buffers. + * hhb: Added better error reporting. + * ak: Made this into a separate routine. + */ +static int interpret_errors(void) +{ + char bad; + + if (inr!=7) { + DPRINT("-- FDC reply error"); + FDCS->reset = 1; + return 1; + } + + /* check IC to find cause of interrupt */ + switch (ST0 & ST0_INTR) { + case 0x40: /* error occurred during command execution */ + if (ST1 & ST1_EOC) + return 0; /* occurs with pseudo-DMA */ + bad = 1; + if (ST1 & ST1_WP) { + DPRINT("Drive is write protected\n"); + CLEARF(FD_DISK_WRITABLE); + cont->done(0); + bad = 2; + } else if (ST1 & ST1_ND) { + SETF(FD_NEED_TWADDLE); + } else if (ST1 & ST1_OR) { + if (DP->flags & FTD_MSG) + DPRINT("Over/Underrun - retrying\n"); + bad = 0; + }else if (*errors >= DP->max_errors.reporting){ + if (ST0 & ST0_ECE) { + printk("Recalibrate failed!"); + } else if (ST2 & ST2_CRC) { + printk("data CRC error"); + tell_sector(); + } else if (ST1 & ST1_CRC) { + printk("CRC error"); + tell_sector(); + } else if ((ST1 & (ST1_MAM|ST1_ND)) || (ST2 & ST2_MAM)) { + if (auto_detect_mode) { + bad = (char)auto_detect_mode_pc9800(); + access_mode_change_pc9800(); + } + + if (bad) { + printk("floppy error: MA: _floppy - floppy_type=%d\n", (int)(_floppy - floppy_type)); + printk("bad=%d\n", (int)bad); + if (!probing) { + printk("sector not found"); + tell_sector(); + } else + printk("probe failed..."); + } + } else if (ST2 & ST2_WC) { /* seek error */ + printk("wrong cylinder"); + } else if (ST2 & ST2_BC) { /* cylinder marked as bad */ + printk("bad cylinder"); + } else { + printk("unknown error. ST[0..2] are: 0x%x 0x%x 0x%x", ST0, ST1, ST2); + tell_sector(); + } + printk("\n"); + + } + if (ST2 & ST2_WC || ST2 & ST2_BC) + /* wrong cylinder => recal */ + DRS->track = NEED_2_RECAL; + return bad; + case 0x80: /* invalid command given */ + DPRINT("Invalid FDC command given!\n"); + cont->done(0); + return 2; + case 0xc0: + SETF(FD_DISK_CHANGED); + SETF(FD_DISK_WRITABLE); + DPRINT("Abnormal termination caused by polling\n"); + cont->error(); + return 2; + default: /* (0) Normal command termination */ + auto_detect_mode = 0; + return 0; + } +} + +/* + * This routine is called when everything should be correctly set up + * for the transfer (i.e. floppy motor is on, the correct floppy is + * selected, and the head is sitting on the right track). + */ +static void setup_rw_floppy(void) +{ + int i,r, flags,dflags; + unsigned long ready_date; + timeout_fn function; + + access_mode_change_pc9800(); + flags = raw_cmd->flags; + if (flags & (FD_RAW_READ | FD_RAW_WRITE)) + flags |= FD_RAW_INTR; + + if ((flags & FD_RAW_SPIN) && !(flags & FD_RAW_NO_MOTOR)){ + ready_date = DRS->spinup_date + DP->spinup; + /* If spinup will take a long time, rerun scandrives + * again just before spinup completion. Beware that + * after scandrives, we must again wait for selection. + */ + if ((signed) (ready_date - jiffies) > DP->select_delay){ + ready_date -= DP->select_delay; + function = (timeout_fn) floppy_start; + } else + function = (timeout_fn) setup_rw_floppy; + + /* wait until the floppy is spinning fast enough */ + if (fd_wait_for_completion(ready_date,function)) + return; + } + dflags = DRS->flags; + + if ((flags & FD_RAW_READ) || (flags & FD_RAW_WRITE)) + setup_DMA(); + + if (flags & FD_RAW_INTR) + do_floppy = main_command_interrupt; + + r=0; + for (i=0; i< raw_cmd->cmd_count; i++) + r|=output_byte(raw_cmd->cmd[i]); + +#ifdef DEBUGT + debugt("rw_command: "); +#endif + if (r){ + cont->error(); + reset_fdc(); + return; + } + + if (!(flags & FD_RAW_INTR)){ + inr = result(); + cont->interrupt(); + } else if (flags & FD_RAW_NEED_DISK) + fd_watchdog(); +} + +static int blind_seek; + +/* + * This is the routine called after every seek (or recalibrate) interrupt + * from the floppy controller. + */ +static void seek_interrupt(void) +{ +#ifdef DEBUGT + debugt("seek interrupt:"); +#endif + if (inr != 2 || (ST0 & 0xF8) != 0x20) { + DRS->track = NEED_2_RECAL; + cont->error(); + cont->redo(); + return; + } + if (DRS->track >= 0 && DRS->track != ST1 && !blind_seek){ +#ifdef DCL_DEBUG + if (DP->flags & FD_DEBUG){ + DPRINT("clearing NEWCHANGE flag because of effective seek\n"); + DPRINT("jiffies=%lu\n", jiffies); + } +#endif + CLEARF(FD_DISK_NEWCHANGE); /* effective seek */ + CLEARF(FD_DISK_CHANGED); /* effective seek */ + DRS->select_date = jiffies; + } + DRS->track = ST1; + floppy_ready(); +} + +static void check_wp(void) +{ + if (TESTF(FD_VERIFY)) { + /* check write protection */ + output_byte(FD_GETSTATUS); + output_byte(UNIT(current_drive)); + if (result() != 1){ + FDCS->reset = 1; + return; + } + CLEARF(FD_VERIFY); + CLEARF(FD_NEED_TWADDLE); +#ifdef DCL_DEBUG + if (DP->flags & FD_DEBUG){ + DPRINT("checking whether disk is write protected\n"); + DPRINT("wp=%x\n",ST3 & 0x40); + } +#endif + if (!(ST3 & 0x40)) + SETF(FD_DISK_WRITABLE); + else + CLEARF(FD_DISK_WRITABLE); + } +} + +static void seek_floppy(void) +{ + int track; + + blind_seek=0; + +#ifdef DCL_DEBUG + if (DP->flags & FD_DEBUG){ + DPRINT("calling disk change from seek\n"); + } +#endif + + if (!TESTF(FD_DISK_NEWCHANGE) && + disk_change(current_drive) && + (raw_cmd->flags & FD_RAW_NEED_DISK)){ + /* the media changed flag should be cleared after the seek. + * If it isn't, this means that there is really no disk in + * the drive. + */ + SETF(FD_DISK_CHANGED); + cont->done(0); + cont->redo(); + return; + } + if (DRS->track <= NEED_1_RECAL){ + recalibrate_floppy(); + return; + } else if (TESTF(FD_DISK_NEWCHANGE) && + (raw_cmd->flags & FD_RAW_NEED_DISK) && + (DRS->track <= NO_TRACK || DRS->track == raw_cmd->track)) { + /* we seek to clear the media-changed condition. Does anybody + * know a more elegant way, which works on all drives? */ + if (raw_cmd->track) + track = raw_cmd->track - 1; + else { + if (DP->flags & FD_SILENT_DCL_CLEAR){ + blind_seek = 1; + raw_cmd->flags |= FD_RAW_NEED_SEEK; + } + track = 1; + } + } else { + check_wp(); + if (raw_cmd->track != DRS->track && + (raw_cmd->flags & FD_RAW_NEED_SEEK)) + track = raw_cmd->track; + else { + setup_rw_floppy(); + return; + } + } + + do_floppy = seek_interrupt; + output_byte(FD_SEEK); + output_byte(UNIT(current_drive)); + LAST_OUT(track); +#ifdef DEBUGT + debugt("seek command:"); +#endif +} + +static void recal_interrupt(void) +{ +#ifdef DEBUGT + debugt("recal interrupt:"); +#endif + if (inr !=2) + FDCS->reset = 1; + else if (ST0 & ST0_ECE) { + switch(DRS->track){ + case NEED_1_RECAL: +#ifdef DEBUGT + debugt("recal interrupt need 1 recal:"); +#endif + /* after a second recalibrate, we still haven't + * reached track 0. Probably no drive. Raise an + * error, as failing immediately might upset + * computers possessed by the Devil :-) */ + cont->error(); + cont->redo(); + return; + case NEED_2_RECAL: +#ifdef DEBUGT + debugt("recal interrupt need 2 recal:"); +#endif + /* If we already did a recalibrate, + * and we are not at track 0, this + * means we have moved. (The only way + * not to move at recalibration is to + * be already at track 0.) Clear the + * new change flag */ +#ifdef DCL_DEBUG + if (DP->flags & FD_DEBUG){ + DPRINT("clearing NEWCHANGE flag because of second recalibrate\n"); + } +#endif + + CLEARF(FD_DISK_NEWCHANGE); + DRS->select_date = jiffies; + /* fall through */ + default: +#ifdef DEBUGT + debugt("recal interrupt default:"); +#endif + /* Recalibrate moves the head by at + * most 80 steps. If after one + * recalibrate we don't have reached + * track 0, this might mean that we + * started beyond track 80. Try + * again. */ + DRS->track = NEED_1_RECAL; + break; + } + } else + DRS->track = ST1; + floppy_ready(); +} + +static void print_result(char *message, int inr) +{ + int i; + + DPRINT("%s ", message); + if (inr >= 0) + for (i=0; i= N_FDC || FDCS->address == -1){ + /* we don't even know which FDC is the culprit */ + printk("DOR0=%x\n", fdc_state[0].dor); + printk("floppy interrupt on bizarre fdc %d\n",fdc); + printk("handler=%p\n", handler); + is_alive("bizarre fdc"); + return; + } + + FDCS->reset = 0; + /* We have to clear the reset flag here, because apparently on boxes + * with level triggered interrupts (PS/2, Sparc, ...), it is needed to + * emit SENSEI's to clear the interrupt line. And FDCS->reset blocks the + * emission of the SENSEI's. + * It is OK to emit floppy commands because we are in an interrupt + * handler here, and thus we have to fear no interference of other + * activity. + */ + + do_print = !handler && !initialising; + + inr = result(); + if (inr && do_print) + print_result("unexpected interrupt", inr); + if (inr == 0){ + do { + output_byte(FD_SENSEI); + inr = result(); + if ((ST0 & ST0_INTR) == 0xC0) { + int drive = ST0 & ST0_DS; + + /* Attention Interrupt. */ + if (ST0 & ST0_NR) { +#ifdef PC9800_DEBUG_FLOPPY + if (do_print) + printk(KERN_DEBUG + "floppy debug: floppy ejected (drive %d)\n", + drive); +#endif + USETF(FD_DISK_CHANGED); + USETF(FD_VERIFY); + } else { +#ifdef PC9800_DEBUG_FLOPPY + if (do_print) + printk(KERN_DEBUG + "floppy debug: floppy inserted (drive %d)\n", + drive); +#endif + } + } /* Attention Interrupt */ +#ifdef PC9800_DEBUG_FLOPPY + else { + printk(KERN_DEBUG + "floppy debug : unknown interrupt\n"); + } +#endif + } while ((ST0 & 0x83) != UNIT(current_drive) && inr == 2); + } + if (handler) { + schedule_bh( (void *)(void *) handler); + } else { +#if 0 + FDCS->reset = 1; +#endif + } + is_alive("normal interrupt end"); +} + +static void recalibrate_floppy(void) +{ +#ifdef DEBUGT + debugt("recalibrate floppy:"); +#endif + do_floppy = recal_interrupt; + output_byte(FD_RECALIBRATE); + LAST_OUT(UNIT(current_drive)); +} + +/* + * Must do 4 FD_SENSEIs after reset because of ``drive polling''. + */ +static void reset_interrupt(void) +{ +#ifdef PC9800_DEBUG_FLOPPY + printk("floppy debug: reset interrupt\n"); +#endif +#ifdef DEBUGT + debugt("reset interrupt:"); +#endif + result(); /* get the status ready for set_fdc */ + if (FDCS->reset) { + printk("reset set in interrupt, calling %p\n", cont->error); + cont->error(); /* a reset just after a reset. BAD! */ + } + cont->redo(); +} + +/* + * reset is done by pulling bit 2 of DOR low for a while (old FDCs), + * or by setting the self clearing bit 7 of STATUS (newer FDCs) + */ +static void reset_fdc(void) +{ + unsigned long flags; + +#ifdef PC9800_DEBUG_FLOPPY + printk("floppy debug: reset_fdc\n"); +#endif + + do_floppy = reset_interrupt; + FDCS->reset = 0; + reset_fdc_info(0); + + /* Pseudo-DMA may intercept 'reset finished' interrupt. */ + /* Irrelevant for systems with true DMA (i386). */ + + flags=claim_dma_lock(); + fd_disable_dma(); + release_dma_lock(flags); + + fd_outb(FDCS->dor | 0x80, FD_MODE); + udelay(FD_RESET_DELAY); + fd_outb(FDCS->dor, FD_MODE); + udelay(FD_AFTER_RESET_DELAY); +} + +static void show_floppy(void) +{ + int i; + + printk("\n"); + printk("floppy driver state\n"); + printk("-------------------\n"); + printk("now=%lu last interrupt=%lu diff=%lu last called handler=%p\n", + jiffies, interruptjiffies, jiffies-interruptjiffies, lasthandler); + + +#ifdef FLOPPY_SANITY_CHECK + printk("timeout_message=%s\n", timeout_message); + printk("last output bytes:\n"); + for (i=0; i < OLOGSIZE; i++) + printk("%2x %2x %lu\n", + output_log[(i+output_log_pos) % OLOGSIZE].data, + output_log[(i+output_log_pos) % OLOGSIZE].status, + output_log[(i+output_log_pos) % OLOGSIZE].jiffies); + printk("last result at %lu\n", resultjiffies); + printk("last redo_fd_request at %lu\n", lastredo); + for (i=0; ireset = 1; + if (cont){ + cont->done(0); + cont->redo(); /* this will recall reset when needed */ + } else { + printk("no cont in shutdown!\n"); + process_fd_request(); + } + is_alive("floppy shutdown"); +} +/*typedef void (*timeout_fn)(unsigned long);*/ + +static void access_mode_change_pc9800(void) +{ + static int access_mode, mode_change_now, old_mode, new_set = 1; +#ifdef PC9800_DEBUG_FLOPPY2 + printk("enter access_mode_change\n"); +#endif + access_mode = mode_change_now = 0; + if (DP->cmos==4) { + switch ((int)(_floppy - &floppy_type[0])) { + case 1: + case 2: + new_set = 1; + access_mode = 2; + break; + + case 4: + case 6: + new_set = 1; + access_mode = 3; + break; + + case 7: + case 10: + new_set = 1; + access_mode = 1; + break; + + default: + access_mode = 1; + break; + } + + old_mode = fd_inb(FD_MODE_CHANGE) & 3; + + switch (access_mode) { + case 1: + if ((old_mode & 2) == 0) { + fd_outb(old_mode | 2, FD_MODE_CHANGE); + mode_change_now = 1; + } else { + fd_outb(current_drive << 5, FD_EMODE_CHANGE); + if (fd_inb(FD_EMODE_CHANGE) == 0xff) + return; + } + + fd_outb((current_drive << 5) | 0x11, FD_EMODE_CHANGE); + mode_change_now = 1; + break; + + case 2: + if ((old_mode & 2) == 0) { + fd_outb(old_mode | 2, FD_MODE_CHANGE); + mode_change_now = 1; + } else { + fd_outb(current_drive << 5, FD_EMODE_CHANGE); + if ((fd_inb(FD_EMODE_CHANGE) & 1) == 0) + return; + fd_outb((current_drive << 5) | 0x10, FD_EMODE_CHANGE); + mode_change_now = 1; + } + + break; + + case 3: + if ((old_mode & 2) == 0) + return; + fd_outb(current_drive << 5, FD_EMODE_CHANGE); + if (fd_inb(FD_EMODE_CHANGE) & 1) + fd_outb((current_drive << 5) | 0x10, FD_EMODE_CHANGE); + fd_outb(old_mode & 0xfd, FD_MODE_CHANGE); + mode_change_now = 1; + break; + + default: + break; + } + } else { + switch ((int)(_floppy - &floppy_type[0])) { + case 1: + case 2: + new_set = 1; + access_mode = 2; + break; + + case 4: + case 6: + new_set = 1; + access_mode = 3; + break; + + default: + switch (DP->cmos) { + case 2: + access_mode = 2; + break; + + case 3: + access_mode = 3; + break; + + default: + break; + } + + break; + } + + old_mode = fd_inb(FD_MODE_CHANGE) & 3; + + switch (access_mode) { + case 2: + if ((old_mode & 2) == 0) { + fd_outb(old_mode | 2, FD_MODE_CHANGE); + mode_change_now = 1; + } + + break; + + case 3: + if (old_mode & 2) { + fd_outb(old_mode & 0xfd, FD_MODE_CHANGE); + mode_change_now = 1; + } + + break; + + default: + break; + } + } +#ifdef PC9800_DEBUG_FLOPPY2 + printk("floppy debug: DP->cmos=%d\n", DP->cmos); + printk("floppy debug: mode_change_now=%d\n", mode_change_now); + printk("floppy debug: access_mode=%d\n", access_mode); + printk("floppy debug: old_mode=%d\n", old_mode); + printk("floppy debug: _floppy - &floppy_type[0]=%d\n", (int)(_floppy - &floppy_type[0])); +#endif /* PC9800_DEBUG_FLOPPY2 */ + if(mode_change_now) + reset_fdc(); +} + +/* start motor, check media-changed condition and write protection */ +static int start_motor(void (*function)(void) ) +{ + access_mode_change_pc9800(); + set_mode(~0, 0x8); + + /* wait_for_completion also schedules reset if needed. */ + return(fd_wait_for_completion(DRS->select_date+DP->select_delay, + (timeout_fn) function)); +} + +static void floppy_ready(void) +{ + CHECK_RESET; + if (start_motor(floppy_ready)) return; + +#ifdef DCL_DEBUG + if (DP->flags & FD_DEBUG){ + DPRINT("calling disk change from floppy_ready\n"); + } +#endif + if (!(raw_cmd->flags & FD_RAW_NO_MOTOR) && + disk_change(current_drive) && + !DP->select_delay) + twaddle(); /* this clears the dcl on certain drive/controller + * combinations */ + +#ifdef fd_chose_dma_mode + if ((raw_cmd->flags & FD_RAW_READ) || + (raw_cmd->flags & FD_RAW_WRITE)) + { + unsigned long flags = claim_dma_lock(); + fd_chose_dma_mode(raw_cmd->kernel_data, + raw_cmd->length); + release_dma_lock(flags); + } +#endif + +#if 0 + access_mode_change_pc9800(); +#endif + if (raw_cmd->flags & (FD_RAW_NEED_SEEK | FD_RAW_NEED_DISK)){ + fdc_specify(); /* must be done here because of hut, hlt ... */ + seek_floppy(); + } else { + if ((raw_cmd->flags & FD_RAW_READ) || + (raw_cmd->flags & FD_RAW_WRITE)) + fdc_specify(); + setup_rw_floppy(); + } +} + +static void floppy_start(void) +{ + reschedule_timeout(current_reqD, "floppy start", 0); + + scandrives(); +#ifdef DCL_DEBUG + if (DP->flags & FD_DEBUG){ + DPRINT("setting NEWCHANGE in floppy_start\n"); + } +#endif + SETF(FD_DISK_NEWCHANGE); + floppy_ready(); +} + +/* + * ======================================================================== + * here ends the bottom half. Exported routines are: + * floppy_start, floppy_off, floppy_ready, lock_fdc, unlock_fdc, set_fdc, + * start_motor, reset_fdc, reset_fdc_info, interpret_errors. + * Initialization also uses output_byte, result, set_dor, floppy_interrupt + * and set_dor. + * ======================================================================== + */ +/* + * General purpose continuations. + * ============================== + */ + +static void do_wakeup(void) +{ + reschedule_timeout(MAXTIMEOUT, "do wakeup", 0); + cont = 0; + command_status += 2; + wake_up(&command_done); +} + +static struct cont_t wakeup_cont={ + empty, + do_wakeup, + empty, + (done_f)empty +}; + + +static struct cont_t intr_cont={ + empty, + process_fd_request, + empty, + (done_f) empty +}; + +static int wait_til_done(void (*handler)(void), int interruptible) +{ + int ret; + + schedule_bh((void *)(void *)handler); + + if (command_status < 2 && NO_SIGNAL) { + DECLARE_WAITQUEUE(wait, current); + + add_wait_queue(&command_done, &wait); + for (;;) { + set_current_state(interruptible? + TASK_INTERRUPTIBLE: + TASK_UNINTERRUPTIBLE); + + if (command_status >= 2 || !NO_SIGNAL) + break; + + is_alive("wait_til_done"); + + schedule(); + } + + set_current_state(TASK_RUNNING); + remove_wait_queue(&command_done, &wait); + } + + if (command_status < 2){ + cancel_activity(); + cont = &intr_cont; + reset_fdc(); + return -EINTR; + } + +#ifdef PC9800_DEBUG_FLOPPY + if (command_status != FD_COMMAND_OKAY) + printk("floppy check: wait_til_done out:%d\n", command_status); +#endif + if (FDCS->reset) + command_status = FD_COMMAND_ERROR; + if (command_status == FD_COMMAND_OKAY) + ret=0; + else + ret=-EIO; + command_status = FD_COMMAND_NONE; + return ret; +} + +static void generic_done(int result) +{ + command_status = result; + cont = &wakeup_cont; +} + +static void generic_success(void) +{ + cont->done(1); +} + +static void generic_failure(void) +{ + cont->done(0); +} + +static void success_and_wakeup(void) +{ + generic_success(); + cont->redo(); +} + + +/* + * formatting and rw support. + * ========================== + */ + +static int next_valid_format(void) +{ + int probed_format; + + probed_format = DRS->probed_format; + while(1){ + if (probed_format >= 8 || + !DP->autodetect[probed_format]){ + DRS->probed_format = 0; + return 1; + } + if (floppy_type[DP->autodetect[probed_format]].sect){ + DRS->probed_format = probed_format; + return 0; + } + probed_format++; + } +} + +static void bad_flp_intr(void) +{ + if (probing){ + DRS->probed_format++; + if (!next_valid_format()) + return; + } + (*errors)++; + INFBOUND(DRWE->badness, *errors); + if (*errors > DP->max_errors.abort) + cont->done(0); + if (*errors > DP->max_errors.reset) + FDCS->reset = 1; + else if (*errors > DP->max_errors.recal) + DRS->track = NEED_2_RECAL; +} + +static void set_floppy(int drive) +{ + int type = ITYPE(UDRS->fd_device); + if (type) { + auto_detect_mode = 0; + _floppy = floppy_type + type; + } else if (auto_detect_mode == 0) { + auto_detect_mode = 1; + retry_auto_detect = 0; + _floppy = current_type[drive]; + } +#ifdef PC9800_DEBUG_FLOPPY2 + printk("set_floppy: set floppy type=%d\n", (int)(_floppy - floppy_type)); +#endif +} + +/* + * formatting support. + * =================== + */ +static void format_interrupt(void) +{ + switch (interpret_errors()){ + case 1: + cont->error(); + case 2: + break; + case 0: + cont->done(1); + } + cont->redo(); +} + +#define CODE2SIZE (ssize = ((1 << SIZECODE) + 3) >> 2) +#define FM_MODE(x,y) ((y) & ~(((x)->rate & 0x80) >>1)) +#define CT(x) ((x) | 0xc0) +static void setup_format_params(int track) +{ + struct fparm { + unsigned char track,head,sect,size; + } *here = (struct fparm *)floppy_track_buffer; + int il,n; + int count,head_shift,track_shift; + + raw_cmd = &default_raw_cmd; + raw_cmd->track = track; + + raw_cmd->flags = FD_RAW_WRITE | FD_RAW_INTR | FD_RAW_SPIN | + FD_RAW_NEED_DISK | FD_RAW_NEED_SEEK; + raw_cmd->rate = _floppy->rate & 0x43; + raw_cmd->cmd_count = NR_F; + COMMAND = FM_MODE(_floppy,FD_FORMAT); + DR_SELECT = UNIT(current_drive) + PH_HEAD(_floppy,format_req.head); + F_SIZECODE = FD_SIZECODE(_floppy); + F_SECT_PER_TRACK = _floppy->sect << 2 >> F_SIZECODE; + F_GAP = _floppy->fmt_gap; + F_FILL = FD_FILL_BYTE; + + raw_cmd->kernel_data = floppy_track_buffer; + raw_cmd->length = 4 * F_SECT_PER_TRACK; + + /* allow for about 30ms for data transport per track */ + head_shift = (F_SECT_PER_TRACK + 5) / 6; + + /* a ``cylinder'' is two tracks plus a little stepping time */ + track_shift = 2 * head_shift + 3; + + /* position of logical sector 1 on this track */ + n = (track_shift * format_req.track + head_shift * format_req.head) + % F_SECT_PER_TRACK; + + /* determine interleave */ + il = 1; + if (_floppy->fmt_gap < 0x22) + il++; + + /* initialize field */ + for (count = 0; count < F_SECT_PER_TRACK; ++count) { + here[count].track = format_req.track; + here[count].head = format_req.head; + here[count].sect = 0; + here[count].size = F_SIZECODE; + } + /* place logical sectors */ + for (count = 1; count <= F_SECT_PER_TRACK; ++count) { + here[n].sect = count; + n = (n+il) % F_SECT_PER_TRACK; + if (here[n].sect) { /* sector busy, find next free sector */ + ++n; + if (n>= F_SECT_PER_TRACK) { + n-=F_SECT_PER_TRACK; + while (here[n].sect) ++n; + } + } + } +} + +static void redo_format(void) +{ + buffer_track = -1; + setup_format_params(format_req.track << STRETCH(_floppy)); + floppy_start(); +#ifdef DEBUGT + debugt("queue format request"); +#endif +} + +static struct cont_t format_cont={ + format_interrupt, + redo_format, + bad_flp_intr, + generic_done }; + +static int do_format(kdev_t device, struct format_descr *tmp_format_req) +{ + int ret; + int drive=DRIVE(device); + + LOCK_FDC(drive,1); + set_floppy(drive); + if (!_floppy || + _floppy->track > DP->tracks || + tmp_format_req->track >= _floppy->track || + tmp_format_req->head >= _floppy->head || + (_floppy->sect << 2) % (1 << FD_SIZECODE(_floppy)) || + !_floppy->fmt_gap) { + process_fd_request(); + return -EINVAL; + } + format_req = *tmp_format_req; + format_errors = 0; + cont = &format_cont; + errors = &format_errors; + IWAIT(redo_format); + process_fd_request(); + return ret; +} + +/* + * Buffer read/write and support + * ============================= + */ + +static inline void end_request(struct request *req, int uptodate) +{ + if (end_that_request_first(req, uptodate, current_count_sectors)) + return; + add_disk_randomness(req->rq_disk); + floppy_off((int)req->rq_disk->private_data); + blkdev_dequeue_request(req); + end_that_request_last(req); + + /* We're done with the request */ + current_req = NULL; +} + + +/* new request_done. Can handle physical sectors which are smaller than a + * logical buffer */ +static void request_done(int uptodate) +{ + struct request_queue *q = &floppy_queue; + struct request *req = current_req; + unsigned long flags; + int block; + + probing = 0; + reschedule_timeout(MAXTIMEOUT, "request done %d", uptodate); + + if (!req) { + printk("floppy.c: no request in request_done\n"); + return; + } + + if (uptodate){ + /* maintain values for invalidation on geometry + * change */ + block = current_count_sectors + req->sector; + INFBOUND(DRS->maxblock, block); + if (block > _floppy->sect) + DRS->maxtrack = 1; + + /* unlock chained buffers */ + spin_lock_irqsave(q->queue_lock, flags); + end_request(req, 1); + spin_unlock_irqrestore(q->queue_lock, flags); + } else { + if (rq_data_dir(req) == WRITE) { + /* record write error information */ + DRWE->write_errors++; + if (DRWE->write_errors == 1) { + DRWE->first_error_sector = req->sector; + DRWE->first_error_generation = DRS->generation; + } + DRWE->last_error_sector = req->sector; + DRWE->last_error_generation = DRS->generation; + } + spin_lock_irqsave(q->queue_lock, flags); + end_request(req, 0); + spin_unlock_irqrestore(q->queue_lock, flags); + } +} + +/* Interrupt handler evaluating the result of the r/w operation */ +static void rw_interrupt(void) +{ + int nr_sectors, ssize, eoc, heads; + + if (R_HEAD >= 2) { + /* some Toshiba floppy controllers occasionnally seem to + * return bogus interrupts after read/write operations, which + * can be recognized by a bad head number (>= 2) */ + return; + } + + if (!DRS->first_read_date) + DRS->first_read_date = jiffies; + + nr_sectors = 0; + CODE2SIZE; + + if (ST1 & ST1_EOC) + eoc = 1; + else + eoc = 0; + + if (COMMAND & 0x80) + heads = 2; + else + heads = 1; + + nr_sectors = (((R_TRACK-TRACK) * heads + + R_HEAD-HEAD) * SECT_PER_TRACK + + R_SECTOR-SECTOR + eoc) << SIZECODE >> 2; + +#ifdef FLOPPY_SANITY_CHECK + if (nr_sectors / ssize > + (in_sector_offset + current_count_sectors + ssize - 1) / ssize) { + DPRINT("long rw: %x instead of %lx\n", + nr_sectors, current_count_sectors); + printk("rs=%d s=%d\n", R_SECTOR, SECTOR); + printk("rh=%d h=%d\n", R_HEAD, HEAD); + printk("rt=%d t=%d\n", R_TRACK, TRACK); + printk("heads=%d eoc=%d\n", heads, eoc); + printk("spt=%d st=%d ss=%d\n", SECT_PER_TRACK, + fsector_t, ssize); + printk("in_sector_offset=%d\n", in_sector_offset); + } +#endif + + nr_sectors -= in_sector_offset; + INFBOUND(nr_sectors,0); + SUPBOUND(current_count_sectors, nr_sectors); + + switch (interpret_errors()){ + case 2: + cont->redo(); + return; + case 1: + if (!current_count_sectors){ + cont->error(); + cont->redo(); + return; + } + break; + case 0: + if (!current_count_sectors){ + cont->redo(); + return; + } + current_type[current_drive] = _floppy; + floppy_sizes[TOMINOR(current_drive) ]= _floppy->size; + break; + } + + if (probing) { + if (DP->flags & FTD_MSG) + DPRINT("Auto-detected floppy type %s in fd%d\n", + _floppy->name,current_drive); + current_type[current_drive] = _floppy; + floppy_sizes[TOMINOR(current_drive)] = _floppy->size; + probing = 0; + } + + if (CT(COMMAND) != FD_READ || + raw_cmd->kernel_data == current_req->buffer){ + /* transfer directly from buffer */ + cont->done(1); + } else if (CT(COMMAND) == FD_READ){ + buffer_track = raw_cmd->track; + buffer_drive = current_drive; + INFBOUND(buffer_max, nr_sectors + fsector_t); + } + cont->redo(); +} + +/* Compute maximal contiguous buffer size. */ +static int buffer_chain_size(void) +{ + struct bio *bio; + struct bio_vec *bv; + int size, i; + char *base; + + base = bio_data(current_req->bio); + size = 0; + + rq_for_each_bio(bio, current_req) { + bio_for_each_segment(bv, bio, i) { + if (page_address(bv->bv_page) + bv->bv_offset != base + size) + break; + + size += bv->bv_len; + } + } + + return size >> 9; +} + +/* Compute the maximal transfer size */ +static int transfer_size(int ssize, int max_sector, int max_size) +{ + SUPBOUND(max_sector, fsector_t + max_size); + + /* alignment */ + max_sector -= (max_sector % _floppy->sect) % ssize; + + /* transfer size, beginning not aligned */ + current_count_sectors = max_sector - fsector_t ; + + return max_sector; +} + +/* + * Move data from/to the track buffer to/from the buffer cache. + */ +static void copy_buffer(int ssize, int max_sector, int max_sector_2) +{ + int remaining; /* number of transferred 512-byte sectors */ + struct bio_vec *bv; + struct bio *bio; + char *buffer, *dma_buffer; + int size, i; + + max_sector = transfer_size(ssize, + minimum(max_sector, max_sector_2), + current_req->nr_sectors); + + if (current_count_sectors <= 0 && CT(COMMAND) == FD_WRITE && + buffer_max > fsector_t + current_req->nr_sectors) + current_count_sectors = minimum(buffer_max - fsector_t, + current_req->nr_sectors); + + remaining = current_count_sectors << 9; +#ifdef FLOPPY_SANITY_CHECK + if ((remaining >> 9) > current_req->nr_sectors && + CT(COMMAND) == FD_WRITE){ + DPRINT("in copy buffer\n"); + printk("current_count_sectors=%ld\n", current_count_sectors); + printk("remaining=%d\n", remaining >> 9); + printk("current_req->nr_sectors=%ld\n",current_req->nr_sectors); + printk("current_req->current_nr_sectors=%u\n", + current_req->current_nr_sectors); + printk("max_sector=%d\n", max_sector); + printk("ssize=%d\n", ssize); + } +#endif + + buffer_max = maximum(max_sector, buffer_max); + + dma_buffer = floppy_track_buffer + ((fsector_t - buffer_min) << 9); + + size = current_req->current_nr_sectors << 9; + + rq_for_each_bio(bio, current_req) { + bio_for_each_segment(bv, bio, i) { + if (!remaining) + break; + + size = bv->bv_len; + SUPBOUND(size, remaining); + + buffer = page_address(bv->bv_page) + bv->bv_offset; +#ifdef FLOPPY_SANITY_CHECK + if (dma_buffer + size > + floppy_track_buffer + (max_buffer_sectors << 10) || + dma_buffer < floppy_track_buffer){ + DPRINT("buffer overrun in copy buffer %d\n", + (int) ((floppy_track_buffer - dma_buffer) >>9)); + printk("fsector_t=%d buffer_min=%d\n", + fsector_t, buffer_min); + printk("current_count_sectors=%ld\n", + current_count_sectors); + if (CT(COMMAND) == FD_READ) + printk("read\n"); + if (CT(COMMAND) == FD_READ) + printk("write\n"); + break; + } + if (((unsigned long)buffer) % 512) + DPRINT("%p buffer not aligned\n", buffer); +#endif + if (CT(COMMAND) == FD_READ) + memcpy(buffer, dma_buffer, size); + else + memcpy(dma_buffer, buffer, size); + + remaining -= size; + dma_buffer += size; + } + } +#ifdef FLOPPY_SANITY_CHECK + if (remaining){ + if (remaining > 0) + max_sector -= remaining >> 9; + DPRINT("weirdness: remaining %d\n", remaining>>9); + } +#endif +} + +#if 0 +static inline int check_dma_crossing(char *start, + unsigned long length, char *message) +{ + if (CROSS_64KB(start, length)) { + printk("DMA xfer crosses 64KB boundary in %s %p-%p\n", + message, start, start+length); + return 1; + } else + return 0; +} +#endif + +/* work around a bug in pseudo DMA + * (on some FDCs) pseudo DMA does not stop when the CPU stops + * sending data. Hence we need a different way to signal the + * transfer length: We use SECT_PER_TRACK. Unfortunately, this + * does not work with MT, hence we can only transfer one head at + * a time + */ +static void virtualdmabug_workaround(void) +{ + int hard_sectors, end_sector; + + if(CT(COMMAND) == FD_WRITE) { + COMMAND &= ~0x80; /* switch off multiple track mode */ + + hard_sectors = raw_cmd->length >> (7 + SIZECODE); + end_sector = SECTOR + hard_sectors - 1; +#ifdef FLOPPY_SANITY_CHECK + if(end_sector > SECT_PER_TRACK) { + printk("too many sectors %d > %d\n", + end_sector, SECT_PER_TRACK); + return; + } +#endif + SECT_PER_TRACK = end_sector; /* make sure SECT_PER_TRACK points + * to end of transfer */ + } +} + +/* + * Formulate a read/write request. + * this routine decides where to load the data (directly to buffer, or to + * tmp floppy area), how much data to load (the size of the buffer, the whole + * track, or a single sector) + * All floppy_track_buffer handling goes in here. If we ever add track buffer + * allocation on the fly, it should be done here. No other part should need + * modification. + */ + +static int make_raw_rw_request(void) +{ + int aligned_sector_t; + int max_sector, max_size, tracksize, ssize; + + if(max_buffer_sectors == 0) { + printk("VFS: Block I/O scheduled on unopened device\n"); + return 0; + } + + set_fdc((int)current_req->rq_disk->private_data); + + raw_cmd = &default_raw_cmd; + raw_cmd->flags = FD_RAW_SPIN | FD_RAW_NEED_DISK | FD_RAW_NEED_DISK | + FD_RAW_NEED_SEEK; + raw_cmd->cmd_count = NR_RW; + if (rq_data_dir(current_req) == READ) { + raw_cmd->flags |= FD_RAW_READ; + COMMAND = FM_MODE(_floppy,FD_READ); + } else if (rq_data_dir(current_req) == WRITE){ + raw_cmd->flags |= FD_RAW_WRITE; + COMMAND = FM_MODE(_floppy,FD_WRITE); + } else { + DPRINT("make_raw_rw_request: unknown command\n"); + return 0; + } + + max_sector = _floppy->sect * _floppy->head; + + TRACK = (int)current_req->sector / max_sector; + fsector_t = (int)current_req->sector % max_sector; + if (_floppy->track && TRACK >= _floppy->track) { + if (current_req->current_nr_sectors & 1) { + current_count_sectors = 1; + return 1; + } else + return 0; + } + HEAD = fsector_t / _floppy->sect; + + if (((_floppy->stretch & FD_SWAPSIDES) || TESTF(FD_NEED_TWADDLE)) && + fsector_t < _floppy->sect) + max_sector = _floppy->sect; + + /* 2M disks have phantom sectors on the first track */ + if ((_floppy->rate & FD_2M) && (!TRACK) && (!HEAD)){ + max_sector = 2 * _floppy->sect / 3; + if (fsector_t >= max_sector){ + current_count_sectors = minimum(_floppy->sect - fsector_t, + current_req->nr_sectors); + return 1; + } + SIZECODE = 2; + } else + SIZECODE = FD_SIZECODE(_floppy); + raw_cmd->rate = _floppy->rate & 0x43; + if ((_floppy->rate & FD_2M) && + (TRACK || HEAD) && + raw_cmd->rate == 2) + raw_cmd->rate = 1; + + if (SIZECODE) + SIZECODE2 = 0xff; + else + SIZECODE2 = 0x80; + raw_cmd->track = TRACK << STRETCH(_floppy); + DR_SELECT = UNIT(current_drive) + PH_HEAD(_floppy,HEAD); + GAP = _floppy->gap; + CODE2SIZE; + SECT_PER_TRACK = _floppy->sect << 2 >> SIZECODE; + SECTOR = ((fsector_t % _floppy->sect) << 2 >> SIZECODE) + 1; + + /* tracksize describes the size which can be filled up with sectors + * of size ssize. + */ + tracksize = _floppy->sect - _floppy->sect % ssize; + if (tracksize < _floppy->sect){ + SECT_PER_TRACK ++; + if (tracksize <= fsector_t % _floppy->sect) + SECTOR--; + + /* if we are beyond tracksize, fill up using smaller sectors */ + while (tracksize <= fsector_t % _floppy->sect){ + while(tracksize + ssize > _floppy->sect){ + SIZECODE--; + ssize >>= 1; + } + SECTOR++; SECT_PER_TRACK ++; + tracksize += ssize; + } + max_sector = HEAD * _floppy->sect + tracksize; + } else if (!TRACK && !HEAD && !(_floppy->rate & FD_2M) && probing) { + max_sector = _floppy->sect; + } else if (!HEAD && CT(COMMAND) == FD_WRITE) { + /* for virtual DMA bug workaround */ + max_sector = _floppy->sect; + } + + in_sector_offset = (fsector_t % _floppy->sect) % ssize; + aligned_sector_t = fsector_t - in_sector_offset; + max_size = current_req->nr_sectors; + if ((raw_cmd->track == buffer_track) && + (current_drive == buffer_drive) && + (fsector_t >= buffer_min) && (fsector_t < buffer_max)) { + /* data already in track buffer */ + if (CT(COMMAND) == FD_READ) { + copy_buffer(1, max_sector, buffer_max); + return 1; + } + } else if (in_sector_offset || current_req->nr_sectors < ssize){ + if (CT(COMMAND) == FD_WRITE){ + if (fsector_t + current_req->nr_sectors > ssize && + fsector_t + current_req->nr_sectors < ssize + ssize) + max_size = ssize + ssize; + else + max_size = ssize; + } + raw_cmd->flags &= ~FD_RAW_WRITE; + raw_cmd->flags |= FD_RAW_READ; + COMMAND = FM_MODE(_floppy,FD_READ); + } else if ((unsigned long)current_req->buffer < MAX_DMA_ADDRESS) { + unsigned long dma_limit; + int direct, indirect; + + indirect= transfer_size(ssize,max_sector,max_buffer_sectors*2) - + fsector_t; + + /* + * Do NOT use minimum() here---MAX_DMA_ADDRESS is 64 bits wide + * on a 64 bit machine! + */ + max_size = buffer_chain_size(); + dma_limit = (MAX_DMA_ADDRESS - ((unsigned long) current_req->buffer)) >> 9; + if ((unsigned long) max_size > dma_limit) { + max_size = dma_limit; + } + /* 64 kb boundaries */ + if (CROSS_64KB(current_req->buffer, max_size << 9)) + max_size = (K_64 - + ((unsigned long)current_req->buffer) % K_64)>>9; + direct = transfer_size(ssize,max_sector,max_size) - fsector_t; + /* + * We try to read tracks, but if we get too many errors, we + * go back to reading just one sector at a time. + * + * This means we should be able to read a sector even if there + * are other bad sectors on this track. + */ + if (!direct || + (indirect * 2 > direct * 3 && + *errors < DP->max_errors.read_track && + /*!TESTF(FD_NEED_TWADDLE) &&*/ + ((!probing || (DP->read_track&(1<probed_format)))))){ + max_size = current_req->nr_sectors; + } else { + raw_cmd->kernel_data = current_req->buffer; + raw_cmd->length = current_count_sectors << 9; + if (raw_cmd->length == 0){ + DPRINT("zero dma transfer attempted from make_raw_request\n"); + DPRINT("indirect=%d direct=%d fsector_t=%d", + indirect, direct, fsector_t); + return 0; + } +/* check_dma_crossing(raw_cmd->kernel_data, + raw_cmd->length, + "end of make_raw_request [1]");*/ + + virtualdmabug_workaround(); + return 2; + } + } + + if (CT(COMMAND) == FD_READ) + max_size = max_sector; /* unbounded */ + + /* claim buffer track if needed */ + if (buffer_track != raw_cmd->track || /* bad track */ + buffer_drive !=current_drive || /* bad drive */ + fsector_t > buffer_max || + fsector_t < buffer_min || + ((CT(COMMAND) == FD_READ || + (!in_sector_offset && current_req->nr_sectors >= ssize))&& + max_sector > 2 * max_buffer_sectors + buffer_min && + max_size + fsector_t > 2 * max_buffer_sectors + buffer_min) + /* not enough space */){ + buffer_track = -1; + buffer_drive = current_drive; + buffer_max = buffer_min = aligned_sector_t; + } + raw_cmd->kernel_data = floppy_track_buffer + + ((aligned_sector_t-buffer_min)<<9); + + if (CT(COMMAND) == FD_WRITE){ + /* copy write buffer to track buffer. + * if we get here, we know that the write + * is either aligned or the data already in the buffer + * (buffer will be overwritten) */ +#ifdef FLOPPY_SANITY_CHECK + if (in_sector_offset && buffer_track == -1) + DPRINT("internal error offset !=0 on write\n"); +#endif + buffer_track = raw_cmd->track; + buffer_drive = current_drive; + copy_buffer(ssize, max_sector, 2*max_buffer_sectors+buffer_min); + } else + transfer_size(ssize, max_sector, + 2*max_buffer_sectors+buffer_min-aligned_sector_t); + + /* round up current_count_sectors to get dma xfer size */ + raw_cmd->length = in_sector_offset+current_count_sectors; + raw_cmd->length = ((raw_cmd->length -1)|(ssize-1))+1; + raw_cmd->length <<= 9; +#ifdef FLOPPY_SANITY_CHECK + /*check_dma_crossing(raw_cmd->kernel_data, raw_cmd->length, + "end of make_raw_request");*/ + if ((raw_cmd->length < current_count_sectors << 9) || + (raw_cmd->kernel_data != current_req->buffer && + CT(COMMAND) == FD_WRITE && + (aligned_sector_t + (raw_cmd->length >> 9) > buffer_max || + aligned_sector_t < buffer_min)) || + raw_cmd->length % (128 << SIZECODE) || + raw_cmd->length <= 0 || current_count_sectors <= 0){ + DPRINT("fractionary current count b=%lx s=%lx\n", + raw_cmd->length, current_count_sectors); + if (raw_cmd->kernel_data != current_req->buffer) + printk("addr=%d, length=%ld\n", + (int) ((raw_cmd->kernel_data - + floppy_track_buffer) >> 9), + current_count_sectors); + printk("st=%d ast=%d mse=%d msi=%d\n", + fsector_t, aligned_sector_t, max_sector, max_size); + printk("ssize=%x SIZECODE=%d\n", ssize, SIZECODE); + printk("command=%x SECTOR=%d HEAD=%d, TRACK=%d\n", + COMMAND, SECTOR, HEAD, TRACK); + printk("buffer drive=%d\n", buffer_drive); + printk("buffer track=%d\n", buffer_track); + printk("buffer_min=%d\n", buffer_min); + printk("buffer_max=%d\n", buffer_max); + return 0; + } + + if (raw_cmd->kernel_data != current_req->buffer){ + if (raw_cmd->kernel_data < floppy_track_buffer || + current_count_sectors < 0 || + raw_cmd->length < 0 || + raw_cmd->kernel_data + raw_cmd->length > + floppy_track_buffer + (max_buffer_sectors << 10)){ + DPRINT("buffer overrun in schedule dma\n"); + printk("fsector_t=%d buffer_min=%d current_count=%ld\n", + fsector_t, buffer_min, + raw_cmd->length >> 9); + printk("current_count_sectors=%ld\n", + current_count_sectors); + if (CT(COMMAND) == FD_READ) + printk("read\n"); + if (CT(COMMAND) == FD_READ) + printk("write\n"); + return 0; + } + } else if (raw_cmd->length > current_req->nr_sectors << 9 || + current_count_sectors > current_req->nr_sectors){ + DPRINT("buffer overrun in direct transfer\n"); + return 0; + } else if (raw_cmd->length < current_count_sectors << 9){ + DPRINT("more sectors than bytes\n"); + printk("bytes=%ld\n", raw_cmd->length >> 9); + printk("sectors=%ld\n", current_count_sectors); + } + if (raw_cmd->length == 0){ + DPRINT("zero dma transfer attempted from make_raw_request\n"); + return 0; + } +#endif + + virtualdmabug_workaround(); + return 2; +} + +static void redo_fd_request(void) +{ +#define REPEAT {request_done(0); continue; } + int drive; + int tmp; + + lastredo = jiffies; + if (current_drive < N_DRIVE) + floppy_off(current_drive); + + for (;;) { + if (!current_req) { + struct request *req = elv_next_request(&floppy_queue); + if (!req) { + do_floppy = NULL; + unlock_fdc(); + return; + } + current_req = req; + } + drive = (int)current_req->rq_disk->private_data; + set_fdc(drive); + reschedule_timeout(current_reqD, "redo fd request", 0); + + set_floppy(drive); + raw_cmd = & default_raw_cmd; + raw_cmd->flags = 0; + if (start_motor(redo_fd_request)) return; + disk_change(current_drive); + if (test_bit(current_drive, &fake_change) || + TESTF(FD_DISK_CHANGED)){ + DPRINT("disk absent or changed during operation\n"); + REPEAT; + } + if (!_floppy) { /* Autodetection */ + if (!probing){ + DRS->probed_format = 0; + if (next_valid_format()){ + DPRINT("no autodetectable formats\n"); + _floppy = NULL; + REPEAT; + } + } + probing = 1; + _floppy = floppy_type+DP->autodetect[DRS->probed_format]; + } else + probing = 0; + errors = & (current_req->errors); + tmp = make_raw_rw_request(); + if (tmp < 2){ + request_done(tmp); + continue; + } + + if (TESTF(FD_NEED_TWADDLE)) + twaddle(); + schedule_bh( (void *)(void *) floppy_start); +#ifdef DEBUGT + debugt("queue fd request"); +#endif + return; + } +#undef REPEAT +} + +static struct cont_t rw_cont={ + rw_interrupt, + redo_fd_request, + bad_flp_intr, + request_done }; + +static void process_fd_request(void) +{ + cont = &rw_cont; + schedule_bh( (void *)(void *) redo_fd_request); +} + +static void do_fd_request(request_queue_t * q) +{ + if(max_buffer_sectors == 0) { + printk("VFS: do_fd_request called on non-open device\n"); + return; + } + + if (usage_count == 0) { + printk("warning: usage count=0, current_req=%p exiting\n", current_req); + printk("sect=%ld flags=%lx\n", (long)current_req->sector, current_req->flags); + return; + } + if (fdc_busy){ + /* fdc busy, this new request will be treated when the + current one is done */ + is_alive("do fd request, old request running"); + return; + } + lock_fdc(MAXTIMEOUT,0); + process_fd_request(); + is_alive("do fd request"); +} + +static struct cont_t poll_cont={ + success_and_wakeup, + floppy_ready, + generic_failure, + generic_done }; + +static int poll_drive(int interruptible, int flag) +{ + int ret; + /* no auto-sense, just clear dcl */ + raw_cmd = &default_raw_cmd; + raw_cmd->flags= flag; + raw_cmd->track=0; + raw_cmd->cmd_count=0; + cont = &poll_cont; +#ifdef DCL_DEBUG + if (DP->flags & FD_DEBUG){ + DPRINT("setting NEWCHANGE in poll_drive\n"); + } +#endif + SETF(FD_DISK_NEWCHANGE); + WAIT(floppy_ready); + return ret; +} + +/* + * User triggered reset + * ==================== + */ + +static void reset_intr(void) +{ + printk("weird, reset interrupt called\n"); +} + +static struct cont_t reset_cont={ + reset_intr, + success_and_wakeup, + generic_failure, + generic_done }; + +static int user_reset_fdc(int drive, int arg, int interruptible) +{ + int ret; + + ret=0; + LOCK_FDC(drive,interruptible); + if (arg == FD_RESET_ALWAYS) + FDCS->reset=1; + if (FDCS->reset){ + cont = &reset_cont; + WAIT(reset_fdc); + } + process_fd_request(); + return ret; +} + +/* + * Misc Ioctl's and support + * ======================== + */ +static inline int fd_copyout(void *param, const void *address, unsigned long size) +{ + return copy_to_user(param,address, size) ? -EFAULT : 0; +} + +static inline int fd_copyin(void *param, void *address, unsigned long size) +{ + return copy_from_user(address, param, size) ? -EFAULT : 0; +} + +#define _COPYOUT(x) (copy_to_user((void *)param, &(x), sizeof(x)) ? -EFAULT : 0) +#define _COPYIN(x) (copy_from_user(&(x), (void *)param, sizeof(x)) ? -EFAULT : 0) + +#define COPYOUT(x) ECALL(_COPYOUT(x)) +#define COPYIN(x) ECALL(_COPYIN(x)) + +static inline const char *drive_name(int type, int drive) +{ + struct floppy_struct *floppy; + + if (type) + floppy = floppy_type + type; + else { + if (UDP->native_format) + floppy = floppy_type + UDP->native_format; + else + return "(null)"; + } + if (floppy->name) + return floppy->name; + else + return "(null)"; +} + + +/* raw commands */ +static void raw_cmd_done(int flag) +{ + int i; + + if (!flag) { + raw_cmd->flags |= FD_RAW_FAILURE; + raw_cmd->flags |= FD_RAW_HARDFAILURE; + } else { + raw_cmd->reply_count = inr; + if (raw_cmd->reply_count > MAX_REPLIES) + raw_cmd->reply_count=0; + for (i=0; i< raw_cmd->reply_count; i++) + raw_cmd->reply[i] = reply_buffer[i]; + + if (raw_cmd->flags & (FD_RAW_READ | FD_RAW_WRITE)) + { + unsigned long flags; + flags=claim_dma_lock(); + raw_cmd->length = fd_get_dma_residue(); + release_dma_lock(flags); + } + + if ((raw_cmd->flags & FD_RAW_SOFTFAILURE) && + (!raw_cmd->reply_count || (raw_cmd->reply[0] & 0xc0))) + raw_cmd->flags |= FD_RAW_FAILURE; + + if (disk_change(current_drive)) + raw_cmd->flags |= FD_RAW_DISK_CHANGE; + else + raw_cmd->flags &= ~FD_RAW_DISK_CHANGE; + if (raw_cmd->flags & FD_RAW_NO_MOTOR_AFTER) + motor_off_callback(current_drive); + + if (raw_cmd->next && + (!(raw_cmd->flags & FD_RAW_FAILURE) || + !(raw_cmd->flags & FD_RAW_STOP_IF_FAILURE)) && + ((raw_cmd->flags & FD_RAW_FAILURE) || + !(raw_cmd->flags &FD_RAW_STOP_IF_SUCCESS))) { + raw_cmd = raw_cmd->next; + return; + } + } + generic_done(flag); +} + + +static struct cont_t raw_cmd_cont={ + success_and_wakeup, + floppy_start, + generic_failure, + raw_cmd_done +}; + +static inline int raw_cmd_copyout(int cmd, char *param, + struct floppy_raw_cmd *ptr) +{ + int ret; + + while(ptr) { + COPYOUT(*ptr); + param += sizeof(struct floppy_raw_cmd); + if ((ptr->flags & FD_RAW_READ) && ptr->buffer_length){ + if (ptr->length>=0 && ptr->length<=ptr->buffer_length) + ECALL(fd_copyout(ptr->data, + ptr->kernel_data, + ptr->buffer_length - + ptr->length)); + } + ptr = ptr->next; + } + return 0; +} + + +static void raw_cmd_free(struct floppy_raw_cmd **ptr) +{ + struct floppy_raw_cmd *next,*this; + + this = *ptr; + *ptr = 0; + while(this) { + if (this->buffer_length) { + fd_dma_mem_free((unsigned long)this->kernel_data, + this->buffer_length); + this->buffer_length = 0; + } + next = this->next; + kfree(this); + this = next; + } +} + + +static inline int raw_cmd_copyin(int cmd, char *param, + struct floppy_raw_cmd **rcmd) +{ + struct floppy_raw_cmd *ptr; + int ret; + int i; + + *rcmd = 0; + while(1) { + ptr = (struct floppy_raw_cmd *) + kmalloc(sizeof(struct floppy_raw_cmd), GFP_USER); + if (!ptr) + return -ENOMEM; + *rcmd = ptr; + COPYIN(*ptr); + ptr->next = 0; + ptr->buffer_length = 0; + param += sizeof(struct floppy_raw_cmd); + if (ptr->cmd_count > 33) + /* the command may now also take up the space + * initially intended for the reply & the + * reply count. Needed for long 82078 commands + * such as RESTORE, which takes ... 17 command + * bytes. Murphy's law #137: When you reserve + * 16 bytes for a structure, you'll one day + * discover that you really need 17... + */ + return -EINVAL; + + for (i=0; i< 16; i++) + ptr->reply[i] = 0; + ptr->resultcode = 0; + ptr->kernel_data = 0; + + if (ptr->flags & (FD_RAW_READ | FD_RAW_WRITE)) { + if (ptr->length <= 0) + return -EINVAL; + ptr->kernel_data =(char*)fd_dma_mem_alloc(ptr->length); + fallback_on_nodma_alloc(&ptr->kernel_data, + ptr->length); + if (!ptr->kernel_data) + return -ENOMEM; + ptr->buffer_length = ptr->length; + } + if (ptr->flags & FD_RAW_WRITE) + ECALL(fd_copyin(ptr->data, ptr->kernel_data, + ptr->length)); + rcmd = & (ptr->next); + if (!(ptr->flags & FD_RAW_MORE)) + return 0; + ptr->rate &= 0x43; + } +} + + +static int raw_cmd_ioctl(int cmd, void *param) +{ + int drive, ret, ret2; + struct floppy_raw_cmd *my_raw_cmd; + + if (FDCS->rawcmd <= 1) + FDCS->rawcmd = 1; + for (drive= 0; drive < N_DRIVE; drive++){ + if (FDC(drive) != fdc) + continue; + if (drive == current_drive){ + if (UDRS->fd_ref > 1){ + FDCS->rawcmd = 2; + break; + } + } else if (UDRS->fd_ref){ + FDCS->rawcmd = 2; + break; + } + } + + if (FDCS->reset) + return -EIO; + + ret = raw_cmd_copyin(cmd, param, &my_raw_cmd); + if (ret) { + raw_cmd_free(&my_raw_cmd); + return ret; + } + + raw_cmd = my_raw_cmd; + cont = &raw_cmd_cont; + ret=wait_til_done(floppy_start,1); +#ifdef DCL_DEBUG + if (DP->flags & FD_DEBUG){ + DPRINT("calling disk change from raw_cmd ioctl\n"); + } +#endif + + if (ret != -EINTR && FDCS->reset) + ret = -EIO; + + DRS->track = NO_TRACK; + + ret2 = raw_cmd_copyout(cmd, param, my_raw_cmd); + if (!ret) + ret = ret2; + raw_cmd_free(&my_raw_cmd); + return ret; +} + +static int invalidate_drive(struct block_device *bdev) +{ + /* invalidate the buffer track to force a reread */ + set_bit(DRIVE(to_kdev_t(bdev->bd_dev)), &fake_change); + process_fd_request(); + check_disk_change(bdev); + return 0; +} + + +static inline void clear_write_error(int drive) +{ + CLEARSTRUCT(UDRWE); +} + +static inline int set_geometry(unsigned int cmd, struct floppy_struct *g, + int drive, int type, struct block_device *bdev) +{ + int cnt; + + /* sanity checking for parameters.*/ + if (g->sect <= 0 || + g->head <= 0 || + g->track <= 0 || + g->track > UDP->tracks>>STRETCH(g) || + /* check if reserved bits are set */ + (g->stretch&~(FD_STRETCH|FD_SWAPSIDES)) != 0) + return -EINVAL; + if (type){ + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + LOCK_FDC(drive,1); + for (cnt = 0; cnt < N_DRIVE; cnt++){ + if (ITYPE(drive_state[cnt].fd_device) == type && + drive_state[cnt].fd_ref) + set_bit(drive, &fake_change); + } + floppy_type[type] = *g; + floppy_type[type].name="user format"; + for (cnt = type << 2; cnt < (type << 2) + 4; cnt++) + floppy_sizes[cnt]= floppy_sizes[cnt+0x80]= + floppy_type[type].size+1; + process_fd_request(); + for (cnt = 0; cnt < N_DRIVE; cnt++){ + if (ITYPE(drive_state[cnt].fd_device) == type && + drive_state[cnt].fd_ref) + __check_disk_change( + MKDEV(FLOPPY_MAJOR, + drive_state[cnt].fd_device)); + } + } else { + LOCK_FDC(drive,1); + if (cmd != FDDEFPRM) + /* notice a disk change immediately, else + * we lose our settings immediately*/ + CALL(poll_drive(1, FD_RAW_NEED_DISK)); + user_params[drive] = *g; + if (buffer_drive == drive) + SUPBOUND(buffer_max, user_params[drive].sect); + current_type[drive] = &user_params[drive]; + floppy_sizes[drive] = user_params[drive].size; + if (cmd == FDDEFPRM) + DRS->keep_data = -1; + else + DRS->keep_data = 1; + /* invalidation. Invalidate only when needed, i.e. + * when there are already sectors in the buffer cache + * whose number will change. This is useful, because + * mtools often changes the geometry of the disk after + * looking at the boot block */ + if (DRS->maxblock > user_params[drive].sect || DRS->maxtrack) + invalidate_drive(bdev); + else + process_fd_request(); + } + return 0; +} + +/* handle obsolete ioctl's */ +static int ioctl_table[]= { + FDCLRPRM, + FDSETPRM, + FDDEFPRM, + FDGETPRM, + FDMSGON, + FDMSGOFF, + FDFMTBEG, + FDFMTTRK, + FDFMTEND, + FDSETEMSGTRESH, + FDFLUSH, + FDSETMAXERRS, + FDGETMAXERRS, + FDGETDRVTYP, + FDSETDRVPRM, + FDGETDRVPRM, + FDGETDRVSTAT, + FDPOLLDRVSTAT, + FDRESET, + FDGETFDCSTAT, + FDWERRORCLR, + FDWERRORGET, + FDRAWCMD, + FDEJECT, + FDTWADDLE +}; + +static inline int normalize_ioctl(int *cmd, int *size) +{ + int i; + + for (i=0; i < ARRAY_SIZE(ioctl_table); i++) { + if ((*cmd & 0xffff) == (ioctl_table[i] & 0xffff)){ + *size = _IOC_SIZE(*cmd); + *cmd = ioctl_table[i]; + if (*size > _IOC_SIZE(*cmd)) { + printk("ioctl not yet supported\n"); + return -EFAULT; + } + return 0; + } + } + return -EINVAL; +} + +static int get_floppy_geometry(int drive, int type, struct floppy_struct **g) +{ + if (type) + *g = &floppy_type[type]; + else { + LOCK_FDC(drive,0); + CALL(poll_drive(0,0)); + process_fd_request(); + *g = current_type[drive]; + } + if (!*g) + return -ENODEV; + return 0; +} + +static int fd_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, + unsigned long param) +{ +#define FD_IOCTL_ALLOWED ((filp) && (filp)->private_data) +#define OUT(c,x) case c: outparam = (const char *) (x); break +#define IN(c,x,tag) case c: *(x) = inparam. tag ; return 0 + + int i,drive,type; + kdev_t device; + int ret; + int size; + union inparam { + struct floppy_struct g; /* geometry */ + struct format_descr f; + struct floppy_max_errors max_errors; + struct floppy_drive_params dp; + } inparam; /* parameters coming from user space */ + const char *outparam; /* parameters passed back to user space */ + + device = inode->i_rdev; + type = TYPE(device); + drive = DRIVE(device); + + /* convert compatibility eject ioctls into floppy eject ioctl. + * We do this in order to provide a means to eject floppy disks before + * installing the new fdutils package */ + if (cmd == CDROMEJECT || /* CD-ROM eject */ + cmd == 0x6470 /* SunOS floppy eject */) { + DPRINT("obsolete eject ioctl\n"); + DPRINT("please use floppycontrol --eject\n"); + cmd = FDEJECT; + } + + /* generic block device ioctls */ + switch(cmd) { + /* the following have been inspired by the corresponding + * code for other block devices. */ + struct floppy_struct *g; + case HDIO_GETGEO: + { + struct hd_geometry loc; + ECALL(get_floppy_geometry(drive, type, &g)); + loc.heads = g->head; + loc.sectors = g->sect; + loc.cylinders = g->track; + loc.start = 0; + return _COPYOUT(loc); + } + } + + /* convert the old style command into a new style command */ + if ((cmd & 0xff00) == 0x0200) { + ECALL(normalize_ioctl(&cmd, &size)); + } else + return -EINVAL; + + /* permission checks */ + if (((cmd & 0x40) && !FD_IOCTL_ALLOWED) || + ((cmd & 0x80) && !capable(CAP_SYS_ADMIN))) + return -EPERM; + + /* copyin */ + CLEARSTRUCT(&inparam); + if (_IOC_DIR(cmd) & _IOC_WRITE) + ECALL(fd_copyin((void *)param, &inparam, size)) + + switch (cmd) { + case FDEJECT: + if (UDRS->fd_ref != 1) + /* somebody else has this drive open */ + return -EBUSY; + LOCK_FDC(drive,1); + + /* do the actual eject. Fails on + * non-Sparc architectures */ + ret=fd_eject(UNIT(drive)); + + USETF(FD_DISK_CHANGED); + USETF(FD_VERIFY); + process_fd_request(); + return ret; + case FDCLRPRM: + LOCK_FDC(drive,1); + current_type[drive] = NULL; + floppy_sizes[drive] = MAX_DISK_SIZE << 1; + UDRS->keep_data = 0; + return invalidate_drive(inode->i_bdev); + case FDSETPRM: + case FDDEFPRM: + return set_geometry(cmd, & inparam.g, + drive, type, inode->i_bdev); + case FDGETPRM: + ECALL(get_floppy_geometry(drive, type, + (struct floppy_struct**) + &outparam)); + break; + + case FDMSGON: + UDP->flags |= FTD_MSG; + return 0; + case FDMSGOFF: + UDP->flags &= ~FTD_MSG; + return 0; + + case FDFMTBEG: + LOCK_FDC(drive,1); + CALL(poll_drive(1, FD_RAW_NEED_DISK)); + ret = UDRS->flags; + if (ret & FD_VERIFY) { + CALL(poll_drive(1, FD_RAW_NEED_DISK)); + ret = UDRS->flags; + } + + if (ret & FD_VERIFY) { + CALL(poll_drive(1, FD_RAW_NEED_DISK)); + ret = UDRS->flags; + } + + if (ret & FD_VERIFY) { + CALL(poll_drive(1, FD_RAW_NEED_DISK)); + ret = UDRS->flags; + } + + if (ret & FD_VERIFY) { + CALL(poll_drive(1, FD_RAW_NEED_DISK)); + ret = UDRS->flags; + } + + if(ret & FD_VERIFY){ + CALL(poll_drive(1, FD_RAW_NEED_DISK)); + ret = UDRS->flags; + } + process_fd_request(); + if (ret & FD_VERIFY) + return -ENODEV; + if (!(ret & FD_DISK_WRITABLE)) + return -EROFS; + return 0; + case FDFMTTRK: + if (UDRS->fd_ref != 1) + return -EBUSY; + return do_format(device, &inparam.f); + case FDFMTEND: + case FDFLUSH: + LOCK_FDC(drive,1); + return invalidate_drive(inode->i_bdev); + + case FDSETEMSGTRESH: + UDP->max_errors.reporting = + (unsigned short) (param & 0x0f); + return 0; + OUT(FDGETMAXERRS, &UDP->max_errors); + IN(FDSETMAXERRS, &UDP->max_errors, max_errors); + + case FDGETDRVTYP: + outparam = drive_name(type,drive); + SUPBOUND(size,strlen(outparam)+1); + break; + + IN(FDSETDRVPRM, UDP, dp); + OUT(FDGETDRVPRM, UDP); + + case FDPOLLDRVSTAT: + LOCK_FDC(drive,1); + CALL(poll_drive(1, FD_RAW_NEED_DISK)); + process_fd_request(); + /* fall through */ + OUT(FDGETDRVSTAT, UDRS); + + case FDRESET: + return user_reset_fdc(drive, (int)param, 1); + + OUT(FDGETFDCSTAT,UFDCS); + + case FDWERRORCLR: + CLEARSTRUCT(UDRWE); + return 0; + OUT(FDWERRORGET,UDRWE); + + case FDRAWCMD: + if (type) + return -EINVAL; + LOCK_FDC(drive,1); + set_floppy(drive); + CALL(i = raw_cmd_ioctl(cmd,(void *) param)); + process_fd_request(); + return i; + + case FDTWADDLE: + LOCK_FDC(drive,1); + twaddle(); + process_fd_request(); + return 0; + + default: + return -EINVAL; + } + + if (_IOC_DIR(cmd) & _IOC_READ) + return fd_copyout((void *)param, outparam, size); + else + return 0; +#undef OUT +#undef IN +} + +static void __init config_types(void) +{ + int first=1; + int drive; + extern struct fd_info { + unsigned char dummy[4 * 6]; + unsigned char fd_types[8]; + } drive_info; + + for (drive = 0; drive < 4; drive++) + UDP->cmos = drive_info.fd_types[drive]; + + /* XXX */ + /* additional physical CMOS drive detection should go here */ + + for (drive=0; drive < N_DRIVE; drive++){ + unsigned int type = UDP->cmos; + struct floppy_drive_params *params; + const char *name = NULL; + static char temparea[32]; + + if (type < NUMBER(default_drive_params)) { + params = &default_drive_params[type].params; + if (type) { + name = default_drive_params[type].name; + allowed_drive_mask |= 1 << drive; + } + } else { + params = &default_drive_params[0].params; + sprintf(temparea, "unknown type %d (usb?)", type); + name = temparea; + } + if (name) { + const char * prepend = ","; + if (first) { + prepend = KERN_INFO "Floppy drive(s):"; + first = 0; + } + printk("%s fd%d is %s", prepend, drive, name); + register_devfs_entries (drive); + } + *UDP = *params; + } + if (!first) + printk("\n"); +} + +static int floppy_release(struct inode * inode, struct file * filp) +{ + int drive = DRIVE(inode->i_rdev); + + if (UDRS->fd_ref < 0) + UDRS->fd_ref=0; + else if (!UDRS->fd_ref--) { + DPRINT("floppy_release with fd_ref == 0"); + UDRS->fd_ref = 0; + } + floppy_release_irq_and_dma(); + return 0; +} + +/* + * floppy_open check for aliasing (/dev/fd0 can be the same as + * /dev/PS0 etc), and disallows simultaneous access to the same + * drive with different device numbers. + */ +#define RETERR(x) do{floppy_release(inode,filp); return -(x);}while(0) + +static int floppy_open(struct inode * inode, struct file * filp) +{ + int drive; + int old_dev; + int try; + char *tmp; + +#ifdef PC9800_DEBUG_FLOPPY + printk("floppy open: start\n"); +#endif + filp->private_data = (void*) 0; + + drive = DRIVE(inode->i_rdev); +#ifdef PC9800_DEBUG_FLOPPY + printk("floppy open: drive=%d, current_drive=%d, UDP->cmos=%d\n" + "floppy open: FDCS={spec1=%d, spec2=%d, dtr=%d, version=%d, dor=%d, address=%lu}\n", + drive, current_drive, UDP->cmos, FDCS->spec1, FDCS->spec2, + FDCS->dtr, FDCS->version, FDCS->dor, FDCS->address); + if (_floppy) { + printk("floppy open: _floppy={size=%d, sect=%d, head=%d, track=%d, spec1=%d}\n", + _floppy->size, _floppy->sect, _floppy->head, + _floppy->track, _floppy->spec1); + } else { + printk("floppy open: _floppy=NULL\n"); + } +#endif /* PC9800_DEBUG_FLOPPY */ + + if (drive >= N_DRIVE || + !(allowed_drive_mask & (1 << drive)) || + fdc_state[FDC(drive)].version == FDC_NONE) + return -ENXIO; + + if (TYPE(inode->i_rdev) >= NUMBER(floppy_type)) + return -ENXIO; + old_dev = UDRS->fd_device; + if (UDRS->fd_ref && old_dev != minor(inode->i_rdev)) + return -EBUSY; + + if (!UDRS->fd_ref && (UDP->flags & FD_BROKEN_DCL)){ + USETF(FD_DISK_CHANGED); + USETF(FD_VERIFY); + } + + if (UDRS->fd_ref == -1 || + (UDRS->fd_ref && (filp->f_flags & O_EXCL))) + return -EBUSY; + + if (floppy_grab_irq_and_dma()) + return -EBUSY; + + if (filp->f_flags & O_EXCL) + UDRS->fd_ref = -1; + else + UDRS->fd_ref++; + + if (!floppy_track_buffer){ + /* if opening an ED drive, reserve a big buffer, + * else reserve a small one */ + if ((UDP->cmos == 6) || (UDP->cmos == 5)) + try = 64; /* Only 48 actually useful */ + else + try = 32; /* Only 24 actually useful */ + + tmp=(char *)fd_dma_mem_alloc(1024 * try); + if (!tmp && !floppy_track_buffer) { + try >>= 1; /* buffer only one side */ + INFBOUND(try, 16); + tmp= (char *)fd_dma_mem_alloc(1024*try); + } + if (!tmp && !floppy_track_buffer) { + fallback_on_nodma_alloc(&tmp, 2048 * try); + } + if (!tmp && !floppy_track_buffer) { + DPRINT("Unable to allocate DMA memory\n"); + RETERR(ENXIO); + } + if (floppy_track_buffer) { + if (tmp) + fd_dma_mem_free((unsigned long)tmp,try*1024); + } else { + buffer_min = buffer_max = -1; + floppy_track_buffer = tmp; + max_buffer_sectors = try; + } + } + + UDRS->fd_device = minor(inode->i_rdev); + set_capacity(disks[drive], floppy_sizes[minor(inode->i_rdev)]); + if (old_dev != -1 && old_dev != minor(inode->i_rdev)) { + if (buffer_drive == drive) + buffer_track = -1; + /* umm, invalidate_buffers() in ->open?? --hch */ + invalidate_buffers(mk_kdev(FLOPPY_MAJOR,old_dev)); + } + +#ifdef PC9800_DEBUG_FLOPPY + printk("floppy open: floppy.c:%d passed\n", __LINE__); +#endif + + + /* Allow ioctls if we have write-permissions even if read-only open. + * Needed so that programs such as fdrawcmd still can work on write + * protected disks */ + if ((filp->f_mode & 2) || + (inode->i_sb && (permission(inode,2) == 0))) + filp->private_data = (void*) 8; + + if (UFDCS->rawcmd == 1) + UFDCS->rawcmd = 2; + +#ifdef PC9800_DEBUG_FLOPPY + printk("floppy open: floppy.c:%d passed\n", __LINE__); +#endif + + if (filp->f_flags & O_NDELAY) + return 0; + if (filp->f_mode & 3) { + UDRS->last_checked = 0; + check_disk_change(inode->i_bdev); + if (UTESTF(FD_DISK_CHANGED)) + RETERR(ENXIO); + } + if ((filp->f_mode & 2) && !(UTESTF(FD_DISK_WRITABLE))) + RETERR(EROFS); +#ifdef PC9800_DEBUG_FLOPPY + printk("floppy open: end normally\n"); +#endif + + return 0; +#undef RETERR +} + +/* + * Check if the disk has been changed or if a change has been faked. + */ +static int check_floppy_change(struct gendisk *disk) +{ + int drive = (int)disk->private_data; + +#ifdef PC9800_DEBUG_FLOPPY + printk("check_floppy_change: MINOR=%d\n", minor(dev)); +#endif + + if (UTESTF(FD_DISK_CHANGED) || UTESTF(FD_VERIFY)) + return 1; + + if (UDP->checkfreq < (int)(jiffies - UDRS->last_checked)) { + if(floppy_grab_irq_and_dma()) { + return 1; + } + + lock_fdc(drive,0); + poll_drive(0,0); + process_fd_request(); + floppy_release_irq_and_dma(); + } + + if (UTESTF(FD_DISK_CHANGED) || + UTESTF(FD_VERIFY) || + test_bit(drive, &fake_change) || + (!ITYPE(UDRS->fd_device) && !current_type[drive])) + return 1; + return 0; +} + +/* + * This implements "read block 0" for floppy_revalidate(). + * Needed for format autodetection, checking whether there is + * a disk in the drive, and whether that disk is writable. + */ + +static int floppy_rb0_complete(struct bio *bio, unsigned int bytes_done, int err) +{ + if (bio->bi_size) + return 1; + + complete((struct completion*)bio->bi_private); + return 0; +} + +static int __floppy_read_block_0(struct block_device *bdev) +{ + struct bio bio; + struct bio_vec bio_vec; + struct completion complete; + struct page *page; + size_t size; + + page = alloc_page(GFP_NOIO); + if (!page) { + process_fd_request(); + return -ENOMEM; + } + + size = bdev->bd_block_size; + if (!size) + size = 1024; + + bio_init(&bio); + bio.bi_io_vec = &bio_vec; + bio_vec.bv_page = page; + bio_vec.bv_len = size; + bio_vec.bv_offset = 0; + bio.bi_vcnt = 1; + bio.bi_idx = 0; + bio.bi_size = size; + bio.bi_bdev = bdev; + bio.bi_sector = 0; + init_completion(&complete); + bio.bi_private = &complete; + bio.bi_end_io = floppy_rb0_complete; + + submit_bio(READ, &bio); + generic_unplug_device(bdev_get_queue(bdev)); + process_fd_request(); + wait_for_completion(&complete); + + __free_page(page); + + return 0; +} + +static int floppy_read_block_0(struct gendisk *disk) +{ + struct block_device *bdev; + int ret; + + bdev = bdget(MKDEV(disk->major, disk->first_minor)); + if (!bdev) { + printk("No block device for %s\n", disk->disk_name); + BUG(); + } + bdev->bd_disk = disk; /* ewww */ + ret = __floppy_read_block_0(bdev); + atomic_dec(&bdev->bd_count); + return ret; +} + +/* revalidate the floppy disk, i.e. trigger format autodetection by reading + * the bootblock (block 0). "Autodetection" is also needed to check whether + * there is a disk in the drive at all... Thus we also do it for fixed + * geometry formats */ +static int floppy_revalidate(struct gendisk *disk) +{ + int drive=(int)disk->private_data; +#define NO_GEOM (!current_type[drive] && !ITYPE(UDRS->fd_device)) + int cf; + int res = 0; + + if (UTESTF(FD_DISK_CHANGED) || + UTESTF(FD_VERIFY) || + test_bit(drive, &fake_change) || + NO_GEOM){ + if(usage_count == 0) { + printk("VFS: revalidate called on non-open device.\n"); + return -EFAULT; + } + lock_fdc(drive,0); + cf = UTESTF(FD_DISK_CHANGED) || UTESTF(FD_VERIFY); + if (!(cf || test_bit(drive, &fake_change) || NO_GEOM)){ + process_fd_request(); /*already done by another thread*/ + return 0; + } + UDRS->maxblock = 0; + UDRS->maxtrack = 0; + if (buffer_drive == drive) + buffer_track = -1; + clear_bit(drive, &fake_change); + UCLEARF(FD_DISK_CHANGED); + if (cf) + UDRS->generation++; + if (NO_GEOM){ + /* auto-sensing */ + res = floppy_read_block_0(disk); + } else { + if (cf) + poll_drive(0, FD_RAW_NEED_DISK); + process_fd_request(); + } + } + set_capacity(disk, floppy_sizes[UDRS->fd_device]); + return res; +} + +static struct block_device_operations floppy_fops = { + .owner = THIS_MODULE, + .open = floppy_open, + .release = floppy_release, + .ioctl = fd_ioctl, + .media_changed = check_floppy_change, + .revalidate_disk= floppy_revalidate, +}; + +static void __init register_devfs_entries (int drive) +{ + int base_minor, i; + static char *table[] = + {"", +#if 0 + "d360", +#else + "h1232", +#endif + "h1200", "u360", "u720", "h360", "h720", + "u1440", "u2880", "CompaQ", "h1440", "u1680", "h410", + "u820", "h1476", "u1722", "h420", "u830", "h1494", "u1743", + "h880", "u1040", "u1120", "h1600", "u1760", "u1920", + "u3200", "u3520", "u3840", "u1840", "u800", "u1600", + NULL + }; + static int t360[] = {1,0}, t1200[] = {2,5,6,10,12,14,16,18,20,23,0}, + t3in[] = {8,9,26,27,28, 7,11,15,19,24,25,29,31, 3,4,13,17,21,22,30,0}; + static int *table_sup[] = + {NULL, t360, t1200, t3in+5+8, t3in+5, t3in, t3in}; + + base_minor = (drive < 4) ? drive : (124 + drive); + if (UDP->cmos < NUMBER(default_drive_params)) { + i = 0; + do { + char name[16]; + + sprintf (name, "%d%s", drive, table[table_sup[UDP->cmos][i]]); + devfs_register (devfs_handle, name, DEVFS_FL_DEFAULT, MAJOR_NR, + base_minor + (table_sup[UDP->cmos][i] << 2), + S_IFBLK | S_IRUSR | S_IWUSR | S_IRGRP |S_IWGRP, + &floppy_fops, NULL); + } while (table_sup[UDP->cmos][i++]); + } +} + +/* + * Floppy Driver initialization + * ============================= + */ + +static inline char __init get_fdc_version(void) +{ + return FDC_8272A; +} + +/* lilo configuration */ + +static void __init floppy_set_flags(int *ints,int param, int param2) +{ + int i; + + for (i=0; i < ARRAY_SIZE(default_drive_params); i++){ + if (param) + default_drive_params[i].params.flags |= param2; + else + default_drive_params[i].params.flags &= ~param2; + } + DPRINT("%s flag 0x%x\n", param2 ? "Setting" : "Clearing", param); +} + +static void __init daring(int *ints,int param, int param2) +{ + int i; + + for (i=0; i < ARRAY_SIZE(default_drive_params); i++){ + if (param){ + default_drive_params[i].params.select_delay = 0; + default_drive_params[i].params.flags |= FD_SILENT_DCL_CLEAR; + } else { + default_drive_params[i].params.select_delay = 2*HZ/100; + default_drive_params[i].params.flags &= ~FD_SILENT_DCL_CLEAR; + } + } + DPRINT("Assuming %s floppy hardware\n", param ? "standard" : "broken"); +} + +static void __init set_cmos(int *ints, int dummy, int dummy2) +{ + int current_drive=0; + + if (ints[0] != 2){ + DPRINT("wrong number of parameters for CMOS\n"); + return; + } + current_drive = ints[1]; + if (current_drive < 0 || current_drive >= 8){ + DPRINT("bad drive for set_cmos\n"); + return; + } +#if N_FDC > 1 + if (current_drive >= 4 && !FDC2) + FDC2 = 0x370; +#endif + DP->cmos = ints[2]; + DPRINT("setting CMOS code to %d\n", ints[2]); +} + +static struct param_table { + const char *name; + void (*fn)(int *ints, int param, int param2); + int *var; + int def_param; + int param2; +} config_params[]={ + { "allowed_drive_mask", 0, &allowed_drive_mask, 0xff, 0}, /* obsolete */ + { "all_drives", 0, &allowed_drive_mask, 0xff, 0 }, /* obsolete */ + { "irq", 0, &FLOPPY_IRQ, DEFAULT_FLOPPY_IRQ, 0 }, + { "dma", 0, &FLOPPY_DMA, DEFAULT_FLOPPY_DMA, 0 }, + + { "daring", daring, 0, 1, 0}, +#if N_FDC > 1 + { "two_fdc", 0, &FDC2, 0x370, 0 }, + { "one_fdc", 0, &FDC2, 0, 0 }, +#endif + { "broken_dcl", floppy_set_flags, 0, 1, FD_BROKEN_DCL }, + { "messages", floppy_set_flags, 0, 1, FTD_MSG }, + { "silent_dcl_clear", floppy_set_flags, 0, 1, FD_SILENT_DCL_CLEAR }, + { "debug", floppy_set_flags, 0, 1, FD_DEBUG }, + + { "nodma", 0, &can_use_virtual_dma, 1, 0 }, + { "yesdma", 0, &can_use_virtual_dma, 0, 0 }, + + { "fifo_depth", 0, &fifo_depth, 0xa, 0 }, + { "nofifo", 0, &no_fifo, 0x20, 0 }, + { "usefifo", 0, &no_fifo, 0, 0 }, + + { "cmos", set_cmos, 0, 0, 0 }, + { "slow", 0, &slow_floppy, 1, 0 }, + + { "unexpected_interrupts", 0, &print_unex, 1, 0 }, + { "no_unexpected_interrupts", 0, &print_unex, 0, 0 }, + + EXTRA_FLOPPY_PARAMS +}; + +static int __init floppy_setup(char *str) +{ + int i; + int param; + int ints[11]; + + str = get_options(str,ARRAY_SIZE(ints),ints); + if (str) { + for (i=0; i< ARRAY_SIZE(config_params); i++){ + if (strcmp(str,config_params[i].name) == 0){ + if (ints[0]) + param = ints[1]; + else + param = config_params[i].def_param; + if (config_params[i].fn) + config_params[i]. + fn(ints,param, + config_params[i].param2); + if (config_params[i].var) { + DPRINT("%s=%d\n", str, param); + *config_params[i].var = param; + } + return 1; + } + } + } + if (str) { + DPRINT("unknown floppy option [%s]\n", str); + + DPRINT("allowed options are:"); + for (i=0; i< ARRAY_SIZE(config_params); i++) + printk(" %s",config_params[i].name); + printk("\n"); + } else + DPRINT("botched floppy option\n"); + DPRINT("Read linux/Documentation/floppy.txt\n"); + return 0; +} + +static int have_no_fdc= -ENODEV; + +static struct platform_device floppy_device = { + .name = "floppy", + .id = 0, + .dev = { + .name = "Floppy Drive", + }, +}; + +static struct gendisk *floppy_find(dev_t dev, int *part, void *data) +{ + int drive = (*part&3) | ((*part&0x80) >> 5); + if (drive >= N_DRIVE || + !(allowed_drive_mask & (1 << drive)) || + fdc_state[FDC(drive)].version == FDC_NONE) + return NULL; + return get_disk(disks[drive]); +} + +int __init floppy_init(void) +{ + int i,unit,drive; + int err; + + raw_cmd = NULL; + FDC1 = 0x90; + + for (i=0; imajor = MAJOR_NR; + disks[i]->first_minor = TOMINOR(i); + disks[i]->fops = &floppy_fops; + sprintf(disks[i]->disk_name, "fd%d", i); + } + + blk_register_region(MKDEV(MAJOR_NR, 0), 256, THIS_MODULE, + floppy_find, NULL, NULL); + + for (i=0; i<256; i++) + if (ITYPE(i)) + floppy_sizes[i] = floppy_type[ITYPE(i)].size; + else + floppy_sizes[i] = MAX_DISK_SIZE << 1; + + blk_init_queue(&floppy_queue, do_fd_request, &floppy_lock); + reschedule_timeout(MAXTIMEOUT, "floppy init", MAXTIMEOUT); + config_types(); + + for (i = 0; i < N_FDC; i++) { + fdc = i; + CLEARSTRUCT(FDCS); + FDCS->dtr = -1; + FDCS->dor = 0; + } + + if ((fd_inb(FD_MODE_CHANGE) & 1) == 0) + FDC1 = 0xc8; + + use_virtual_dma = can_use_virtual_dma & 1; + fdc_state[0].address = FDC1; + if (fdc_state[0].address == -1) { + err = -ENODEV; + goto out1; + } +#if N_FDC > 1 + fdc_state[1].address = FDC2; +#endif + + fdc = 0; /* reset fdc in case of unexpected interrupt */ + if (floppy_grab_irq_and_dma()){ + err = -EBUSY; + goto out1; + } + + /* initialise drive state */ + for (drive = 0; drive < N_DRIVE; drive++) { + CLEARSTRUCT(UDRS); + CLEARSTRUCT(UDRWE); + USETF(FD_DISK_NEWCHANGE); + USETF(FD_DISK_CHANGED); + USETF(FD_VERIFY); + UDRS->fd_device = -1; + floppy_track_buffer = NULL; + max_buffer_sectors = 0; + } + + for (i = 0; i < N_FDC; i++) { + fdc = i; + FDCS->driver_version = FD_DRIVER_VERSION; + for (unit=0; unit<4; unit++) + FDCS->track[unit] = 0; + if (FDCS->address == -1) + continue; + FDCS->rawcmd = 2; + user_reset_fdc(-1, FD_RESET_ALWAYS, 0); + + /* Try to determine the floppy controller type */ + FDCS->version = get_fdc_version(); + if (FDCS->version == FDC_NONE){ + /* free ioports reserved by floppy_grab_irq_and_dma() */ + release_region(FDCS->address, 1); + release_region(FDCS->address + 2, 1); + release_region(FDCS->address + 4, 1); + release_region(0xbe, 1); + release_region(0x4be, 1); + FDCS->address = -1; + continue; + } + if (can_use_virtual_dma == 2 && FDCS->version < FDC_82072A) + can_use_virtual_dma = 0; + + have_no_fdc = 0; + /* Not all FDCs seem to be able to handle the version command + * properly, so force a reset for the standard FDC clones, + * to avoid interrupt garbage. + */ + user_reset_fdc(-1,FD_RESET_ALWAYS,0); + } + fdc=0; + del_timer(&fd_timeout); + current_drive = 0; + floppy_release_irq_and_dma(); +#if 0 /* no message */ + initialising=0; +#endif + if (have_no_fdc) { + DPRINT("no floppy controllers found\n"); + flush_scheduled_work(); + if (usage_count) + floppy_release_irq_and_dma(); + err = have_no_fdc; + goto out2; + } + + for (drive = 0; drive < N_DRIVE; drive++) { + init_timer(&motor_off_timer[drive]); + motor_off_timer[drive].data = drive; + motor_off_timer[drive].function = motor_off_callback; + if (!(allowed_drive_mask & (1 << drive))) + continue; + if (fdc_state[FDC(drive)].version == FDC_NONE) + continue; + /* to be cleaned up... */ + disks[drive]->private_data = (void*)drive; + disks[drive]->queue = &floppy_queue; + add_disk(disks[drive]); + } + + platform_device_register(&floppy_device); + return 0; + +out1: + del_timer(&fd_timeout); +out2: + blk_unregister_region(MKDEV(MAJOR_NR, 0), 256); + unregister_blkdev(MAJOR_NR,"fd"); + blk_cleanup_queue(&floppy_queue); +out: + for (i=0; iaddress != -1){ + static char floppy[] = "floppy"; + if (!request_region(FDCS->address, 1, floppy)) + goto cleanup0; + + if (!request_region(FDCS->address + 2, 1, floppy)) { + release_region(FDCS->address, 1); + goto cleanup0; + } + + if (!request_region(FDCS->address + 4, 1, floppy)) { + release_region(FDCS->address, 1); + release_region(FDCS->address + 2, 1); + goto cleanup0; + } + + if (fdc == 0) { /* internal FDC */ + if (request_region(0xbe, 1, "floppy mode change")) { + if (request_region(0x4be, 1, "floppy ex. mode change")) + continue; + else + DPRINT("Floppy io-port 0x4be in use\n"); + + release_region(0xbe, 1); + } else + DPRINT("Floppy io-port 0xbe in use\n"); + + release_region(FDCS->address, 1); + release_region(FDCS->address + 2, 1); + release_region(FDCS->address + 4, 1); + } + + goto cleanup1; + } + } + for (fdc=0; fdc< N_FDC; fdc++){ + if (FDCS->address != -1){ + reset_fdc_info(1); + fd_outb(FDCS->dor, FD_MODE); + } + } + fdc = 0; + fd_outb((FDCS->dor & 8), FD_MODE); + + for (fdc = 0; fdc < N_FDC; fdc++) + if (FDCS->address != -1) + fd_outb(FDCS->dor, FD_MODE); + /* + * The driver will try and free resources and relies on us + * to know if they were allocated or not. + */ + fdc = 0; + irqdma_allocated = 1; + return 0; + +cleanup0: + DPRINT("Floppy io-port 0x%04lx in use\n", FDCS->address); +cleanup1: + fd_free_irq(); + fd_free_dma(); + while(--fdc >= 0) { + release_region(FDCS->address, 1); + release_region(FDCS->address + 2, 1); + release_region(FDCS->address + 4, 1); + if (fdc == 0) { + release_region(0x00be, 1); + release_region(0x04be, 1); + } + } + MOD_DEC_USE_COUNT; + spin_lock_irqsave(&floppy_usage_lock, flags); + usage_count--; + spin_unlock_irqrestore(&floppy_usage_lock, flags); + return -1; +} + +static void floppy_release_irq_and_dma(void) +{ + int old_fdc; +#ifdef FLOPPY_SANITY_CHECK + int drive; +#endif + long tmpsize; + unsigned long tmpaddr; + unsigned long flags; + + spin_lock_irqsave(&floppy_usage_lock, flags); + if (--usage_count){ + spin_unlock_irqrestore(&floppy_usage_lock, flags); + return; + } + spin_unlock_irqrestore(&floppy_usage_lock, flags); + if(irqdma_allocated) + { + fd_disable_dma(); + fd_free_dma(); + fd_free_irq(); + irqdma_allocated=0; + } + fd_outb(0, FD_MODE); + floppy_enable_hlt(); + + if (floppy_track_buffer && max_buffer_sectors) { + tmpsize = max_buffer_sectors*1024; + tmpaddr = (unsigned long)floppy_track_buffer; + floppy_track_buffer = NULL; + max_buffer_sectors = 0; + buffer_min = buffer_max = -1; + fd_dma_mem_free(tmpaddr, tmpsize); + } + +#ifdef FLOPPY_SANITY_CHECK + for (drive=0; drive < N_FDC * 4; drive++) + if (timer_pending(motor_off_timer + drive)) + printk("motor off timer %d still active\n", drive); + + if (timer_pending(&fd_timeout)) + printk("floppy timer still active:%s\n", timeout_message); + if (timer_pending(&fd_timer)) + printk("auxiliary floppy timer still active\n"); + if (floppy_work.pending) + printk("work still pending\n"); +#endif + old_fdc = fdc; + for (fdc = 0; fdc < N_FDC; fdc++) + if (FDCS->address != -1) { + release_region(FDCS->address, 1); + release_region(FDCS->address + 2, 1); + release_region(FDCS->address + 4, 1); + if (fdc == 0) { + release_region(0xbe, 1); + release_region(0x4be, 1); + } + } + fdc = old_fdc; + MOD_DEC_USE_COUNT; +} + + +#ifdef MODULE + +char *floppy; + +static void __init parse_floppy_cfg_string(char *cfg) +{ + char *ptr; + + while(*cfg) { + for(ptr = cfg;*cfg && *cfg != ' ' && *cfg != '\t'; cfg++); + if (*cfg) { + *cfg = '\0'; + cfg++; + } + if (*ptr) + floppy_setup(ptr); + } +} + +int init_module(void) +{ + printk(KERN_INFO "inserting floppy driver for " UTS_RELEASE "\n"); + + if (floppy) + parse_floppy_cfg_string(floppy); + return floppy_init(); +} + +void cleanup_module(void) +{ + int drive; + + platform_device_unregister(&floppy_device); + devfs_unregister (devfs_handle); + blk_unregister_region(MKDEV(MAJOR_NR, 0), 256); + unregister_blkdev(MAJOR_NR, "fd"); + for (drive = 0; drive < N_DRIVE; drive++) { + if ((allowed_drive_mask & (1 << drive)) && + fdc_state[FDC(drive)].version != FDC_NONE) + del_gendisk(disks[drive]); + put_disk(disks[drive]); + } + + blk_cleanup_queue(&floppy_queue); + /* eject disk, if any */ + fd_eject(0); +} + +MODULE_PARM(floppy,"s"); +MODULE_PARM(FLOPPY_IRQ,"i"); +MODULE_PARM(FLOPPY_DMA,"i"); +MODULE_AUTHOR("Osamu Tomita"); +MODULE_SUPPORTED_DEVICE("fd"); +MODULE_LICENSE("GPL"); + +#else + +__setup ("floppy=", floppy_setup); +module_init(floppy_init) +#endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/drivers/block/genhd.c linux.2.5.47-ac6/drivers/block/genhd.c --- linux.2.5.47/drivers/block/genhd.c 2002-11-11 16:39:09.000000000 +0000 +++ linux.2.5.47-ac6/drivers/block/genhd.c 2002-11-11 16:51:32.000000000 +0000 @@ -123,6 +123,7 @@ EXPORT_SYMBOL(add_disk); EXPORT_SYMBOL(del_gendisk); +EXPORT_SYMBOL(get_gendisk); void unlink_gendisk(struct gendisk *disk) { diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/drivers/block/loop.c linux.2.5.47-ac6/drivers/block/loop.c --- linux.2.5.47/drivers/block/loop.c 2002-11-11 16:39:09.000000000 +0000 +++ linux.2.5.47-ac6/drivers/block/loop.c 2002-11-13 15:24:26.000000000 +0000 @@ -304,21 +304,16 @@ { struct lo_read_data cookie; struct file *file; - int error; + int retval; cookie.lo = lo; cookie.data = kmap(bvec->bv_page) + bvec->bv_offset; cookie.bsize = bsize; - - /* umm, what does this lock actually try to protect? */ - spin_lock_irq(&lo->lo_lock); file = lo->lo_backing_file; - spin_unlock_irq(&lo->lo_lock); - - error = file->f_op->sendfile(file, &pos, bvec->bv_len, + retval = file->f_op->sendfile(file, &pos, bvec->bv_len, lo_read_actor, &cookie); kunmap(bvec->bv_page); - return error; + return (retval < 0)? retval: 0; } static int diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/drivers/block/Makefile linux.2.5.47-ac6/drivers/block/Makefile --- linux.2.5.47/drivers/block/Makefile 2002-10-31 14:57:17.000000000 +0000 +++ linux.2.5.47-ac6/drivers/block/Makefile 2002-10-31 15:05:41.000000000 +0000 @@ -14,7 +14,11 @@ obj-y := elevator.o ll_rw_blk.o ioctl.o genhd.o scsi_ioctl.o deadline-iosched.o obj-$(CONFIG_MAC_FLOPPY) += swim3.o +ifneq ($(CONFIG_PC9800),y) obj-$(CONFIG_BLK_DEV_FD) += floppy.o +else +obj-$(CONFIG_BLK_DEV_FD) += floppy98.o +endif obj-$(CONFIG_AMIGA_FLOPPY) += amiflop.o obj-$(CONFIG_ATARI_FLOPPY) += ataflop.o obj-$(CONFIG_BLK_DEV_SWIM_IOP) += swim_iop.o diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/drivers/bluetooth/bluecard_cs.c linux.2.5.47-ac6/drivers/bluetooth/bluecard_cs.c --- linux.2.5.47/drivers/bluetooth/bluecard_cs.c 2002-10-31 15:05:01.000000000 +0000 +++ linux.2.5.47-ac6/drivers/bluetooth/bluecard_cs.c 2002-11-13 15:21:49.000000000 +0000 @@ -849,6 +849,7 @@ link = &info->link; link->priv = info; + init_timer(&link->release); link->release.function = &bluecard_release; link->release.data = (u_long)link; link->io.Attributes1 = IO_DATA_PATH_WIDTH_8; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/drivers/bluetooth/bt3c_cs.c linux.2.5.47-ac6/drivers/bluetooth/bt3c_cs.c --- linux.2.5.47/drivers/bluetooth/bt3c_cs.c 2002-10-31 15:05:01.000000000 +0000 +++ linux.2.5.47-ac6/drivers/bluetooth/bt3c_cs.c 2002-11-13 15:21:49.000000000 +0000 @@ -643,6 +643,7 @@ link = &info->link; link->priv = info; + init_timer(&link->release); link->release.function = &bt3c_release; link->release.data = (u_long)link; link->io.Attributes1 = IO_DATA_PATH_WIDTH_8; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/drivers/bluetooth/dtl1_cs.c linux.2.5.47-ac6/drivers/bluetooth/dtl1_cs.c --- linux.2.5.47/drivers/bluetooth/dtl1_cs.c 2002-10-31 14:57:19.000000000 +0000 +++ linux.2.5.47-ac6/drivers/bluetooth/dtl1_cs.c 2002-11-13 15:21:49.000000000 +0000 @@ -582,6 +582,7 @@ link = &info->link; link->priv = info; + init_timer(&link->release); link->release.function = &dtl1_release; link->release.data = (u_long)link; link->io.Attributes1 = IO_DATA_PATH_WIDTH_8; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/drivers/cdrom/cm206.c linux.2.5.47-ac6/drivers/cdrom/cm206.c --- linux.2.5.47/drivers/cdrom/cm206.c 2002-11-11 16:39:09.000000000 +0000 +++ linux.2.5.47-ac6/drivers/cdrom/cm206.c 2002-11-13 15:21:49.000000000 +0000 @@ -1514,6 +1514,7 @@ memset(cd, 0, sizeof(*cd)); /* give'm some reasonable value */ cd->sector_last = -1; /* flag no data buffered */ cd->adapter_last = -1; + init_timer(&cd->timer); cd->timer.function = cm206_timeout; cd->max_sectors = (inw(r_data_status) & ds_ram_size) ? 24 : 97; printk(KERN_INFO "%d kB adapter memory available, " diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/drivers/cdrom/gscd.c linux.2.5.47-ac6/drivers/cdrom/gscd.c --- linux.2.5.47/drivers/cdrom/gscd.c 2002-11-11 16:39:09.000000000 +0000 +++ linux.2.5.47-ac6/drivers/cdrom/gscd.c 2002-11-17 02:10:37.000000000 +0000 @@ -268,7 +268,7 @@ goto out; if (req->cmd != READ) { - printk("GSCD: bad cmd %d\n", rq_data_dir(req)); + printk("GSCD: bad cmd %ld\n", rq_data_dir(req)); end_request(req, 0); goto repeat; } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/drivers/char/agp/agp.h linux.2.5.47-ac6/drivers/char/agp/agp.h --- linux.2.5.47/drivers/char/agp/agp.h 2002-10-31 14:57:09.000000000 +0000 +++ linux.2.5.47-ac6/drivers/char/agp/agp.h 2002-10-31 15:05:30.000000000 +0000 @@ -294,7 +294,14 @@ #define I810_DRAM_ROW_0 0x00000001 #define I810_DRAM_ROW_0_SDRAM 0x00000001 - +/* Intel 7505 registers */ +#define INTEL_I7505_NAPBASELO 0x10 +#define INTEL_I7505_APSIZE 0x74 +#define INTEL_I7505_NCAPID 0x60 +#define INTEL_I7505_NISTAT 0x6c +#define INTEL_I7505_ATTBASE 0x78 +#define INTEL_I7505_ERRSTS 0x42 +#define INTEL_I7505_AGPCTRL 0x70 /* VIA register */ #define VIA_APBASE 0x10 diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/drivers/char/Kconfig linux.2.5.47-ac6/drivers/char/Kconfig --- linux.2.5.47/drivers/char/Kconfig 2002-10-31 15:05:01.000000000 +0000 +++ linux.2.5.47-ac6/drivers/char/Kconfig 2002-11-15 16:00:49.000000000 +0000 @@ -574,6 +574,17 @@ console. This driver allows each pSeries partition to have a console which is accessed via the HMC. +config PC9800_OLDLP + tristate "NEC PC-9800 old-style printer port support" + depends on PC9800 && !PARPORT + ---help--- + If you intend to attach a printer to the parallel port of NEC PC-9801 + /PC-9821 with OLD compatibility mode, Say Y. + +config PC9800_OLDLP_CONSOLE + bool "Support for console on line printer" + depends on PC9800_OLDLP + source "drivers/i2c/Kconfig" @@ -1053,6 +1064,7 @@ config RTC tristate "Enhanced Real Time Clock Support" + depends on PPC32 != y && PARISC != y && PC9800 != y ---help--- If you say Y here and create a character special file /dev/rtc with major number 10 and minor number 135 using mknod ("man mknod"), you @@ -1111,6 +1123,15 @@ bool "EFI Real Time Clock Services" depends on IA64 +config RTC98 + tristate "NEC PC-9800 Real Time Clock Support" + depends on PC9800 + default y + ---help--- + If you say Y here and create a character special file /dev/rtc with + major number 10 and minor number 135 using mknod ("man mknod"), you + will get access to the real time clock (or hardware clock) built + config H8 bool "Tadpole ANA H8 Support (OBSOLETE)" depends on OBSOLETE && ALPHA_BOOK1 diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/drivers/char/keyboard.c linux.2.5.47-ac6/drivers/char/keyboard.c --- linux.2.5.47/drivers/char/keyboard.c 2002-11-11 16:39:09.000000000 +0000 +++ linux.2.5.47-ac6/drivers/char/keyboard.c 2002-11-11 16:52:13.000000000 +0000 @@ -681,8 +681,8 @@ static void k_pad(struct vc_data *vc, unsigned char value, char up_flag) { - static const char *pad_chars = "0123456789+-*/\015,.?()"; - static const char *app_map = "pqrstuvwxylSRQMnnmPQ"; + static const char *pad_chars = "0123456789+-*/\015,.?()#"; + static const char *app_map = "pqrstuvwxylSRQMnnmPQS"; if (up_flag) return; /* no action, if this is a key release */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/drivers/char/lp_old98.c linux.2.5.47-ac6/drivers/char/lp_old98.c --- linux.2.5.47/drivers/char/lp_old98.c 1970-01-01 01:00:00.000000000 +0100 +++ linux.2.5.47-ac6/drivers/char/lp_old98.c 2002-11-15 16:00:49.000000000 +0000 @@ -0,0 +1,577 @@ +/* + * linux/drivers/char/lp_old98.c + * + * printer port driver for ancient PC-9800s with no bidirectional port support + * + * Copyright (C) 1998,99 Kousuke Takai , + * Kyoto University Microcomputer Club + * + * This driver is based on and has compatibility with `lp.c', + * generic PC printer port driver. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#if !defined(CONFIG_PC9800) && !defined(CONFIG_PC98) +#error This driver works only for NEC PC-9800 series +#endif + +#if LINUX_VERSION_CODE < 0x20200 +# define LP_STATS +#endif + +#if LINUX_VERSION_CODE >= 0x2030b +# define CONFIG_RESOURCE98 +#endif + +#include + +/* + * I/O port numbers + */ +#define LP_PORT_DATA 0x40 +#define LP_PORT_STATUS (LP_PORT_DATA+2) +#define LP_PORT_STROBE (LP_PORT_DATA+4) +#define LP_PORT_CONTROL (LP_PORT_DATA+6) + +#define LP_PORT_H98MODE 0x0448 +#define LP_PORT_EXTMODE 0x0149 + +/* + * bit mask for I/O + */ +#define LP_MASK_nBUSY (1 << 2) +#define LP_MASK_nSTROBE (1 << 7) + +#define LP_CONTROL_ASSERT_STROBE (0x0e) +#define LP_CONTROL_NEGATE_STROBE (0x0f) + +/* + * Acceptable maximum value for non-privileged user for LPCHARS ioctl. + */ +#define LP_CHARS_NOPRIV_MAX 65535 + +#define DC1 '\x11' +#define DC3 '\x13' + +/* PC-9800s have at least and at most one old-style printer port. */ +static struct lp_struct lp = { + /* Following `TAG: INITIALIZER' notations are GNU CC extension. */ + flags: LP_EXIST | LP_ABORTOPEN, + chars: LP_INIT_CHAR, + time: LP_INIT_TIME, + wait: LP_INIT_WAIT, +}; + +static int dc1_check = 1000; + +#undef LP_OLD98_DEBUG + +#ifndef __udelay_val +# define __udelay_val current_cpu_data.loops_per_sec +#endif + +static inline void nanodelay(unsigned long nanosecs) /* Evil ? */ +{ + if( nanosecs ) { + nanosecs *= (unsigned long)((1ULL << 40) / 1000000000ULL); + __asm__("mul%L2 %2" + : "=d"(nanosecs) : "a"(nanosecs), "g"(__udelay_val)); + __delay(nanosecs >> 8); + } +} + +#ifdef CONFIG_PC9800_OLDLP_CONSOLE +static struct console lp_old98_console; /* defined later */ +static __typeof__(lp_old98_console.flags) saved_console_flags; +#endif + +static DECLARE_WAIT_QUEUE_HEAD (lp_old98_waitq); + +static void lp_old98_timer_function(unsigned long data); + +static void lp_old98_timer_function(unsigned long data) +{ + if (inb(LP_PORT_STATUS) & LP_MASK_nBUSY) + wake_up_interruptible(&lp_old98_waitq); + else { + struct timer_list *t = (struct timer_list *) data; + + t->expires = jiffies + 1; + add_timer(t); + } +} + +static inline int +lp_old98_wait_ready(void) +{ + struct timer_list timer; + + init_timer(&timer); + timer.function = lp_old98_timer_function; + timer.expires = jiffies + 1; + timer.data = (unsigned long) &timer; + add_timer(&timer); + interruptible_sleep_on(&lp_old98_waitq); + del_timer(&timer); + return signal_pending(current); +} + +static inline int lp_old98_char(char lpchar) +{ + unsigned long count = 0; +#ifdef LP_STATS + int tmp; +#endif + + while( !(inb(LP_PORT_STATUS) & LP_MASK_nBUSY) ) { + count++; + if (count >= lp.chars) + return 0; + } + + outb(lpchar, LP_PORT_DATA); + +#ifdef LP_STATS + /* + * Update lp statsistics here (and between next two outb()'s). + * Time to compute it is part of storobe delay. + */ + if( count > lp.stats.maxwait ) { +#ifdef LP_OLD98_DEBUG + printk(KERN_DEBUG "lp_old98: success after %d counts.\n", + count); +#endif + lp.stats.maxwait = count; + } + count *= 256; + tmp = count - lp.stats.meanwait; + if( tmp < 0 ) + tmp = -tmp; +#endif + nanodelay(lp.wait); + + /* negate PSTB# (activate strobe) */ + outb(LP_CONTROL_ASSERT_STROBE, LP_PORT_CONTROL); + +#ifdef LP_STATS + lp.stats.meanwait = (255 * lp.stats.meanwait + count + 128) / 256; + lp.stats.mdev = (127 * lp.stats.mdev + tmp + 64) / 128; + lp.stats.chars++; +#endif + + nanodelay(lp.wait); + + /* assert PSTB# (deactivate strobe) */ + outb(LP_CONTROL_NEGATE_STROBE, LP_PORT_CONTROL); + + return 1; +} + +#if LINUX_VERSION_CODE < 0x20200 +static long lp_old98_write(struct inode * inode, struct file * file, + const char * buf, unsigned long count) +#else +static ssize_t lp_old98_write(struct file * file, + const char * buf, size_t count, + loff_t *dummy) +#endif +{ + unsigned long total_bytes_written = 0; + + if (!access_ok(VERIFY_READ, buf, count)) + return -EFAULT; + +#ifdef LP_STATS + if( jiffies - lp.lastcall > lp.time ) + lp.runchars = 0; + lp.lastcall = jiffies; +#endif + + do { + unsigned long bytes_written = 0; + unsigned long copy_size + = (count < LP_BUFFER_SIZE ? count : LP_BUFFER_SIZE); + + if (__copy_from_user(lp.lp_buffer, buf, copy_size)) + return -EFAULT; + + while( bytes_written < copy_size ) { + if( lp_old98_char(lp.lp_buffer[bytes_written]) ) + bytes_written++; + else { +#ifdef LP_STATS + int rc = lp.runchars + bytes_written; + + if( rc > lp.stats.maxrun ) + lp.stats.maxrun = rc; + + lp.stats.sleeps++; +#endif +#ifdef LP_OLD98_DEBUG + printk(KERN_DEBUG + "lp_old98: sleeping at %d characters" + " for %d jiffies\n", + lp.runchars, lp.time); + lp.runchars = 0; +#endif + if (lp_old98_wait_ready()) + return ((total_bytes_written + + bytes_written) + ? : -EINTR); + } + } + total_bytes_written += bytes_written; + buf += bytes_written; +#ifdef LP_STATS + lp.runchars += bytes_written; +#endif + count -= bytes_written; + } while( count > 0 ); + + return total_bytes_written; +} + +static long long lp_old98_llseek(struct file * file, + long long offset, int whence) +{ + return -ESPIPE; /* cannot seek like pipe */ +} + +static int lp_old98_open(struct inode * inode, struct file * file) +{ + if( MINOR(inode->i_rdev) != 0 ) + return -ENXIO; + if( lp.flags & LP_BUSY ) + return -EBUSY; + + if ((lp.lp_buffer = kmalloc(LP_BUFFER_SIZE, GFP_KERNEL)) == NULL) + return -ENOMEM; + + if (dc1_check && (lp.flags & LP_ABORTOPEN) + && !(file->f_flags & O_NONBLOCK) ) { + /* + * Check whether printer is on-line. + * PC-9800's old style port have only BUSY# as status input, + * so that it is impossible to distinguish that the printer is + * ready and that the printer is off-line or not connected + * (in both case BUSY# is in the same state). So: + * + * (1) output DC1 (0x11) to printer port and do strobe. + * (2) watch BUSY# line for a while. If BUSY# is pulled + * down, the printer will be ready. Otherwise, + * it will be off-line (or not connected, or power-off, + * ...). + * + * The source of this procedure: + * Terumasa KODAKA, Kazufumi SHIMIZU, Yu HAYAMI: + * `PC-9801 Super Technique', Ascii, 1992. + */ + int count; + unsigned long eflags; + + save_flags(eflags); + cli(); /* interrupts while check is fairly bad */ + + if (!lp_old98_char(DC1)) { + restore_flags(eflags); + return -EBUSY; + } + count = (unsigned int)dc1_check > 10000 ? 10000 : dc1_check; + while( inb(LP_PORT_STATUS) & LP_MASK_nBUSY ) + if( --count == 0 ) { + restore_flags(eflags); + return -ENODEV; + } + restore_flags(eflags); + } + + lp.flags |= LP_BUSY; + +#ifdef CONFIG_PC9800_OLDLP_CONSOLE + saved_console_flags = lp_old98_console.flags; + lp_old98_console.flags &= ~CON_ENABLED; +#endif + + MOD_INC_USE_COUNT; + return 0; +} + +static int lp_old98_release(struct inode * inode, struct file * file) +{ + kfree(lp.lp_buffer); + lp.lp_buffer = NULL; + lp.flags &= ~LP_BUSY; +#ifdef CONFIG_PC9800_OLDLP_CONSOLE + lp_old98_console.flags = saved_console_flags; +#endif + MOD_DEC_USE_COUNT; + return 0; +} + +static int lp_old98_init_device(void) +{ + unsigned char data; + + if( (data = inb(LP_PORT_EXTMODE)) != 0xFF && (data & 0x10) ) { + printk(KERN_INFO + "lp_old98: shutting down extended parallel port mode...\n"); + outb(data & ~0x10, LP_PORT_EXTMODE); + } +#ifdef PC98_HW_H98 + if( (pc98_hw_flags & PC98_HW_H98) + && ((data = inb(LP_PORT_H98MODE)) & 0x01) ) { + printk(KERN_INFO + "lp_old98: shutting down H98 full centronics mode...\n"); + outb(data & ~0x01, LP_PORT_H98MODE); + } +#endif + return 0; +} + +/* + * Many use of `put_user' macro enlarge code size... + */ +static /* not inline */ int lp_old98_put_user(int val, int *addr) +{ + return put_user(val, addr); +} + +static int lp_old98_ioctl(struct inode *inode, struct file *file, + unsigned int command, unsigned long arg) +{ + int retval = 0; + + switch ( command ) { + case LPTIME: + lp.time = arg * HZ/100; + break; + case LPCHAR: + lp.chars = arg; + break; + case LPABORT: + if( arg ) + lp.flags |= LP_ABORT; + else + lp.flags &= ~LP_ABORT; + break; + case LPABORTOPEN: + if( arg ) + lp.flags |= LP_ABORTOPEN; + else + lp.flags &= ~LP_ABORTOPEN; + break; + case LPCAREFUL: + /* do nothing */ + break; + case LPWAIT: + lp.wait = arg; + break; + case LPGETIRQ: + retval = lp_old98_put_user(0, (int *)arg); + break; + case LPGETSTATUS: + /* + * convert PC-9800's status to IBM PC's one, so that tunelp(8) + * works in the same way on this driver. + */ + retval = lp_old98_put_user((inb(LP_PORT_STATUS) + & LP_MASK_nBUSY) + ? (LP_PBUSY | LP_PERRORP) + : LP_PERRORP, + (int *)arg); + break; + case LPRESET: + retval = lp_old98_init_device(); + break; +#ifdef LP_STATS + case LPGETSTATS: + if( copy_to_user((struct lp_stats *)arg, &lp.stats, + sizeof(struct lp_stats)) ) + retval = -EFAULT; + else if (suser()) + memset(&lp.stats, 0, sizeof(struct lp_stats)); + break; +#endif + case LPGETFLAGS: + retval = lp_old98_put_user(lp.flags, (int *)arg); + break; + case LPSETIRQ: + default: + retval = -EINVAL; + } + return retval; +} + +static struct file_operations lp_old98_fops = { + owner: THIS_MODULE, + llseek: lp_old98_llseek, + read: NULL, + write: lp_old98_write, + ioctl: lp_old98_ioctl, + open: lp_old98_open, + release:lp_old98_release, +}; + +/* + * Support for console on lp_old98 + */ +#ifdef CONFIG_PC9800_OLDLP_CONSOLE + +static inline void io_delay(void) +{ + unsigned char dummy; /* actually not output */ + + asm volatile ("out%B0 %0,%1" : "=a"(dummy) : "N"(0x5f)); +} + +static void lp_old98_console_write(struct console *console, + const char *s, unsigned int count) +{ + int i; + static unsigned int timeout_run = 0; + + while (count) { + /* wait approx 1.2 seconds */ + for (i = 2000000; + !(inb(LP_PORT_STATUS) & LP_MASK_nBUSY); + io_delay()) + if (!--i) { + if (++timeout_run >= 10) + /* disable forever... */ + console->flags &= ~CON_ENABLED; + return; + } + + timeout_run = 0; + + if (*s == '\n') { + outb('\r', LP_PORT_DATA); + io_delay(); + io_delay(); + outb(LP_CONTROL_ASSERT_STROBE, LP_PORT_CONTROL); + io_delay(); + io_delay(); + outb(LP_CONTROL_NEGATE_STROBE, LP_PORT_CONTROL); + io_delay(); + io_delay(); + for (i = 1000000; + !(inb(LP_PORT_STATUS) & LP_MASK_nBUSY); + io_delay()) + if (!--i) + return; + } + + outb(*s++, LP_PORT_DATA); + io_delay(); + io_delay(); + outb(LP_CONTROL_ASSERT_STROBE, LP_PORT_CONTROL); + io_delay(); + io_delay(); + outb(LP_CONTROL_NEGATE_STROBE, LP_PORT_CONTROL); + io_delay(); + io_delay(); + + --count; + } +} + +static kdev_t lp_old98_console_device(struct console *console) +{ + return MKDEV(LP_MAJOR, 0); +} + +static struct console lp_old98_console = { + name: "lp_old98", + write: lp_old98_console_write, + device: lp_old98_console_device, + flags: CON_PRINTBUFFER, + index: -1, +}; + +#endif /* console on lp_old98 */ + +#ifdef MODULE +#define lp_old98_init init_module +#endif + +int __init lp_old98_init(void) +{ + if (check_region(LP_PORT_DATA, 1) || check_region(LP_PORT_STATUS, 1) + || check_region(LP_PORT_STROBE, 1) +#ifdef PC98_HW_H98 + || ((pc98_hw_flags & PC98_HW_H98) + && check_region(LP_PORT_H98MODE, 1)) +#endif + || check_region(LP_PORT_EXTMODE, 1)) { + printk(KERN_ERR + "lp_old98: I/O ports already occupied, giving up.\n"); + return -EBUSY; + } + if (register_chrdev(LP_MAJOR, "lp", &lp_old98_fops)) { + printk(KERN_ERR "lp_old98: unable to get major %d\n", + LP_MAJOR); + return -EBUSY; + } + +#ifdef CONFIG_PC9800_OLDLP_CONSOLE + register_console(&lp_old98_console); + printk(KERN_INFO "lp_old98: console ready\n"); +#endif + + request_region(LP_PORT_DATA, 1, "lp_old98"); + request_region(LP_PORT_STATUS, 1, "lp_old98"); + request_region(LP_PORT_STROBE, 1, "lp_old98"); + + /* + * rest are not needed by this driver, + * but for locking out other printer drivers... + */ +#ifdef PC98_HW_H98 + if( pc98_hw_flags & PC98_HW_H98 ) + request_region(LP_PORT_H98MODE, 1, "lp_old98"); +#endif + request_region(LP_PORT_EXTMODE, 1, "lp_old98"); + lp_old98_init_device(); + + return 0; +} + +#ifdef MODULE +void cleanup_module(void) +{ +#ifdef CONFIG_PC9800_OLDLP_CONSOLE + unregister_console(&lp_old98_console); +#endif + unregister_chrdev(LP_MAJOR, "lp"); + + release_region(LP_PORT_DATA, 1); + release_region(LP_PORT_STATUS, 1); + release_region(LP_PORT_STROBE, 1); +#ifdef PC98_HW_H98 + if( pc98_hw_flags & PC98_HW_H98 ) + release_region(LP_PORT_H98MODE, 1); +#endif + release_region(LP_PORT_EXTMODE, 1); +} + +MODULE_PARM(dc1_check, "1i"); +MODULE_AUTHOR("Kousuke Takai "); + +#endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/drivers/char/pcmcia/synclink_cs.c linux.2.5.47-ac6/drivers/char/pcmcia/synclink_cs.c --- linux.2.5.47/drivers/char/pcmcia/synclink_cs.c 2002-10-31 14:57:09.000000000 +0000 +++ linux.2.5.47-ac6/drivers/char/pcmcia/synclink_cs.c 2002-11-13 15:21:49.000000000 +0000 @@ -582,6 +582,7 @@ link->priv = info; /* Initialize the dev_link_t structure */ + init_timer(&link->release); link->release.function = &mgslpc_release; link->release.data = (u_long)link; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/drivers/char/raw.c linux.2.5.47-ac6/drivers/char/raw.c --- linux.2.5.47/drivers/char/raw.c 2002-11-05 13:54:43.000000000 +0000 +++ linux.2.5.47-ac6/drivers/char/raw.c 2002-11-17 00:34:43.000000000 +0000 @@ -103,7 +103,7 @@ { struct block_device *bdev = filp->private_data; - return blkdev_ioctl(bdev->bd_inode, NULL, command, arg); + return ioctl_by_bdev(bdev->bd_inode, command, arg); } /* @@ -243,3 +243,4 @@ module_init(raw_init); module_exit(raw_exit); +MODULE_LICENSE("GPL"); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/drivers/char/sx.c linux.2.5.47-ac6/drivers/char/sx.c --- linux.2.5.47/drivers/char/sx.c 2002-11-11 16:39:09.000000000 +0000 +++ linux.2.5.47-ac6/drivers/char/sx.c 2002-11-11 20:19:35.000000000 +0000 @@ -2197,6 +2197,23 @@ } } + /* Now we're pretty much convinced that there is an SI board here, + but to prevent trouble, we'd better double check that we don't + have an SI1 board when we're probing for an SI2 board.... */ + + write_sx_byte (board, SI2_ISA_ID_BASE,0x10); + if ( IS_SI1_BOARD(board)) { + /* This should be an SI1 board, which has this + location writable... */ + if (read_sx_byte (board, SI2_ISA_ID_BASE) != 0x10) + return 0; + } else { + /* This should be an SI2 board, which has the bottom + 3 bits non-writable... */ + if (read_sx_byte (board, SI2_ISA_ID_BASE) == 0x10) + return 0; + } + printheader (); printk (KERN_DEBUG "sx: Found an SI board at %lx\n", board->hw_base); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/drivers/char/sysrq.c linux.2.5.47-ac6/drivers/char/sysrq.c --- linux.2.5.47/drivers/char/sysrq.c 2002-11-11 16:39:09.000000000 +0000 +++ linux.2.5.47-ac6/drivers/char/sysrq.c 2002-11-17 00:19:07.000000000 +0000 @@ -35,10 +35,6 @@ #include -#ifdef CONFIG_VOYAGER -#include -#endif - extern void reset_vc(unsigned int); extern struct list_head super_blocks; @@ -323,14 +319,6 @@ .action_msg = "Terminate All Tasks", }; -#ifdef CONFIG_VOYAGER -static struct sysrq_key_op sysrq_voyager_dump_op = { - .handler = voyager_dump, - .help_msg = "voyager", - .action_msg = "Dump Voyager Status\n", -}; -#endif - static void sysrq_handle_kill(int key, struct pt_regs *pt_regs, struct tty_struct *tty) { @@ -364,11 +352,7 @@ it is handled specially on the sparc and will never arrive */ /* b */ &sysrq_reboot_op, -#ifdef CONFIG_VOYAGER -/* c */ &sysrq_voyager_dump_op, -#else -/* c */ NULL, -#endif +/* c */ NULL, /* May be assigned at init time by SMP VOYAGER */ /* d */ NULL, /* e */ &sysrq_term_op, /* f */ NULL, diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/drivers/char/tty_io.c linux.2.5.47-ac6/drivers/char/tty_io.c --- linux.2.5.47/drivers/char/tty_io.c 2002-11-11 16:39:09.000000000 +0000 +++ linux.2.5.47-ac6/drivers/char/tty_io.c 2002-11-11 16:52:39.000000000 +0000 @@ -155,6 +155,9 @@ extern void uart_console_init(void); extern void sgi_serial_console_init(void); extern void sci_console_init(void); +extern void m68328_console_init(void); +extern void mcfrs_console_init(void); +extern void rs_360_init(void); extern void tx3912_console_init(void); extern void tx3912_rs_init(void); extern void hvc_console_init(void); @@ -2227,6 +2230,15 @@ #ifdef CONFIG_ARC_CONSOLE arc_console_init(); #endif +#ifdef CONFIG_SERIAL_68328 + m68328_console_init(); +#endif +#ifdef CONFIG_SERIAL_COLDFIRE + mcfrs_console_init(); +#endif +#ifdef CONFIG_SERIAL_68360 + rs_360_init(); +#endif #ifdef CONFIG_SERIAL_TX3912_CONSOLE tx3912_console_init(); #endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/drivers/char/upd4990a.c linux.2.5.47-ac6/drivers/char/upd4990a.c --- linux.2.5.47/drivers/char/upd4990a.c 1970-01-01 01:00:00.000000000 +0100 +++ linux.2.5.47-ac6/drivers/char/upd4990a.c 2002-10-31 15:05:31.000000000 +0000 @@ -0,0 +1,438 @@ +/* + * NEC PC-9800 Real Time Clock interface for Linux + * + * Copyright (C) 1997-2001 Linux/98 project, + * Kyoto University Microcomputer Club. + * + * Based on: + * drivers/char/rtc.c by Paul Gortmaker + * + * Changes: + * 2001-02-09 Call check_region on rtc_init and do not request I/O 0033h. + * Call del_timer and release_region on rtc_exit. -- tak + * 2001-07-14 Rewrite and split to + * and . + * Introduce a lot of spin_lock/unlock (&rtc_lock). + */ + +#define RTC98_VERSION "1.2" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#define BCD_TO_BINARY(val) (((val) >> 4) * 10 + ((val) & 0xF)) +#define BINARY_TO_BCD(val) ((((val) / 10) << 4) | ((val) % 10)) + +/* + * We sponge a minor off of the misc major. No need slurping + * up another valuable major dev number for this. If you add + * an ioctl, make sure you don't conflict with SPARC's RTC + * ioctls. + */ + +static struct fasync_struct *rtc_async_queue; + +static DECLARE_WAIT_QUEUE_HEAD(rtc_wait); + +static struct timer_list rtc_uie_timer; +static u8 old_refclk; + +static long long rtc_llseek(struct file *file, loff_t offset, int origin); + +static int rtc_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg); + +static int rtc_read_proc(char *page, char **start, off_t off, + int count, int *eof, void *data); + +/* + * Bits in rtc_status. (5 bits of room for future expansion) + */ + +#define RTC_IS_OPEN 0x01 /* means /dev/rtc is in use */ +#define RTC_TIMER_ON 0x02 /* not used */ +#define RTC_UIE_TIMER_ON 0x04 /* UIE emulation timer is active */ + +/* + * rtc_status is never changed by rtc_interrupt, and ioctl/open/close is + * protected by the big kernel lock. However, ioctl can still disable the timer + * in rtc_status and then with del_timer after the interrupt has read + * rtc_status but before mod_timer is called, which would then reenable the + * timer (but you would need to have an awful timing before you'd trip on it) + */ +static unsigned char rtc_status; /* bitmapped status byte. */ +static unsigned long rtc_irq_data; /* our output to the world */ + +static const unsigned char days_in_mo[] = +{31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; + +extern spinlock_t rtc_lock; /* defined in arch/i386/kernel/time.c */ + +static void rtc_uie_intr(unsigned long data) +{ + u8 refclk, tmp; + + /* Kernel timer does del_timer internally before calling + each timer entry, so this is unnecessary. + del_timer(&rtc_uie_timer); */ + spin_lock(&rtc_lock); + + /* Detect rising edge of 1Hz reference clock. */ + refclk = UPD4990A_READ_DATA(); + tmp = old_refclk & refclk; + old_refclk = ~refclk; + if (!(tmp & 1)) + rtc_irq_data += 0x100; + + spin_unlock(&rtc_lock); + + if (!(tmp & 1)) { + /* Now do the rest of the actions */ + wake_up_interruptible(&rtc_wait); + kill_fasync(&rtc_async_queue, SIGIO, POLL_IN); + } + + rtc_uie_timer.expires = jiffies + 1; + add_timer(&rtc_uie_timer); +} + +/* + * Now all the various file operations that we export. + */ + +static long long rtc_llseek(struct file *file, loff_t offset, int origin) +{ + return -ESPIPE; +} + +static ssize_t rtc_read(struct file *file, char *buf, + size_t count, loff_t *ppos) +{ + DECLARE_WAITQUEUE(wait, current); + unsigned long data; + ssize_t retval = 0; + + if (count < sizeof(unsigned long)) + return -EINVAL; + + add_wait_queue(&rtc_wait, &wait); + + set_current_state(TASK_INTERRUPTIBLE); + + do { + /* First make it right. Then make it fast. Putting this whole + * block within the parentheses of a while would be too + * confusing. And no, xchg() is not the answer. */ + spin_lock_irq(&rtc_lock); + data = rtc_irq_data; + rtc_irq_data = 0; + spin_unlock_irq(&rtc_lock); + + if (data != 0) + break; + + if (file->f_flags & O_NONBLOCK) { + retval = -EAGAIN; + goto out; + } + if (signal_pending(current)) { + retval = -ERESTARTSYS; + goto out; + } + schedule(); + } while (1); + + retval = put_user(data, (unsigned long *)buf); + if (!retval) + retval = sizeof(unsigned long); + out: + set_current_state(TASK_RUNNING); + remove_wait_queue(&rtc_wait, &wait); + + return retval; +} + +static int rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd, + unsigned long arg) +{ + struct rtc_time wtime; + struct upd4990a_raw_data raw; + + switch (cmd) { + case RTC_UIE_OFF: /* Mask ints from RTC updates. */ + spin_lock_irq(&rtc_lock); + if (rtc_status & RTC_UIE_TIMER_ON) { + rtc_status &= ~RTC_UIE_TIMER_ON; + del_timer(&rtc_uie_timer); + } + spin_unlock_irq(&rtc_lock); + return 0; + + case RTC_UIE_ON: /* Allow ints for RTC updates. */ + spin_lock_irq(&rtc_lock); + rtc_irq_data = 0; + if (!(rtc_status & RTC_UIE_TIMER_ON)){ + rtc_status |= RTC_UIE_TIMER_ON; + rtc_uie_timer.expires = jiffies + 1; + add_timer(&rtc_uie_timer); + } + /* Just in case... */ + upd4990a_serial_command(UPD4990A_REGISTER_HOLD); + old_refclk = ~UPD4990A_READ_DATA(); + spin_unlock_irq(&rtc_lock); + return 0; + + case RTC_RD_TIME: /* Read the time/date from RTC */ + spin_lock_irq(&rtc_lock); + upd4990a_get_time(&raw, 0); + spin_unlock_irq(&rtc_lock); + + wtime.tm_sec = BCD_TO_BINARY(raw.sec); + wtime.tm_min = BCD_TO_BINARY(raw.min); + wtime.tm_hour = BCD_TO_BINARY(raw.hour); + wtime.tm_mday = BCD_TO_BINARY(raw.mday); + wtime.tm_mon = raw.mon - 1; /* convert to 0-base */ + wtime.tm_wday = raw.wday; + + /* + * Account for differences between how the RTC uses the values + * and how they are defined in a struct rtc_time; + */ + if ((wtime.tm_year = BCD_TO_BINARY(raw.year)) < 95) + wtime.tm_year += 100; + + wtime.tm_isdst = 0; + break; + + case RTC_SET_TIME: /* Set the RTC */ + { + int leap_yr; + + if (!capable(CAP_SYS_TIME)) + return -EACCES; + + if (copy_from_user(&wtime, (struct rtc_time *) arg, + sizeof (struct rtc_time))) + return -EFAULT; + + /* Valid year is 1995 - 2094, inclusive. */ + if (wtime.tm_year < 95 || wtime.tm_year > 194) + return -EINVAL; + + if (wtime.tm_mon > 11 || wtime.tm_mday == 0) + return -EINVAL; + + /* For acceptable year domain (1995 - 2094), + this IS sufficient. */ + leap_yr = !(wtime.tm_year % 4); + + if (wtime.tm_mday > (days_in_mo[wtime.tm_mon] + + (wtime.tm_mon == 2 && leap_yr))) + return -EINVAL; + + if (wtime.tm_hour >= 24 + || wtime.tm_min >= 60 || wtime.tm_sec >= 60) + return -EINVAL; + + if (wtime.tm_wday > 6) + return -EINVAL; + + raw.sec = BINARY_TO_BCD(wtime.tm_sec); + raw.min = BINARY_TO_BCD(wtime.tm_min); + raw.hour = BINARY_TO_BCD(wtime.tm_hour); + raw.mday = BINARY_TO_BCD(wtime.tm_mday); + raw.mon = wtime.tm_mon + 1; + raw.wday = wtime.tm_wday; + raw.year = BINARY_TO_BCD(wtime.tm_year % 100); + + spin_lock_irq(&rtc_lock); + upd4990a_set_time(&raw, 0); + spin_unlock_irq(&rtc_lock); + + return 0; + } + default: + return -EINVAL; + } + return copy_to_user((void *)arg, &wtime, sizeof wtime) ? -EFAULT : 0; +} + +/* + * We enforce only one user at a time here with the open/close. + * Also clear the previous interrupt data on an open, and clean + * up things on a close. + */ + +static int rtc_open(struct inode *inode, struct file *file) +{ + spin_lock_irq(&rtc_lock); + + if(rtc_status & RTC_IS_OPEN) + goto out_busy; + + rtc_status |= RTC_IS_OPEN; + + rtc_irq_data = 0; + spin_unlock_irq(&rtc_lock); + return 0; + + out_busy: + spin_unlock_irq(&rtc_lock); + return -EBUSY; +} + +static int rtc_fasync(int fd, struct file *filp, int on) +{ + return fasync_helper(fd, filp, on, &rtc_async_queue); +} + +static int rtc_release(struct inode *inode, struct file *file) +{ + del_timer(&rtc_uie_timer); + + if (file->f_flags & FASYNC) + rtc_fasync(-1, file, 0); + + rtc_irq_data = 0; + + /* No need for locking -- nobody else can do anything until this rmw is + * committed, and no timer is running. */ + rtc_status &= ~(RTC_IS_OPEN | RTC_UIE_TIMER_ON); + return 0; +} + +static unsigned int rtc_poll(struct file *file, poll_table *wait) +{ + unsigned long l; + + poll_wait(file, &rtc_wait, wait); + + spin_lock_irq(&rtc_lock); + l = rtc_irq_data; + spin_unlock_irq(&rtc_lock); + + if (l != 0) + return POLLIN | POLLRDNORM; + return 0; +} + +/* + * The various file operations we support. + */ + +static struct file_operations rtc_fops = { + owner: THIS_MODULE, + llseek: rtc_llseek, + read: rtc_read, + poll: rtc_poll, + ioctl: rtc_ioctl, + open: rtc_open, + release: rtc_release, + fasync: rtc_fasync, +}; + +static struct miscdevice rtc_dev= +{ + RTC_MINOR, + "rtc", + &rtc_fops +}; + +static int __init rtc_init(void) +{ + if (!request_region(UPD4990A_IO, 1, "rtc")) { + printk(KERN_ERR "upd4990a: could not acquire I/O port %#x\n", + UPD4990A_IO); + return -EBUSY; + } + +#if 0 + printk(KERN_INFO "\xB6\xDA\xDD\xC0\xDE \xC4\xDE\xB9\xB2 Driver\n"); /* Calender Clock Driver */ +#else + printk(KERN_INFO + "Real Time Clock driver for NEC PC-9800 v" RTC98_VERSION "\n"); +#endif + misc_register(&rtc_dev); + create_proc_read_entry("driver/rtc", 0, NULL, rtc_read_proc, NULL); + + init_timer(&rtc_uie_timer); + rtc_uie_timer.function = rtc_uie_intr; + + return 0; +} + +module_init (rtc_init); + +#ifdef MODULE +static void __exit rtc_exit(void) +{ + del_timer(&rtc_uie_timer); + release_region(UPD4990A_IO, 1); + remove_proc_entry("driver/rtc", NULL); + misc_deregister(&rtc_dev); +} + +module_exit (rtc_exit); +#endif + +EXPORT_NO_SYMBOLS; + +/* + * Info exported via "/proc/driver/rtc". + */ + +static inline int rtc_get_status(char *buf) +{ + char *p; + unsigned int year; + struct upd4990a_raw_data data; + + p = buf; + + upd4990a_get_time(&data, 0); + + /* + * There is no way to tell if the luser has the RTC set for local + * time or for Universal Standard Time (GMT). Probably local though. + */ + if ((year = BCD_TO_BINARY(data.year) + 1900) < 1995) + year += 100; + p += sprintf(p, + "rtc_time\t: %02d:%02d:%02d\n" + "rtc_date\t: %04d-%02d-%02d\n", + BCD_TO_BINARY(data.hour), BCD_TO_BINARY(data.min), + BCD_TO_BINARY(data.sec), + year, data.mon, BCD_TO_BINARY(data.mday)); + + return p - buf; +} + +static int rtc_read_proc(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + int len = rtc_get_status(page); + + if (len <= off + count) + *eof = 1; + *start = page + off; + len -= off; + if (len > count) + len = count; + if (len < 0) + len = 0; + return len; +} diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/drivers/fc4/fc.c linux.2.5.47-ac6/drivers/fc4/fc.c --- linux.2.5.47/drivers/fc4/fc.c 2002-11-11 16:39:09.000000000 +0000 +++ linux.2.5.47-ac6/drivers/fc4/fc.c 2002-11-13 15:21:49.000000000 +0000 @@ -676,6 +676,7 @@ l.magic = LSOMAGIC; FCND(("FCP Force Offline for %d channels\n", count)) init_MUTEX_LOCKED(&l.sem); + init_timer(&l.timer); l.timer.function = fcp_login_timeout; l.timer.data = (unsigned long)&l; atomic_set (&l.todo, count); @@ -977,7 +978,7 @@ fc->rst_pkt->eh_state = SCSI_STATE_QUEUED; - + init_timer(&fc->rst_pkt->eh_timeout); fc->rst_pkt->eh_timeout.data = (unsigned long) fc->rst_pkt; fc->rst_pkt->eh_timeout.expires = jiffies + FCP_RESET_TIMEOUT; fc->rst_pkt->eh_timeout.function = (void (*)(unsigned long))fcp_scsi_reset_done; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/drivers/hotplug/cpqphp_nvram.c linux.2.5.47-ac6/drivers/hotplug/cpqphp_nvram.c --- linux.2.5.47/drivers/hotplug/cpqphp_nvram.c 2002-10-31 14:57:01.000000000 +0000 +++ linux.2.5.47-ac6/drivers/hotplug/cpqphp_nvram.c 2002-11-02 22:11:18.000000000 +0000 @@ -177,12 +177,12 @@ spin_lock_irqsave(&int15_lock, flags); __asm__ ( - "xorl %%ebx,%%ebx - xorl %%edx,%%edx - pushf - push %%cs - cli - call *%6" + "xorl %%ebx,%%ebx\n" \ + "xorl %%edx,%%edx\n" \ + "pushf\n" \ + "push %%cs\n" \ + "cli\n" \ + "call *%6\n" : "=c" (*buf_size), "=a" (ret_val) : "a" (op), "c" (*buf_size), "S" (ev_name), "D" (buffer), "m" (compaq_int15_entry_point) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/drivers/ide/ide.c linux.2.5.47-ac6/drivers/ide/ide.c --- linux.2.5.47/drivers/ide/ide.c 2002-11-11 16:39:10.000000000 +0000 +++ linux.2.5.47-ac6/drivers/ide/ide.c 2002-11-18 14:31:54.000000000 +0000 @@ -222,37 +222,6 @@ EXPORT_SYMBOL(idetape); EXPORT_SYMBOL(idescsi); -#if (DISK_RECOVERY_TIME > 0) - -Error So the User Has To Fix the Compilation And Stop Hacking Port 0x43 -Does anyone ever use this anyway ?? - -/* - * For really screwy hardware (hey, at least it *can* be used with Linux) - * we can enforce a minimum delay time between successive operations. - */ -static unsigned long read_timer (ide_hwif_t *hwif) -{ - unsigned long t, flags; - int i; - - /* FIXME this is completely unsafe! */ - local_irq_save(flags); - t = jiffies * 11932; - outb_p(0, 0x43); - i = inb_p(0x40); - i |= inb_p(0x40) << 8; - local_irq_restore(flags); - return (t - i); -} -#endif /* DISK_RECOVERY_TIME */ - -static inline void set_recovery_timer (ide_hwif_t *hwif) -{ -#if (DISK_RECOVERY_TIME > 0) - hwif->last_time = read_timer(hwif); -#endif /* DISK_RECOVERY_TIME */ -} /* * Do not even *think* about calling this! @@ -310,6 +279,7 @@ drive->max_failures = IDE_DEFAULT_MAX_FAILURES; drive->using_dma = 0; drive->is_flash = 0; + drive->vdma = 0; INIT_LIST_HEAD(&drive->list); } } @@ -372,7 +342,7 @@ /* safe default value for VESA and PCI */ system_bus_speed = 50; } - printk("ide: Assuming %dMHz system bus speed " + printk(KERN_INFO "ide: Assuming %dMHz system bus speed " "for PIO modes%s\n", system_bus_speed, idebus_parameter ? "" : "; override with idebus=xx"); } @@ -380,48 +350,6 @@ } /* - * This is our end_request replacement function. - */ -int ide_end_request (ide_drive_t *drive, int uptodate, int nr_sectors) -{ - struct request *rq; - unsigned long flags; - int ret = 1; - - spin_lock_irqsave(&ide_lock, flags); - rq = HWGROUP(drive)->rq; - - BUG_ON(!(rq->flags & REQ_STARTED)); - - if (!nr_sectors) - nr_sectors = rq->hard_cur_sectors; - - /* - * decide whether to reenable DMA -- 3 is a random magic for now, - * if we DMA timeout more than 3 times, just stay in PIO - */ - if (drive->state == DMA_PIO_RETRY && drive->retry_pio <= 3) { - drive->state = 0; - HWGROUP(drive)->hwif->ide_dma_on(drive); - } - - if (!end_that_request_first(rq, uptodate, nr_sectors)) { - add_disk_randomness(rq->rq_disk); - if (!blk_rq_tagged(rq)) - blkdev_dequeue_request(rq); - else - blk_queue_end_tag(&drive->queue, rq); - HWGROUP(drive)->rq = NULL; - end_that_request_last(rq); - ret = 0; - } - spin_unlock_irqrestore(&ide_lock, flags); - return ret; -} - -EXPORT_SYMBOL(ide_end_request); - -/* * current_capacity() returns the capacity (in sectors) of a drive * according to its current geometry/LBA settings. */ @@ -444,82 +372,6 @@ } /* - * Clean up after success/failure of an explicit drive cmd - */ -void ide_end_drive_cmd (ide_drive_t *drive, u8 stat, u8 err) -{ - ide_hwif_t *hwif = HWIF(drive); - unsigned long flags; - struct request *rq; - - spin_lock_irqsave(&ide_lock, flags); - rq = HWGROUP(drive)->rq; - spin_unlock_irqrestore(&ide_lock, flags); - - if (rq->flags & REQ_DRIVE_CMD) { - u8 *args = (u8 *) rq->buffer; - if (rq->errors == 0) - rq->errors = !OK_STAT(stat,READY_STAT,BAD_STAT); - - if (args) { - args[0] = stat; - args[1] = err; - args[2] = hwif->INB(IDE_NSECTOR_REG); - } - } else if (rq->flags & REQ_DRIVE_TASK) { - u8 *args = (u8 *) rq->buffer; - if (rq->errors == 0) - rq->errors = !OK_STAT(stat,READY_STAT,BAD_STAT); - - if (args) { - args[0] = stat; - args[1] = err; - args[2] = hwif->INB(IDE_NSECTOR_REG); - args[3] = hwif->INB(IDE_SECTOR_REG); - args[4] = hwif->INB(IDE_LCYL_REG); - args[5] = hwif->INB(IDE_HCYL_REG); - args[6] = hwif->INB(IDE_SELECT_REG); - } - } else if (rq->flags & REQ_DRIVE_TASKFILE) { - ide_task_t *args = (ide_task_t *) rq->special; - if (rq->errors == 0) - rq->errors = !OK_STAT(stat,READY_STAT,BAD_STAT); - - if (args) { - if (args->tf_in_flags.b.data) { - u16 data = hwif->INW(IDE_DATA_REG); - args->tfRegister[IDE_DATA_OFFSET] = (data) & 0xFF; - args->hobRegister[IDE_DATA_OFFSET_HOB] = (data >> 8) & 0xFF; - } - args->tfRegister[IDE_ERROR_OFFSET] = err; - args->tfRegister[IDE_NSECTOR_OFFSET] = hwif->INB(IDE_NSECTOR_REG); - args->tfRegister[IDE_SECTOR_OFFSET] = hwif->INB(IDE_SECTOR_REG); - args->tfRegister[IDE_LCYL_OFFSET] = hwif->INB(IDE_LCYL_REG); - args->tfRegister[IDE_HCYL_OFFSET] = hwif->INB(IDE_HCYL_REG); - args->tfRegister[IDE_SELECT_OFFSET] = hwif->INB(IDE_SELECT_REG); - args->tfRegister[IDE_STATUS_OFFSET] = stat; - - if (drive->addressing == 1) { - hwif->OUTB(drive->ctl|0x80, IDE_CONTROL_REG_HOB); - args->hobRegister[IDE_FEATURE_OFFSET_HOB] = hwif->INB(IDE_FEATURE_REG); - args->hobRegister[IDE_NSECTOR_OFFSET_HOB] = hwif->INB(IDE_NSECTOR_REG); - args->hobRegister[IDE_SECTOR_OFFSET_HOB] = hwif->INB(IDE_SECTOR_REG); - args->hobRegister[IDE_LCYL_OFFSET_HOB] = hwif->INB(IDE_LCYL_REG); - args->hobRegister[IDE_HCYL_OFFSET_HOB] = hwif->INB(IDE_HCYL_REG); - } - } - } - - spin_lock_irqsave(&ide_lock, flags); - blkdev_dequeue_request(rq); - HWGROUP(drive)->rq = NULL; - end_that_request_last(rq); - spin_unlock_irqrestore(&ide_lock, flags); -} - -EXPORT_SYMBOL(ide_end_drive_cmd); - -/* * Error reporting, in human readable form (luxurious, but a memory hog). */ u8 ide_dump_status (ide_drive_t *drive, const char *msg, u8 stat) @@ -529,7 +381,7 @@ u8 err = 0; local_irq_set(flags); - printk("%s: %s: status=0x%02x", drive->name, msg, stat); + printk(KERN_WARNING "%s: %s: status=0x%02x", drive->name, msg, stat); #if FANCY_STATUS_DUMPS printk(" { "); if (stat & BUSY_STAT) { @@ -602,967 +454,7 @@ EXPORT_SYMBOL(ide_dump_status); -/* - * try_to_flush_leftover_data() is invoked in response to a drive - * unexpectedly having its DRQ_STAT bit set. As an alternative to - * resetting the drive, this routine tries to clear the condition - * by read a sector's worth of data from the drive. Of course, - * this may not help if the drive is *waiting* for data from *us*. - */ -void try_to_flush_leftover_data (ide_drive_t *drive) -{ - int i = (drive->mult_count ? drive->mult_count : 1) * SECTOR_WORDS; - - if (drive->media != ide_disk) - return; - while (i > 0) { - u32 buffer[16]; - u32 wcount = (i > 16) ? 16 : i; - - i -= wcount; - HWIF(drive)->ata_input_data(drive, buffer, wcount); - } -} - -EXPORT_SYMBOL(try_to_flush_leftover_data); - -/* - * FIXME Add an ATAPI error - */ - -/* - * ide_error() takes action based on the error returned by the drive. - */ -ide_startstop_t ide_error (ide_drive_t *drive, const char *msg, u8 stat) -{ - ide_hwif_t *hwif; - struct request *rq; - u8 err; - - err = ide_dump_status(drive, msg, stat); - if (drive == NULL || (rq = HWGROUP(drive)->rq) == NULL) - return ide_stopped; - - hwif = HWIF(drive); - /* retry only "normal" I/O: */ - if (rq->flags & (REQ_DRIVE_CMD | REQ_DRIVE_TASK)) { - rq->errors = 1; - ide_end_drive_cmd(drive, stat, err); - return ide_stopped; - } - if (rq->flags & REQ_DRIVE_TASKFILE) { - rq->errors = 1; - ide_end_drive_cmd(drive, stat, err); -// ide_end_taskfile(drive, stat, err); - return ide_stopped; - } - - if (stat & BUSY_STAT || ((stat & WRERR_STAT) && !drive->nowerr)) { - /* other bits are useless when BUSY */ - rq->errors |= ERROR_RESET; - } else { - if (drive->media != ide_disk) - goto media_out; - - if (stat & ERR_STAT) { - /* err has different meaning on cdrom and tape */ - if (err == ABRT_ERR) { - if (drive->select.b.lba && - (hwif->INB(IDE_COMMAND_REG) == WIN_SPECIFY)) - /* some newer drives don't - * support WIN_SPECIFY - */ - return ide_stopped; - } else if ((err & BAD_CRC) == BAD_CRC) { - drive->crc_count++; - /* UDMA crc error -- just retry the operation */ - } else if (err & (BBD_ERR | ECC_ERR)) { - /* retries won't help these */ - rq->errors = ERROR_MAX; - } else if (err & TRK0_ERR) { - /* help it find track zero */ - rq->errors |= ERROR_RECAL; - } - } -media_out: - if ((stat & DRQ_STAT) && rq_data_dir(rq) != WRITE) - try_to_flush_leftover_data(drive); - } - if (hwif->INB(IDE_STATUS_REG) & (BUSY_STAT|DRQ_STAT)) { - /* force an abort */ - hwif->OUTB(WIN_IDLEIMMEDIATE,IDE_COMMAND_REG); - } - if (rq->errors >= ERROR_MAX) { - if (drive->driver != NULL) - DRIVER(drive)->end_request(drive, 0, 0); - else - ide_end_request(drive, 0, 0); - } else { - if ((rq->errors & ERROR_RESET) == ERROR_RESET) { - ++rq->errors; - return ide_do_reset(drive); - } - if ((rq->errors & ERROR_RECAL) == ERROR_RECAL) - drive->special.b.recalibrate = 1; - ++rq->errors; - } - return ide_stopped; -} -EXPORT_SYMBOL(ide_error); - -/* - * Issue a simple drive command - * The drive must be selected beforehand. - */ -void ide_cmd (ide_drive_t *drive, u8 cmd, u8 nsect, ide_handler_t *handler) -{ - ide_hwif_t *hwif = HWIF(drive); - if (HWGROUP(drive)->handler != NULL) - BUG(); - ide_set_handler(drive, handler, WAIT_CMD, NULL); - if (IDE_CONTROL_REG) - hwif->OUTB(drive->ctl,IDE_CONTROL_REG); /* clear nIEN */ - SELECT_MASK(drive,0); - hwif->OUTB(nsect,IDE_NSECTOR_REG); - hwif->OUTB(cmd,IDE_COMMAND_REG); -} - -EXPORT_SYMBOL(ide_cmd); - -/* - * drive_cmd_intr() is invoked on completion of a special DRIVE_CMD. - */ -ide_startstop_t drive_cmd_intr (ide_drive_t *drive) -{ - struct request *rq = HWGROUP(drive)->rq; - ide_hwif_t *hwif = HWIF(drive); - u8 *args = (u8 *) rq->buffer; - u8 stat = hwif->INB(IDE_STATUS_REG); - int retries = 10; - - local_irq_enable(); - if ((stat & DRQ_STAT) && args && args[3]) { - u8 io_32bit = drive->io_32bit; - drive->io_32bit = 0; - hwif->ata_input_data(drive, &args[4], args[3] * SECTOR_WORDS); - drive->io_32bit = io_32bit; - while (((stat = hwif->INB(IDE_STATUS_REG)) & BUSY_STAT) && retries--) - udelay(100); - } - - if (!OK_STAT(stat, READY_STAT, BAD_STAT)) - return DRIVER(drive)->error(drive, "drive_cmd", stat); - /* calls ide_end_drive_cmd */ - ide_end_drive_cmd(drive, stat, hwif->INB(IDE_ERROR_REG)); - return ide_stopped; -} - -EXPORT_SYMBOL(drive_cmd_intr); - -/* - * do_special() is used to issue WIN_SPECIFY, WIN_RESTORE, and WIN_SETMULT - * commands to a drive. It used to do much more, but has been scaled back. - */ -ide_startstop_t do_special (ide_drive_t *drive) -{ - special_t *s = &drive->special; - -#ifdef DEBUG - printk("%s: do_special: 0x%02x\n", drive->name, s->all); -#endif - if (s->b.set_tune) { - s->b.set_tune = 0; - if (HWIF(drive)->tuneproc != NULL) - HWIF(drive)->tuneproc(drive, drive->tune_req); - } else if (drive->driver != NULL) { - return DRIVER(drive)->special(drive); - } else if (s->all) { - printk("%s: bad special flag: 0x%02x\n", drive->name, s->all); - s->all = 0; - } - return ide_stopped; -} - -EXPORT_SYMBOL(do_special); - -/* - * execute_drive_cmd() issues a special drive command, - * usually initiated by ioctl() from the external hdparm program. - */ -ide_startstop_t execute_drive_cmd (ide_drive_t *drive, struct request *rq) -{ - ide_hwif_t *hwif = HWIF(drive); - if (rq->flags & REQ_DRIVE_TASKFILE) { - ide_task_t *args = rq->special; - - if (!args) - goto done; - - if (args->tf_out_flags.all != 0) - return flagged_taskfile(drive, args); - return do_rw_taskfile(drive, args); - } else if (rq->flags & REQ_DRIVE_TASK) { - u8 *args = rq->buffer; - u8 sel; - - if (!args) - goto done; -#ifdef DEBUG - printk("%s: DRIVE_TASK_CMD ", drive->name); - printk("cmd=0x%02x ", args[0]); - printk("fr=0x%02x ", args[1]); - printk("ns=0x%02x ", args[2]); - printk("sc=0x%02x ", args[3]); - printk("lcyl=0x%02x ", args[4]); - printk("hcyl=0x%02x ", args[5]); - printk("sel=0x%02x\n", args[6]); -#endif - hwif->OUTB(args[1], IDE_FEATURE_REG); - hwif->OUTB(args[3], IDE_SECTOR_REG); - hwif->OUTB(args[4], IDE_LCYL_REG); - hwif->OUTB(args[5], IDE_HCYL_REG); - sel = (args[6] & ~0x10); - if (drive->select.b.unit) - sel |= 0x10; - hwif->OUTB(sel, IDE_SELECT_REG); - ide_cmd(drive, args[0], args[2], &drive_cmd_intr); - return ide_started; - } else if (rq->flags & REQ_DRIVE_CMD) { - u8 *args = rq->buffer; - - if (!args) - goto done; -#ifdef DEBUG - printk("%s: DRIVE_CMD ", drive->name); - printk("cmd=0x%02x ", args[0]); - printk("sc=0x%02x ", args[1]); - printk("fr=0x%02x ", args[2]); - printk("xx=0x%02x\n", args[3]); -#endif - if (args[0] == WIN_SMART) { - hwif->OUTB(0x4f, IDE_LCYL_REG); - hwif->OUTB(0xc2, IDE_HCYL_REG); - hwif->OUTB(args[2],IDE_FEATURE_REG); - hwif->OUTB(args[1],IDE_SECTOR_REG); - ide_cmd(drive, args[0], args[3], &drive_cmd_intr); - return ide_started; - } - hwif->OUTB(args[2],IDE_FEATURE_REG); - ide_cmd(drive, args[0], args[1], &drive_cmd_intr); - return ide_started; - } - -done: - /* - * NULL is actually a valid way of waiting for - * all current requests to be flushed from the queue. - */ -#ifdef DEBUG - printk("%s: DRIVE_CMD (null)\n", drive->name); -#endif - ide_end_drive_cmd(drive, - hwif->INB(IDE_STATUS_REG), - hwif->INB(IDE_ERROR_REG)); - return ide_stopped; -} - -EXPORT_SYMBOL(execute_drive_cmd); - -/* - * start_request() initiates handling of a new I/O request - * needed to reverse the perverted changes anonymously made back - * 2.3.99-pre6 - */ -ide_startstop_t start_request (ide_drive_t *drive, struct request *rq) -{ - ide_startstop_t startstop; - unsigned long block; - - BUG_ON(!(rq->flags & REQ_STARTED)); - -#ifdef DEBUG - printk("%s: start_request: current=0x%08lx\n", - HWIF(drive)->name, (unsigned long) rq); -#endif - - /* bail early if we've exceeded max_failures */ - if (drive->max_failures && (drive->failures > drive->max_failures)) { - goto kill_rq; - } - - /* - * bail early if we've sent a device to sleep, however how to wake - * this needs to be a masked flag. FIXME for proper operations. - */ - if (drive->suspend_reset) - goto kill_rq; - - block = rq->sector; - if (blk_fs_request(rq) && - (drive->media == ide_disk || drive->media == ide_floppy)) { - block += drive->sect0; - } - /* Yecch - this will shift the entire interval, - possibly killing some innocent following sector */ - if (block == 0 && drive->remap_0_to_1 == 1) - block = 1; /* redirect MBR access to EZ-Drive partn table */ - -#if (DISK_RECOVERY_TIME > 0) - while ((read_timer() - HWIF(drive)->last_time) < DISK_RECOVERY_TIME); -#endif - - SELECT_DRIVE(drive); - if (ide_wait_stat(&startstop, drive, drive->ready_stat, BUSY_STAT|DRQ_STAT, WAIT_READY)) { - printk("%s: drive not ready for command\n", drive->name); - return startstop; - } - if (!drive->special.all) { - if (rq->flags & (REQ_DRIVE_CMD | REQ_DRIVE_TASK)) - return execute_drive_cmd(drive, rq); - else if (rq->flags & REQ_DRIVE_TASKFILE) - return execute_drive_cmd(drive, rq); - - if (drive->driver != NULL) { - return (DRIVER(drive)->do_request(drive, rq, block)); - } - printk("%s: media type %d not supported\n", drive->name, drive->media); - goto kill_rq; - } - return do_special(drive); -kill_rq: - if (drive->driver != NULL) - DRIVER(drive)->end_request(drive, 0, 0); - else - ide_end_request(drive, 0, 0); - return ide_stopped; -} - -EXPORT_SYMBOL(start_request); - -int restart_request (ide_drive_t *drive, struct request *rq) -{ - (void) start_request(drive, rq); - return 0; -} - -EXPORT_SYMBOL(restart_request); - -/* - * ide_stall_queue() can be used by a drive to give excess bandwidth back - * to the hwgroup by sleeping for timeout jiffies. - */ -void ide_stall_queue (ide_drive_t *drive, unsigned long timeout) -{ - if (timeout > WAIT_WORSTCASE) - timeout = WAIT_WORSTCASE; - drive->sleep = timeout + jiffies; -} - -EXPORT_SYMBOL(ide_stall_queue); - -#define WAKEUP(drive) ((drive)->service_start + 2 * (drive)->service_time) - -/* - * choose_drive() selects the next drive which will be serviced. - */ -static inline ide_drive_t *choose_drive (ide_hwgroup_t *hwgroup) -{ - ide_drive_t *drive, *best; - -repeat: - best = NULL; - drive = hwgroup->drive; - do { - if (!blk_queue_empty(&drive->queue) && (!drive->sleep || time_after_eq(jiffies, drive->sleep))) { - if (!best - || (drive->sleep && (!best->sleep || 0 < (signed long)(best->sleep - drive->sleep))) - || (!best->sleep && 0 < (signed long)(WAKEUP(best) - WAKEUP(drive)))) - { - if (!blk_queue_plugged(&drive->queue)) - best = drive; - } - } - } while ((drive = drive->next) != hwgroup->drive); - if (best && best->nice1 && !best->sleep && best != hwgroup->drive && best->service_time > WAIT_MIN_SLEEP) { - long t = (signed long)(WAKEUP(best) - jiffies); - if (t >= WAIT_MIN_SLEEP) { - /* - * We *may* have some time to spare, but first let's see if - * someone can potentially benefit from our nice mood today.. - */ - drive = best->next; - do { - if (!drive->sleep - && 0 < (signed long)(WAKEUP(drive) - (jiffies - best->service_time)) - && 0 < (signed long)((jiffies + t) - WAKEUP(drive))) - { - ide_stall_queue(best, IDE_MIN(t, 10 * WAIT_MIN_SLEEP)); - goto repeat; - } - } while ((drive = drive->next) != best); - } - } - return best; -} - -/* - * Issue a new request to a drive from hwgroup - * Caller must have already done spin_lock_irqsave(&ide_lock, ..); - * - * A hwgroup is a serialized group of IDE interfaces. Usually there is - * exactly one hwif (interface) per hwgroup, but buggy controllers (eg. CMD640) - * may have both interfaces in a single hwgroup to "serialize" access. - * Or possibly multiple ISA interfaces can share a common IRQ by being grouped - * together into one hwgroup for serialized access. - * - * Note also that several hwgroups can end up sharing a single IRQ, - * possibly along with many other devices. This is especially common in - * PCI-based systems with off-board IDE controller cards. - * - * The IDE driver uses the single global ide_lock spinlock to protect - * access to the request queues, and to protect the hwgroup->busy flag. - * - * The first thread into the driver for a particular hwgroup sets the - * hwgroup->busy flag to indicate that this hwgroup is now active, - * and then initiates processing of the top request from the request queue. - * - * Other threads attempting entry notice the busy setting, and will simply - * queue their new requests and exit immediately. Note that hwgroup->busy - * remains set even when the driver is merely awaiting the next interrupt. - * Thus, the meaning is "this hwgroup is busy processing a request". - * - * When processing of a request completes, the completing thread or IRQ-handler - * will start the next request from the queue. If no more work remains, - * the driver will clear the hwgroup->busy flag and exit. - * - * The ide_lock (spinlock) is used to protect all access to the - * hwgroup->busy flag, but is otherwise not needed for most processing in - * the driver. This makes the driver much more friendlier to shared IRQs - * than previous designs, while remaining 100% (?) SMP safe and capable. - */ -/* --BenH: made non-static as ide-pmac.c uses it to kick the hwgroup back - * into life on wakeup from machine sleep. - */ -void ide_do_request (ide_hwgroup_t *hwgroup, int masked_irq) -{ - ide_drive_t *drive; - ide_hwif_t *hwif; - struct request *rq; - ide_startstop_t startstop; - - /* for atari only: POSSIBLY BROKEN HERE(?) */ - ide_get_lock(&ide_intr_lock, ide_intr, hwgroup); - - /* necessary paranoia: ensure IRQs are masked on local CPU */ - local_irq_disable(); - - while (!hwgroup->busy) { - hwgroup->busy = 1; - drive = choose_drive(hwgroup); - if (drive == NULL) { - unsigned long sleep = 0; - hwgroup->rq = NULL; - drive = hwgroup->drive; - do { - if (drive->sleep && (!sleep || 0 < (signed long)(sleep - drive->sleep))) - sleep = drive->sleep; - } while ((drive = drive->next) != hwgroup->drive); - if (sleep) { - /* - * Take a short snooze, and then wake up this hwgroup again. - * This gives other hwgroups on the same a chance to - * play fairly with us, just in case there are big differences - * in relative throughputs.. don't want to hog the cpu too much. - */ - if (time_before(sleep, jiffies + WAIT_MIN_SLEEP)) - sleep = jiffies + WAIT_MIN_SLEEP; -#if 1 - if (timer_pending(&hwgroup->timer)) - printk("ide_set_handler: timer already active\n"); -#endif - /* so that ide_timer_expiry knows what to do */ - hwgroup->sleeping = 1; - mod_timer(&hwgroup->timer, sleep); - /* we purposely leave hwgroup->busy==1 - * while sleeping */ - } else { - /* Ugly, but how can we sleep for the lock - * otherwise? perhaps from tq_disk? - */ - - /* for atari only */ - ide_release_lock(&ide_intr_lock); - hwgroup->busy = 0; - } - - /* no more work for this hwgroup (for now) */ - return; - } - hwif = HWIF(drive); - if (hwgroup->hwif->sharing_irq && - hwif != hwgroup->hwif && - hwif->io_ports[IDE_CONTROL_OFFSET]) { - /* set nIEN for previous hwif */ - SELECT_INTERRUPT(drive); - } - hwgroup->hwif = hwif; - hwgroup->drive = drive; - drive->sleep = 0; - drive->service_start = jiffies; - -queue_next: - if (!ata_can_queue(drive)) { - if (!ata_pending_commands(drive)) - hwgroup->busy = 0; - - break; - } - - if (blk_queue_plugged(&drive->queue)) { - if (drive->using_tcq) - break; - - printk("ide: huh? queue was plugged!\n"); - break; - } - - /* - * we know that the queue isn't empty, but this can happen - * if the q->prep_rq_fn() decides to kill a request - */ - rq = elv_next_request(&drive->queue); - if (!rq) { - hwgroup->busy = !!ata_pending_commands(drive); - break; - } - - if (!rq->bio && ata_pending_commands(drive)) - break; - - hwgroup->rq = rq; - - /* - * Some systems have trouble with IDE IRQs arriving while - * the driver is still setting things up. So, here we disable - * the IRQ used by this interface while the request is being started. - * This may look bad at first, but pretty much the same thing - * happens anyway when any interrupt comes in, IDE or otherwise - * -- the kernel masks the IRQ while it is being handled. - */ - if (masked_irq && hwif->irq != masked_irq) - disable_irq_nosync(hwif->irq); - spin_unlock(&ide_lock); - local_irq_enable(); - /* allow other IRQs while we start this request */ - startstop = start_request(drive, rq); - spin_lock_irq(&ide_lock); - if (masked_irq && hwif->irq != masked_irq) - enable_irq(hwif->irq); - if (startstop == ide_released) - goto queue_next; - if (startstop == ide_stopped) - hwgroup->busy = 0; - } -} - -EXPORT_SYMBOL(ide_do_request); - -/* - * Passes the stuff to ide_do_request - */ -void do_ide_request(request_queue_t *q) -{ - ide_do_request(q->queuedata, 0); -} - -/* - * un-busy the hwgroup etc, and clear any pending DMA status. we want to - * retry the current request in pio mode instead of risking tossing it - * all away - */ -void ide_dma_timeout_retry(ide_drive_t *drive) -{ - ide_hwif_t *hwif = HWIF(drive); - struct request *rq; - - /* - * end current dma transaction - */ - (void) hwif->ide_dma_end(drive); - - /* - * complain a little, later we might remove some of this verbosity - */ - printk("%s: timeout waiting for DMA\n", drive->name); - (void) hwif->ide_dma_timeout(drive); - - /* - * disable dma for now, but remember that we did so because of - * a timeout -- we'll reenable after we finish this next request - * (or rather the first chunk of it) in pio. - */ - drive->retry_pio++; - drive->state = DMA_PIO_RETRY; - (void) hwif->ide_dma_off_quietly(drive); - - /* - * un-busy drive etc (hwgroup->busy is cleared on return) and - * make sure request is sane - */ - rq = HWGROUP(drive)->rq; - HWGROUP(drive)->rq = NULL; - - rq->errors = 0; - rq->sector = rq->bio->bi_sector; - rq->current_nr_sectors = bio_iovec(rq->bio)->bv_len >> 9; - rq->hard_cur_sectors = rq->current_nr_sectors; - if (rq->bio) - rq->buffer = NULL; -} - -EXPORT_SYMBOL(ide_dma_timeout_retry); - -/* - * ide_timer_expiry() is our timeout function for all drive operations. - * But note that it can also be invoked as a result of a "sleep" operation - * triggered by the mod_timer() call in ide_do_request. - */ -void ide_timer_expiry (unsigned long data) -{ - ide_hwgroup_t *hwgroup = (ide_hwgroup_t *) data; - ide_handler_t *handler; - ide_expiry_t *expiry; - unsigned long flags; - unsigned long wait; - - spin_lock_irqsave(&ide_lock, flags); - del_timer(&hwgroup->timer); - - if ((handler = hwgroup->handler) == NULL) { - /* - * Either a marginal timeout occurred - * (got the interrupt just as timer expired), - * or we were "sleeping" to give other devices a chance. - * Either way, we don't really want to complain about anything. - */ - if (hwgroup->sleeping) { - hwgroup->sleeping = 0; - hwgroup->busy = 0; - } - } else { - ide_drive_t *drive = hwgroup->drive; - if (!drive) { - printk("ide_timer_expiry: hwgroup->drive was NULL\n"); - hwgroup->handler = NULL; - } else { - ide_hwif_t *hwif; - ide_startstop_t startstop = ide_stopped; - if (!hwgroup->busy) { - hwgroup->busy = 1; /* paranoia */ - printk("%s: ide_timer_expiry: hwgroup->busy was 0 ??\n", drive->name); - } - if ((expiry = hwgroup->expiry) != NULL) { - /* continue */ - if ((wait = expiry(drive)) != 0) { - /* reset timer */ - hwgroup->timer.expires = jiffies + wait; - add_timer(&hwgroup->timer); - spin_unlock_irqrestore(&ide_lock, flags); - return; - } - } - hwgroup->handler = NULL; - /* - * We need to simulate a real interrupt when invoking - * the handler() function, which means we need to - * globally mask the specific IRQ: - */ - spin_unlock(&ide_lock); - hwif = HWIF(drive); -#if DISABLE_IRQ_NOSYNC - disable_irq_nosync(hwif->irq); -#else - /* disable_irq_nosync ?? */ - disable_irq(hwif->irq); -#endif /* DISABLE_IRQ_NOSYNC */ - /* local CPU only, - * as if we were handling an interrupt */ - local_irq_disable(); - if (hwgroup->poll_timeout != 0) { - startstop = handler(drive); - } else if (drive_is_ready(drive)) { - if (drive->waiting_for_dma) - (void) hwgroup->hwif->ide_dma_lostirq(drive); - (void)ide_ack_intr(hwif); - printk("%s: lost interrupt\n", drive->name); - startstop = handler(drive); - } else { - if (drive->waiting_for_dma) { - startstop = ide_stopped; - ide_dma_timeout_retry(drive); - } else - startstop = DRIVER(drive)->error(drive, "irq timeout", hwif->INB(IDE_STATUS_REG)); - } - set_recovery_timer(hwif); - drive->service_time = jiffies - drive->service_start; - enable_irq(hwif->irq); - spin_lock_irq(&ide_lock); - if (startstop == ide_stopped) - hwgroup->busy = 0; - } - } - ide_do_request(hwgroup, 0); - spin_unlock_irqrestore(&ide_lock, flags); -} - -EXPORT_SYMBOL(ide_timer_expiry); - -/* - * There's nothing really useful we can do with an unexpected interrupt, - * other than reading the status register (to clear it), and logging it. - * There should be no way that an irq can happen before we're ready for it, - * so we needn't worry much about losing an "important" interrupt here. - * - * On laptops (and "green" PCs), an unexpected interrupt occurs whenever the - * drive enters "idle", "standby", or "sleep" mode, so if the status looks - * "good", we just ignore the interrupt completely. - * - * This routine assumes __cli() is in effect when called. - * - * If an unexpected interrupt happens on irq15 while we are handling irq14 - * and if the two interfaces are "serialized" (CMD640), then it looks like - * we could screw up by interfering with a new request being set up for irq15. - * - * In reality, this is a non-issue. The new command is not sent unless the - * drive is ready to accept one, in which case we know the drive is not - * trying to interrupt us. And ide_set_handler() is always invoked before - * completing the issuance of any new drive command, so we will not be - * accidentally invoked as a result of any valid command completion interrupt. - * - */ -static void unexpected_intr (int irq, ide_hwgroup_t *hwgroup) -{ - u8 stat; - ide_hwif_t *hwif = hwgroup->hwif; - - /* - * handle the unexpected interrupt - */ - do { - if (hwif->irq == irq) { - stat = hwif->INB(hwif->io_ports[IDE_STATUS_OFFSET]); - if (!OK_STAT(stat, READY_STAT, BAD_STAT)) { - /* Try to not flood the console with msgs */ - static unsigned long last_msgtime, count; - ++count; - if (time_after(jiffies, last_msgtime + HZ)) { - last_msgtime = jiffies; - printk("%s%s: unexpected interrupt, " - "status=0x%02x, count=%ld\n", - hwif->name, - (hwif->next==hwgroup->hwif) ? "" : "(?)", stat, count); - } - } - } - } while ((hwif = hwif->next) != hwgroup->hwif); -} - -/* - * entry point for all interrupts, caller does __cli() for us - */ -void ide_intr (int irq, void *dev_id, struct pt_regs *regs) -{ - unsigned long flags; - ide_hwgroup_t *hwgroup = (ide_hwgroup_t *)dev_id; - ide_hwif_t *hwif; - ide_drive_t *drive; - ide_handler_t *handler; - ide_startstop_t startstop; - - spin_lock_irqsave(&ide_lock, flags); - hwif = hwgroup->hwif; - - if (!ide_ack_intr(hwif)) { - spin_unlock_irqrestore(&ide_lock, flags); - return; - } - - if ((handler = hwgroup->handler) == NULL || - hwgroup->poll_timeout != 0) { - /* - * Not expecting an interrupt from this drive. - * That means this could be: - * (1) an interrupt from another PCI device - * sharing the same PCI INT# as us. - * or (2) a drive just entered sleep or standby mode, - * and is interrupting to let us know. - * or (3) a spurious interrupt of unknown origin. - * - * For PCI, we cannot tell the difference, - * so in that case we just ignore it and hope it goes away. - */ -#ifdef CONFIG_BLK_DEV_IDEPCI - if (hwif->pci_dev && !hwif->pci_dev->vendor) -#endif /* CONFIG_BLK_DEV_IDEPCI */ - { - /* - * Probably not a shared PCI interrupt, - * so we can safely try to do something about it: - */ - unexpected_intr(irq, hwgroup); -#ifdef CONFIG_BLK_DEV_IDEPCI - } else { - /* - * Whack the status register, just in case - * we have a leftover pending IRQ. - */ - (void) hwif->INB(hwif->io_ports[IDE_STATUS_OFFSET]); -#endif /* CONFIG_BLK_DEV_IDEPCI */ - } - spin_unlock_irqrestore(&ide_lock, flags); - return; - } - drive = hwgroup->drive; - if (!drive) { - /* - * This should NEVER happen, and there isn't much - * we could do about it here. - */ - spin_unlock_irqrestore(&ide_lock, flags); - return; - } - if (!drive_is_ready(drive)) { - /* - * This happens regularly when we share a PCI IRQ with - * another device. Unfortunately, it can also happen - * with some buggy drives that trigger the IRQ before - * their status register is up to date. Hopefully we have - * enough advance overhead that the latter isn't a problem. - */ - spin_unlock_irqrestore(&ide_lock, flags); - return; - } - if (!hwgroup->busy) { - hwgroup->busy = 1; /* paranoia */ - printk("%s: ide_intr: hwgroup->busy was 0 ??\n", drive->name); - } - hwgroup->handler = NULL; - del_timer(&hwgroup->timer); - spin_unlock(&ide_lock); - - if (drive->unmask) - local_irq_enable(); - /* service this interrupt, may set handler for next interrupt */ - startstop = handler(drive); - spin_lock_irq(&ide_lock); - - /* - * Note that handler() may have set things up for another - * interrupt to occur soon, but it cannot happen until - * we exit from this routine, because it will be the - * same irq as is currently being serviced here, and Linux - * won't allow another of the same (on any CPU) until we return. - */ - set_recovery_timer(HWIF(drive)); - drive->service_time = jiffies - drive->service_start; - if (startstop == ide_stopped) { - if (hwgroup->handler == NULL) { /* paranoia */ - hwgroup->busy = 0; - ide_do_request(hwgroup, hwif->irq); - } else { - printk("%s: ide_intr: huh? expected NULL handler " - "on exit\n", drive->name); - } - } - spin_unlock_irqrestore(&ide_lock, flags); -} - -EXPORT_SYMBOL(ide_intr); - -/* - * This function is intended to be used prior to invoking ide_do_drive_cmd(). - */ -void ide_init_drive_cmd (struct request *rq) -{ - memset(rq, 0, sizeof(*rq)); - rq->flags = REQ_DRIVE_CMD; -} - -EXPORT_SYMBOL(ide_init_drive_cmd); - -/* - * This function issues a special IDE device request - * onto the request queue. - * - * If action is ide_wait, then the rq is queued at the end of the - * request queue, and the function sleeps until it has been processed. - * This is for use when invoked from an ioctl handler. - * - * If action is ide_preempt, then the rq is queued at the head of - * the request queue, displacing the currently-being-processed - * request and this function returns immediately without waiting - * for the new rq to be completed. This is VERY DANGEROUS, and is - * intended for careful use by the ATAPI tape/cdrom driver code. - * - * If action is ide_next, then the rq is queued immediately after - * the currently-being-processed-request (if any), and the function - * returns without waiting for the new rq to be completed. As above, - * This is VERY DANGEROUS, and is intended for careful use by the - * ATAPI tape/cdrom driver code. - * - * If action is ide_end, then the rq is queued at the end of the - * request queue, and the function returns immediately without waiting - * for the new rq to be completed. This is again intended for careful - * use by the ATAPI tape/cdrom driver code. - */ -int ide_do_drive_cmd (ide_drive_t *drive, struct request *rq, ide_action_t action) -{ - unsigned long flags; - ide_hwgroup_t *hwgroup = HWGROUP(drive); - DECLARE_COMPLETION(wait); - int insert_end = 1, err; - -#ifdef CONFIG_BLK_DEV_PDC4030 - if (HWIF(drive)->chipset == ide_pdc4030 && rq->buffer != NULL) - return -ENOSYS; /* special drive cmds not supported */ -#endif - rq->errors = 0; - rq->rq_status = RQ_ACTIVE; - - rq->rq_disk = drive->disk; - - /* - * we need to hold an extra reference to request for safe inspection - * after completion - */ - if (action == ide_wait) { - rq->ref_count++; - rq->waiting = &wait; - } - - spin_lock_irqsave(&ide_lock, flags); - if (action == ide_preempt) { - hwgroup->rq = NULL; - insert_end = 0; - } - __elv_add_request(&drive->queue, rq, insert_end, 0); - ide_do_request(hwgroup, 0); - spin_unlock_irqrestore(&ide_lock, flags); - - err = 0; - if (action == ide_wait) { - wait_for_completion(&wait); - if (rq->errors) - err = -EIO; - - blk_put_request(rq); - } - - return err; -} - -EXPORT_SYMBOL(ide_do_drive_cmd); void ide_probe_module (void) { @@ -1632,11 +524,18 @@ #define hwif_release_region(addr, num) \ ((hwif->mmio) ? release_mem_region((addr),(num)) : release_region((addr),(num))) -/* - * Note that we only release the standard ports, - * and do not even try to handle any extra ports - * allocated for weird IDE interface chipsets. +/** + * hwif_unregister - free IDE resources + * + * Note that we only release the standard ports, + * and do not even try to handle any extra ports + * allocated for weird IDE interface chipsets. + * + * Note also that we don't yet handle mmio resources here. More + * importantly our caller should be doing this so we need to + * restructure this as a helper function for drivers. */ + void hwif_unregister (ide_hwif_t *hwif) { u32 i = 0; @@ -1665,6 +564,28 @@ extern void init_hwif_data(unsigned int index); +/** + * ide_unregister - free an ide interface + * @index: index of interface (will change soon to a pointer) + * + * Perform the final unregister of an IDE interface. At the moment + * we don't refcount interfaces so this will also get split up. + * + * Locking: + * The caller must not hold the IDE locks + * The drive present/vanishing is not yet properly locked + * Take care with the callbacks. These have been split to avoid + * deadlocking the IDE layer. The shutdown callback is called + * before we take the lock and free resources. It is up to the + * caller to be sure there is no pending I/O here, and that + * the interfce will not be reopened (present/vanishing locking + * isnt yet done btw). After we commit to the final kill we + * call the cleanup callback with the ide locks held. + * + * Unregister restores the hwif structures to the default state. + * This is raving bonkers. + */ + void ide_unregister (unsigned int index) { ide_drive_t *drive, *d; @@ -1675,7 +596,8 @@ ide_hwif_t old_hwif; if (index >= MAX_HWIFS) - return; + BUG(); + spin_lock_irqsave(&ide_lock, flags); hwif = &ide_hwifs[index]; if (!hwif->present) @@ -1686,12 +608,21 @@ continue; if (drive->usage) goto abort; - if (drive->driver != NULL && DRIVER(drive)->cleanup(drive)) + if (drive->driver != NULL && DRIVER(drive)->shutdown(drive)) goto abort; } hwif->present = 0; spin_unlock_irqrestore(&ide_lock, flags); + + for (unit = 0; unit < MAX_DRIVES; ++unit) { + drive = &hwif->drives[unit]; + if (!drive->present) + continue; + if (drive->driver != NULL) + DRIVER(drive)->cleanup(drive); + } + #ifdef CONFIG_PROC_FS destroy_proc_ide_drives(hwif); #endif @@ -1752,7 +683,7 @@ else hwgroup->hwif = HWIF(hwgroup->drive); -#if defined(CONFIG_BLK_DEV_IDEDMA) && !defined(CONFIG_DMA_NONPCI) +#if !defined(CONFIG_DMA_NONPCI) if (hwif->dma_base) { (void) ide_release_dma(hwif); @@ -1764,7 +695,7 @@ hwif->dma_vendor3 = 0; hwif->dma_prdtable = 0; } -#endif /* (CONFIG_BLK_DEV_IDEDMA) && !(CONFIG_DMA_NONPCI) */ +#endif /* !(CONFIG_DMA_NONPCI) */ /* * Remove us from the kernel's knowledge @@ -1894,11 +825,21 @@ EXPORT_SYMBOL(ide_unregister); -/* - * Setup hw_regs_t structure described by parameters. You - * may set up the hw structure yourself OR use this routine to - * do it for you. +/** + * ide_setup_ports - set up IDE interface ports + * @hw: register descriptions + * @base: base register + * @offsets: table of register offsets + * @ctrl: control register + * @ack_irq: IRQ ack + * @irq: interrupt lie + * + * Setup hw_regs_t structure described by parameters. You + * may set up the hw structure yourself OR use this routine to + * do it for you. This is basically a helper + * */ + void ide_setup_ports ( hw_regs_t *hw, ide_ioreg_t base, int *offsets, ide_ioreg_t ctrl, ide_ioreg_t intr, @@ -2004,6 +945,27 @@ EXPORT_SYMBOL(ide_register); +/** + * ide_add_setting - attach an IDE setting + * drive: drive the setting is for + * name: name of setting + * rw: set if writable + * read_ioctl: read function + * write_ioctl: write function + * data_type: form expected + * min: minimum + * max: maximum + * mul_factor: multiply by + * div_factor: divide by + * data: value + * set: handling for setting + * + * Add a setting to the IDE drive. Support automatic removal and allow + * all the work to be done by plugged in handlers. This code is also + * rather short on locking, but the current plan is to do the locking + * internally to the function. + */ + void ide_add_setting (ide_drive_t *drive, const char *name, int rw, int read_ioctl, int write_ioctl, int data_type, int min, int max, int mul_factor, int div_factor, void *data, ide_procset_t *set) { ide_settings_t **p = (ide_settings_t **) &drive->settings, *setting = NULL; @@ -2038,6 +1000,14 @@ EXPORT_SYMBOL(ide_add_setting); +/** + * ide_remove_setting - remove an ioctl setting + * @name: name of the property + * + * Remove a drive ioctl setting that was created by ide_add_setting. + * Again this needs the locking fixed + */ + void ide_remove_setting (ide_drive_t *drive, char *name) { ide_settings_t **p = (ide_settings_t **) &drive->settings, *setting; @@ -2053,6 +1023,16 @@ EXPORT_SYMBOL(ide_remove_setting); +/** + * ide_find_setting_by_ioctl - find a setting handler by its command + * @drive: drive to act for + * @cmd: ioctl command code + * + * Scan the drive handlers for an ioctl handler for this function. + * The handlers vary by drive and sometimes by drive state. + * Needs locking fixes. + */ + static ide_settings_t *ide_find_setting_by_ioctl (ide_drive_t *drive, int cmd) { ide_settings_t *setting = drive->settings; @@ -2065,6 +1045,16 @@ return setting; } +/** + * ide_find_setting_by_name - find a setting handler by its name + * @drive: drive to act for + * @cmd: ioctl command code + * + * Scan the drive handlers handler matching the name for this function. + * The handlers vary by drive and sometimes by drive state. + * Needs locking fixes. + */ + ide_settings_t *ide_find_setting_by_name (ide_drive_t *drive, char *name) { ide_settings_t *setting = drive->settings; @@ -2077,6 +1067,17 @@ return setting; } +/** + * auto_remove_settings - remove driver settings on a device + * @drive: drive to clean + * + * Called when we change the driver bindings for a device, for + * example if the device is hot plugged. We must scrub the driver + * bindings that are thus no longer relevant to the device in case + * it changes from say a CD-ROM to a disk + * Needs locking fixes + */ + static void auto_remove_settings (ide_drive_t *drive) { ide_settings_t *setting; @@ -2128,7 +1129,7 @@ local_irq_set(lflags); if (time_after(jiffies, timeout)) { local_irq_restore(lflags); - printk("%s: channel busy\n", drive->name); + printk(KERN_ERR "%s: channel busy\n", drive->name); return -EBUSY; } local_irq_restore(lflags); @@ -2229,8 +1230,7 @@ SETFEATURES_XFER, 0, NULL); if (!err && arg) { - if ((HWIF(drive)->speedproc) != NULL) - HWIF(drive)->speedproc(drive, (u8) arg); + ide_set_xfer_rate(drive, (u8) arg); ide_driveid_update(drive); } return err; @@ -2312,7 +1312,7 @@ */ int ide_replace_subdriver (ide_drive_t *drive, const char *driver) { - if (!drive->present || drive->usage) + if (!drive->present || drive->usage || drive->dead) goto abort; if (drive->driver != NULL && DRIVER(drive)->cleanup(drive)) goto abort; @@ -2487,7 +1487,7 @@ #if 1 spin_lock_irqsave(&ide_lock, flags); if ( HWGROUP(drive)->handler != NULL) { - printk("%s: ide_set_handler: handler not null; %p\n", drive->name, HWGROUP(drive)->handler); + printk(KERN_ERR "%s: ide_set_handler: handler not null; %p\n", drive->name, HWGROUP(drive)->handler); (void) HWGROUP(drive)->handler(drive); // HWGROUP(drive)->handler = NULL; HWGROUP(drive)->expiry = NULL; @@ -2702,7 +1702,7 @@ strncmp(s,"hd",2)) /* hdx= & hdxlun= */ return 0; - printk("ide_setup: %s", s); + printk(KERN_INFO "ide_setup: %s", s); init_ide_data (); #ifdef CONFIG_BLK_DEV_IDEDOUBLER @@ -3122,21 +2122,39 @@ #endif } -static int default_standby (ide_drive_t *drive) -{ - return 0; -} - -static int default_suspend (ide_drive_t *drive) +/* + * Actually unregister the subdriver. Called with the + * request lock dropped. + */ + +static int default_cleanup (ide_drive_t *drive) { - return 0; + return ide_unregister_subdriver(drive); } -static int default_resume (ide_drive_t *drive) +/* + * Check if we can unregister the subdriver. Called with the + * request lock held. + */ + +static int default_shutdown(ide_drive_t *drive) { + if (drive->usage || drive->driver == NULL || DRIVER(drive)->busy) { + return 1; + } + drive->dead = 1; return 0; } +/* + * Default function to use for the cache flush operation. This + * must be replaced for disk devices (see ATA specification + * documents on cache flush and drive suspend rules) + * + * If we have no device attached or the device is not writable + * this handler is sufficient. + */ + static int default_flushcache (ide_drive_t *drive) { return 0; @@ -3193,9 +2211,8 @@ { ide_driver_t *d = drive->driver; - if (d->standby == NULL) d->standby = default_standby; - if (d->suspend == NULL) d->suspend = default_suspend; - if (d->resume == NULL) d->resume = default_resume; + if (d->cleanup == NULL) d->cleanup = default_cleanup; + if (d->shutdown == NULL) d->shutdown = default_shutdown; if (d->flushcache == NULL) d->flushcache = default_flushcache; if (d->do_request == NULL) d->do_request = default_do_request; if (d->end_request == NULL) d->end_request = default_end_request; @@ -3213,7 +2230,7 @@ spin_lock_irqsave(&ide_lock, flags); if (version != IDE_SUBDRIVER_VERSION || !drive->present || - drive->driver != NULL || drive->usage) { + drive->driver != NULL || drive->usage || drive->dead) { spin_unlock_irqrestore(&ide_lock, flags); return 1; } @@ -3274,13 +2291,8 @@ ide_drive_t * drive = container_of(dev,ide_drive_t,gendev); ide_driver_t * driver = drive->driver; - if (driver) { - if (driver->standby) - driver->standby(drive); - if (driver->cleanup) - driver->cleanup(drive); - } - + if (driver && driver->cleanup) + driver->cleanup(drive); return 0; } @@ -3321,7 +2333,7 @@ while(!list_empty(&driver->drives)) { drive = list_entry(driver->drives.next, ide_drive_t, list); if (driver->cleanup(drive)) { - printk("%s: cleanup_module() called while still busy\n", drive->name); + printk(KERN_ERR "%s: cleanup_module() called while still busy\n", drive->name); BUG(); } /* We must remove proc entries defined in this module. @@ -3395,7 +2407,7 @@ if ((next = strchr(line,' ')) != NULL) *next++ = 0; if (!ide_setup(line)) - printk ("Unknown option '%s'\n", line); + printk (KERN_INFO "Unknown option '%s'\n", line); } } @@ -3411,10 +2423,10 @@ for (index = 0; index < MAX_HWIFS; ++index) { ide_unregister(index); -#if defined(CONFIG_BLK_DEV_IDEDMA) && !defined(CONFIG_DMA_NONPCI) +#if !defined(CONFIG_DMA_NONPCI) if (ide_hwifs[index].dma_base) (void) ide_release_dma(&ide_hwifs[index]); -#endif /* (CONFIG_BLK_DEV_IDEDMA) && !(CONFIG_DMA_NONPCI) */ +#endif /* !(CONFIG_DMA_NONPCI) */ } #ifdef CONFIG_PROC_FS diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/drivers/ide/ide-cd.c linux.2.5.47-ac6/drivers/ide/ide-cd.c --- linux.2.5.47/drivers/ide/ide-cd.c 2002-11-11 16:39:09.000000000 +0000 +++ linux.2.5.47-ac6/drivers/ide/ide-cd.c 2002-11-13 15:05:26.000000000 +0000 @@ -2965,10 +2965,8 @@ printk(", %dkB Cache", be16_to_cpu(cap.buffer_size)); -#ifdef CONFIG_BLK_DEV_IDEDMA if (drive->using_dma) (void) HWIF(drive)->ide_dma_verbose(drive); -#endif /* CONFIG_BLK_DEV_IDEDMA */ printk("\n"); return nslots; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/drivers/ide/ide-disk.c linux.2.5.47-ac6/drivers/ide/ide-disk.c --- linux.2.5.47/drivers/ide/ide-disk.c 2002-11-11 16:39:10.000000000 +0000 +++ linux.2.5.47-ac6/drivers/ide/ide-disk.c 2002-11-13 22:49:14.000000000 +0000 @@ -1412,24 +1412,6 @@ return call_idedisk_standby(drive, 0); } -static int call_idedisk_suspend (ide_drive_t *drive, int arg) -{ - ide_task_t args; - u8 suspend = (arg) ? WIN_SLEEPNOW2 : WIN_SLEEPNOW1; - memset(&args, 0, sizeof(ide_task_t)); - args.tfRegister[IDE_COMMAND_OFFSET] = suspend; - args.command_type = ide_cmd_type_parser(&args); - return ide_raw_taskfile(drive, &args, NULL); -} - -static int do_idedisk_suspend (ide_drive_t *drive) -{ - if (drive->suspend_reset) - return 1; - - return call_idedisk_suspend(drive, 0); -} - #if 0 static int call_idedisk_checkpower (ide_drive_t *drive, int arg) { @@ -1456,13 +1438,6 @@ } #endif -static int do_idedisk_resume (ide_drive_t *drive) -{ - if (!drive->suspend_reset) - return 1; - return 0; -} - static int do_idedisk_flushcache (ide_drive_t *drive) { ide_task_t args; @@ -1561,6 +1536,39 @@ #endif } +static int idedisk_suspend(struct device *dev, u32 state, u32 level) +{ + ide_drive_t *drive = dev->driver_data; + + printk("Suspending device %p\n", dev->driver_data); + + /* I hope that every freeze operation from the upper levels have + * already been done... + */ + + if (level != SUSPEND_SAVE_STATE) + return 0; + + /* set the drive to standby */ + printk(KERN_INFO "suspending: %s ", drive->name); + do_idedisk_standby(drive); + drive->blocked = 1; + + BUG_ON (HWGROUP(drive)->handler); + return 0; +} + +static int idedisk_resume(struct device *dev, u32 level) +{ + ide_drive_t *drive = dev->driver_data; + + if (level != RESUME_RESTORE_STATE) + return 0; + BUG_ON(!drive->blocked); + drive->blocked = 0; + return 0; +} + static void idedisk_setup (ide_drive_t *drive) { struct hd_driveid *id = drive->id; @@ -1641,10 +1649,8 @@ printk(", CHS=%d/%d/%d", drive->bios_cyl, drive->bios_head, drive->bios_sect); -#ifdef CONFIG_BLK_DEV_IDEDMA if (drive->using_dma) (void) HWIF(drive)->ide_dma_verbose(drive); -#endif /* CONFIG_BLK_DEV_IDEDMA */ printk("\n"); drive->mult_count = 0; @@ -1671,6 +1677,7 @@ { struct gendisk *g = drive->disk; + do_idedisk_standby(drive); if ((drive->id->cfs_enable_2 & 0x3000) && drive->wcache) if (do_idedisk_flushcache(drive)) printk (KERN_INFO "%s: Write Cache FAILED Flushing!\n", @@ -1696,9 +1703,6 @@ .supports_dma = 1, .supports_dsc_overlap = 0, .cleanup = idedisk_cleanup, - .standby = do_idedisk_standby, - .suspend = do_idedisk_suspend, - .resume = do_idedisk_resume, .flushcache = do_idedisk_flushcache, .do_request = do_rw_disk, .sense = idedisk_dump_status, @@ -1709,6 +1713,10 @@ .proc = idedisk_proc, .attach = idedisk_attach, .drives = LIST_HEAD_INIT(idedisk_driver.drives), + .gen_driver = { + .suspend = idedisk_suspend, + .resume = idedisk_resume, + } }; static int idedisk_open(struct inode *inode, struct file *filp) @@ -1835,8 +1843,7 @@ static int idedisk_init (void) { - ide_register_driver(&idedisk_driver); - return 0; + return ide_register_driver(&idedisk_driver); } module_init(idedisk_init); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/drivers/ide/ide-dma.c linux.2.5.47-ac6/drivers/ide/ide-dma.c --- linux.2.5.47/drivers/ide/ide-dma.c 2002-11-11 16:39:10.000000000 +0000 +++ linux.2.5.47-ac6/drivers/ide/ide-dma.c 2002-11-19 00:01:52.000000000 +0000 @@ -145,7 +145,16 @@ }; -int in_drive_list(struct hd_driveid *id, struct drive_list_entry * drive_table) +/** + * in_drive_list - look for drive in black/white list + * @id: drive identifier + * @drive_table: list to inspect + * + * Look for a drive in the blacklist and the whitelist tables + * Returns 1 if the drive is found in the table. + */ + +static int in_drive_list(struct hd_driveid *id, struct drive_list_entry * drive_table) { for ( ; drive_table->id_model ; drive_table++) if ((!strcmp(drive_table->id_model, id->model)) && @@ -189,9 +198,14 @@ #endif /* CONFIG_IDEDMA_NEW_DRIVE_LISTINGS */ -/* - * dma_intr() is the handler for disk read/write DMA interrupts +/** + * ide_dma_intr - IDE DMA interrupt handler + * @drive: the drive the interrupt is for + * + * Handle an interrupt completing a read/write DMA transfer on an + * IDE device */ + ide_startstop_t ide_dma_intr (ide_drive_t *drive) { u8 stat = 0, dma_stat = 0; @@ -205,7 +219,7 @@ DRIVER(drive)->end_request(drive, 1, rq->nr_sectors); return ide_stopped; } - printk("%s: dma_intr: bad DMA status (dma_stat=%x)\n", + printk(KERN_ERR "%s: dma_intr: bad DMA status (dma_stat=%x)\n", drive->name, dma_stat); } return DRIVER(drive)->error(drive, "dma_intr", stat); @@ -213,6 +227,17 @@ EXPORT_SYMBOL_GPL(ide_dma_intr); +/** + * ide_build_sglist - map IDE scatter gather for DMA I/O + * @drive: the drive to build the DMA table for + * @rq: the request holding the sg list + * + * Perform the PCI mapping magic neccessary to access the source or + * target buffers of a request via PCI DMA. The lower layers of the + * kernel provide the neccessary cache management so that we can + * operate in a portable fashion + */ + static int ide_build_sglist (ide_drive_t *drive, struct request *rq) { ide_hwif_t *hwif = HWIF(drive); @@ -232,6 +257,17 @@ return pci_map_sg(hwif->pci_dev, sg, nents, hwif->sg_dma_direction); } +/** + * ide_raw_build_sglist - map IDE scatter gather for DMA + * @drive: the drive to build the DMA table for + * @rq: the request holding the sg list + * + * Perform the PCI mapping magic neccessary to access the source or + * target buffers of a taskfile request via PCI DMA. The lower layers + * of the kernel provide the neccessary cache management so that we can + * operate in a portable fashion + */ + static int ide_raw_build_sglist (ide_drive_t *drive, struct request *rq) { ide_hwif_t *hwif = HWIF(drive); @@ -246,6 +282,9 @@ else hwif->sg_dma_direction = PCI_DMA_FROMDEVICE; #if 1 + if (sector_count > 256) + BUG(); + if (sector_count > 128) { memset(&sg[nents], 0, sizeof(*sg)); sg[nents].page = virt_to_page(virt_addr); @@ -279,11 +318,18 @@ return pci_map_sg(hwif->pci_dev, sg, nents, hwif->sg_dma_direction); } -/* - * ide_build_dmatable() prepares a dma request. - * Returns 0 if all went okay, returns 1 otherwise. - * May also be invoked from trm290.c +/** + * ide_build_dmatable - build IDE DMA table + * + * ide_build_dmatable() prepares a dma request. We map the command + * to get the pci bus addresses of the buffers and then build up + * the PRD table that the IDE layer wants to be fed. The code + * knows about the 64K wrap bug in the CS5530. + * + * Returns 0 if all went okay, returns 1 otherwise. + * May also be invoked from trm290.c */ + int ide_build_dmatable (ide_drive_t *drive, struct request *rq) { ide_hwif_t *hwif = HWIF(drive); @@ -317,7 +363,7 @@ while (cur_len) { if (count++ >= PRD_ENTRIES) { - printk("%s: DMA table too small\n", drive->name); + printk(KERN_ERR "%s: DMA table too small\n", drive->name); goto use_pio_instead; } else { u32 xcount, bcount = 0x10000 - (cur_addr & 0xffff); @@ -335,7 +381,7 @@ * So here we break the 64KB entry into two 32KB entries instead. */ if (count++ >= PRD_ENTRIES) { - printk("%s: DMA table too small\n", drive->name); + printk(KERN_ERR "%s: DMA table too small\n", drive->name); goto use_pio_instead; } *table++ = cpu_to_le32(0x8000); @@ -357,7 +403,7 @@ *--table |= cpu_to_le32(0x80000000); return count; } - printk("%s: empty DMA table?\n", drive->name); + printk(KERN_ERR "%s: empty DMA table?\n", drive->name); use_pio_instead: pci_unmap_sg(hwif->pci_dev, hwif->sg_table, @@ -369,7 +415,17 @@ EXPORT_SYMBOL_GPL(ide_build_dmatable); -/* Teardown mappings after DMA has completed. */ +/** + * ide_destroy_dmatable - clean up DMA mapping + * @drive: The drive to unmap + * + * Teardown mappings after DMA has completed. This must be called + * after the completion of each use of ide_build_dmatable and before + * the next use of ide_build_dmatable. Failure to do so will cause + * an oops as only one mapping can be live for each target at a given + * time. + */ + void ide_destroy_dmatable (ide_drive_t *drive) { struct pci_dev *dev = HWIF(drive)->pci_dev; @@ -382,6 +438,17 @@ EXPORT_SYMBOL_GPL(ide_destroy_dmatable); +/** + * config_drive_for_dma - attempt to activate IDE DMA + * @drive: the drive to place in DMA mode + * + * If the drive supports at least mode 2 DMA or UDMA of any kind + * then attempt to place it into DMA mode. Drives that are known to + * support DMA but predate the DMA properties or that are known + * to have DMA handling bugs are also set up appropriately based + * on the good/bad drive lists. + */ + static int config_drive_for_dma (ide_drive_t *drive) { struct hd_driveid *id = drive->id; @@ -415,15 +482,25 @@ return hwif->ide_dma_off_quietly(drive); } -/* - * 1 dmaing, 2 error, 4 intr +/** + * dma_timer_expiry - handle a DMA timeout + * @drive: Drive that timed out + * + * An IDE DMA transfer timed out. In the event of an error we ask + * the driver to resolve the problem, if a DMA transfer is still + * in progress we continue to wait (arguably we need to add a + * secondary 'I dont care what the drive thinks' timeout here) + * Finally if we have an interrupt but for some reason got the + * timeout first we complete the I/O. This can occur if an + * interrupt is lost or due to bugs. */ + static int dma_timer_expiry (ide_drive_t *drive) { ide_hwif_t *hwif = HWIF(drive); u8 dma_stat = hwif->INB(hwif->dma_status); - printk("%s: dma_timer_expiry: dma status == 0x%02x\n", + printk(KERN_WARNING "%s: dma_timer_expiry: dma status == 0x%02x\n", drive->name, dma_stat); if ((dma_stat & 0x18) == 0x18) /* BUSY Stupid Early Timer !! */ @@ -431,6 +508,8 @@ HWGROUP(drive)->expiry = NULL; /* one free ride for now */ + /* 1 dmaing, 2 error, 4 intr */ + if (dma_stat & 2) { /* ERROR */ (void) hwif->ide_dma_end(drive); return DRIVER(drive)->error(drive, @@ -445,6 +524,14 @@ return 0; } +/** + * __ide_dma_host_off - Generic DMA kill + * @drive: drive to control + * + * Perform the generic IDE controller DMA off operation. This + * works for most IDE bus mastering controllers + */ + int __ide_dma_host_off (ide_drive_t *drive) { ide_hwif_t *hwif = HWIF(drive); @@ -457,6 +544,13 @@ EXPORT_SYMBOL(__ide_dma_host_off); +/** + * __ide_dma_host_off_quietly - Generic DMA kill + * @drive: drive to control + * + * Turn off the current DMA on this IDE controller. + */ + int __ide_dma_off_quietly (ide_drive_t *drive) { drive->using_dma = 0; @@ -473,14 +567,30 @@ EXPORT_SYMBOL(__ide_dma_off_quietly); +/** + * __ide_dma_host_off - Generic DMA kill + * @drive: drive to control + * + * Turn off the current DMA on this IDE controller. Inform the + * user that DMA has been disabled. + */ + int __ide_dma_off (ide_drive_t *drive) { - printk("%s: DMA disabled\n", drive->name); + printk(KERN_INFO "%s: DMA disabled\n", drive->name); return HWIF(drive)->ide_dma_off_quietly(drive); } EXPORT_SYMBOL(__ide_dma_off); +/** + * __ide_dma_host_on - Enable DMA on a host + * @drive: drive to enable for DMA + * + * Enable DMA on an IDE controller following generic bus mastering + * IDE controller behaviour + */ + int __ide_dma_host_on (ide_drive_t *drive) { if (drive->using_dma) { @@ -496,6 +606,13 @@ EXPORT_SYMBOL(__ide_dma_host_on); +/** + * __ide_dma_on - Enable DMA on a device + * @drive: drive to enable DMA on + * + * Enable IDE DMA for a device on this IDE controller. + */ + int __ide_dma_on (ide_drive_t *drive) { drive->using_dma = 1; @@ -512,6 +629,13 @@ EXPORT_SYMBOL(__ide_dma_on); +/** + * __ide_dma_check - check DMA setup + * @drive: drive to check + * + * Don't use - due for extermination + */ + int __ide_dma_check (ide_drive_t *drive) { return config_drive_for_dma(drive); @@ -519,6 +643,21 @@ EXPORT_SYMBOL(__ide_dma_check); +/** + * ide_start_dma - begin a DMA phase + * @hwif: interface + * @drive: target device + * @reading: set if reading, clear if writing + * + * Build an IDE DMA PRD (IDE speak for scatter gather table) + * and then set up the DMA transfer registers for a device + * that follows generic IDE PCI DMA behaviour. Controllers can + * override this function if they need to + * + * Returns 0 on success. If a PIO fallback is required then 1 + * is returned. + */ + int ide_start_dma(ide_hwif_t *hwif, ide_drive_t *drive, int reading) { struct request *rq = HWGROUP(drive)->rq; @@ -566,6 +705,10 @@ ide_set_handler(drive, &ide_dma_intr, 2*WAIT_CMD, dma_timer_expiry); command = (lba48) ? WIN_READDMA_EXT : WIN_READDMA; + + if (drive->vdma) + command = (lba48) ? WIN_READ_EXT: WIN_READ; + if (rq->flags & REQ_DRIVE_TASKFILE) { ide_task_t *args = rq->special; command = args->tfRegister[IDE_COMMAND_OFFSET]; @@ -600,6 +743,9 @@ ide_set_handler(drive, &ide_dma_intr, 2*WAIT_CMD, dma_timer_expiry); command = (lba48) ? WIN_WRITEDMA_EXT : WIN_WRITEDMA; + if (drive->vdma) + command = (lba48) ? WIN_WRITE_EXT: WIN_WRITE; + if (rq->flags & REQ_DRIVE_TASKFILE) { ide_task_t *args = rq->special; command = args->tfRegister[IDE_COMMAND_OFFSET]; @@ -791,9 +937,17 @@ EXPORT_SYMBOL(__ide_dma_verbose); +/** + * __ide_dma_retune - default retune handler + * @drive: drive to retune + * + * Default behaviour when we decide to return the IDE DMA setup. + * The default behaviour is "we don't" + */ + int __ide_dma_retune (ide_drive_t *drive) { - printk("%s: chipset supported call only\n", __FUNCTION__); + printk(KERN_WARNING "%s: chipset supported call only\n", __FUNCTION__); return 1; } @@ -809,7 +963,7 @@ int __ide_dma_timeout (ide_drive_t *drive) { - printk("%s: timeout waiting for DMA\n", drive->name); + printk(KERN_ERR "%s: timeout waiting for DMA\n", drive->name); if (HWIF(drive)->ide_dma_test_irq(drive)) return 0; @@ -882,7 +1036,7 @@ if ((hwif->dmatable_cpu) && (hwif->sg_table)) return 0; - printk("%s: -- Error, unable to allocate%s%s table(s).\n", + printk(KERN_ERR "%s: -- Error, unable to allocate%s%s table(s).\n", (hwif->dmatable_cpu == NULL) ? " CPU" : "", (hwif->sg_table == NULL) ? " SG DMA" : " DMA", hwif->cds->name); @@ -893,7 +1047,7 @@ int ide_mmio_dma (ide_hwif_t *hwif, unsigned long base, unsigned int ports) { - printk(" %s: MMIO-DMA at 0x%08lx-0x%08lx", + printk(KERN_INFO " %s: MMIO-DMA at 0x%08lx-0x%08lx", hwif->name, base, base + ports - 1); if (check_mem_region(base, ports)) { printk(" -- Error, MMIO ports already in use.\n"); @@ -905,7 +1059,11 @@ request_region(base+16, hwif->cds->extra, hwif->cds->name); hwif->dma_extra = hwif->cds->extra; } - hwif->dma_master = (hwif->channel) ? hwif->mate->dma_base : base; + + if(hwif->mate) + hwif->dma_master = (hwif->channel) ? hwif->mate->dma_base : base; + else + hwif->dma_master = base; if (hwif->dma_base2) { if (!check_mem_region(hwif->dma_base2, ports)) request_mem_region(hwif->dma_base2, ports, hwif->name); @@ -915,7 +1073,7 @@ int ide_iomio_dma (ide_hwif_t *hwif, unsigned long base, unsigned int ports) { - printk(" %s: BM-DMA at 0x%04lx-0x%04lx", + printk(KERN_INFO " %s: BM-DMA at 0x%04lx-0x%04lx", hwif->name, base, base + ports - 1); if (!request_region(base, ports, hwif->name)) { printk(" -- Error, ports in use.\n"); @@ -926,7 +1084,11 @@ request_region(base+16, hwif->cds->extra, hwif->cds->name); hwif->dma_extra = hwif->cds->extra; } - hwif->dma_master = (hwif->channel) ? hwif->mate->dma_base : base; + + if(hwif->mate) + hwif->dma_master = (hwif->channel) ? hwif->mate->dma_base : base; + else + hwif->dma_master = base; if (hwif->dma_base2) { if (!request_region(hwif->dma_base2, ports, hwif->name)) { diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/drivers/ide/ide-floppy.c linux.2.5.47-ac6/drivers/ide/ide-floppy.c --- linux.2.5.47/drivers/ide/ide-floppy.c 2002-11-05 13:54:43.000000000 +0000 +++ linux.2.5.47-ac6/drivers/ide/ide-floppy.c 2002-11-17 02:15:30.000000000 +0000 @@ -115,6 +115,12 @@ /* #define IDEFLOPPY_DEBUG(fmt, args...) printk(KERN_INFO fmt, ## args) */ #define IDEFLOPPY_DEBUG( fmt, args... ) +#ifndef IDEFLOPPY_DEBUG_LOG +#define debug_log(fmt, args... ) do {} while(0) +#else +#define debug_log printk +#endif + /* * Some drives require a longer irq timeout. @@ -543,9 +549,7 @@ struct request *rq = HWGROUP(drive)->rq; int error; -#if IDEFLOPPY_DEBUG_LOG - printk(KERN_INFO "Reached idefloppy_end_request\n"); -#endif /* IDEFLOPPY_DEBUG_LOG */ + debug_log(KERN_INFO "Reached idefloppy_end_request\n"); switch (uptodate) { case 0: error = IDEFLOPPY_ERROR_GENERAL; break; @@ -627,7 +631,6 @@ } } -#ifdef CONFIG_BLK_DEV_IDEDMA static void idefloppy_update_buffers (ide_drive_t *drive, idefloppy_pc_t *pc) { struct request *rq = pc->rq; @@ -636,7 +639,6 @@ while ((bio = rq->bio) != NULL) idefloppy_do_end_request(drive, 1, 0); } -#endif /* CONFIG_BLK_DEV_IDEDMA */ /* * idefloppy_queue_pc_head generates a new packet command request in front @@ -682,25 +684,22 @@ floppy->ascq = result->ascq; floppy->progress_indication = result->sksv[0] & 0x80 ? (u16)get_unaligned((u16 *)(result->sksv+1)):0x10000; -#if IDEFLOPPY_DEBUG_LOG if (floppy->failed_pc) - printk(KERN_INFO "ide-floppy: pc = %x, sense key = %x, " + debug_log(KERN_INFO "ide-floppy: pc = %x, sense key = %x, " "asc = %x, ascq = %x\n", floppy->failed_pc->c[0], result->sense_key, result->asc, result->ascq); else - printk(KERN_INFO "ide-floppy: sense key = %x, asc = %x, " + debug_log(KERN_INFO "ide-floppy: sense key = %x, asc = %x, " "ascq = %x\n", result->sense_key, result->asc, result->ascq); -#endif /* IDEFLOPPY_DEBUG_LOG */ } static void idefloppy_request_sense_callback (ide_drive_t *drive) { idefloppy_floppy_t *floppy = drive->driver_data; -#if IDEFLOPPY_DEBUG_LOG - printk(KERN_INFO "ide-floppy: Reached %s\n", __FUNCTION__); -#endif /* IDEFLOPPY_DEBUG_LOG */ + debug_log(KERN_INFO "ide-floppy: Reached %s\n", __FUNCTION__); + if (!floppy->pc->error) { idefloppy_analyze_error(drive,(idefloppy_request_sense_result_t *) floppy->pc->buffer); idefloppy_do_end_request(drive, 1, 0); @@ -717,9 +716,7 @@ { idefloppy_floppy_t *floppy = drive->driver_data; -#if IDEFLOPPY_DEBUG_LOG - printk (KERN_INFO "ide-floppy: Reached %s\n", __FUNCTION__); -#endif /* IDEFLOPPY_DEBUG_LOG */ + debug_log(KERN_INFO "ide-floppy: Reached %s\n", __FUNCTION__); idefloppy_do_end_request(drive, floppy->pc->error ? 0 : 1, 0); } @@ -781,12 +778,9 @@ struct request *rq = pc->rq; unsigned int temp; -#if IDEFLOPPY_DEBUG_LOG - printk(KERN_INFO "ide-floppy: Reached %s interrupt handler\n", + debug_log(KERN_INFO "ide-floppy: Reached %s interrupt handler\n", __FUNCTION__); -#endif /* IDEFLOPPY_DEBUG_LOG */ -#ifdef CONFIG_BLK_DEV_IDEDMA if (test_bit(PC_DMA_IN_PROGRESS, &pc->flags)) { if (HWIF(drive)->ide_dma_end(drive)) { set_bit(PC_DMA_ERROR, &pc->flags); @@ -794,30 +788,23 @@ pc->actually_transferred = pc->request_transfer; idefloppy_update_buffers(drive, pc); } -#if IDEFLOPPY_DEBUG_LOG - printk (KERN_INFO "ide-floppy: DMA finished\n"); -#endif /* IDEFLOPPY_DEBUG_LOG */ + debug_log(KERN_INFO "ide-floppy: DMA finished\n"); } -#endif /* CONFIG_BLK_DEV_IDEDMA */ /* Clear the interrupt */ status.all = HWIF(drive)->INB(IDE_STATUS_REG); if (!status.b.drq) { /* No more interrupts */ -#if IDEFLOPPY_DEBUG_LOG - printk(KERN_INFO "Packet command completed, %d bytes " + debug_log(KERN_INFO "Packet command completed, %d bytes " "transferred\n", pc->actually_transferred); -#endif /* IDEFLOPPY_DEBUG_LOG */ clear_bit(PC_DMA_IN_PROGRESS, &pc->flags); local_irq_enable(); if (status.b.check || test_bit(PC_DMA_ERROR, &pc->flags)) { /* Error detected */ -#if IDEFLOPPY_DEBUG_LOG - printk(KERN_INFO "ide-floppy: %s: I/O error\n", + debug_log(KERN_INFO "ide-floppy: %s: I/O error\n", drive->name); -#endif /* IDEFLOPPY_DEBUG_LOG */ rq->errors++; if (pc->c[0] == IDEFLOPPY_REQUEST_SENSE_CMD) { printk(KERN_ERR "ide-floppy: I/O error in " @@ -836,14 +823,14 @@ pc->callback(drive); return ide_stopped; } -#ifdef CONFIG_BLK_DEV_IDEDMA + if (test_and_clear_bit(PC_DMA_IN_PROGRESS, &pc->flags)) { printk(KERN_ERR "ide-floppy: The floppy wants to issue " "more interrupts in DMA mode\n"); (void) HWIF(drive)->ide_dma_off(drive); return ide_do_reset(drive); } -#endif /* CONFIG_BLK_DEV_IDEDMA */ + /* Get the number of bytes to transfer */ bcount.b.high = HWIF(drive)->INB(IDE_BCOUNTH_REG); bcount.b.low = HWIF(drive)->INB(IDE_BCOUNTL_REG); @@ -879,11 +866,9 @@ NULL); return ide_started; } -#if IDEFLOPPY_DEBUG_LOG - printk(KERN_NOTICE "ide-floppy: The floppy wants to " + debug_log(KERN_NOTICE "ide-floppy: The floppy wants to " "send us more data than expected - " "allowing transfer\n"); -#endif /* IDEFLOPPY_DEBUG_LOG */ } } if (test_bit(PC_WRITING, &pc->flags)) { @@ -1047,9 +1032,8 @@ pc->callback(drive); return ide_stopped; } -#if IDEFLOPPY_DEBUG_LOG - printk(KERN_INFO "Retry number - %d\n",pc->retries); -#endif /* IDEFLOPPY_DEBUG_LOG */ + + debug_log(KERN_INFO "Retry number - %d\n",pc->retries); pc->retries++; /* We haven't transferred any data yet */ @@ -1057,13 +1041,11 @@ pc->current_position = pc->buffer; bcount.all = min(pc->request_transfer, 63 * 1024); -#ifdef CONFIG_BLK_DEV_IDEDMA if (test_and_clear_bit(PC_DMA_ERROR, &pc->flags)) { (void) HWIF(drive)->ide_dma_off(drive); } -#endif /* CONFIG_BLK_DEV_IDEDMA */ feature.all = 0; -#ifdef CONFIG_BLK_DEV_IDEDMA + if (test_bit(PC_DMA_RECOMMENDED, &pc->flags) && drive->using_dma) { if (test_bit(PC_WRITING, &pc->flags)) { feature.b.dma = !HWIF(drive)->ide_dma_write(drive); @@ -1071,7 +1053,6 @@ feature.b.dma = !HWIF(drive)->ide_dma_read(drive); } } -#endif /* CONFIG_BLK_DEV_IDEDMA */ if (IDE_CONTROL_REG) HWIF(drive)->OUTB(drive->ctl, IDE_CONTROL_REG); @@ -1081,12 +1062,10 @@ HWIF(drive)->OUTB(bcount.b.low, IDE_BCOUNTL_REG); HWIF(drive)->OUTB(drive->select.all, IDE_SELECT_REG); -#ifdef CONFIG_BLK_DEV_IDEDMA if (feature.b.dma) { /* Begin DMA, if necessary */ set_bit(PC_DMA_IN_PROGRESS, &pc->flags); (void) (HWIF(drive)->ide_dma_begin(drive)); } -#endif /* CONFIG_BLK_DEV_IDEDMA */ /* Can we transfer the packet when we get the interrupt or wait? */ if (test_bit(IDEFLOPPY_ZIP_DRIVE, &floppy->flags)) { @@ -1116,9 +1095,7 @@ static void idefloppy_rw_callback (ide_drive_t *drive) { -#if IDEFLOPPY_DEBUG_LOG - printk (KERN_INFO "ide-floppy: Reached idefloppy_rw_callback\n"); -#endif /* IDEFLOPPY_DEBUG_LOG */ + debug_log(KERN_INFO "ide-floppy: Reached idefloppy_rw_callback\n"); idefloppy_do_end_request(drive, 1, 0); return; @@ -1126,10 +1103,8 @@ static void idefloppy_create_prevent_cmd (idefloppy_pc_t *pc, int prevent) { -#if IDEFLOPPY_DEBUG_LOG - printk(KERN_INFO "ide-floppy: creating prevent removal command, " + debug_log(KERN_INFO "ide-floppy: creating prevent removal command, " "prevent = %d\n", prevent); -#endif /* IDEFLOPPY_DEBUG_LOG */ idefloppy_init_pc(pc); pc->c[0] = IDEFLOPPY_PREVENT_REMOVAL_CMD; @@ -1212,11 +1187,9 @@ int blocks = rq->nr_sectors / floppy->bs_factor; int cmd = rq_data_dir(rq); -#if IDEFLOPPY_DEBUG_LOG - printk("create_rw1%d_cmd: block == %d, blocks == %d\n", + debug_log("create_rw1%d_cmd: block == %d, blocks == %d\n", 2 * test_bit (IDEFLOPPY_USE_READ12, &floppy->flags), block, blocks); -#endif /* IDEFLOPPY_DEBUG_LOG */ idefloppy_init_pc(pc); if (test_bit(IDEFLOPPY_USE_READ12, &floppy->flags)) { @@ -1262,14 +1235,12 @@ idefloppy_pc_t *pc; unsigned long block = (unsigned long)block_s; -#if IDEFLOPPY_DEBUG_LOG - printk(KERN_INFO "rq_status: %d, dev: %s, flags: %lx, errors: %d\n", + debug_log(KERN_INFO "rq_status: %d, dev: %s, flags: %lx, errors: %d\n", rq->rq_status, rq->rq_disk->disk_name, rq->flags, rq->errors); - printk(KERN_INFO "sector: %ld, nr_sectors: %ld, " - "current_nr_sectors: %ld\n", (long)rq->sector, + debug_log(KERN_INFO "sector: %ld, nr_sectors: %ld, " + "current_nr_sectors: %d\n", (long)rq->sector, rq->nr_sectors, rq->current_nr_sectors); -#endif /* IDEFLOPPY_DEBUG_LOG */ if (rq->errors >= ERROR_MAX) { if (floppy->failed_pc != NULL) @@ -1473,10 +1444,10 @@ } } if (!i) { - IDEFLOPPY_DEBUG( "Descriptor 0 Code: %d\n", + debug_log( "Descriptor 0 Code: %d\n", descriptor->dc); } - IDEFLOPPY_DEBUG( "Descriptor %d: %dkB, %d blocks, %d " + debug_log( "Descriptor %d: %dkB, %d blocks, %d " "sector size\n", i, blocks * length / 1024, blocks, length); } @@ -1909,9 +1880,7 @@ drive->usage++; -#if IDEFLOPPY_DEBUG_LOG - printk(KERN_INFO "Reached idefloppy_open\n"); -#endif /* IDEFLOPPY_DEBUG_LOG */ + debug_log(KERN_INFO "Reached idefloppy_open\n"); if (drive->usage == 1) { clear_bit(IDEFLOPPY_FORMAT_IN_PROGRESS, &floppy->flags); @@ -1958,9 +1927,7 @@ ide_drive_t *drive = inode->i_bdev->bd_disk->private_data; idefloppy_pc_t pc; -#if IDEFLOPPY_DEBUG_LOG - printk (KERN_INFO "Reached idefloppy_release\n"); -#endif /* IDEFLOPPY_DEBUG_LOG */ + debug_log(KERN_INFO "Reached idefloppy_release\n"); if (drive->usage == 1) { idefloppy_floppy_t *floppy = drive->driver_data; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/drivers/ide/ide-io.c linux.2.5.47-ac6/drivers/ide/ide-io.c --- linux.2.5.47/drivers/ide/ide-io.c 1970-01-01 01:00:00.000000000 +0100 +++ linux.2.5.47-ac6/drivers/ide/ide-io.c 2002-11-14 18:00:06.000000000 +0000 @@ -0,0 +1,1320 @@ +/* + * IDE I/O functions + * + * Basic PIO and command management functionality. + * + * This code was split off from ide.c. See ide.c for history and original + * copyrights. + * + * 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, 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. + * + * For the avoidance of doubt the "preferred form" of this code is one which + * is in an open non patent encumbered format. Where cryptographic key signing + * forms part of the process of creating an executable the information + * including keys needed to generate an equivalently functional executable + * are deemed to be part of the source code. + */ + + +#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 +#include + +#include "ide_modes.h" + +#if (DISK_RECOVERY_TIME > 0) + +Error So the User Has To Fix the Compilation And Stop Hacking Port 0x43 +Does anyone ever use this anyway ?? + +/* + * For really screwy hardware (hey, at least it *can* be used with Linux) + * we can enforce a minimum delay time between successive operations. + */ +static unsigned long read_timer (ide_hwif_t *hwif) +{ + unsigned long t, flags; + int i; + + /* FIXME this is completely unsafe! */ + local_irq_save(flags); + t = jiffies * 11932; + outb_p(0, 0x43); + i = inb_p(0x40); + i |= inb_p(0x40) << 8; + local_irq_restore(flags); + return (t - i); +} +#endif /* DISK_RECOVERY_TIME */ + +static inline void set_recovery_timer (ide_hwif_t *hwif) +{ +#if (DISK_RECOVERY_TIME > 0) + hwif->last_time = read_timer(hwif); +#endif /* DISK_RECOVERY_TIME */ +} + +/** + * ide_end_request - complete an IDE I/O + * @drive: IDE device for the I/O + * @uptodate: + * @nr_sectors: number of sectors completed + * + * This is our end_request wrapper function. We complete the I/O + * update random number input and dequeue the request, which if + * it was tagged may be out of order. + */ + +int ide_end_request (ide_drive_t *drive, int uptodate, int nr_sectors) +{ + struct request *rq; + unsigned long flags; + int ret = 1; + + spin_lock_irqsave(&ide_lock, flags); + rq = HWGROUP(drive)->rq; + + BUG_ON(!(rq->flags & REQ_STARTED)); + + if (!nr_sectors) + nr_sectors = rq->hard_cur_sectors; + + /* + * decide whether to reenable DMA -- 3 is a random magic for now, + * if we DMA timeout more than 3 times, just stay in PIO + */ + if (drive->state == DMA_PIO_RETRY && drive->retry_pio <= 3) { + drive->state = 0; + HWGROUP(drive)->hwif->ide_dma_on(drive); + } + + if (!end_that_request_first(rq, uptodate, nr_sectors)) { + add_disk_randomness(rq->rq_disk); + if (!blk_rq_tagged(rq)) + blkdev_dequeue_request(rq); + else + blk_queue_end_tag(&drive->queue, rq); + HWGROUP(drive)->rq = NULL; + end_that_request_last(rq); + ret = 0; + } + spin_unlock_irqrestore(&ide_lock, flags); + return ret; +} + +EXPORT_SYMBOL(ide_end_request); + +/** + * ide_end_drive_cmd - end an explicit drive command + * @drive: command + * @stat: status bits + * @err: error bits + * + * Clean up after success/failure of an explicit drive command. + * These get thrown onto the queue so they are synchronized with + * real I/O operations on the drive. + * + * In LBA48 mode we have to read the register set twice to get + * all the extra information out. + */ + +void ide_end_drive_cmd (ide_drive_t *drive, u8 stat, u8 err) +{ + ide_hwif_t *hwif = HWIF(drive); + unsigned long flags; + struct request *rq; + + spin_lock_irqsave(&ide_lock, flags); + rq = HWGROUP(drive)->rq; + spin_unlock_irqrestore(&ide_lock, flags); + + if (rq->flags & REQ_DRIVE_CMD) { + u8 *args = (u8 *) rq->buffer; + if (rq->errors == 0) + rq->errors = !OK_STAT(stat,READY_STAT,BAD_STAT); + + if (args) { + args[0] = stat; + args[1] = err; + args[2] = hwif->INB(IDE_NSECTOR_REG); + } + } else if (rq->flags & REQ_DRIVE_TASK) { + u8 *args = (u8 *) rq->buffer; + if (rq->errors == 0) + rq->errors = !OK_STAT(stat,READY_STAT,BAD_STAT); + + if (args) { + args[0] = stat; + args[1] = err; + args[2] = hwif->INB(IDE_NSECTOR_REG); + args[3] = hwif->INB(IDE_SECTOR_REG); + args[4] = hwif->INB(IDE_LCYL_REG); + args[5] = hwif->INB(IDE_HCYL_REG); + args[6] = hwif->INB(IDE_SELECT_REG); + } + } else if (rq->flags & REQ_DRIVE_TASKFILE) { + ide_task_t *args = (ide_task_t *) rq->special; + if (rq->errors == 0) + rq->errors = !OK_STAT(stat,READY_STAT,BAD_STAT); + + if (args) { + if (args->tf_in_flags.b.data) { + u16 data = hwif->INW(IDE_DATA_REG); + args->tfRegister[IDE_DATA_OFFSET] = (data) & 0xFF; + args->hobRegister[IDE_DATA_OFFSET_HOB] = (data >> 8) & 0xFF; + } + args->tfRegister[IDE_ERROR_OFFSET] = err; + args->tfRegister[IDE_NSECTOR_OFFSET] = hwif->INB(IDE_NSECTOR_REG); + args->tfRegister[IDE_SECTOR_OFFSET] = hwif->INB(IDE_SECTOR_REG); + args->tfRegister[IDE_LCYL_OFFSET] = hwif->INB(IDE_LCYL_REG); + args->tfRegister[IDE_HCYL_OFFSET] = hwif->INB(IDE_HCYL_REG); + args->tfRegister[IDE_SELECT_OFFSET] = hwif->INB(IDE_SELECT_REG); + args->tfRegister[IDE_STATUS_OFFSET] = stat; + + if (drive->addressing == 1) { + hwif->OUTB(drive->ctl|0x80, IDE_CONTROL_REG_HOB); + args->hobRegister[IDE_FEATURE_OFFSET_HOB] = hwif->INB(IDE_FEATURE_REG); + args->hobRegister[IDE_NSECTOR_OFFSET_HOB] = hwif->INB(IDE_NSECTOR_REG); + args->hobRegister[IDE_SECTOR_OFFSET_HOB] = hwif->INB(IDE_SECTOR_REG); + args->hobRegister[IDE_LCYL_OFFSET_HOB] = hwif->INB(IDE_LCYL_REG); + args->hobRegister[IDE_HCYL_OFFSET_HOB] = hwif->INB(IDE_HCYL_REG); + } + } + } + + spin_lock_irqsave(&ide_lock, flags); + blkdev_dequeue_request(rq); + HWGROUP(drive)->rq = NULL; + end_that_request_last(rq); + spin_unlock_irqrestore(&ide_lock, flags); +} + +EXPORT_SYMBOL(ide_end_drive_cmd); + +/** + * try_to_flush_leftover_data - flush junk + * @drive: drive to flush + * + * try_to_flush_leftover_data() is invoked in response to a drive + * unexpectedly having its DRQ_STAT bit set. As an alternative to + * resetting the drive, this routine tries to clear the condition + * by read a sector's worth of data from the drive. Of course, + * this may not help if the drive is *waiting* for data from *us*. + */ +void try_to_flush_leftover_data (ide_drive_t *drive) +{ + int i = (drive->mult_count ? drive->mult_count : 1) * SECTOR_WORDS; + + if (drive->media != ide_disk) + return; + while (i > 0) { + u32 buffer[16]; + u32 wcount = (i > 16) ? 16 : i; + + i -= wcount; + HWIF(drive)->ata_input_data(drive, buffer, wcount); + } +} + +EXPORT_SYMBOL(try_to_flush_leftover_data); + +/* + * FIXME Add an ATAPI error + */ + +/** + * ide_error - handle an error on the IDE + * @drive: drive the error occurred on + * @msg: message to report + * @stat: status bits + * + * ide_error() takes action based on the error returned by the drive. + * For normal I/O that may well include retries. We deal with + * both new-style (taskfile) and old style command handling here. + * In the case of taskfile command handling there is work left to + * do + */ + +ide_startstop_t ide_error (ide_drive_t *drive, const char *msg, u8 stat) +{ + ide_hwif_t *hwif; + struct request *rq; + u8 err; + + err = ide_dump_status(drive, msg, stat); + if (drive == NULL || (rq = HWGROUP(drive)->rq) == NULL) + return ide_stopped; + + hwif = HWIF(drive); + /* retry only "normal" I/O: */ + if (rq->flags & (REQ_DRIVE_CMD | REQ_DRIVE_TASK)) { + rq->errors = 1; + ide_end_drive_cmd(drive, stat, err); + return ide_stopped; + } + if (rq->flags & REQ_DRIVE_TASKFILE) { + rq->errors = 1; + ide_end_drive_cmd(drive, stat, err); +// ide_end_taskfile(drive, stat, err); + return ide_stopped; + } + + if (stat & BUSY_STAT || ((stat & WRERR_STAT) && !drive->nowerr)) { + /* other bits are useless when BUSY */ + rq->errors |= ERROR_RESET; + } else { + if (drive->media != ide_disk) + goto media_out; + + if (stat & ERR_STAT) { + /* err has different meaning on cdrom and tape */ + if (err == ABRT_ERR) { + if (drive->select.b.lba && + (hwif->INB(IDE_COMMAND_REG) == WIN_SPECIFY)) + /* some newer drives don't + * support WIN_SPECIFY + */ + return ide_stopped; + } else if ((err & BAD_CRC) == BAD_CRC) { + drive->crc_count++; + /* UDMA crc error -- just retry the operation */ + } else if (err & (BBD_ERR | ECC_ERR)) { + /* retries won't help these */ + rq->errors = ERROR_MAX; + } else if (err & TRK0_ERR) { + /* help it find track zero */ + rq->errors |= ERROR_RECAL; + } + } +media_out: + if ((stat & DRQ_STAT) && rq_data_dir(rq) != WRITE) + try_to_flush_leftover_data(drive); + } + if (hwif->INB(IDE_STATUS_REG) & (BUSY_STAT|DRQ_STAT)) { + /* force an abort */ + hwif->OUTB(WIN_IDLEIMMEDIATE,IDE_COMMAND_REG); + } + if (rq->errors >= ERROR_MAX) { + if (drive->driver != NULL) + DRIVER(drive)->end_request(drive, 0, 0); + else + ide_end_request(drive, 0, 0); + } else { + if ((rq->errors & ERROR_RESET) == ERROR_RESET) { + ++rq->errors; + return ide_do_reset(drive); + } + if ((rq->errors & ERROR_RECAL) == ERROR_RECAL) + drive->special.b.recalibrate = 1; + ++rq->errors; + } + return ide_stopped; +} + +EXPORT_SYMBOL(ide_error); + +/** + * ide_cmd - issue a simple drive command + * @drive: drive the command is for + * @cmd: command byte + * @nsect: sector byte + * @handler: handler for the command completion + * + * Issue a simple drive command with interrupts. + * The drive must be selected beforehand. + */ + +void ide_cmd (ide_drive_t *drive, u8 cmd, u8 nsect, ide_handler_t *handler) +{ + ide_hwif_t *hwif = HWIF(drive); + if (HWGROUP(drive)->handler != NULL) + BUG(); + ide_set_handler(drive, handler, WAIT_CMD, NULL); + if (IDE_CONTROL_REG) + hwif->OUTB(drive->ctl,IDE_CONTROL_REG); /* clear nIEN */ + SELECT_MASK(drive,0); + hwif->OUTB(nsect,IDE_NSECTOR_REG); + hwif->OUTB(cmd,IDE_COMMAND_REG); +} + +EXPORT_SYMBOL(ide_cmd); + +/** + * drive_cmd_intr - drive command completion interrupt + * @drive: drive the completion interrupt occurred on + * + * drive_cmd_intr() is invoked on completion of a special DRIVE_CMD. + * We do any neccessary daya reading and then wait for the drive to + * go non busy. At that point we may read the error data and complete + * the request + */ + +ide_startstop_t drive_cmd_intr (ide_drive_t *drive) +{ + struct request *rq = HWGROUP(drive)->rq; + ide_hwif_t *hwif = HWIF(drive); + u8 *args = (u8 *) rq->buffer; + u8 stat = hwif->INB(IDE_STATUS_REG); + int retries = 10; + + local_irq_enable(); + if ((stat & DRQ_STAT) && args && args[3]) { + u8 io_32bit = drive->io_32bit; + drive->io_32bit = 0; + hwif->ata_input_data(drive, &args[4], args[3] * SECTOR_WORDS); + drive->io_32bit = io_32bit; + while (((stat = hwif->INB(IDE_STATUS_REG)) & BUSY_STAT) && retries--) + udelay(100); + } + + if (!OK_STAT(stat, READY_STAT, BAD_STAT)) + return DRIVER(drive)->error(drive, "drive_cmd", stat); + /* calls ide_end_drive_cmd */ + ide_end_drive_cmd(drive, stat, hwif->INB(IDE_ERROR_REG)); + return ide_stopped; +} + +EXPORT_SYMBOL(drive_cmd_intr); + +/** + * do_special - issue some special commands + * @drive: drive the command is for + * + * do_special() is used to issue WIN_SPECIFY, WIN_RESTORE, and WIN_SETMULT + * commands to a drive. It used to do much more, but has been scaled + * back. + */ + +ide_startstop_t do_special (ide_drive_t *drive) +{ + special_t *s = &drive->special; + +#ifdef DEBUG + printk("%s: do_special: 0x%02x\n", drive->name, s->all); +#endif + if (s->b.set_tune) { + s->b.set_tune = 0; + if (HWIF(drive)->tuneproc != NULL) + HWIF(drive)->tuneproc(drive, drive->tune_req); + } else if (drive->driver != NULL) { + return DRIVER(drive)->special(drive); + } else if (s->all) { + printk(KERN_ERR "%s: bad special flag: 0x%02x\n", drive->name, s->all); + s->all = 0; + } + return ide_stopped; +} + +EXPORT_SYMBOL(do_special); + +/** + * execute_drive_command - issue special drive command + * @drive: the drive to issue th command on + * @rq: the request structure holding the command + * + * execute_drive_cmd() issues a special drive command, usually + * initiated by ioctl() from the external hdparm program. The + * command can be a drive command, drive task or taskfile + * operation. Weirdly you can call it with NULL to wait for + * all commands to finish. Don't do this as that is due to change + */ + +ide_startstop_t execute_drive_cmd (ide_drive_t *drive, struct request *rq) +{ + ide_hwif_t *hwif = HWIF(drive); + if (rq->flags & REQ_DRIVE_TASKFILE) { + ide_task_t *args = rq->special; + + if (!args) + goto done; + + if (args->tf_out_flags.all != 0) + return flagged_taskfile(drive, args); + return do_rw_taskfile(drive, args); + } else if (rq->flags & REQ_DRIVE_TASK) { + u8 *args = rq->buffer; + u8 sel; + + if (!args) + goto done; +#ifdef DEBUG + printk("%s: DRIVE_TASK_CMD ", drive->name); + printk("cmd=0x%02x ", args[0]); + printk("fr=0x%02x ", args[1]); + printk("ns=0x%02x ", args[2]); + printk("sc=0x%02x ", args[3]); + printk("lcyl=0x%02x ", args[4]); + printk("hcyl=0x%02x ", args[5]); + printk("sel=0x%02x\n", args[6]); +#endif + hwif->OUTB(args[1], IDE_FEATURE_REG); + hwif->OUTB(args[3], IDE_SECTOR_REG); + hwif->OUTB(args[4], IDE_LCYL_REG); + hwif->OUTB(args[5], IDE_HCYL_REG); + sel = (args[6] & ~0x10); + if (drive->select.b.unit) + sel |= 0x10; + hwif->OUTB(sel, IDE_SELECT_REG); + ide_cmd(drive, args[0], args[2], &drive_cmd_intr); + return ide_started; + } else if (rq->flags & REQ_DRIVE_CMD) { + u8 *args = rq->buffer; + + if (!args) + goto done; +#ifdef DEBUG + printk("%s: DRIVE_CMD ", drive->name); + printk("cmd=0x%02x ", args[0]); + printk("sc=0x%02x ", args[1]); + printk("fr=0x%02x ", args[2]); + printk("xx=0x%02x\n", args[3]); +#endif + if (args[0] == WIN_SMART) { + hwif->OUTB(0x4f, IDE_LCYL_REG); + hwif->OUTB(0xc2, IDE_HCYL_REG); + hwif->OUTB(args[2],IDE_FEATURE_REG); + hwif->OUTB(args[1],IDE_SECTOR_REG); + ide_cmd(drive, args[0], args[3], &drive_cmd_intr); + return ide_started; + } + hwif->OUTB(args[2],IDE_FEATURE_REG); + ide_cmd(drive, args[0], args[1], &drive_cmd_intr); + return ide_started; + } + +done: + /* + * NULL is actually a valid way of waiting for + * all current requests to be flushed from the queue. + */ +#ifdef DEBUG + printk("%s: DRIVE_CMD (null)\n", drive->name); +#endif + ide_end_drive_cmd(drive, + hwif->INB(IDE_STATUS_REG), + hwif->INB(IDE_ERROR_REG)); + return ide_stopped; +} + +EXPORT_SYMBOL(execute_drive_cmd); + +/** + * start_request - start of I/O and command issuing for IDE + * + * start_request() initiates handling of a new I/O request. It + * accepts commands and I/O (read/write) requests. It also does + * the final remapping for weird stuff like EZDrive. Once + * device mapper can work sector level the EZDrive stuff can go away + * + * FIXME: this function needs a rename + */ + +ide_startstop_t start_request (ide_drive_t *drive, struct request *rq) +{ + ide_startstop_t startstop; + unsigned long block; + + BUG_ON(!(rq->flags & REQ_STARTED)); + +#ifdef DEBUG + printk("%s: start_request: current=0x%08lx\n", + HWIF(drive)->name, (unsigned long) rq); +#endif + + /* bail early if we've exceeded max_failures */ + if (drive->max_failures && (drive->failures > drive->max_failures)) { + goto kill_rq; + } + + /* + * bail early if we've sent a device to sleep, however how to wake + * this needs to be a masked flag. FIXME for proper operations. + */ + if (drive->suspend_reset) + goto kill_rq; + + block = rq->sector; + if (blk_fs_request(rq) && + (drive->media == ide_disk || drive->media == ide_floppy)) { + block += drive->sect0; + } + /* Yecch - this will shift the entire interval, + possibly killing some innocent following sector */ + if (block == 0 && drive->remap_0_to_1 == 1) + block = 1; /* redirect MBR access to EZ-Drive partn table */ + +#if (DISK_RECOVERY_TIME > 0) + while ((read_timer() - HWIF(drive)->last_time) < DISK_RECOVERY_TIME); +#endif + + SELECT_DRIVE(drive); + if (ide_wait_stat(&startstop, drive, drive->ready_stat, BUSY_STAT|DRQ_STAT, WAIT_READY)) { + printk(KERN_ERR "%s: drive not ready for command\n", drive->name); + return startstop; + } + if (!drive->special.all) { + if (rq->flags & (REQ_DRIVE_CMD | REQ_DRIVE_TASK)) + return execute_drive_cmd(drive, rq); + else if (rq->flags & REQ_DRIVE_TASKFILE) + return execute_drive_cmd(drive, rq); + + if (drive->driver != NULL) { + return (DRIVER(drive)->do_request(drive, rq, block)); + } + printk(KERN_ERR "%s: media type %d not supported\n", drive->name, drive->media); + goto kill_rq; + } + return do_special(drive); +kill_rq: + if (drive->driver != NULL) + DRIVER(drive)->end_request(drive, 0, 0); + else + ide_end_request(drive, 0, 0); + return ide_stopped; +} + +EXPORT_SYMBOL(start_request); + +/** + * restart_request - reissue an IDE request + * @drive: drive for request + * @rq: request to reissue + * + * Reissue a request. See start_request for details and for + * FIXME + */ + +int restart_request (ide_drive_t *drive, struct request *rq) +{ + (void) start_request(drive, rq); + return 0; +} + +EXPORT_SYMBOL(restart_request); + +/** + * ide_stall_queue - pause an IDE device + * @drive: drive to stall + * @timeout: time to stall for (jiffies) + * + * ide_stall_queue() can be used by a drive to give excess bandwidth back + * to the hwgroup by sleeping for timeout jiffies. + */ + +void ide_stall_queue (ide_drive_t *drive, unsigned long timeout) +{ + if (timeout > WAIT_WORSTCASE) + timeout = WAIT_WORSTCASE; + drive->sleep = timeout + jiffies; +} + +EXPORT_SYMBOL(ide_stall_queue); + +#define WAKEUP(drive) ((drive)->service_start + 2 * (drive)->service_time) + +/** + * choose_drive - select a drive to service + * @hwgroup: hardware group to select on + * + * choose_drive() selects the next drive which will be serviced. + * This is neccessary because the IDE layer can't issue commands + * to both drives on the same cable, unlike SCSI. + */ + +static inline ide_drive_t *choose_drive (ide_hwgroup_t *hwgroup) +{ + ide_drive_t *drive, *best; + +repeat: + best = NULL; + drive = hwgroup->drive; + do { + if (!blk_queue_empty(&drive->queue) && (!drive->sleep || time_after_eq(jiffies, drive->sleep))) { + if (!best + || (drive->sleep && (!best->sleep || 0 < (signed long)(best->sleep - drive->sleep))) + || (!best->sleep && 0 < (signed long)(WAKEUP(best) - WAKEUP(drive)))) + { + if (!blk_queue_plugged(&drive->queue)) + best = drive; + } + } + } while ((drive = drive->next) != hwgroup->drive); + if (best && best->nice1 && !best->sleep && best != hwgroup->drive && best->service_time > WAIT_MIN_SLEEP) { + long t = (signed long)(WAKEUP(best) - jiffies); + if (t >= WAIT_MIN_SLEEP) { + /* + * We *may* have some time to spare, but first let's see if + * someone can potentially benefit from our nice mood today.. + */ + drive = best->next; + do { + if (!drive->sleep + /* FIXME: use time_before */ + && 0 < (signed long)(WAKEUP(drive) - (jiffies - best->service_time)) + && 0 < (signed long)((jiffies + t) - WAKEUP(drive))) + { + ide_stall_queue(best, IDE_MIN(t, 10 * WAIT_MIN_SLEEP)); + goto repeat; + } + } while ((drive = drive->next) != best); + } + } + return best; +} + +/* + * Issue a new request to a drive from hwgroup + * Caller must have already done spin_lock_irqsave(&ide_lock, ..); + * + * A hwgroup is a serialized group of IDE interfaces. Usually there is + * exactly one hwif (interface) per hwgroup, but buggy controllers (eg. CMD640) + * may have both interfaces in a single hwgroup to "serialize" access. + * Or possibly multiple ISA interfaces can share a common IRQ by being grouped + * together into one hwgroup for serialized access. + * + * Note also that several hwgroups can end up sharing a single IRQ, + * possibly along with many other devices. This is especially common in + * PCI-based systems with off-board IDE controller cards. + * + * The IDE driver uses the single global ide_lock spinlock to protect + * access to the request queues, and to protect the hwgroup->busy flag. + * + * The first thread into the driver for a particular hwgroup sets the + * hwgroup->busy flag to indicate that this hwgroup is now active, + * and then initiates processing of the top request from the request queue. + * + * Other threads attempting entry notice the busy setting, and will simply + * queue their new requests and exit immediately. Note that hwgroup->busy + * remains set even when the driver is merely awaiting the next interrupt. + * Thus, the meaning is "this hwgroup is busy processing a request". + * + * When processing of a request completes, the completing thread or IRQ-handler + * will start the next request from the queue. If no more work remains, + * the driver will clear the hwgroup->busy flag and exit. + * + * The ide_lock (spinlock) is used to protect all access to the + * hwgroup->busy flag, but is otherwise not needed for most processing in + * the driver. This makes the driver much more friendlier to shared IRQs + * than previous designs, while remaining 100% (?) SMP safe and capable. + */ +/* --BenH: made non-static as ide-pmac.c uses it to kick the hwgroup back + * into life on wakeup from machine sleep. + */ +void ide_do_request (ide_hwgroup_t *hwgroup, int masked_irq) +{ + ide_drive_t *drive; + ide_hwif_t *hwif; + struct request *rq; + ide_startstop_t startstop; + + /* for atari only: POSSIBLY BROKEN HERE(?) */ + ide_get_lock(&ide_intr_lock, ide_intr, hwgroup); + + /* necessary paranoia: ensure IRQs are masked on local CPU */ + local_irq_disable(); + + while (!hwgroup->busy) { + hwgroup->busy = 1; + drive = choose_drive(hwgroup); + if (drive == NULL) { + unsigned long sleep = 0; + hwgroup->rq = NULL; + drive = hwgroup->drive; + do { + if (drive->sleep && (!sleep || 0 < (signed long)(sleep - drive->sleep))) + sleep = drive->sleep; + } while ((drive = drive->next) != hwgroup->drive); + if (sleep) { + /* + * Take a short snooze, and then wake up this hwgroup again. + * This gives other hwgroups on the same a chance to + * play fairly with us, just in case there are big differences + * in relative throughputs.. don't want to hog the cpu too much. + */ + if (time_before(sleep, jiffies + WAIT_MIN_SLEEP)) + sleep = jiffies + WAIT_MIN_SLEEP; +#if 1 + if (timer_pending(&hwgroup->timer)) + printk(KERN_CRIT "ide_set_handler: timer already active\n"); +#endif + /* so that ide_timer_expiry knows what to do */ + hwgroup->sleeping = 1; + mod_timer(&hwgroup->timer, sleep); + /* we purposely leave hwgroup->busy==1 + * while sleeping */ + } else { + /* Ugly, but how can we sleep for the lock + * otherwise? perhaps from tq_disk? + */ + + /* for atari only */ + ide_release_lock(&ide_intr_lock); + hwgroup->busy = 0; + } + + /* no more work for this hwgroup (for now) */ + return; + } + hwif = HWIF(drive); + if (hwgroup->hwif->sharing_irq && + hwif != hwgroup->hwif && + hwif->io_ports[IDE_CONTROL_OFFSET]) { + /* set nIEN for previous hwif */ + SELECT_INTERRUPT(drive); + } + hwgroup->hwif = hwif; + hwgroup->drive = drive; + drive->sleep = 0; + drive->service_start = jiffies; + +queue_next: + if (!ata_can_queue(drive)) { + if (!ata_pending_commands(drive)) + hwgroup->busy = 0; + + break; + } + + if (blk_queue_plugged(&drive->queue)) { + if (drive->using_tcq) + break; + + printk(KERN_ERR "ide: huh? queue was plugged!\n"); + break; + } + + /* + * we know that the queue isn't empty, but this can happen + * if the q->prep_rq_fn() decides to kill a request + */ + rq = elv_next_request(&drive->queue); + if (!rq) { + hwgroup->busy = !!ata_pending_commands(drive); + break; + } + + if (!rq->bio && ata_pending_commands(drive)) + break; + + hwgroup->rq = rq; + + /* + * Some systems have trouble with IDE IRQs arriving while + * the driver is still setting things up. So, here we disable + * the IRQ used by this interface while the request is being started. + * This may look bad at first, but pretty much the same thing + * happens anyway when any interrupt comes in, IDE or otherwise + * -- the kernel masks the IRQ while it is being handled. + */ + if (masked_irq && hwif->irq != masked_irq) + disable_irq_nosync(hwif->irq); + spin_unlock(&ide_lock); + local_irq_enable(); + /* allow other IRQs while we start this request */ + startstop = start_request(drive, rq); + spin_lock_irq(&ide_lock); + if (masked_irq && hwif->irq != masked_irq) + enable_irq(hwif->irq); + if (startstop == ide_released) + goto queue_next; + if (startstop == ide_stopped) + hwgroup->busy = 0; + } +} + +EXPORT_SYMBOL(ide_do_request); + +/* + * Passes the stuff to ide_do_request + */ +void do_ide_request(request_queue_t *q) +{ + ide_do_request(q->queuedata, 0); +} + +/* + * un-busy the hwgroup etc, and clear any pending DMA status. we want to + * retry the current request in pio mode instead of risking tossing it + * all away + */ +void ide_dma_timeout_retry(ide_drive_t *drive) +{ + ide_hwif_t *hwif = HWIF(drive); + struct request *rq; + + /* + * end current dma transaction + */ + (void) hwif->ide_dma_end(drive); + + /* + * complain a little, later we might remove some of this verbosity + */ + printk(KERN_WARNING "%s: timeout waiting for DMA\n", drive->name); + (void) hwif->ide_dma_timeout(drive); + + /* + * disable dma for now, but remember that we did so because of + * a timeout -- we'll reenable after we finish this next request + * (or rather the first chunk of it) in pio. + */ + drive->retry_pio++; + drive->state = DMA_PIO_RETRY; + (void) hwif->ide_dma_off_quietly(drive); + + /* + * un-busy drive etc (hwgroup->busy is cleared on return) and + * make sure request is sane + */ + rq = HWGROUP(drive)->rq; + HWGROUP(drive)->rq = NULL; + + rq->errors = 0; + rq->sector = rq->bio->bi_sector; + rq->current_nr_sectors = bio_iovec(rq->bio)->bv_len >> 9; + rq->hard_cur_sectors = rq->current_nr_sectors; + if (rq->bio) + rq->buffer = NULL; +} + +EXPORT_SYMBOL(ide_dma_timeout_retry); + +/** + * ide_timer_expiry - handle lack of an IDE interrupt + * @data: timer callback magic (hwgroup) + * + * An IDE command has timed out before the expected drive return + * occurred. At this point we attempt to clean up the current + * mess. If the current handler includes an expiry handler then + * we invoke the expiry handler, and providing it is happy the + * work is done. If that fails we apply generic recovery rules + * invoking the handler and checking the drive DMA status. We + * have an excessively incestuous relationship with the DMA + * logic that wants cleaning up. + */ + +void ide_timer_expiry (unsigned long data) +{ + ide_hwgroup_t *hwgroup = (ide_hwgroup_t *) data; + ide_handler_t *handler; + ide_expiry_t *expiry; + unsigned long flags; + unsigned long wait; + + spin_lock_irqsave(&ide_lock, flags); + del_timer(&hwgroup->timer); + + if ((handler = hwgroup->handler) == NULL) { + /* + * Either a marginal timeout occurred + * (got the interrupt just as timer expired), + * or we were "sleeping" to give other devices a chance. + * Either way, we don't really want to complain about anything. + */ + if (hwgroup->sleeping) { + hwgroup->sleeping = 0; + hwgroup->busy = 0; + } + } else { + ide_drive_t *drive = hwgroup->drive; + if (!drive) { + printk(KERN_ERR "ide_timer_expiry: hwgroup->drive was NULL\n"); + hwgroup->handler = NULL; + } else { + ide_hwif_t *hwif; + ide_startstop_t startstop = ide_stopped; + if (!hwgroup->busy) { + hwgroup->busy = 1; /* paranoia */ + printk(KERN_ERR "%s: ide_timer_expiry: hwgroup->busy was 0 ??\n", drive->name); + } + if ((expiry = hwgroup->expiry) != NULL) { + /* continue */ + if ((wait = expiry(drive)) != 0) { + /* reset timer */ + hwgroup->timer.expires = jiffies + wait; + add_timer(&hwgroup->timer); + spin_unlock_irqrestore(&ide_lock, flags); + return; + } + } + hwgroup->handler = NULL; + /* + * We need to simulate a real interrupt when invoking + * the handler() function, which means we need to + * globally mask the specific IRQ: + */ + spin_unlock(&ide_lock); + hwif = HWIF(drive); +#if DISABLE_IRQ_NOSYNC + disable_irq_nosync(hwif->irq); +#else + /* disable_irq_nosync ?? */ + disable_irq(hwif->irq); +#endif /* DISABLE_IRQ_NOSYNC */ + /* local CPU only, + * as if we were handling an interrupt */ + local_irq_disable(); + if (hwgroup->poll_timeout != 0) { + startstop = handler(drive); + } else if (drive_is_ready(drive)) { + if (drive->waiting_for_dma) + (void) hwgroup->hwif->ide_dma_lostirq(drive); + (void)ide_ack_intr(hwif); + printk(KERN_WARNING "%s: lost interrupt\n", drive->name); + startstop = handler(drive); + } else { + if (drive->waiting_for_dma) { + startstop = ide_stopped; + ide_dma_timeout_retry(drive); + } else + startstop = DRIVER(drive)->error(drive, "irq timeout", hwif->INB(IDE_STATUS_REG)); + } + set_recovery_timer(hwif); + drive->service_time = jiffies - drive->service_start; + enable_irq(hwif->irq); + spin_lock_irq(&ide_lock); + if (startstop == ide_stopped) + hwgroup->busy = 0; + } + } + ide_do_request(hwgroup, 0); + spin_unlock_irqrestore(&ide_lock, flags); +} + +EXPORT_SYMBOL(ide_timer_expiry); + +/** + * unexpected_intr - handle an unexpected IDE interrupt + * @irq: interrupt line + * @hwgroup: hwgroup being processed + * + * There's nothing really useful we can do with an unexpected interrupt, + * other than reading the status register (to clear it), and logging it. + * There should be no way that an irq can happen before we're ready for it, + * so we needn't worry much about losing an "important" interrupt here. + * + * On laptops (and "green" PCs), an unexpected interrupt occurs whenever + * the drive enters "idle", "standby", or "sleep" mode, so if the status + * looks "good", we just ignore the interrupt completely. + * + * This routine assumes __cli() is in effect when called. + * + * If an unexpected interrupt happens on irq15 while we are handling irq14 + * and if the two interfaces are "serialized" (CMD640), then it looks like + * we could screw up by interfering with a new request being set up for + * irq15. + * + * In reality, this is a non-issue. The new command is not sent unless + * the drive is ready to accept one, in which case we know the drive is + * not trying to interrupt us. And ide_set_handler() is always invoked + * before completing the issuance of any new drive command, so we will not + * be accidentally invoked as a result of any valid command completion + * interrupt. + * + * Note that we must walk the entire hwgroup here. We know which hwif + * is doing the current command, but we don't know which hwif burped + * mysteriously. + */ + +static void unexpected_intr (int irq, ide_hwgroup_t *hwgroup) +{ + u8 stat; + ide_hwif_t *hwif = hwgroup->hwif; + + /* + * handle the unexpected interrupt + */ + do { + if (hwif->irq == irq) { + stat = hwif->INB(hwif->io_ports[IDE_STATUS_OFFSET]); + if (!OK_STAT(stat, READY_STAT, BAD_STAT)) { + /* Try to not flood the console with msgs */ + static unsigned long last_msgtime, count; + ++count; + if (time_after(jiffies, last_msgtime + HZ)) { + last_msgtime = jiffies; + printk(KERN_ERR "%s%s: unexpected interrupt, " + "status=0x%02x, count=%ld\n", + hwif->name, + (hwif->next==hwgroup->hwif) ? "" : "(?)", stat, count); + } + } + } + } while ((hwif = hwif->next) != hwgroup->hwif); +} + +/** + * ide_intr - default IDE interrupt handler + * @irq: interrupt number + * @dev_id: hwif group + * @regs: unused weirdness from the kernel irq layer + * + * This is the default IRQ handler for the IDE layer. You should + * not need to override it. If you do be aware it is subtle in + * places + * + * hwgroup->hwif is the interface in the group currently performing + * a command. hwgroup->drive is the drive and hwgroup->handler is + * the IRQ handler to call. As we issue a command the handlers + * step through multiple states, reassigning the handler to the + * next step in the process. Unlike a smart SCSI controller IDE + * expects the main processor to sequence the various transfer + * stages. We also manage a poll timer to catch up with most + * timeout situations. There are still a few where the handlers + * don't ever decide to give up. + * + * The handler eventually returns ide_stopped to indicate the + * request completed. At this point we issue the next request + * on the hwgroup and the process begins again. + */ + +void ide_intr (int irq, void *dev_id, struct pt_regs *regs) +{ + unsigned long flags; + ide_hwgroup_t *hwgroup = (ide_hwgroup_t *)dev_id; + ide_hwif_t *hwif; + ide_drive_t *drive; + ide_handler_t *handler; + ide_startstop_t startstop; + + spin_lock_irqsave(&ide_lock, flags); + hwif = hwgroup->hwif; + + if (!ide_ack_intr(hwif)) { + spin_unlock_irqrestore(&ide_lock, flags); + return; + } + + if ((handler = hwgroup->handler) == NULL || + hwgroup->poll_timeout != 0) { + /* + * Not expecting an interrupt from this drive. + * That means this could be: + * (1) an interrupt from another PCI device + * sharing the same PCI INT# as us. + * or (2) a drive just entered sleep or standby mode, + * and is interrupting to let us know. + * or (3) a spurious interrupt of unknown origin. + * + * For PCI, we cannot tell the difference, + * so in that case we just ignore it and hope it goes away. + * + * FIXME: unexpected_intr should be hwif-> then we can + * remove all the ifdef PCI crap + */ +#ifdef CONFIG_BLK_DEV_IDEPCI + if (hwif->pci_dev && !hwif->pci_dev->vendor) +#endif /* CONFIG_BLK_DEV_IDEPCI */ + { + /* + * Probably not a shared PCI interrupt, + * so we can safely try to do something about it: + */ + unexpected_intr(irq, hwgroup); +#ifdef CONFIG_BLK_DEV_IDEPCI + } else { + /* + * Whack the status register, just in case + * we have a leftover pending IRQ. + */ + (void) hwif->INB(hwif->io_ports[IDE_STATUS_OFFSET]); +#endif /* CONFIG_BLK_DEV_IDEPCI */ + } + spin_unlock_irqrestore(&ide_lock, flags); + return; + } + drive = hwgroup->drive; + if (!drive) { + /* + * This should NEVER happen, and there isn't much + * we could do about it here. + * + * [Note - this can occur if the drive is hot unplugged] + */ + spin_unlock_irqrestore(&ide_lock, flags); + return; + } + if (!drive_is_ready(drive)) { + /* + * This happens regularly when we share a PCI IRQ with + * another device. Unfortunately, it can also happen + * with some buggy drives that trigger the IRQ before + * their status register is up to date. Hopefully we have + * enough advance overhead that the latter isn't a problem. + */ + spin_unlock_irqrestore(&ide_lock, flags); + return; + } + if (!hwgroup->busy) { + hwgroup->busy = 1; /* paranoia */ + printk(KERN_ERR "%s: ide_intr: hwgroup->busy was 0 ??\n", drive->name); + } + hwgroup->handler = NULL; + del_timer(&hwgroup->timer); + spin_unlock(&ide_lock); + + if (drive->unmask) + local_irq_enable(); + /* service this interrupt, may set handler for next interrupt */ + startstop = handler(drive); + spin_lock_irq(&ide_lock); + + /* + * Note that handler() may have set things up for another + * interrupt to occur soon, but it cannot happen until + * we exit from this routine, because it will be the + * same irq as is currently being serviced here, and Linux + * won't allow another of the same (on any CPU) until we return. + */ + set_recovery_timer(HWIF(drive)); + drive->service_time = jiffies - drive->service_start; + if (startstop == ide_stopped) { + if (hwgroup->handler == NULL) { /* paranoia */ + hwgroup->busy = 0; + ide_do_request(hwgroup, hwif->irq); + } else { + printk(KERN_ERR "%s: ide_intr: huh? expected NULL handler " + "on exit\n", drive->name); + } + } + spin_unlock_irqrestore(&ide_lock, flags); +} + +EXPORT_SYMBOL(ide_intr); + +/** + * ide_init_drive_cmd - initialize a drive command request + * @rq: request object + * + * Initialize a request before we fill it in and send it down to + * ide_do_drive_cmd. Commands must be set up by this function. Right + * now it doesn't do a lot, but if that changes abusers will have a + * nasty suprise. + */ + +void ide_init_drive_cmd (struct request *rq) +{ + memset(rq, 0, sizeof(*rq)); + rq->flags = REQ_DRIVE_CMD; +} + +EXPORT_SYMBOL(ide_init_drive_cmd); + +/** + * ide_do_drive_cmd - issue IDE special command + * @drive: device to issue command + * @rq: request to issue + * @action: action for processing + * + * This function issues a special IDE device request + * onto the request queue. + * + * If action is ide_wait, then the rq is queued at the end of the + * request queue, and the function sleeps until it has been processed. + * This is for use when invoked from an ioctl handler. + * + * If action is ide_preempt, then the rq is queued at the head of + * the request queue, displacing the currently-being-processed + * request and this function returns immediately without waiting + * for the new rq to be completed. This is VERY DANGEROUS, and is + * intended for careful use by the ATAPI tape/cdrom driver code. + * + * If action is ide_next, then the rq is queued immediately after + * the currently-being-processed-request (if any), and the function + * returns without waiting for the new rq to be completed. As above, + * This is VERY DANGEROUS, and is intended for careful use by the + * ATAPI tape/cdrom driver code. + * + * If action is ide_end, then the rq is queued at the end of the + * request queue, and the function returns immediately without waiting + * for the new rq to be completed. This is again intended for careful + * use by the ATAPI tape/cdrom driver code. + */ + +int ide_do_drive_cmd (ide_drive_t *drive, struct request *rq, ide_action_t action) +{ + unsigned long flags; + ide_hwgroup_t *hwgroup = HWGROUP(drive); + DECLARE_COMPLETION(wait); + int insert_end = 1, err; + +#ifdef CONFIG_BLK_DEV_PDC4030 + /* + * FIXME: there should be a drive or hwif->special + * handler that points here by default, not hacks + * in the ide-io.c code + */ + if (HWIF(drive)->chipset == ide_pdc4030 && rq->buffer != NULL) + return -ENOSYS; /* special drive cmds not supported */ +#endif + rq->errors = 0; + rq->rq_status = RQ_ACTIVE; + + rq->rq_disk = drive->disk; + + /* + * we need to hold an extra reference to request for safe inspection + * after completion + */ + if (action == ide_wait) { + rq->ref_count++; + rq->waiting = &wait; + } + + spin_lock_irqsave(&ide_lock, flags); + if (action == ide_preempt) { + hwgroup->rq = NULL; + insert_end = 0; + } + __elv_add_request(&drive->queue, rq, insert_end, 0); + ide_do_request(hwgroup, 0); + spin_unlock_irqrestore(&ide_lock, flags); + + err = 0; + if (action == ide_wait) { + wait_for_completion(&wait); + if (rq->errors) + err = -EIO; + + blk_put_request(rq); + } + + return err; +} + +EXPORT_SYMBOL(ide_do_drive_cmd); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/drivers/ide/ide-iops.c linux.2.5.47-ac6/drivers/ide/ide-iops.c --- linux.2.5.47/drivers/ide/ide-iops.c 2002-10-31 14:57:17.000000000 +0000 +++ linux.2.5.47-ac6/drivers/ide/ide-iops.c 2002-11-13 15:06:55.000000000 +0000 @@ -57,14 +57,14 @@ insl(port, addr, count); } -static void ide_outb (u8 addr, ide_ioreg_t port) +static void ide_outb (u8 value, ide_ioreg_t port) { - outb(addr, port); + outb(value, port); } -static void ide_outw (u16 addr, ide_ioreg_t port) +static void ide_outw (u16 value, ide_ioreg_t port) { - outw(addr, port); + outw(value, port); } static void ide_outsw (ide_ioreg_t port, void *addr, u32 count) @@ -72,9 +72,9 @@ outsw(port, addr, count); } -static void ide_outl (u32 addr, ide_ioreg_t port) +static void ide_outl (u32 value, ide_ioreg_t port) { - outl(addr, port); + outl(value, port); } static void ide_outsl (ide_ioreg_t port, void *addr, u32 count) @@ -819,9 +819,9 @@ // while (HWGROUP(drive)->busy) // ide_delay_50ms(); -#if defined(CONFIG_BLK_DEV_IDEDMA) && !defined(CONFIG_DMA_NONPCI) +#if !defined(CONFIG_DMA_NONPCI) hwif->ide_dma_host_off(drive); -#endif /* (CONFIG_BLK_DEV_IDEDMA) && !(CONFIG_DMA_NONPCI) */ +#endif /* !(CONFIG_DMA_NONPCI) */ /* * Don't use ide_wait_cmd here - it will @@ -887,12 +887,12 @@ drive->id->dma_mword &= ~0x0F00; drive->id->dma_1word &= ~0x0F00; -#if defined(CONFIG_BLK_DEV_IDEDMA) && !defined(CONFIG_DMA_NONPCI) +#if !defined(CONFIG_DMA_NONPCI) if (speed >= XFER_SW_DMA_0) hwif->ide_dma_host_on(drive); else hwif->ide_dma_off(drive); -#endif /* (CONFIG_BLK_DEV_IDEDMA) && !(CONFIG_DMA_NONPCI) */ +#endif /* !(CONFIG_DMA_NONPCI) */ switch(speed) { case XFER_UDMA_7: drive->id->dma_ultra |= 0x8080; break; @@ -1057,8 +1057,7 @@ { if (drive->crc_count) { (void) HWIF(drive)->ide_dma_off_quietly(drive); - if ((HWIF(drive)->speedproc) != NULL) - HWIF(drive)->speedproc(drive, ide_auto_reduce_xfer(drive)); + ide_set_xfer_rate(drive, ide_auto_reduce_xfer(drive)); if (drive->current_speed >= XFER_SW_DMA_0) (void) HWIF(drive)->ide_dma_on(drive); } else { diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/drivers/ide/ide-lib.c linux.2.5.47-ac6/drivers/ide/ide-lib.c --- linux.2.5.47/drivers/ide/ide-lib.c 2002-11-05 13:54:43.000000000 +0000 +++ linux.2.5.47-ac6/drivers/ide/ide-lib.c 2002-11-14 17:12:22.000000000 +0000 @@ -300,7 +300,7 @@ } /** - * ide_get_best_pio_mode - get PIO mode fro drive + * ide_get_best_pio_mode - get PIO mode from drive * @driver: drive to consider * @mode_wanted: preferred mode * @max_mode: highest allowed @@ -387,6 +387,15 @@ EXPORT_SYMBOL_GPL(ide_get_best_pio_mode); +/** + * ide_toggle_bounce - handle bounce buffering + * @drive: drive to update + * @on: on/off boolean + * + * Enable or disable bounce buffering for the device. Drives move + * between PIO and DMA and that changes the rules we need. + */ + void ide_toggle_bounce(ide_drive_t *drive, int on) { u64 addr = BLK_BOUNCE_HIGH; /* dma64_addr_t */ @@ -402,3 +411,28 @@ } EXPORT_SYMBOL(ide_toggle_bounce); + +/** + * ide_set_xfer_rate - set transfer rate + * @drive: drive to set + * @speed: speed to attempt to set + * + * General helper for setting the speed of an IDE device. This + * function knows about user enforced limits from the configuration + * which speedproc() does not. High level drivers should never + * invoke speedproc() directly. + */ + +int ide_set_xfer_rate(ide_drive_t *drive, u8 rate) +{ +#ifndef CONFIG_BLK_DEV_IDEDMA + rate = min(rate, (u8) XFER_PIO_4); +#endif + if(HWIF(drive)->speedproc) + return HWIF(drive)->speedproc(drive, rate); + else + return -1; +} + +EXPORT_SYMBOL_GPL(ide_set_xfer_rate); + diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/drivers/ide/ide-probe.c linux.2.5.47-ac6/drivers/ide/ide-probe.c --- linux.2.5.47/drivers/ide/ide-probe.c 2002-11-11 16:39:10.000000000 +0000 +++ linux.2.5.47-ac6/drivers/ide/ide-probe.c 2002-11-18 18:31:45.000000000 +0000 @@ -144,6 +144,7 @@ id->model[sizeof(id->model)-1] = '\0'; printk("%s: %s, ", drive->name, id->model); drive->present = 1; + drive->dead = 0; /* * Check for an ATAPI device @@ -546,8 +547,24 @@ return 1; } -#define hwif_check_region(addr, num) \ - ((hwif->mmio) ? check_mem_region((addr),(num)) : check_region((addr),(num))) +static int hwif_check_region(ide_hwif_t *hwif, unsigned long addr, int num) +{ + int err; + + if(hwif->mmio) + err = check_mem_region(addr, num); + else + err = check_region(addr, num); + + if(err) + { + printk("%s: %s resource 0x%lX-0x%lX not free.\n", + hwif->name, hwif->mmio?"MMIO":"I/O", addr, addr+num-1); + mdelay(2000); + } + return err; +} + static int hwif_check_regions (ide_hwif_t *hwif) { @@ -556,14 +573,14 @@ if (hwif->mmio == 2) return 0; - addr_errs = hwif_check_region(hwif->io_ports[IDE_DATA_OFFSET], 1); + addr_errs = hwif_check_region(hwif, hwif->io_ports[IDE_DATA_OFFSET], 1); for (i = IDE_ERROR_OFFSET; i <= IDE_STATUS_OFFSET; i++) - addr_errs += hwif_check_region(hwif->io_ports[i], 1); + addr_errs += hwif_check_region(hwif, hwif->io_ports[i], 1); if (hwif->io_ports[IDE_CONTROL_OFFSET]) - addr_errs += hwif_check_region(hwif->io_ports[IDE_CONTROL_OFFSET], 1); + addr_errs += hwif_check_region(hwif, hwif->io_ports[IDE_CONTROL_OFFSET], 1); #if defined(CONFIG_AMIGA) || defined(CONFIG_MAC) if (hwif->io_ports[IDE_IRQ_OFFSET]) - addr_errs += hwif_check_region(hwif->io_ports[IDE_IRQ_OFFSET], 1); + addr_errs += hwif_check_region(hwif, hwif->io_ports[IDE_IRQ_OFFSET], 1); #endif /* (CONFIG_AMIGA) || (CONFIG_MAC) */ /* If any errors are return, we drop the hwif interface. */ hwif->straight8 = 0; @@ -629,7 +646,7 @@ } #endif - if ((hwif->chipset != ide_4drives || !hwif->mate->present) && + if ((hwif->chipset != ide_4drives || !hwif->mate || !hwif->mate->present) && #if CONFIG_BLK_DEV_PDC4030 (hwif->chipset != ide_pdc4030 || hwif->channel == 0) && #endif /* CONFIG_BLK_DEV_PDC4030 */ @@ -1059,6 +1076,7 @@ "%s","IDE Drive"); drive->gendev.parent = &hwif->gendev; drive->gendev.bus = &ide_bus_type; + drive->gendev.driver_data = drive; sprintf (name, "host%d/bus%d/target%d/lun%d", (hwif->channel && hwif->mate) ? hwif->mate->index : hwif->index, diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/drivers/ide/ide-tape.c linux.2.5.47-ac6/drivers/ide/ide-tape.c --- linux.2.5.47/drivers/ide/ide-tape.c 2002-11-05 13:54:43.000000000 +0000 +++ linux.2.5.47-ac6/drivers/ide/ide-tape.c 2002-11-13 15:00:24.000000000 +0000 @@ -1450,7 +1450,6 @@ } } -#ifdef CONFIG_BLK_DEV_IDEDMA static void idetape_update_buffers (idetape_pc_t *pc) { struct bio *bio = pc->bio; @@ -1475,7 +1474,6 @@ } pc->bio = bio; } -#endif /* CONFIG_BLK_DEV_IDEDMA */ /* * idetape_next_pc_storage returns a pointer to a place in which we can @@ -1580,7 +1578,6 @@ ide_stall_queue(drive, HZ / 2); return; } -#ifdef CONFIG_BLK_DEV_IDEDMA /* * Correct pc->actually_transferred by asking the tape. @@ -1589,7 +1586,7 @@ pc->actually_transferred = pc->request_transfer - tape->tape_block_size * ntohl(get_unaligned(&result->information)); idetape_update_buffers(pc); } -#endif /* CONFIG_BLK_DEV_IDEDMA */ + if (pc->c[0] == IDETAPE_READ_CMD && result->filemark) { pc->error = IDETAPE_ERROR_FILEMARK; set_bit(PC_ABORT, &pc->flags); @@ -1982,7 +1979,6 @@ /* Clear the interrupt */ status.all = HWIF(drive)->INB(IDE_STATUS_REG); -#ifdef CONFIG_BLK_DEV_IDEDMA if (test_bit(PC_DMA_IN_PROGRESS, &pc->flags)) { if (HWIF(drive)->ide_dma_end(drive)) { /* @@ -2006,7 +2002,6 @@ printk(KERN_INFO "ide-tape: DMA finished\n"); #endif /* IDETAPE_DEBUG_LOG */ } -#endif /* CONFIG_BLK_DEV_IDEDMA */ /* No more interrupts */ if (!status.b.drq) { @@ -2061,7 +2056,6 @@ tape->failed_pc = NULL; return pc->callback(drive); /* Command finished - Call the callback function */ } -#ifdef CONFIG_BLK_DEV_IDEDMA if (test_and_clear_bit(PC_DMA_IN_PROGRESS, &pc->flags)) { printk(KERN_ERR "ide-tape: The tape wants to issue more " "interrupts in DMA mode\n"); @@ -2069,7 +2063,6 @@ (void) HWIF(drive)->ide_dma_off(drive); return ide_do_reset(drive); } -#endif /* CONFIG_BLK_DEV_IDEDMA */ bcount.b.high = IN_BYTE(IDE_BCOUNTH_REG); /* Get the number of bytes to transfer */ bcount.b.low = IN_BYTE(IDE_BCOUNTL_REG); /* on this interrupt */ ireason.all = IN_BYTE(IDE_IREASON_REG); @@ -2264,7 +2257,6 @@ pc->current_position = pc->buffer; bcount.all = pc->request_transfer; /* Request to transfer the entire buffer at once */ -#ifdef CONFIG_BLK_DEV_IDEDMA if (test_and_clear_bit(PC_DMA_ERROR, &pc->flags)) { printk(KERN_WARNING "ide-tape: DMA disabled, " "reverting to PIO\n"); @@ -2276,7 +2268,6 @@ else dma_ok = !HWIF(drive)->ide_dma_read(drive); } -#endif /* CONFIG_BLK_DEV_IDEDMA */ if (IDE_CONTROL_REG) OUT_BYTE(drive->ctl, IDE_CONTROL_REG); @@ -2284,12 +2275,10 @@ OUT_BYTE(bcount.b.high, IDE_BCOUNTH_REG); OUT_BYTE(bcount.b.low, IDE_BCOUNTL_REG); OUT_BYTE(drive->select.all, IDE_SELECT_REG); -#ifdef CONFIG_BLK_DEV_IDEDMA if (dma_ok) { /* Begin DMA, if necessary */ set_bit(PC_DMA_IN_PROGRESS, &pc->flags); (void) (HWIF(drive)->ide_dma_begin(drive)); } -#endif /* CONFIG_BLK_DEV_IDEDMA */ if (test_bit(IDETAPE_DRQ_INTERRUPT, &tape->flags)) { if (HWGROUP(drive)->handler != NULL) /* paranoia check */ BUG(); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/drivers/ide/ide-taskfile.c linux.2.5.47-ac6/drivers/ide/ide-taskfile.c --- linux.2.5.47/drivers/ide/ide-taskfile.c 2002-11-05 13:54:43.000000000 +0000 +++ linux.2.5.47-ac6/drivers/ide/ide-taskfile.c 2002-11-13 15:06:17.000000000 +0000 @@ -1068,7 +1068,6 @@ case DISABLE_SEAGATE: case EXABYTE_ENABLE_NEST: return &task_no_data_intr; -#ifdef CONFIG_BLK_DEV_IDEDMA case WIN_READDMA: // case WIN_READDMA_ONCE: case WIN_IDENTIFY_DMA: @@ -1080,7 +1079,6 @@ case WIN_WRITEDMA_QUEUED: case WIN_WRITEDMA_EXT: case WIN_WRITEDMA_QUEUED_EXT: -#endif case WIN_FORMAT: case WIN_INIT: case WIN_DEVICE_RESET: @@ -1164,7 +1162,6 @@ default: return IDE_DRIVE_TASK_NO_DATA; } -#ifdef CONFIG_BLK_DEV_IDEDMA case WIN_READDMA: // case WIN_READDMA_ONCE: case WIN_IDENTIFY_DMA: @@ -1178,7 +1175,6 @@ case WIN_WRITEDMA_EXT: case WIN_WRITEDMA_QUEUED_EXT: return IDE_DRIVE_TASK_RAW_WRITE; -#endif case WIN_SETFEATURES: switch(args->tfRegister[IDE_FEATURE_OFFSET]) { case SETFEATURES_EN_8BIT: @@ -1669,8 +1665,7 @@ if (!err && xfer_rate) { /* active-retuning-calls future */ - if ((HWIF(drive)->speedproc) != NULL) - HWIF(drive)->speedproc(drive, xfer_rate); + ide_set_xfer_rate(drive, xfer_rate); ide_driveid_update(drive); } abort: @@ -1724,8 +1719,7 @@ if (!err && xfer_rate) { /* active-retuning-calls future */ - if ((HWIF(drive)->speedproc) != NULL) - HWIF(drive)->speedproc(drive, xfer_rate); + ide_set_xfer_rate(driver, xfer_rate); ide_driveid_update(drive); } abort: diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/drivers/ide/ide-tcq.c linux.2.5.47-ac6/drivers/ide/ide-tcq.c --- linux.2.5.47/drivers/ide/ide-tcq.c 2002-10-31 14:57:17.000000000 +0000 +++ linux.2.5.47-ac6/drivers/ide/ide-tcq.c 2002-11-12 00:04:36.000000000 +0000 @@ -148,14 +148,14 @@ ide_hwif_t *hwif = HWIF(drive); unsigned long flags; - printk("ide_tcq_intr_timeout: timeout waiting for %s interrupt\n", hwgroup->rq ? "completion" : "service"); + printk(KERN_ERR "ide_tcq_intr_timeout: timeout waiting for %s interrupt\n", hwgroup->rq ? "completion" : "service"); spin_lock_irqsave(&ide_lock, flags); if (!hwgroup->busy) - printk("ide_tcq_intr_timeout: hwgroup not busy\n"); + printk(KERN_ERR "ide_tcq_intr_timeout: hwgroup not busy\n"); if (hwgroup->handler == NULL) - printk("ide_tcq_intr_timeout: missing isr!\n"); + printk(KERN_ERR "ide_tcq_intr_timeout: missing isr!\n"); hwgroup->busy = 1; spin_unlock_irqrestore(&ide_lock, flags); @@ -261,7 +261,7 @@ hwif->OUTB(WIN_QUEUED_SERVICE, IDE_COMMAND_REG); if (ide_tcq_wait_altstat(drive, &stat, BUSY_STAT)) { - printk("ide_service: BUSY clear took too long\n"); + printk(KERN_ERR "ide_service: BUSY clear took too long\n"); ide_dump_status(drive, "ide_service", stat); ide_tcq_invalidate_queue(drive); return ide_stopped; @@ -284,7 +284,7 @@ feat = hwif->INB(IDE_NSECTOR_REG); if (feat & REL) { HWGROUP(drive)->rq = NULL; - printk("%s: release in service\n", drive->name); + printk(KERN_ERR "%s: release in service\n", drive->name); return ide_stopped; } @@ -307,7 +307,7 @@ return HWIF(drive)->ide_dma_queued_start(drive); } - printk("ide_service: missing request for tag %d\n", tag); + printk(KERN_ERR "ide_service: missing request for tag %d\n", tag); spin_unlock_irqrestore(&ide_lock, flags); return ide_stopped; } @@ -347,14 +347,14 @@ * must be end of I/O, check status and complete as necessary */ if (unlikely(!OK_STAT(stat, READY_STAT, drive->bad_wstat | DRQ_STAT))) { - printk("ide_dmaq_intr: %s: error status %x\n",drive->name,stat); + printk(KERN_ERR "ide_dmaq_intr: %s: error status %x\n",drive->name,stat); ide_dump_status(drive, "ide_dmaq_complete", stat); ide_tcq_invalidate_queue(drive); return ide_stopped; } if (dma_stat) - printk("%s: bad DMA status (dma_stat=%x)\n", drive->name, dma_stat); + printk(KERN_WARNING "%s: bad DMA status (dma_stat=%x)\n", drive->name, dma_stat); TCQ_PRINTK("ide_dmaq_complete: ending %p, tag %d\n", rq, rq->tag); ide_end_request(drive, 1, rq->nr_sectors); @@ -465,7 +465,7 @@ args->command_type = ide_cmd_type_parser(args); if (ide_raw_taskfile(drive, args, NULL)) { - printk("%s: failed to enable write cache\n", drive->name); + printk(KERN_WARNING "%s: failed to enable write cache\n", drive->name); goto err; } @@ -479,7 +479,7 @@ args->command_type = ide_cmd_type_parser(args); if (ide_raw_taskfile(drive, args, NULL)) { - printk("%s: disabling release interrupt fail\n", drive->name); + printk(KERN_ERR "%s: disabling release interrupt fail\n", drive->name); goto err; } @@ -493,7 +493,7 @@ args->command_type = ide_cmd_type_parser(args); if (ide_raw_taskfile(drive, args, NULL)) { - printk("%s: enabling service interrupt fail\n", drive->name); + printk(KERN_ERR "%s: enabling service interrupt fail\n", drive->name); goto err; } #endif @@ -518,7 +518,7 @@ */ if (!on) { if (drive->using_tcq) - printk("%s: TCQ disabled\n", drive->name); + printk(KERN_INFO "%s: TCQ disabled\n", drive->name); drive->using_tcq = 0; return 0; @@ -541,7 +541,7 @@ ide_tcq_check_autopoll(drive); if (depth != drive->queue_depth) - printk("%s: tagged command queueing enabled, command queue depth %d\n", drive->name, drive->queue_depth); + printk(KERN_INFO "%s: tagged command queueing enabled, command queue depth %d\n", drive->name, drive->queue_depth); drive->using_tcq = 1; return 0; @@ -588,7 +588,7 @@ return 1; if (ata_pending_commands(drive)) { - printk("ide-tcq; can't toggle tcq feature on busy drive\n"); + printk(KERN_WARNING "ide-tcq; can't toggle tcq feature on busy drive\n"); return 1; } @@ -692,10 +692,10 @@ TCQ_PRINTK("ide_dma: setting up queued tag=%d\n", rq->tag); if (!hwgroup->busy) - printk("queued_rw: hwgroup not busy\n"); + printk(KERN_ERR "queued_rw: hwgroup not busy\n"); if (ide_tcq_wait_dataphase(drive)) { - printk("timeout waiting for data phase\n"); + printk(KERN_WARNING "timeout waiting for data phase\n"); return ide_stopped; } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/drivers/ide/Kconfig linux.2.5.47-ac6/drivers/ide/Kconfig --- linux.2.5.47/drivers/ide/Kconfig 2002-10-31 15:05:01.000000000 +0000 +++ linux.2.5.47-ac6/drivers/ide/Kconfig 2002-11-18 19:26:35.000000000 +0000 @@ -467,17 +467,25 @@ If you say Y here, you need to say Y to "Use DMA by default when available" as well. +config BLK_DEV_CS5520 + tristate "Cyrix CS5510/20 MediaGX chipset support (VERY EXPERIMENTAL)" + depends on BLK_DEV_IDEDMA_PCI && EXPERIMENTAL + help + Include support for PIO tuning an virtual DMA on the Cyrix MediaGX + 5510/5520 chipset. This will automatically be detected and + configured if found. + + It is safe to say Y to this question. + config BLK_DEV_CS5530 - tristate "Cyrix CS5530 MediaGX chipset support" - depends on BLK_DEV_IDEDMA_PCI + tristate "Cyrix/National Semiconductor CS5530 MediaGX chipset support" + depends on BLK_DEV_IDEDMA_PCIOA help Include support for UDMA on the Cyrix MediaGX 5530 chipset. This will automatically be detected and configured if found. It is safe to say Y to this question. - People with SCSI-only systems should say N here. If unsure, say Y. - config BLK_DEV_HPT34X tristate "HPT34X chipset support" depends on BLK_DEV_IDEDMA_PCI @@ -524,6 +532,13 @@ ide-probe at boot. It is reported to support DVD II drives, by the manufacturer. +config BLK_DEV_SC1200 + tristate "National SCx200 chipset support" + depends on BLK_DEV_IDEDMA_PCI + help + This driver adds support for the built in IDE on the National + SCx200 series of embedded x86 "Geode" systems + config BLK_DEV_PIIX tristate "Intel PIIXn chipsets support" depends on BLK_DEV_IDEDMA_PCI @@ -616,6 +631,9 @@ config BLK_DEV_SIIMAGE tristate "Silicon Image chipset support" depends on BLK_DEV_IDEDMA_PCI + help + This driver adds PIO/(U)DMA support for the SI CMD680 and SII + 3112 (Serial ATA) chips. config BLK_DEV_SIS5513 tristate "SiS5513 chipset support" diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/drivers/ide/legacy/ide-cs.c linux.2.5.47-ac6/drivers/ide/legacy/ide-cs.c --- linux.2.5.47/drivers/ide/legacy/ide-cs.c 2002-11-11 16:39:10.000000000 +0000 +++ linux.2.5.47-ac6/drivers/ide/legacy/ide-cs.c 2002-11-13 15:21:49.000000000 +0000 @@ -134,6 +134,7 @@ memset(info, 0, sizeof(*info)); link = &info->link; link->priv = info; + init_timer(&link->release); link->release.function = &ide_release; link->release.data = (u_long)link; link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO; @@ -410,6 +411,8 @@ DEBUG(0, "ide_release(0x%p)\n", link); if (info->ndev) { + /* FIXME: if this fails we need to queue the cleanup somehow + -- need to investigate the required PCMCIA magic */ ide_unregister(info->hd); /* deal with brain dead IDE resource management */ request_region(link->io.BasePort1, link->io.NumPorts1, diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/drivers/ide/Makefile linux.2.5.47-ac6/drivers/ide/Makefile --- linux.2.5.47/drivers/ide/Makefile 2002-10-31 14:57:17.000000000 +0000 +++ linux.2.5.47-ac6/drivers/ide/Makefile 2002-11-13 14:58:53.000000000 +0000 @@ -7,14 +7,14 @@ # Note : at this point, these files are compiled on all systems. # In the future, some of these should be built conditionally. # -export-objs := ide-iops.o ide-taskfile.o ide-proc.o ide.o ide-probe.o ide-dma.o ide-lib.o setup-pci.o +export-objs := ide-iops.o ide-taskfile.o ide-proc.o ide.o ide-probe.o ide-dma.o ide-lib.o setup-pci.o ide-io.o # First come modules that register themselves with the core obj-$(CONFIG_BLK_DEV_IDEPCI) += pci/ # Core IDE code - must come before legacy -obj-$(CONFIG_BLK_DEV_IDE) += ide-probe.o ide-geometry.o ide-iops.o ide-taskfile.o ide.o ide-lib.o +obj-$(CONFIG_BLK_DEV_IDE) += ide-io.o ide-probe.o ide-geometry.o ide-iops.o ide-taskfile.o ide.o ide-lib.o obj-$(CONFIG_BLK_DEV_IDEDISK) += ide-disk.o obj-$(CONFIG_BLK_DEV_IDECD) += ide-cd.o obj-$(CONFIG_BLK_DEV_IDETAPE) += ide-tape.o diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/drivers/ide/pci/aec62xx.c linux.2.5.47-ac6/drivers/ide/pci/aec62xx.c --- linux.2.5.47/drivers/ide/pci/aec62xx.c 2002-10-31 14:57:17.000000000 +0000 +++ linux.2.5.47-ac6/drivers/ide/pci/aec62xx.c 2002-11-13 14:37:13.000000000 +0000 @@ -292,7 +292,6 @@ } } -#ifdef CONFIG_BLK_DEV_IDEDMA static int config_chipset_for_dma (ide_drive_t *drive) { u8 speed = ide_dma_speed(drive, aec62xx_ratemask(drive)); @@ -303,7 +302,6 @@ (void) aec62xx_tune_chipset(drive, speed); return ide_dma_enable(drive); } -#endif /* CONFIG_BLK_DEV_IDEDMA */ static void aec62xx_tune_drive (ide_drive_t *drive, u8 pio) { @@ -321,7 +319,6 @@ (void) aec62xx_tune_chipset(drive, speed); } -#ifdef CONFIG_BLK_DEV_IDEDMA static int aec62xx_config_drive_xfer_rate (ide_drive_t *drive) { ide_hwif_t *hwif = HWIF(drive); @@ -405,7 +402,6 @@ #endif return 0; } -#endif /* CONFIG_BLK_DEV_IDEDMA */ static unsigned int __init init_chipset_aec62xx (struct pci_dev *dev, const char *name) { @@ -457,7 +453,6 @@ hwif->mwdma_mask = 0x07; hwif->swdma_mask = 0x07; -#ifdef CONFIG_BLK_DEV_IDEDMA hwif->ide_dma_check = &aec62xx_config_drive_xfer_rate; hwif->ide_dma_lostirq = &aec62xx_irq_timeout; hwif->ide_dma_timeout = &aec62xx_irq_timeout; @@ -465,7 +460,6 @@ hwif->autodma = 1; hwif->drives[0].autodma = hwif->autodma; hwif->drives[1].autodma = hwif->autodma; -#endif /* CONFIG_BLK_DEV_IDEDMA */ } static void __init init_dma_aec62xx (ide_hwif_t *hwif, unsigned long dmabase) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/drivers/ide/pci/aec62xx.h linux.2.5.47-ac6/drivers/ide/pci/aec62xx.h --- linux.2.5.47/drivers/ide/pci/aec62xx.h 2002-10-31 14:57:17.000000000 +0000 +++ linux.2.5.47-ac6/drivers/ide/pci/aec62xx.h 2002-11-13 14:37:27.000000000 +0000 @@ -14,7 +14,6 @@ }; struct chipset_bus_clock_list_entry aec6xxx_33_base [] = { -#ifdef CONFIG_BLK_DEV_IDEDMA { XFER_UDMA_6, 0x31, 0x07 }, { XFER_UDMA_5, 0x31, 0x06 }, { XFER_UDMA_4, 0x31, 0x05 }, @@ -26,7 +25,6 @@ { XFER_MW_DMA_2, 0x31, 0x00 }, { XFER_MW_DMA_1, 0x31, 0x00 }, { XFER_MW_DMA_0, 0x0a, 0x00 }, -#endif /* CONFIG_BLK_DEV_IDEDMA */ { XFER_PIO_4, 0x31, 0x00 }, { XFER_PIO_3, 0x33, 0x00 }, { XFER_PIO_2, 0x08, 0x00 }, @@ -36,7 +34,6 @@ }; struct chipset_bus_clock_list_entry aec6xxx_34_base [] = { -#ifdef CONFIG_BLK_DEV_IDEDMA { XFER_UDMA_6, 0x41, 0x06 }, { XFER_UDMA_5, 0x41, 0x05 }, { XFER_UDMA_4, 0x41, 0x04 }, @@ -48,7 +45,6 @@ { XFER_MW_DMA_2, 0x41, 0x00 }, { XFER_MW_DMA_1, 0x42, 0x00 }, { XFER_MW_DMA_0, 0x7a, 0x00 }, -#endif /* CONFIG_BLK_DEV_IDEDMA */ { XFER_PIO_4, 0x41, 0x00 }, { XFER_PIO_3, 0x43, 0x00 }, { XFER_PIO_2, 0x78, 0x00 }, diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/drivers/ide/pci/alim15x3.c linux.2.5.47-ac6/drivers/ide/pci/alim15x3.c --- linux.2.5.47/drivers/ide/pci/alim15x3.c 2002-10-31 14:57:17.000000000 +0000 +++ linux.2.5.47-ac6/drivers/ide/pci/alim15x3.c 2002-11-15 02:25:55.000000000 +0000 @@ -450,7 +450,6 @@ if (speed < XFER_SW_DMA_0) ali15x3_tune_drive(drive, speed); -#ifdef CONFIG_BLK_DEV_IDEDMA } else { pci_read_config_byte(dev, m5229_udma, &tmpbyte); tmpbyte &= (0x0f << ((1-unit) << 2)); @@ -464,12 +463,10 @@ tmpbyte |= 1; pci_write_config_byte(dev, 0x4b, tmpbyte); } -#endif /* CONFIG_BLK_DEV_IDEDMA */ } return (ide_config_drive_speed(drive, speed)); } -#ifdef CONFIG_BLK_DEV_IDEDMA /** * config_chipset_for_dma - set up DMA mode @@ -562,7 +559,6 @@ return 1; /* try PIO instead of DMA */ return __ide_dma_write(drive); } -#endif /* CONFIG_BLK_DEV_IDEDMA */ /** * init_chipset_ali15x3 - Initialise an ALi IDE controller @@ -756,7 +752,6 @@ hwif->mwdma_mask = 0x07; hwif->swdma_mask = 0x07; -#ifdef CONFIG_BLK_DEV_IDEDMA if (m5229_revision >= 0x20) { /* * M1543C or newer for DMAing @@ -770,7 +765,6 @@ } hwif->drives[0].autodma = hwif->autodma; hwif->drives[1].autodma = hwif->autodma; -#endif /* CONFIG_BLK_DEV_IDEDMA */ } /** @@ -854,6 +848,12 @@ static int __devinit alim15x3_init_one(struct pci_dev *dev, const struct pci_device_id *id) { ide_pci_device_t *d = &ali15x3_chipsets[id->driver_data]; + + if(pci_find_device(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RADEON_IGP, NULL)) + { + printk(KERN_ERR "Warning: ATI Radeon IGP Northbridge is not supported by Linux\n"); + return 1; + } #if defined(CONFIG_SPARC64) d->init_hwif = init_hwif_common_ali15x3; #endif /* CONFIG_SPARC64 */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/drivers/ide/pci/amd74xx.c linux.2.5.47-ac6/drivers/ide/pci/amd74xx.c --- linux.2.5.47/drivers/ide/pci/amd74xx.c 2002-10-31 14:57:17.000000000 +0000 +++ linux.2.5.47-ac6/drivers/ide/pci/amd74xx.c 2002-11-13 14:40:09.000000000 +0000 @@ -148,7 +148,6 @@ pio_timing &= ~(0x03 << drive->dn); switch(speed) { -#ifdef CONFIG_BLK_DEV_IDEDMA case XFER_UDMA_7: case XFER_UDMA_6: speed = XFER_UDMA_5; @@ -194,7 +193,6 @@ case XFER_SW_DMA_0: dma_pio_timing |= 0xA8; break; -#endif /* CONFIG_BLK_DEV_IDEDMA */ case XFER_PIO_4: dma_pio_timing |= 0x20; break; @@ -215,9 +213,7 @@ pio_timing |= (0x03 << drive->dn); -#ifdef CONFIG_BLK_DEV_IDEDMA pci_write_config_byte(dev, drive_pci[drive->dn], ultra_timing); -#endif /* CONFIG_BLK_DEV_IDEDMA */ pci_write_config_byte(dev, drive_pci2[drive->dn], dma_pio_timing); pci_write_config_byte(dev, 0x4c, pio_timing); @@ -230,7 +226,6 @@ (void) amd74xx_tune_chipset(drive, (XFER_PIO_0 + pio)); } -#ifdef CONFIG_BLK_DEV_IDEDMA /* * This allows the configuration of ide_pci chipset registers * for cards that learn about the drive's UDMA, DMA, PIO capabilities @@ -290,14 +285,11 @@ } return hwif->ide_dma_on(drive); } -#endif /* CONFIG_BLK_DEV_IDEDMA */ static unsigned int __init init_chipset_amd74xx (struct pci_dev *dev, const char *name) { -#ifdef CONFIG_BLK_DEV_IDEDMA if (!amd74xx_swdma_check(dev)) printk("%s: disabling single-word DMA support (revision < C4)\n", name); -#endif /* CONFIG_BLK_DEV_IDEDMA */ #if defined(DISPLAY_VIPER_TIMINGS) && defined(CONFIG_PROC_FS) if (!amd74xx_proc) { @@ -348,11 +340,7 @@ default: break; } -#ifdef CONFIG_AMD74XX_OVERRIDE - return(1); -#else return (unsigned int) ata66; -#endif /* CONFIG_AMD74XX_OVERRIDE */ } static void __init init_hwif_amd74xx (ide_hwif_t *hwif) @@ -373,7 +361,6 @@ if (amd74xx_swdma_check(hwif->pci_dev)) hwif->swdma_mask = 0x07; -#ifdef CONFIG_BLK_DEV_IDEDMA if (!(hwif->udma_four)) hwif->udma_four = ata66_amd74xx(hwif); hwif->ide_dma_check = &amd74xx_config_drive_xfer_rate; @@ -381,7 +368,6 @@ hwif->autodma = 1; hwif->drives[0].autodma = hwif->autodma; hwif->drives[1].autodma = hwif->autodma; -#endif /* CONFIG_BLK_DEV_IDEDMA */ } static void __init init_dma_amd74xx (ide_hwif_t *hwif, unsigned long dmabase) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/drivers/ide/pci/cmd640.c linux.2.5.47-ac6/drivers/ide/pci/cmd640.c --- linux.2.5.47/drivers/ide/pci/cmd640.c 2002-10-31 14:57:17.000000000 +0000 +++ linux.2.5.47-ac6/drivers/ide/pci/cmd640.c 2002-11-15 00:29:04.000000000 +0000 @@ -751,7 +751,7 @@ */ put_cmd640_reg(0x5b, 0xbd); if (get_cmd640_reg(0x5b) != 0xbd) { - printk("ide: cmd640 init failed: wrong value in reg 0x5b\n"); + printk(KERN_ERR "ide: cmd640 init failed: wrong value in reg 0x5b\n"); return 0; } put_cmd640_reg(0x5b, 0); @@ -836,7 +836,7 @@ cmd_hwif1->tuneproc = &cmd640_tune_drive; #endif /* CONFIG_BLK_DEV_CMD640_ENHANCED */ } - printk("%s: %sserialized, secondary interface %s\n", cmd_hwif1->name, + printk(KERN_INFO "%s: %sserialized, secondary interface %s\n", cmd_hwif1->name, cmd_hwif0->serialized ? "" : "not ", port2); /* diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/drivers/ide/pci/cmd64x.c linux.2.5.47-ac6/drivers/ide/pci/cmd64x.c --- linux.2.5.47/drivers/ide/pci/cmd64x.c 2002-10-31 14:57:17.000000000 +0000 +++ linux.2.5.47-ac6/drivers/ide/pci/cmd64x.c 2002-11-13 15:55:39.000000000 +0000 @@ -383,18 +383,15 @@ static int cmd64x_tune_chipset (ide_drive_t *drive, u8 xferspeed) { -#ifdef CONFIG_BLK_DEV_IDEDMA ide_hwif_t *hwif = HWIF(drive); struct pci_dev *dev = hwif->pci_dev; u8 unit = (drive->select.b.unit & 0x01); u8 regU = 0, pciU = (hwif->channel) ? UDIDETCR1 : UDIDETCR0; u8 regD = 0, pciD = (hwif->channel) ? BMIDESR1 : BMIDESR0; -#endif /* CONFIG_BLK_DEV_IDEDMA */ u8 speed = ide_rate_filter(cmd64x_ratemask(drive), xferspeed); -#ifdef CONFIG_BLK_DEV_IDEDMA if (speed > XFER_PIO_4) { (void) pci_read_config_byte(dev, pciD, ®D); (void) pci_read_config_byte(dev, pciU, ®U); @@ -405,10 +402,8 @@ (void) pci_read_config_byte(dev, pciD, ®D); (void) pci_read_config_byte(dev, pciU, ®U); } -#endif /* CONFIG_BLK_DEV_IDEDMA */ switch(speed) { -#ifdef CONFIG_BLK_DEV_IDEDMA case XFER_UDMA_5: regU |= (unit ? 0x0A : 0x05); break; case XFER_UDMA_4: regU |= (unit ? 0x4A : 0x15); break; case XFER_UDMA_3: regU |= (unit ? 0x8A : 0x25); break; @@ -421,7 +416,6 @@ case XFER_SW_DMA_2: regD |= (unit ? 0x40 : 0x10); break; case XFER_SW_DMA_1: regD |= (unit ? 0x80 : 0x20); break; case XFER_SW_DMA_0: regD |= (unit ? 0xC0 : 0x30); break; -#endif /* CONFIG_BLK_DEV_IDEDMA */ case XFER_PIO_4: cmd64x_tuneproc(drive, 4); break; case XFER_PIO_3: cmd64x_tuneproc(drive, 3); break; case XFER_PIO_2: cmd64x_tuneproc(drive, 2); break; @@ -432,29 +426,26 @@ return 1; } -#ifdef CONFIG_BLK_DEV_IDEDMA if (speed > XFER_PIO_4) { (void) pci_write_config_byte(dev, pciU, regU); regD |= (unit ? 0x40 : 0x20); (void) pci_write_config_byte(dev, pciD, regD); } -#endif /* CONFIG_BLK_DEV_IDEDMA */ return (ide_config_drive_speed(drive, speed)); } -#ifdef CONFIG_BLK_DEV_IDEDMA static int config_chipset_for_dma (ide_drive_t *drive) { u8 speed = ide_dma_speed(drive, cmd64x_ratemask(drive)); - config_chipset_for_pio(drive, (!(speed))); + config_chipset_for_pio(drive, !speed); - if ((!(speed))) + if (!speed) return 0; - if (HWIF(drive)->speedproc(drive, speed)) - return 0; + if(ide_set_xfer_rate(drive, speed)) + return 0; if (!drive->init_speed) drive->init_speed = speed; @@ -593,7 +584,6 @@ /* verify good DMA status */ return (dma_stat & 7) != 4; } -#endif /* CONFIG_BLK_DEV_IDEDMA */ static unsigned int __init init_chipset_cmd64x (struct pci_dev *dev, const char *name) { @@ -732,7 +722,6 @@ if (dev->device == PCI_DEVICE_ID_CMD_648) hwif->ultra_mask = 0x1f; -#ifdef CONFIG_BLK_DEV_IDEDMA hwif->ide_dma_check = &cmd64x_config_drive_for_dma; if (!(hwif->udma_four)) hwif->udma_four = ata66_cmd64x(hwif); @@ -755,7 +744,6 @@ hwif->autodma = 1; hwif->drives[0].autodma = hwif->autodma; hwif->drives[1].autodma = hwif->autodma; -#endif /* CONFIG_BLK_DEV_IDEDMA */ } static void __init init_dma_cmd64x (ide_hwif_t *hwif, unsigned long dmabase) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/drivers/ide/pci/cs5520.c linux.2.5.47-ac6/drivers/ide/pci/cs5520.c --- linux.2.5.47/drivers/ide/pci/cs5520.c 1970-01-01 01:00:00.000000000 +0100 +++ linux.2.5.47-ac6/drivers/ide/pci/cs5520.c 2002-11-18 23:27:45.000000000 +0000 @@ -0,0 +1,323 @@ +/* + * IDE tuning and bus mastering support for the CS5510/CS5520 + * chipsets + * + * The CS5510/CS5520 are slightly unusual devices. Unlike the + * typical IDE controllers they do bus mastering with the drive in + * PIO mode and smarter silicon. + * + * The practical upshot of this is that we must always tune the + * drive for the right PIO mode. We must also ignore all the blacklists + * and the drive bus mastering DMA information. + * + * *** This driver is strictly experimental *** + * + * (c) Copyright Red Hat Inc 2002 + * + * 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, 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. + * + * For the avoidance of doubt the "preferred form" of this code is one which + * is in an open non patent encumbered format. Where cryptographic key signing + * forms part of the process of creating an executable the information + * including keys needed to generate an equivalently functional executable + * are deemed to be part of the source code. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include + +#include "ide_modes.h" +#include "cs5520.h" + +#if defined(DISPLAY_CS5520_TIMINGS) && defined(CONFIG_PROC_FS) +#include +#include + +static u8 cs5520_proc = 0; +static struct pci_dev *bmide_dev; + +static int cs5520_get_info(char *buffer, char **addr, off_t offset, int count) +{ + char *p = buffer; + unsigned long bmiba = pci_resource_start(bmide_dev, 2); + u8 c0 = 0, c1 = 0; + u16 reg16; + u32 reg32; + + /* + * at that point bibma+0x2 et bibma+0xa are byte registers + * to investigate: + */ + c0 = inb((unsigned short)bmiba + 0x02); + c1 = inb((unsigned short)bmiba + 0x0a); + + p += sprintf(p, "\nCyrix CS55x0 IDE\n"); + p += sprintf(p, "--------------- Primary Channel " + "---------------- Secondary Channel " + "-------------\n"); + p += sprintf(p, " %sabled " + " %sabled\n", + (c0&0x80) ? "dis" : " en", + (c1&0x80) ? "dis" : " en"); + + p += sprintf(p, "\n\nTimings: \n"); + + pci_read_config_word(bmide_dev, 0x62, ®16); + p += sprintf(p, "8bit CAT/CRT : %04x\n", reg16); + pci_read_config_dword(bmide_dev, 0x64, ®32); + p += sprintf(p, "16bit Primary : %08x\n", reg32); + pci_read_config_dword(bmide_dev, 0x68, ®32); + p += sprintf(p, "16bit Secondary: %08x\n", reg32); + + return p-buffer; +} + +#endif + +struct pio_clocks +{ + int address; + int assert; + int recovery; +}; + +struct pio_clocks cs5520_pio_clocks[]={ + {3, 6, 11}, + {2, 5, 6}, + {1, 4, 3}, + {1, 3, 2}, + {1, 2, 1} +}; + +static int cs5520_tune_chipset(ide_drive_t *drive, u8 xferspeed) +{ + ide_hwif_t *hwif = HWIF(drive); + struct pci_dev *pdev = hwif->pci_dev; + u8 speed = min((u8)XFER_PIO_4, xferspeed); + int pio = speed; + u8 reg; + int controller = drive->dn > 1 ? 1 : 0; + int error; + + switch(speed) + { + case XFER_PIO_4: + case XFER_PIO_3: + case XFER_PIO_2: + case XFER_PIO_1: + case XFER_PIO_0: + pio -= XFER_PIO_0; + break; + default: + pio = 0; + printk(KERN_ERR "cs55x0: bad ide timing.\n"); + } + + printk("PIO clocking = %d\n", pio); + + /* FIXME: if DMA = 1 do we need to set the DMA bit here ? */ + + /* 8bit command timing for channel */ + pci_write_config_byte(pdev, 0x62 + controller, + (cs5520_pio_clocks[pio].recovery << 4) | + (cs5520_pio_clocks[pio].assert)); + + /* FIXME: should these use address ? */ + /* Data read timing */ + pci_write_config_byte(pdev, 0x64 + 4*controller + (drive->dn&1), + (cs5520_pio_clocks[pio].recovery << 4) | + (cs5520_pio_clocks[pio].assert)); + /* Write command timing */ + pci_write_config_byte(pdev, 0x66 + 4*controller + (drive->dn&1), + (cs5520_pio_clocks[pio].recovery << 4) | + (cs5520_pio_clocks[pio].assert)); + + /* Set the DMA enable/disable flag */ + reg = inb(hwif->dma_base + 0x02 + 8*controller); + reg |= 1<<((drive->dn&1)+5); + outb(reg, hwif->dma_base + 0x02 + 8*controller); + + error = ide_config_drive_speed(drive, speed); + /* ATAPI is harder so leave it for now */ + if(!error && drive->media == ide_disk) + error = hwif->ide_dma_on(drive); +} + +static void cs5520_tune_drive(ide_drive_t *drive, u8 pio) +{ + pio = ide_get_best_pio_mode(drive, pio, 4, NULL); + cs5520_tune_chipset(drive, (XFER_PIO_0 + pio)); +} + +static int cs5520_config_drive_xfer_rate(ide_drive_t *drive) +{ + ide_hwif_t *hwif = HWIF(drive); + + /* Tune the drive for PIO modes up to PIO 4 */ + cs5520_tune_drive(drive, 4); + /* Then tell the core to use DMA operations */ + return hwif->ide_dma_on(drive); +} + + +static unsigned int __devinit init_chipset_cs5520(struct pci_dev *dev, const char *name) +{ +#if defined(DISPLAY_CS5520_TIMINGS) && defined(CONFIG_PROC_FS) + if (!cs5520_proc) { + cs5520_proc = 1; + bmide_dev = dev; + ide_pci_register_host_proc(&cs5520_procs[0]); + } +#endif /* DISPLAY_CS5520_TIMINGS && CONFIG_PROC_FS */ + return 0; +} + +/* + * We provide a callback for our nonstandard DMA location + */ + +static void __devinit cs5520_init_setup_dma(struct pci_dev *dev, ide_pci_device_t *d, ide_hwif_t *hwif) +{ + u32 bmide = pci_resource_start(dev, 2); /* Not the usual 4 */ + if(hwif->mate && hwif->mate->dma_base) /* Second channel at primary + 8 */ + bmide += 8; + ide_setup_dma(hwif, bmide, 8); +} + +/* + * We wrap the DMA activate to set the vdma flag. This is needed + * so that the IDE DMA layer issues PIO not DMA commands over the + * DMA channel + */ + +static int cs5520_dma_on(ide_drive_t *drive) +{ + drive->vdma = 1; + return 0; +} + +static void __devinit init_hwif_cs5520(ide_hwif_t *hwif) +{ + hwif->tuneproc = &cs5520_tune_drive; + hwif->speedproc = &cs5520_tune_chipset; + hwif->ide_dma_check = &cs5520_config_drive_xfer_rate; + hwif->ide_dma_on = &cs5520_dma_on; + + if(!noautodma) + hwif->autodma = 1; + + if(!hwif->dma_base) + { + hwif->drives[0].autotune = 1; + hwif->drives[1].autotune = 1; + return; + } + + hwif->atapi_dma = 0; + hwif->ultra_mask = 0; + hwif->swdma_mask = 0; + hwif->mwdma_mask = 0; + + hwif->drives[0].autodma = hwif->autodma; + hwif->drives[1].autodma = hwif->autodma; +} + +/* + * The 5510/5520 are a bit weird. They don't quite set up the way + * the PCI helper layer expects so we must do much of the set up + * work longhand. + */ + +static int __devinit cs5520_init_one(struct pci_dev *dev, const struct pci_device_id *id) +{ + ata_index_t index; + ide_pci_device_t *d = &cyrix_chipsets[id->driver_data]; + + ide_setup_pci_noise(dev, d); + + /* We must not grab the entire device, it has 'ISA' space in its + BARS too and we will freak out other bits of the kernel */ + if(pci_enable_device_bars(dev, 1<<2)) + { + printk(KERN_WARNING "%s: Unable to enable 55x0.\n", d->name); + return 1; + } + pci_set_master(dev); + pci_set_dma_mask(dev, 0xFFFFFFFF); + init_chipset_cs5520(dev, d->name); + + index.all = 0xf0f0; + + /* + * Now the chipset is configured we can let the core + * do all the device setup for us + */ + + ide_pci_setup_ports(dev, d, 1, 14, &index); + + printk("Index.b %d %d\n", index.b.low, index.b.high); + mdelay(2000); + if((index.b.low & 0xf0) != 0xf0) + probe_hwif_init(&ide_hwifs[index.b.low]); + if((index.b.high & 0xf0) != 0xf0) + probe_hwif_init(&ide_hwifs[index.b.high]); + + return 0; +} + +static struct pci_device_id cs5520_pci_tbl[] __devinitdata = { + { PCI_VENDOR_ID_CYRIX, PCI_DEVICE_ID_CYRIX_5510, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + { PCI_VENDOR_ID_CYRIX, PCI_DEVICE_ID_CYRIX_5520, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1}, + { 0, }, +}; + +static struct pci_driver driver = { + .name = "CyrixIDE", + .id_table = cs5520_pci_tbl, + .probe = cs5520_init_one, +}; + +static int cs5520_ide_init(void) +{ + return ide_pci_register_driver(&driver); +} + +static void cs5520_ide_exit(void) +{ + return ide_pci_unregister_driver(&driver); +} + +module_init(cs5520_ide_init); +module_exit(cs5520_ide_exit); + +MODULE_AUTHOR("Alan Cox"); +MODULE_DESCRIPTION("PCI driver module for Cyrix 5510/5520 IDE"); +MODULE_LICENSE("GPL"); + +EXPORT_NO_SYMBOLS; + diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/drivers/ide/pci/cs5520.h linux.2.5.47-ac6/drivers/ide/pci/cs5520.h --- linux.2.5.47/drivers/ide/pci/cs5520.h 1970-01-01 01:00:00.000000000 +0100 +++ linux.2.5.47-ac6/drivers/ide/pci/cs5520.h 2002-11-18 18:55:27.000000000 +0000 @@ -0,0 +1,66 @@ +#ifndef CS5520_H +#define CS5520_H + +#include +#include +#include + +#define DISPLAY_CS5520_TIMINGS + +#if defined(DISPLAY_CS5520_TIMINGS) && defined(CONFIG_PROC_FS) +#include +#include + +static u8 cs5520_proc; + +static int cs5520_get_info(char *, char **, off_t, int); + +static ide_pci_host_proc_t cs5520_procs[] __initdata = { + { + name: "cs5520", + set: 1, + get_info: cs5520_get_info, + parent: NULL, + }, +}; +#endif /* defined(DISPLAY_CS5520_TIMINGS) && defined(CONFIG_PROC_FS) */ + +static unsigned int init_chipset_cs5520(struct pci_dev *, const char *); +static void init_hwif_cs5520(ide_hwif_t *); +static void cs5520_init_setup_dma(struct pci_dev *dev, struct ide_pci_device_s *d, ide_hwif_t *hwif); + +static ide_pci_device_t cyrix_chipsets[] __devinitdata = { + { + vendor: PCI_VENDOR_ID_CYRIX, + device: PCI_DEVICE_ID_CYRIX_5510, + name: "Cyrix 5510", + init_chipset: init_chipset_cs5520, + init_setup_dma: cs5520_init_setup_dma, + init_iops: NULL, + init_hwif: init_hwif_cs5520, + isa_ports: 1, + channels: 2, + autodma: AUTODMA, + bootable: ON_BOARD, + extra: 0, + }, + { + vendor: PCI_VENDOR_ID_CYRIX, + device: PCI_DEVICE_ID_CYRIX_5520, + name: "Cyrix 5520", + init_chipset: init_chipset_cs5520, + init_setup_dma: cs5520_init_setup_dma, + init_iops: NULL, + init_hwif: init_hwif_cs5520, + isa_ports: 1, + channels: 2, + autodma: AUTODMA, + bootable: ON_BOARD, + extra: 0, + } +}; + + +#endif /* CS5520_H */ + + diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/drivers/ide/pci/cs5530.c linux.2.5.47-ac6/drivers/ide/pci/cs5530.c --- linux.2.5.47/drivers/ide/pci/cs5530.c 2002-10-31 14:57:17.000000000 +0000 +++ linux.2.5.47-ac6/drivers/ide/pci/cs5530.c 2002-11-13 14:41:55.000000000 +0000 @@ -135,8 +135,6 @@ } } -#ifdef CONFIG_BLK_DEV_IDEDMA - /** * cs5530_config_dma - select/set DMA and UDMA modes * @drive: drive to tune @@ -256,7 +254,6 @@ */ return hwif->ide_dma_on(drive); /* success */ } -#endif /* CONFIG_BLK_DEV_IDEDMA */ /** * init_chipset_5530 - set up 5530 bridge @@ -396,13 +393,11 @@ hwif->ultra_mask = 0x07; hwif->mwdma_mask = 0x07; -#ifdef CONFIG_BLK_DEV_IDEDMA hwif->ide_dma_check = &cs5530_config_dma; if (!noautodma) hwif->autodma = 1; hwif->drives[0].autodma = hwif->autodma; hwif->drives[1].autodma = hwif->autodma; -#endif /* CONFIG_BLK_DEV_IDEDMA */ } /** diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/drivers/ide/pci/cy82c693.c linux.2.5.47-ac6/drivers/ide/pci/cy82c693.c --- linux.2.5.47/drivers/ide/pci/cy82c693.c 2002-10-31 14:57:17.000000000 +0000 +++ linux.2.5.47-ac6/drivers/ide/pci/cy82c693.c 2002-11-13 14:42:21.000000000 +0000 @@ -123,10 +123,10 @@ p_pclk->time_8 = (u8)clk1; } -#ifdef CONFIG_BLK_DEV_IDEDMA /* * set DMA mode a specific channel for CY82C693 */ + static void cy82c693_dma_enable (ide_drive_t *drive, int mode, int single) { u8 index = 0, data = 0; @@ -213,7 +213,6 @@ } return __ide_dma_on(drive); } -#endif /* CONFIG_BLK_DEV_IDEDMA */ /* * tune ide drive - set PIO mode @@ -405,13 +404,11 @@ hwif->mwdma_mask = 0x04; hwif->swdma_mask = 0x04; -#ifdef CONFIG_BLK_DEV_IDEDMA hwif->ide_dma_on = &cy82c693_ide_dma_on; if (!noautodma) hwif->autodma = 1; hwif->drives[0].autodma = hwif->autodma; hwif->drives[1].autodma = hwif->autodma; -#endif /* CONFIG_BLK_DEV_IDEDMA */ } static __initdata ide_hwif_t *primary; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/drivers/ide/pci/generic.c linux.2.5.47-ac6/drivers/ide/pci/generic.c --- linux.2.5.47/drivers/ide/pci/generic.c 2002-10-31 14:57:17.000000000 +0000 +++ linux.2.5.47-ac6/drivers/ide/pci/generic.c 2002-11-13 14:47:26.000000000 +0000 @@ -50,12 +50,10 @@ hwif->mwdma_mask = 0x07; hwif->swdma_mask = 0x07; -#ifdef CONFIG_BLK_DEV_IDEDMA if (!noautodma) hwif->autodma = 1; hwif->drives[0].autodma = hwif->autodma; hwif->drives[1].autodma = hwif->autodma; -#endif /* CONFIG_BLK_DEV_IDEDMA */ } static void init_dma_generic (ide_hwif_t *hwif, unsigned long dmabase) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/drivers/ide/pci/hpt34x.c linux.2.5.47-ac6/drivers/ide/pci/hpt34x.c --- linux.2.5.47/drivers/ide/pci/hpt34x.c 2002-10-31 14:57:17.000000000 +0000 +++ linux.2.5.47-ac6/drivers/ide/pci/hpt34x.c 2002-11-13 14:48:03.000000000 +0000 @@ -159,13 +159,13 @@ (void) hpt34x_tune_chipset(drive, (XFER_PIO_0 + pio)); } -#ifdef CONFIG_BLK_DEV_IDEDMA /* * This allows the configuration of ide_pci chipset registers * for cards that learn about the drive's UDMA, DMA, PIO capabilities * after the drive is reported by the OS. Initally for designed for * HPT343 UDMA chipset by HighPoint|Triones Technologies, Inc. */ + static int config_chipset_for_dma (ide_drive_t *drive) { u8 speed = ide_dma_speed(drive, hpt34x_ratemask(drive)); @@ -224,7 +224,6 @@ #endif /* CONFIG_HPT34X_AUTODMA */ return hwif->ide_dma_on(drive); } -#endif /* CONFIG_BLK_DEV_IDEDMA */ /* * If the BIOS does not set the IO base addaress to XX00, 343 will fail. @@ -306,13 +305,11 @@ hwif->mwdma_mask = 0x07; hwif->swdma_mask = 0x07; -#ifdef CONFIG_BLK_DEV_IDEDMA hwif->ide_dma_check = &hpt34x_config_drive_xfer_rate; if (!noautodma) hwif->autodma = (pcicmd & PCI_COMMAND_MEMORY) ? 1 : 0; hwif->drives[0].autodma = hwif->autodma; hwif->drives[1].autodma = hwif->autodma; -#endif /* CONFIG_BLK_DEV_IDEDMA */ } static void __init init_dma_hpt34x (ide_hwif_t *hwif, unsigned long dmabase) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/drivers/ide/pci/hpt366.c linux.2.5.47-ac6/drivers/ide/pci/hpt366.c --- linux.2.5.47/drivers/ide/pci/hpt366.c 2002-10-31 15:05:01.000000000 +0000 +++ linux.2.5.47-ac6/drivers/ide/pci/hpt366.c 2002-11-17 00:32:37.000000000 +0000 @@ -216,7 +216,6 @@ static u8 hpt3xx_ratefilter (ide_drive_t *drive, u8 speed) { -#ifdef CONFIG_BLK_DEV_IDEDMA struct pci_dev *dev = HWIF(drive)->pci_dev; u8 mode = hpt3xx_ratemask(drive); @@ -264,9 +263,6 @@ break; } return speed; -#else - return min(speed, (u8)XFER_PIO_4); -#endif /* CONFIG_BLK_DEV_IDEDMA */ } static int check_in_drive_lists (ide_drive_t *drive, const char **list) @@ -297,7 +293,7 @@ { struct pci_dev *dev = HWIF(drive)->pci_dev; u8 speed = hpt3xx_ratefilter(drive, xferspeed); -// u8 speed = ide_rate_filter(hpt3xx_ratemask(drive), xferspeed); +// u8 speed = ide_rate_filter(hpt3xx_ratemask(drive), xferspeed); u8 regtime = (drive->select.b.unit & 0x01) ? 0x44 : 0x40; u8 regfast = (HWIF(drive)->channel) ? 0x55 : 0x51; u8 drive_fast = 0; @@ -444,7 +440,6 @@ (void) hpt3xx_tune_chipset(drive, (XFER_PIO_0 + pio)); } -#ifdef CONFIG_BLK_DEV_IDEDMA /* * This allows the configuration of ide_pci chipset registers * for cards that learn about the drive's UDMA, DMA, PIO capabilities @@ -654,7 +649,6 @@ pci_write_config_byte(dev, mscreg, msc_stat|0x30); return __ide_dma_end(drive); } -#endif /* CONFIG_BLK_DEV_IDEDMA */ /* * Since SUN Cobalt is attempting to do this operation, I should disclose @@ -1030,7 +1024,6 @@ hwif->ultra_mask = 0x7f; hwif->mwdma_mask = 0x07; -#ifdef CONFIG_BLK_DEV_IDEDMA if (!(hwif->udma_four)) hwif->udma_four = ((ata66 & regmask) ? 0 : 1); hwif->ide_dma_check = &hpt366_config_drive_xfer_rate; @@ -1053,7 +1046,6 @@ hwif->autodma = 1; hwif->drives[0].autodma = hwif->autodma; hwif->drives[1].autodma = hwif->autodma; -#endif /* CONFIG_BLK_DEV_IDEDMA */ } static void __init init_dma_hpt366 (ide_hwif_t *hwif, unsigned long dmabase) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/drivers/ide/pci/it8172.c linux.2.5.47-ac6/drivers/ide/pci/it8172.c --- linux.2.5.47/drivers/ide/pci/it8172.c 2002-10-31 14:57:17.000000000 +0000 +++ linux.2.5.47-ac6/drivers/ide/pci/it8172.c 2002-11-13 14:49:44.000000000 +0000 @@ -151,7 +151,6 @@ */ switch(speed) { -#ifdef CONFIG_BLK_DEV_IDEDMA case XFER_UDMA_4: case XFER_UDMA_2: //u_speed = 2 << (drive->dn * 4); break; case XFER_UDMA_5: @@ -162,7 +161,6 @@ case XFER_MW_DMA_1: case XFER_MW_DMA_0: case XFER_SW_DMA_2: break; -#endif /* CONFIG_BLK_DEV_IDEDMA */ case XFER_PIO_4: case XFER_PIO_3: case XFER_PIO_2: @@ -183,7 +181,6 @@ return (ide_config_drive_speed(drive, speed)); } -#ifdef CONFIG_BLK_DEV_IDEDMA static int it8172_config_chipset_for_dma (ide_drive_t *drive) { u8 speed = ide_dma_speed(drive, it8172_ratemask(drive)); @@ -239,7 +236,6 @@ } return hwif->ide_dma_on(drive); } -#endif /* CONFIG_BLK_DEV_IDEDMA */ static unsigned int __init init_chipset_it8172 (struct pci_dev *dev, const char *name) { @@ -282,13 +278,11 @@ hwif->mwdma_mask = 0x06; hwif->swdma_mask = 0x04; -#ifdef CONFIG_BLK_DEV_IDEDMA hwif->ide_dma_check = &it8172_config_drive_xfer_rate; if (!noautodma) hwif->autodma = 1; hwif->drives[0].autodma = hwif->autodma; hwif->drives[1].autodma = hwif->autodma; -#endif /* !CONFIG_BLK_DEV_IDEDMA */ } static void __init init_dma_it8172 (ide_hwif_t *hwif, unsigned long dmabase) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/drivers/ide/pci/Makefile linux.2.5.47-ac6/drivers/ide/pci/Makefile --- linux.2.5.47/drivers/ide/pci/Makefile 2002-10-31 14:57:17.000000000 +0000 +++ linux.2.5.47-ac6/drivers/ide/pci/Makefile 2002-11-18 13:39:30.000000000 +0000 @@ -5,7 +5,9 @@ obj-$(CONFIG_BLK_DEV_AMD74XX) += amd74xx.o obj-$(CONFIG_BLK_DEV_CMD640) += cmd640.o obj-$(CONFIG_BLK_DEV_CMD64X) += cmd64x.o +obj-$(CONFIG_BLK_DEV_CS5520) += cs5520.o obj-$(CONFIG_BLK_DEV_CS5530) += cs5530.o +obj-$(CONFIG_BLK_DEV_SC1200) += sc1200.o obj-$(CONFIG_BLK_DEV_CY82C693) += cy82c693.o obj-$(CONFIG_BLK_DEV_HPT34X) += hpt34x.o obj-$(CONFIG_BLK_DEV_HPT366) += hpt366.o diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/drivers/ide/pci/ns87415.c linux.2.5.47-ac6/drivers/ide/pci/ns87415.c --- linux.2.5.47/drivers/ide/pci/ns87415.c 2002-10-31 14:57:17.000000000 +0000 +++ linux.2.5.47-ac6/drivers/ide/pci/ns87415.c 2002-11-13 14:50:10.000000000 +0000 @@ -83,7 +83,6 @@ ns87415_prepare_drive (drive, drive->using_dma); } -#ifdef CONFIG_BLK_DEV_IDEDMA static int ns87415_ide_dma_end (ide_drive_t *drive) { ide_hwif_t *hwif = HWIF(drive); @@ -132,7 +131,6 @@ return HWIF(drive)->ide_dma_off_quietly(drive); return __ide_dma_check(drive); } -#endif /* CONFIG_BLK_DEV_IDEDMA */ static void __init init_hwif_ns87415 (ide_hwif_t *hwif) { @@ -209,7 +207,6 @@ if (!hwif->dma_base) return; -#ifdef CONFIG_BLK_DEV_IDEDMA hwif->OUTB(0x60, hwif->dma_status); hwif->ide_dma_read = &ns87415_ide_dma_read; hwif->ide_dma_write = &ns87415_ide_dma_write; @@ -220,7 +217,6 @@ hwif->autodma = 1; hwif->drives[0].autodma = hwif->autodma; hwif->drives[1].autodma = hwif->autodma; -#endif /* CONFIG_BLK_DEV_IDEDMA */ } static void __init init_dma_ns87415 (ide_hwif_t *hwif, unsigned long dmabase) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/drivers/ide/pci/nvidia.c linux.2.5.47-ac6/drivers/ide/pci/nvidia.c --- linux.2.5.47/drivers/ide/pci/nvidia.c 2002-10-31 14:57:17.000000000 +0000 +++ linux.2.5.47-ac6/drivers/ide/pci/nvidia.c 2002-11-17 14:13:46.000000000 +0000 @@ -38,7 +38,7 @@ static int nforce_get_info (char *buffer, char **addr, off_t offset, int count) { char *p = buffer; - u32 bibma = pci_resource_start(bmide_dev, 4); + unsigned long bibma = pci_resource_start(bmide_dev, 4); u8 c0 = 0, c1 = 0; /* @@ -109,7 +109,6 @@ pio_timing &= ~(0x03 << drive->dn); switch(speed) { -#ifdef CONFIG_BLK_DEV_IDEDMA case XFER_UDMA_7: case XFER_UDMA_6: speed = XFER_UDMA_5; @@ -155,7 +154,6 @@ case XFER_SW_DMA_0: dma_pio_timing |= 0xA8; break; -#endif /* CONFIG_BLK_DEV_IDEDMA */ case XFER_PIO_4: dma_pio_timing |= 0x20; break; @@ -176,9 +174,7 @@ pio_timing |= (0x03 << drive->dn); -#ifdef CONFIG_BLK_DEV_IDEDMA pci_write_config_byte(dev, drive_pci[drive->dn], ultra_timing); -#endif /* CONFIG_BLK_DEV_IDEDMA */ pci_write_config_byte(dev, drive_pci2[drive->dn], dma_pio_timing); pci_write_config_byte(dev, 0x5c, pio_timing); @@ -191,7 +187,6 @@ (void) nforce_tune_chipset(drive, (XFER_PIO_0 + pio)); } -#ifdef CONFIG_BLK_DEV_IDEDMA /* * This allows the configuration of ide_pci chipset registers * for cards that learn about the drive's UDMA, DMA, PIO capabilities @@ -251,9 +246,8 @@ } return hwif->ide_dma_on(drive); } -#endif /* CONFIG_BLK_DEV_IDEDMA */ -unsigned int __init init_chipset_nforce (struct pci_dev *dev, const char *name) +static unsigned int __init init_chipset_nforce (struct pci_dev *dev, const char *name) { #if defined(DISPLAY_NFORCE_TIMINGS) && defined(CONFIG_PROC_FS) if (!nforce_proc) { @@ -318,7 +312,6 @@ hwif->mwdma_mask = 0x07; hwif->swdma_mask = 0x07; -#ifdef CONFIG_BLK_DEV_IDEDMA if (!(hwif->udma_four)) hwif->udma_four = ata66_nforce(hwif); hwif->ide_dma_check = &nforce_config_drive_xfer_rate; @@ -326,7 +319,6 @@ hwif->autodma = 1; hwif->drives[0].autodma = hwif->autodma; hwif->drives[1].autodma = hwif->autodma; -#endif /* CONFIG_BLK_DEV_IDEDMA */ } /* FIXME - not needed */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/drivers/ide/pci/opti621.c linux.2.5.47-ac6/drivers/ide/pci/opti621.c --- linux.2.5.47/drivers/ide/pci/opti621.c 2002-10-31 14:57:17.000000000 +0000 +++ linux.2.5.47-ac6/drivers/ide/pci/opti621.c 2002-11-13 14:51:16.000000000 +0000 @@ -343,13 +343,10 @@ hwif->mwdma_mask = 0x07; hwif->swdma_mask = 0x07; -#ifdef CONFIG_BLK_DEV_IDEDMA if (!noautodma) hwif->autodma = 1; hwif->drives[0].autodma = hwif->autodma; hwif->drives[1].autodma = hwif->autodma; -#endif /* CONFIG_BLK_DEV_IDEDMA */ - } static void __init init_dma_opti621 (ide_hwif_t *hwif, unsigned long dmabase) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/drivers/ide/pci/pdc202xx_new.c linux.2.5.47-ac6/drivers/ide/pci/pdc202xx_new.c --- linux.2.5.47/drivers/ide/pci/pdc202xx_new.c 2002-10-31 14:57:17.000000000 +0000 +++ linux.2.5.47-ac6/drivers/ide/pci/pdc202xx_new.c 2002-11-13 14:52:59.000000000 +0000 @@ -165,7 +165,6 @@ pci_read_config_byte(dev, (drive_pci), &AP); pci_read_config_byte(dev, (drive_pci)|0x01, &BP); } -#ifdef CONFIG_BLK_DEV_IDEDMA } else { if ((BP & 0xF0) && (CP & 0x0F)) { /* clear DMA modes of upper 842 bits of B Register */ @@ -177,7 +176,6 @@ pci_write_config_byte(dev, (drive_pci)|0x02, CP &~0x0F); pci_read_config_byte(dev, (drive_pci)|0x02, &CP); } -#endif /* CONFIG_BLK_DEV_IDEDMA */ } pci_read_config_byte(dev, (drive_pci), &AP); @@ -185,7 +183,6 @@ pci_read_config_byte(dev, (drive_pci)|0x02, &CP); switch(speed) { -#ifdef CONFIG_BLK_DEV_IDEDMA case XFER_UDMA_6: speed = XFER_UDMA_5; case XFER_UDMA_5: case XFER_UDMA_4: TB = 0x20; TC = 0x01; break; @@ -199,7 +196,6 @@ case XFER_SW_DMA_2: TB = 0x60; TC = 0x05; break; case XFER_SW_DMA_1: TB = 0x80; TC = 0x06; break; case XFER_SW_DMA_0: TB = 0xC0; TC = 0x0B; break; -#endif /* CONFIG_BLK_DEV_IDEDMA */ case XFER_PIO_4: TA = 0x01; TB = 0x04; break; case XFER_PIO_3: TA = 0x02; TB = 0x06; break; case XFER_PIO_2: TA = 0x03; TB = 0x08; break; @@ -211,11 +207,9 @@ if (speed < XFER_SW_DMA_0) { pci_write_config_byte(dev, (drive_pci), AP|TA); pci_write_config_byte(dev, (drive_pci)|0x01, BP|TB); -#ifdef CONFIG_BLK_DEV_IDEDMA } else { pci_write_config_byte(dev, (drive_pci)|0x01, BP|TB); pci_write_config_byte(dev, (drive_pci)|0x02, CP|TC); -#endif /* CONFIG_BLK_DEV_IDEDMA */ } #if PDC202XX_DECODE_REGISTER_INFO @@ -243,28 +237,18 @@ static int pdcnew_new_tune_chipset (ide_drive_t *drive, u8 xferspeed) { ide_hwif_t *hwif = HWIF(drive); -#ifdef CONFIG_BLK_DEV_IDEDMA u32 indexreg = hwif->dma_vendor1; u32 datareg = hwif->dma_vendor3; -#else /* !CONFIG_BLK_DEV_IDEDMA */ - struct pci_dev *dev = hwif->pci_dev; - u32 high_16 = pci_resource_start(dev, 4); - u32 indexreg = high_16 + (hwif->channel ? 0x09 : 0x01); - u32 datareg = (indexreg + 2); -#endif /* CONFIG_BLK_DEV_IDEDMA */ u8 thold = 0x10; u8 adj = (drive->dn%2) ? 0x08 : 0x00; u8 speed = ide_rate_filter(pdcnew_ratemask(drive), xferspeed); -#ifdef CONFIG_BLK_DEV_IDEDMA if (speed == XFER_UDMA_2) { hwif->OUTB((thold + adj), indexreg); hwif->OUTB((hwif->INB(datareg) & 0x7f), datareg); } -#endif /* CONFIG_BLK_DEV_IDEDMA */ switch (speed) { -#ifdef CONFIG_BLK_DEV_IDEDMA case XFER_UDMA_7: speed = XFER_UDMA_6; case XFER_UDMA_6: set_ultra(0x1a, 0x01, 0xcb); break; @@ -277,7 +261,6 @@ case XFER_MW_DMA_2: set_ata2(0x69, 0x25); break; case XFER_MW_DMA_1: set_ata2(0x6b, 0x27); break; case XFER_MW_DMA_0: set_ata2(0xdf, 0x5f); break; -#endif /* CONFIG_BLK_DEV_IDEDMA */ case XFER_PIO_4: set_pio(0x23, 0x09, 0x25); break; case XFER_PIO_3: set_pio(0x27, 0x0d, 0x35); break; case XFER_PIO_2: set_pio(0x23, 0x26, 0x64); break; @@ -312,8 +295,6 @@ (void) config_chipset_for_pio(drive, pio); } -#ifdef CONFIG_BLK_DEV_IDEDMA - static u8 pdcnew_new_cable_detect (ide_hwif_t *hwif) { hwif->OUTB(0x0b, hwif->dma_vendor1); @@ -458,8 +439,6 @@ return __ide_dma_timeout(drive); } -#endif /* CONFIG_BLK_DEV_IDEDMA */ - static void pdcnew_new_reset (ide_drive_t *drive) { /* @@ -471,12 +450,8 @@ static void pdcnew_reset_host (ide_hwif_t *hwif) { -#ifdef CONFIG_BLK_DEV_IDEDMA // unsigned long high_16 = hwif->dma_base - (8*(hwif->channel)); unsigned long high_16 = hwif->dma_master; -#else /* !CONFIG_BLK_DEV_IDEDMA */ - unsigned long high_16 = pci_resource_start(hwif->pci_dev, 4); -#endif /* CONFIG_BLK_DEV_IDEDMA */ u8 udma_speed_flag = hwif->INB(high_16|0x001f); hwif->OUTB((udma_speed_flag | 0x10), (high_16|0x001f)); @@ -571,8 +546,6 @@ hwif->ultra_mask = 0x7f; hwif->mwdma_mask = 0x07; -#ifdef CONFIG_BLK_DEV_IDEDMA - hwif->ide_dma_check = &pdcnew_config_drive_xfer_rate; hwif->ide_dma_lostirq = &pdcnew_ide_dma_lostirq; hwif->ide_dma_timeout = &pdcnew_ide_dma_timeout; @@ -581,7 +554,6 @@ if (!noautodma) hwif->autodma = 1; hwif->drives[0].autodma = hwif->drives[1].autodma = hwif->autodma; -#endif /* CONFIG_BLK_DEV_IDEDMA */ #if PDC202_DEBUG_CABLE printk("%s: %s-pin cable\n", hwif->name, hwif->udma_four ? "80" : "40"); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/drivers/ide/pci/pdc202xx_old.c linux.2.5.47-ac6/drivers/ide/pci/pdc202xx_old.c --- linux.2.5.47/drivers/ide/pci/pdc202xx_old.c 2002-10-31 14:57:17.000000000 +0000 +++ linux.2.5.47-ac6/drivers/ide/pci/pdc202xx_old.c 2002-11-13 14:54:01.000000000 +0000 @@ -264,7 +264,6 @@ pci_read_config_byte(dev, (drive_pci), &AP); pci_read_config_byte(dev, (drive_pci)|0x01, &BP); } -#ifdef CONFIG_BLK_DEV_IDEDMA } else { if ((BP & 0xF0) && (CP & 0x0F)) { /* clear DMA modes of upper 842 bits of B Register */ @@ -276,7 +275,6 @@ pci_write_config_byte(dev, (drive_pci)|0x02, CP &~0x0F); pci_read_config_byte(dev, (drive_pci)|0x02, &CP); } -#endif /* CONFIG_BLK_DEV_IDEDMA */ } pci_read_config_byte(dev, (drive_pci), &AP); @@ -284,7 +282,6 @@ pci_read_config_byte(dev, (drive_pci)|0x02, &CP); switch(speed) { -#ifdef CONFIG_BLK_DEV_IDEDMA case XFER_UDMA_6: speed = XFER_UDMA_5; case XFER_UDMA_5: case XFER_UDMA_4: TB = 0x20; TC = 0x01; break; @@ -298,7 +295,6 @@ case XFER_SW_DMA_2: TB = 0x60; TC = 0x05; break; case XFER_SW_DMA_1: TB = 0x80; TC = 0x06; break; case XFER_SW_DMA_0: TB = 0xC0; TC = 0x0B; break; -#endif /* CONFIG_BLK_DEV_IDEDMA */ case XFER_PIO_4: TA = 0x01; TB = 0x04; break; case XFER_PIO_3: TA = 0x02; TB = 0x06; break; case XFER_PIO_2: TA = 0x03; TB = 0x08; break; @@ -310,11 +306,9 @@ if (speed < XFER_SW_DMA_0) { pci_write_config_byte(dev, (drive_pci), AP|TA); pci_write_config_byte(dev, (drive_pci)|0x01, BP|TB); -#ifdef CONFIG_BLK_DEV_IDEDMA } else { pci_write_config_byte(dev, (drive_pci)|0x01, BP|TB); pci_write_config_byte(dev, (drive_pci)|0x02, CP|TC); -#endif /* CONFIG_BLK_DEV_IDEDMA */ } #if PDC202XX_DECODE_REGISTER_INFO @@ -362,8 +356,6 @@ (void) config_chipset_for_pio(drive, pio); } -#ifdef CONFIG_BLK_DEV_IDEDMA - static u8 pdc202xx_old_cable_detect (ide_hwif_t *hwif) { u16 CIS = 0, mask = (hwif->channel) ? (1<<11) : (1<<10); @@ -618,8 +610,6 @@ return __ide_dma_timeout(drive); } -#endif /* CONFIG_BLK_DEV_IDEDMA */ - static void pdc202xx_reset_host (ide_hwif_t *hwif) { #ifdef CONFIG_BLK_DEV_IDEDMA @@ -692,12 +682,8 @@ static int pdc202xx_tristate (ide_drive_t * drive, int state) { ide_hwif_t *hwif = HWIF(drive); -#ifdef CONFIG_BLK_DEV_IDEDMA // unsigned long high_16 = hwif->dma_base - (8*(hwif->channel)); unsigned long high_16 = hwif->dma_master; -#else /* !CONFIG_BLK_DEV_IDEDMA */ - unsigned long high_16 = pci_resource_start(hwif->pci_dev, 4); -#endif /* CONFIG_BLK_DEV_IDEDMA */ u8 sc1f = hwif->INB(high_16|0x001f); if (!hwif) @@ -783,8 +769,6 @@ hwif->mwdma_mask = 0x07; hwif->swdma_mask = 0x07; -#ifdef CONFIG_BLK_DEV_IDEDMA - hwif->ide_dma_check = &pdc202xx_config_drive_xfer_rate; hwif->ide_dma_lostirq = &pdc202xx_ide_dma_lostirq; hwif->ide_dma_timeout = &pdc202xx_ide_dma_timeout; @@ -800,7 +784,6 @@ if (!noautodma) hwif->autodma = 1; hwif->drives[0].autodma = hwif->drives[1].autodma = hwif->autodma; -#endif /* CONFIG_BLK_DEV_IDEDMA */ #if PDC202_DEBUG_CABLE printk("%s: %s-pin cable\n", hwif->name, hwif->udma_four ? "80" : "40"); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/drivers/ide/pci/pdcadma.c linux.2.5.47-ac6/drivers/ide/pci/pdcadma.c --- linux.2.5.47/drivers/ide/pci/pdcadma.c 2002-10-31 14:57:17.000000000 +0000 +++ linux.2.5.47-ac6/drivers/ide/pci/pdcadma.c 2002-11-13 14:54:20.000000000 +0000 @@ -55,7 +55,6 @@ } #endif /* defined(DISPLAY_PDCADMA_TIMINGS) && defined(CONFIG_PROC_FS) */ -#ifdef CONFIG_BLK_DEV_IDEDMA /* * pdcadma_dma functions() initiates/aborts (U)DMA read/write * operations on a drive. @@ -82,8 +81,6 @@ #endif -#endif /* CONFIG_BLK_DEV_IDEDMA */ - static unsigned int __init init_chipset_pdcadma (struct pci_dev *dev, const char *name) { #if defined(DISPLAY_PDCADMA_TIMINGS) && defined(CONFIG_PROC_FS) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/drivers/ide/pci/piix.c linux.2.5.47-ac6/drivers/ide/pci/piix.c --- linux.2.5.47/drivers/ide/pci/piix.c 2002-10-31 14:57:17.000000000 +0000 +++ linux.2.5.47-ac6/drivers/ide/pci/piix.c 2002-11-13 14:36:38.000000000 +0000 @@ -373,7 +373,7 @@ ide_hwif_t *hwif = HWIF(drive); struct pci_dev *dev = hwif->pci_dev; u8 maslave = hwif->channel ? 0x42 : 0x40; - u8 speed = ide_rate_filter(piix_ratemask(drive), xferspeed); + u8 speed = ide_rate_filter(piix_ratemask(drive), xferspeed); int a_speed = 3 << (drive->dn * 4); int u_flag = 1 << drive->dn; int v_flag = 0x01 << drive->dn; @@ -392,7 +392,6 @@ pci_read_config_byte(dev, 0x55, ®55); switch(speed) { -#ifdef CONFIG_BLK_DEV_IDEDMA case XFER_UDMA_4: case XFER_UDMA_2: u_speed = 2 << (drive->dn * 4); break; case XFER_UDMA_5: @@ -402,7 +401,6 @@ case XFER_MW_DMA_2: case XFER_MW_DMA_1: case XFER_SW_DMA_2: break; -#endif /* CONFIG_BLK_DEV_IDEDMA */ case XFER_PIO_4: case XFER_PIO_3: case XFER_PIO_2: @@ -444,8 +442,6 @@ return (ide_config_drive_speed(drive, speed)); } -#ifdef CONFIG_BLK_DEV_IDEDMA - /** * piix_config_drive_for_dma - configure drive for DMA * @drive: IDE drive to configure @@ -518,7 +514,6 @@ } return hwif->ide_dma_on(drive); } -#endif /* CONFIG_BLK_DEV_IDEDMA */ /** * init_chipset_piix - set up the PIIX chipset @@ -570,10 +565,8 @@ static void __init init_hwif_piix (ide_hwif_t *hwif) { -#ifdef CONFIG_BLK_DEV_IDEDMA u8 reg54h = 0, reg55h = 0, ata66 = 0; u8 mask = hwif->channel ? 0xc0 : 0x30; -#endif /* !CONFIG_BLK_DEV_IDEDMA */ #ifndef CONFIG_IA64 if (!hwif->irq) @@ -599,7 +592,6 @@ hwif->mwdma_mask = 0x06; hwif->swdma_mask = 0x04; -#ifdef CONFIG_BLK_DEV_IDEDMA switch(hwif->pci_dev->device) { case PCI_DEVICE_ID_INTEL_82371MX: hwif->mwdma_mask = 0x80; @@ -630,7 +622,6 @@ hwif->drives[1].autodma = hwif->autodma; hwif->drives[0].autodma = hwif->autodma; -#endif /* !CONFIG_BLK_DEV_IDEDMA */ } /** diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/drivers/ide/pci/sc1200.c linux.2.5.47-ac6/drivers/ide/pci/sc1200.c --- linux.2.5.47/drivers/ide/pci/sc1200.c 1970-01-01 01:00:00.000000000 +0100 +++ linux.2.5.47-ac6/drivers/ide/pci/sc1200.c 2002-11-13 22:49:14.000000000 +0000 @@ -0,0 +1,593 @@ +/* + * linux/drivers/ide/sc1200.c Version 0.9 24-Oct-2002 + * + * Copyright (C) 2000-2002 Mark Lord + * May be copied or modified under the terms of the GNU General Public License + * + * Development of this chipset driver was funded + * by the nice folks at National Semiconductor. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "ide_modes.h" +#include "sc1200.h" + +#define DISPLAY_SC1200_TIMINGS + +#if defined(DISPLAY_SC1200_TIMINGS) && defined(CONFIG_PROC_FS) +#include +#include + +static int sc1200_get_info(char *, char **, off_t, int); +extern int (*sc1200_display_info)(char *, char **, off_t, int); /* ide-proc.c */ +extern char *ide_media_verbose(ide_drive_t *); +static u8 sc1200_proc = 0; + +#define SC1200_REV_A 0x00 +#define SC1200_REV_B1 0x01 +#define SC1200_REV_B3 0x02 +#define SC1200_REV_C1 0x03 +#define SC1200_REV_D1 0x04 + +#define PCI_CLK_33 0x00 +#define PCI_CLK_48 0x01 +#define PCI_CLK_66 0x02 +#define PCI_CLK_33A 0x03 + +static unsigned short sc1200_get_pci_clock (void) +{ + unsigned char chip_id, silicon_revision; + unsigned int pci_clock; + /* + * Check the silicon revision, as not all versions of the chip + * have the register with the fast PCI bus timings. + */ + chip_id = inb (0x903c); + silicon_revision = inb (0x903d); + + // Read the fast pci clock frequency + if (chip_id == 0x04 && silicon_revision < SC1200_REV_B1) { + pci_clock = PCI_CLK_33; + } else { + // check clock generator configuration (cfcc) + // the clock is in bits 8 and 9 of this word + + pci_clock = inw (0x901e); + pci_clock >>= 8; + pci_clock &= 0x03; + if (pci_clock == PCI_CLK_33A) + pci_clock = PCI_CLK_33; + } + return pci_clock; +} + +static struct pci_dev *bmide_dev; + +static int sc1200_get_info (char *buffer, char **addr, off_t offset, int count) +{ + char *p = buffer; + u32 bibma = pci_resource_start(bmide_dev, 4); + u8 c0 = 0, c1 = 0; + + /* + * at that point bibma+0x2 et bibma+0xa are byte registers + * to investigate: + */ + + c0 = inb_p((unsigned short)bibma + 0x02); + c1 = inb_p((unsigned short)bibma + 0x0a); + + p += sprintf(p, "\n National SCx200 Chipset.\n"); + p += sprintf(p, "--------------- Primary Channel ---------------- Secondary Channel -------------\n"); + p += sprintf(p, " %sabled %sabled\n", + (c0&0x80) ? "dis" : " en", + (c1&0x80) ? "dis" : " en"); + p += sprintf(p, "--------------- drive0 --------- drive1 -------- drive0 ---------- drive1 ------\n"); + p += sprintf(p, "DMA enabled: %s %s %s %s\n", + (c0&0x20) ? "yes" : "no ", (c0&0x40) ? "yes" : "no ", + (c1&0x20) ? "yes" : "no ", (c1&0x40) ? "yes" : "no " ); + + p += sprintf(p, "UDMA\n"); + p += sprintf(p, "DMA\n"); + p += sprintf(p, "PIO\n"); + + return p-buffer; +} +#endif /* DISPLAY_SC1200_TIMINGS && CONFIG_PROC_FS */ + +extern char *ide_xfer_verbose (byte xfer_rate); + +/* + * Set a new transfer mode at the drive + */ +int sc1200_set_xfer_mode (ide_drive_t *drive, byte mode) +{ + printk("%s: sc1200_set_xfer_mode(%s)\n", drive->name, ide_xfer_verbose(mode)); + return ide_config_drive_speed(drive, mode); +} + +/* + * Here are the standard PIO mode 0-4 timings for each "format". + * Format-0 uses fast data reg timings, with slower command reg timings. + * Format-1 uses fast timings for all registers, but won't work with all drives. + */ +static const unsigned int sc1200_pio_timings[4][5] = + {{0x00009172, 0x00012171, 0x00020080, 0x00032010, 0x00040010}, // format0 33Mhz + {0xd1329172, 0x71212171, 0x30200080, 0x20102010, 0x00100010}, // format1, 33Mhz + {0xfaa3f4f3, 0xc23232b2, 0x513101c1, 0x31213121, 0x10211021}, // format1, 48Mhz + {0xfff4fff4, 0xf35353d3, 0x814102f1, 0x42314231, 0x11311131}}; // format1, 66Mhz + +/* + * After chip reset, the PIO timings are set to 0x00009172, which is not valid. + */ +//#define SC1200_BAD_PIO(timings) (((timings)&~0x80000000)==0x00009172) + +static int sc1200_autoselect_dma_mode (ide_drive_t *drive) +{ + int udma_ok = 1, mode = 0; + ide_hwif_t *hwif = HWIF(drive); + int unit = drive->select.b.unit; + ide_drive_t *mate = &hwif->drives[unit^1]; + struct hd_driveid *id = drive->id; + + /* + * The SC1200 specifies that two drives sharing a cable cannot + * mix UDMA/MDMA. It has to be one or the other, for the pair, + * though different timings can still be chosen for each drive. + * We could set the appropriate timing bits on the fly, + * but that might be a bit confusing. So, for now we statically + * handle this requirement by looking at our mate drive to see + * what it is capable of, before choosing a mode for our own drive. + */ + if (mate->present) { + struct hd_driveid *mateid = mate->id; + if (mateid && (mateid->capability & 1) && !hwif->ide_dma_bad_drive(mate)) { + if ((mateid->field_valid & 4) && (mateid->dma_ultra & 7)) + udma_ok = 1; + else if ((mateid->field_valid & 2) && (mateid->dma_mword & 7)) + udma_ok = 0; + else + udma_ok = 1; + } + } + /* + * Now see what the current drive is capable of, + * selecting UDMA only if the mate said it was ok. + */ + if (id && (id->capability & 1) && hwif->autodma && !hwif->ide_dma_bad_drive(drive)) { + if (udma_ok && (id->field_valid & 4) && (id->dma_ultra & 7)) { + if (id->dma_ultra & 4) + mode = XFER_UDMA_2; + else if (id->dma_ultra & 2) + mode = XFER_UDMA_1; + else if (id->dma_ultra & 1) + mode = XFER_UDMA_0; + } + if (!mode && (id->field_valid & 2) && (id->dma_mword & 7)) { + if (id->dma_mword & 4) + mode = XFER_MW_DMA_2; + else if (id->dma_mword & 2) + mode = XFER_MW_DMA_1; + else if (id->dma_mword & 1) + mode = XFER_MW_DMA_0; + } + } + return mode; +} + +/* + * sc1200_config_dma2() handles selection/setting of DMA/UDMA modes + * for both the chipset and drive. + */ +static int sc1200_config_dma2 (ide_drive_t *drive, int mode) +{ + ide_hwif_t *hwif = HWIF(drive); + int unit = drive->select.b.unit; + unsigned int reg, timings; + unsigned short pci_clock; + unsigned int basereg = hwif->channel ? 0x50 : 0x40; + + /* + * Default to DMA-off in case we run into trouble here. + */ + hwif->ide_dma_off_quietly(drive); /* turn off DMA while we fiddle */ + outb(inb(hwif->dma_base+2)&~(unit?0x40:0x20), hwif->dma_base+2); /* clear DMA_capable bit */ + + /* + * Tell the drive to switch to the new mode; abort on failure. + */ + if (!mode || sc1200_set_xfer_mode(drive, mode)) { + printk("SC1200: set xfer mode failure\n"); + return 1; /* failure */ + } + + pci_clock = sc1200_get_pci_clock(); + + /* + * Now tune the chipset to match the drive: + * + * Note that each DMA mode has several timings associated with it. + * The correct timing depends on the fast PCI clock freq. + */ + timings = 0; + switch (mode) { + case XFER_UDMA_0: + switch (pci_clock) { + case PCI_CLK_33: timings = 0x00921250; break; + case PCI_CLK_48: timings = 0x00932470; break; + case PCI_CLK_66: timings = 0x009436a1; break; + } + break; + case XFER_UDMA_1: + switch (pci_clock) { + case PCI_CLK_33: timings = 0x00911140; break; + case PCI_CLK_48: timings = 0x00922260; break; + case PCI_CLK_66: timings = 0x00933481; break; + } + break; + case XFER_UDMA_2: + switch (pci_clock) { + case PCI_CLK_33: timings = 0x00911030; break; + case PCI_CLK_48: timings = 0x00922140; break; + case PCI_CLK_66: timings = 0x00923261; break; + } + break; + case XFER_MW_DMA_0: + switch (pci_clock) { + case PCI_CLK_33: timings = 0x00077771; break; + case PCI_CLK_48: timings = 0x000bbbb2; break; + case PCI_CLK_66: timings = 0x000ffff3; break; + } + break; + case XFER_MW_DMA_1: + switch (pci_clock) { + case PCI_CLK_33: timings = 0x00012121; break; + case PCI_CLK_48: timings = 0x00024241; break; + case PCI_CLK_66: timings = 0x00035352; break; + } + break; + case XFER_MW_DMA_2: + switch (pci_clock) { + case PCI_CLK_33: timings = 0x00002020; break; + case PCI_CLK_48: timings = 0x00013131; break; + case PCI_CLK_66: timings = 0x00015151; break; + } + break; + } + + if (timings == 0) { + printk("%s: sc1200_config_dma: huh? mode=%02x clk=%x \n", drive->name, mode, pci_clock); + return 1; /* failure */ + } + + if (unit == 0) { /* are we configuring drive0? */ + pci_read_config_dword(hwif->pci_dev, basereg+4, ®); + timings |= reg & 0x80000000; /* preserve PIO format bit */ + pci_write_config_dword(hwif->pci_dev, basereg+4, timings); + } else { + pci_write_config_dword(hwif->pci_dev, basereg+12, timings); + } + + outb(inb(hwif->dma_base+2)|(unit?0x40:0x20), hwif->dma_base+2); /* set DMA_capable bit */ + + /* + * Finally, turn DMA on in software, and exit. + */ + return hwif->ide_dma_on(drive); /* success */ +} + +/* + * sc1200_config_dma() handles selection/setting of DMA/UDMA modes + * for both the chipset and drive. + */ +static int sc1200_config_dma (ide_drive_t *drive) +{ + return sc1200_config_dma2(drive, sc1200_autoselect_dma_mode(drive)); +} + + +/* Replacement for the standard ide_dma_end action in + * dma_proc. + * + * returns 1 on error, 0 otherwise + */ +int sc1200_ide_dma_end (ide_drive_t *drive) +{ + ide_hwif_t *hwif = HWIF(drive); + unsigned long dma_base = hwif->dma_base; + byte dma_stat; + + dma_stat = inb(dma_base+2); /* get DMA status */ + + if (!(dma_stat & 4)) + printk(" ide_dma_end dma_stat=%0x err=%x newerr=%x\n", + dma_stat, ((dma_stat&7)!=4), ((dma_stat&2)==2)); + + outb(dma_stat|0x1b, dma_base+2); /* clear the INTR & ERROR bits */ + outb(inb(dma_base)&~1, dma_base); /* !! DO THIS HERE !! stop DMA */ + + drive->waiting_for_dma = 0; + ide_destroy_dmatable(drive); /* purge DMA mappings */ + + return (dma_stat & 7) != 4; /* verify good DMA status */ +} + +/* + * sc1200_tuneproc() handles selection/setting of PIO modes + * for both the chipset and drive. + * + * All existing BIOSs for this chipset guarantee that all drives + * will have valid default PIO timings set up before we get here. + */ +static void sc1200_tuneproc (ide_drive_t *drive, byte pio) /* mode=255 means "autotune" */ +{ + ide_hwif_t *hwif = HWIF(drive); + unsigned int format; + static byte modes[5] = {XFER_PIO_0, XFER_PIO_1, XFER_PIO_2, XFER_PIO_3, XFER_PIO_4}; + int mode = -1; + + switch (pio) { + case 200: mode = XFER_UDMA_0; break; + case 201: mode = XFER_UDMA_1; break; + case 202: mode = XFER_UDMA_2; break; + case 100: mode = XFER_MW_DMA_0; break; + case 101: mode = XFER_MW_DMA_1; break; + case 102: mode = XFER_MW_DMA_2; break; + } + if (mode != -1) { + printk("SC1200: %s: changing (U)DMA mode\n", drive->name); + (void)sc1200_config_dma2(drive, mode); + return; + } + + pio = ide_get_best_pio_mode(drive, pio, 4, NULL); + printk("SC1200: %s: setting PIO mode%d\n", drive->name, pio); + if (!sc1200_set_xfer_mode(drive, modes[pio])) { + unsigned int basereg = hwif->channel ? 0x50 : 0x40; + pci_read_config_dword (hwif->pci_dev, basereg+4, &format); + format = (format >> 31) & 1; + if (format) + format += sc1200_get_pci_clock(); + pci_write_config_dword(hwif->pci_dev, basereg + (drive->select.b.unit << 3), sc1200_pio_timings[format][pio]); + } +} + +static ide_hwif_t *lookup_pci_dev (ide_hwif_t *prev, struct pci_dev *dev) +{ + int h; + + for (h = 0; h < MAX_HWIFS; h++) { + ide_hwif_t *hwif = &ide_hwifs[h]; + if (prev) { + if (hwif == prev) + prev = NULL; // found previous, now look for next match + } else { + if (hwif && hwif->pci_dev == dev) + return hwif; // found next match + } + } + return NULL; // not found +} + +typedef struct sc1200_saved_state_s { + __u32 regs[4]; +} sc1200_saved_state_t; + +static int sc1200_save_state (struct pci_dev *dev, u32 state) +{ + ide_hwif_t *hwif = NULL; + +printk("SC1200: save_state(%u)\n", state); + if (state != 0) + return 0; // we only save state when going from full power to less + // + // Loop over all interfaces that are part of this PCI device: + // + while ((hwif = lookup_pci_dev(hwif, dev)) != NULL) { + sc1200_saved_state_t *ss; + unsigned int basereg, r; + // + // allocate a permanent save area, if not already allocated + // + ss = (sc1200_saved_state_t *)hwif->config_data; + if (ss == NULL) { + ss = kmalloc(sizeof(sc1200_saved_state_t), GFP_KERNEL); + if (ss == NULL) + return -ENOMEM; + (sc1200_saved_state_t *)hwif->config_data = ss; + } + ss = (sc1200_saved_state_t *)hwif->config_data; + // + // Save timing registers: this may be unnecessary if BIOS also does it + // + basereg = hwif->channel ? 0x50 : 0x40; + for (r = 0; r < 4; ++r) { + pci_read_config_dword (hwif->pci_dev, basereg + (r<<2), &ss->regs[r]); + } + } + return 0; +} + +static int sc1200_suspend (struct pci_dev *dev, u32 state) +{ + ide_hwif_t *hwif = NULL; + + printk("SC1200: suspend(%u)\n", state); + /* You don't need to iterate over disks -- sysfs should have done that for you already */ + + pci_disable_device(dev); + pci_set_power_state(dev,state); + dev->current_state = state; + return 0; +} + +static int sc1200_resume (struct pci_dev *dev) +{ + ide_hwif_t *hwif = NULL; + +printk("SC1200: resume\n"); + pci_set_power_state(dev,0); // bring chip back from sleep state + dev->current_state = 0; + pci_enable_device(dev); + // + // loop over all interfaces that are part of this pci device: + // + while ((hwif = lookup_pci_dev(hwif, dev)) != NULL) { + unsigned int basereg, r, d, format; + sc1200_saved_state_t *ss = (sc1200_saved_state_t *)hwif->config_data; +printk("%s: SC1200: resume\n", hwif->name); + + // + // Restore timing registers: this may be unnecessary if BIOS also does it + // + basereg = hwif->channel ? 0x50 : 0x40; + if (ss != NULL) { + for (r = 0; r < 4; ++r) { + pci_write_config_dword(hwif->pci_dev, basereg + (r<<2), ss->regs[r]); + } + } + // + // Re-program drive PIO modes + // + pci_read_config_dword(hwif->pci_dev, basereg+4, &format); + format = (format >> 31) & 1; + if (format) + format += sc1200_get_pci_clock(); + for (d = 0; d < 2; ++d) { + ide_drive_t *drive = &(hwif->drives[d]); + if (drive->present) { + unsigned int pio, timings; + pci_read_config_dword(hwif->pci_dev, basereg+(drive->select.b.unit << 3), &timings); + for (pio = 0; pio <= 4; ++pio) { + if (sc1200_pio_timings[format][pio] == timings) + break; + } + if (pio > 4) + pio = 255; /* autotune */ + (void)sc1200_tuneproc(drive, pio); + } + } + // + // Re-program drive DMA modes + // + for (d = 0; d < MAX_DRIVES; ++d) { + ide_drive_t *drive = &(hwif->drives[d]); + if (drive->present && !hwif->ide_dma_bad_drive(drive)) { + int was_using_dma = drive->using_dma; + hwif->ide_dma_off_quietly(drive); + sc1200_config_dma(drive); + if (!was_using_dma && drive->using_dma) { + hwif->ide_dma_off_quietly(drive); + } + } + } + } + return 0; +} + +/* + * Initialize the sc1200 bridge for reliable IDE DMA operation. + */ +static unsigned int __init init_chipset_sc1200 (struct pci_dev *dev, const char *name) +{ +#if defined(DISPLAY_SC1200_TIMINGS) && defined(CONFIG_PROC_FS) + if (!bmide_dev) { + sc1200_proc = 1; + bmide_dev = dev; + ide_pci_register_host_proc(&sc1200_procs[0]); + } +#endif /* DISPLAY_SC1200_TIMINGS && CONFIG_PROC_FS */ + return 0; +} + +/* + * This gets invoked by the IDE driver once for each channel, + * and performs channel-specific pre-initialization before drive probing. + */ +static void __init init_hwif_sc1200 (ide_hwif_t *hwif) +{ + if (hwif->mate) + hwif->serialized = hwif->mate->serialized = 1; + hwif->autodma = 0; + if (hwif->dma_base) { + hwif->ide_dma_check = &sc1200_config_dma; + hwif->ide_dma_end = &sc1200_ide_dma_end; + if (!noautodma) + hwif->autodma = 1; + hwif->tuneproc = &sc1200_tuneproc; + } + hwif->atapi_dma = 1; + hwif->ultra_mask = 0x07; + hwif->mwdma_mask = 0x07; + + hwif->drives[0].autodma = hwif->autodma; + hwif->drives[1].autodma = hwif->autodma; +} + +static void __init init_dma_sc1200 (ide_hwif_t *hwif, unsigned long dmabase) +{ + ide_setup_dma(hwif, dmabase, 8); +} + +extern void ide_setup_pci_device(struct pci_dev *, ide_pci_device_t *); + + +static int __devinit sc1200_init_one(struct pci_dev *dev, const struct pci_device_id *id) +{ + ide_pci_device_t *d = &sc1200_chipsets[id->driver_data]; + if (dev->device != d->device) + BUG(); + ide_setup_pci_device(dev, d); + MOD_INC_USE_COUNT; + return 0; +} + +static struct pci_device_id sc1200_pci_tbl[] __devinitdata = { + { PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_SCx200_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + { 0, }, +}; + +static struct pci_driver driver = { + .name = "SC1200 IDE", + .id_table = sc1200_pci_tbl, + .probe = sc1200_init_one, + .save_state = sc1200_save_state, + .suspend = sc1200_suspend, + .resume = sc1200_resume, +}; + +static int sc1200_ide_init(void) +{ + return ide_pci_register_driver(&driver); +} + +static void sc1200_ide_exit(void) +{ + ide_pci_unregister_driver(&driver); +} + +module_init(sc1200_ide_init); +module_exit(sc1200_ide_exit); + +MODULE_AUTHOR("Mark Lord"); +MODULE_DESCRIPTION("PCI driver module for NS SC1200 IDE"); +MODULE_LICENSE("GPL"); + +EXPORT_NO_SYMBOLS; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/drivers/ide/pci/sc1200.h linux.2.5.47-ac6/drivers/ide/pci/sc1200.h --- linux.2.5.47/drivers/ide/pci/sc1200.h 1970-01-01 01:00:00.000000000 +0100 +++ linux.2.5.47-ac6/drivers/ide/pci/sc1200.h 2002-11-11 21:18:42.000000000 +0000 @@ -0,0 +1,54 @@ +#ifndef SC1200_H +#define SC1200_H + +#include +#include +#include + +#define DISPLAY_SC1200_TIMINGS + +#if defined(DISPLAY_SC1200_TIMINGS) && defined(CONFIG_PROC_FS) +#include +#include + +static u8 sc1200_proc; + +static int sc1200_get_info(char *, char **, off_t, int); + +static ide_pci_host_proc_t sc1200_procs[] __initdata = { + { + name: "sc1200", + set: 1, + get_info: sc1200_get_info, + parent: NULL, + }, +}; +#endif /* DISPLAY_SC1200_TIMINGS && CONFIG_PROC_FS */ + +static unsigned int init_chipset_sc1200(struct pci_dev *, const char *); +static void init_hwif_sc1200(ide_hwif_t *); +static void init_dma_sc1200(ide_hwif_t *, unsigned long); + +static ide_pci_device_t sc1200_chipsets[] __devinitdata = { + { /* 0 */ + vendor: PCI_VENDOR_ID_NS, + device: PCI_DEVICE_ID_NS_SCx200_IDE, + name: "SC1200", + init_chipset: init_chipset_sc1200, + init_iops: NULL, + init_hwif: init_hwif_sc1200, + init_dma: init_dma_sc1200, + channels: 2, + autodma: AUTODMA, + enablebits: {{0x00,0x00,0x00}, {0x00,0x00,0x00}}, + bootable: ON_BOARD, + extra: 0, + },{ + vendor: 0, + device: 0, + channels: 0, + bootable: EOL, + } +}; + +#endif /* SC1200_H */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/drivers/ide/pci/serverworks.c linux.2.5.47-ac6/drivers/ide/pci/serverworks.c --- linux.2.5.47/drivers/ide/pci/serverworks.c 2002-10-31 14:57:17.000000000 +0000 +++ linux.2.5.47-ac6/drivers/ide/pci/serverworks.c 2002-11-13 14:56:07.000000000 +0000 @@ -251,7 +251,7 @@ ide_hwif_t *hwif = HWIF(drive); struct pci_dev *dev = hwif->pci_dev; - u8 speed = ide_rate_filter(svwks_ratemask(drive), xferspeed); + u8 speed = ide_rate_filter(svwks_ratemask(drive), xferspeed); u8 pio = ide_get_best_pio_mode(drive, 255, 5, NULL); u8 unit = (drive->select.b.unit & 0x01); u8 csb5 = svwks_csb_check(dev); @@ -259,6 +259,13 @@ u8 dma_timing = 0, pio_timing = 0; u16 csb5_pio = 0; + /* If we are about to put a disk into UDMA mode we screwed up. + Our code assumes we never _ever_ do this on an OSB4 */ + + if(dev->device == PCI_DEVICE_ID_SERVERWORKS_OSB4 && + drive->media != ide_disk && speed >= XFER_UDMA_0) + BUG(); + pci_read_config_byte(dev, drive_pci[drive->dn], &pio_timing); pci_read_config_byte(dev, drive_pci2[drive->dn], &dma_timing); pci_read_config_byte(dev, (0x56|hwif->channel), &ultra_timing); @@ -331,7 +338,6 @@ csb5_pio |= ((speed - XFER_PIO_0) << (4*drive->dn)); break; -#ifdef CONFIG_BLK_DEV_IDEDMA case XFER_MW_DMA_2: case XFER_MW_DMA_1: case XFER_MW_DMA_0: @@ -351,7 +357,6 @@ dma_timing |= dma_modes[2]; ultra_timing |= ((udma_modes[speed - XFER_UDMA_0]) << (4*unit)); ultra_enable |= (0x01 << drive->dn); -#endif default: break; } @@ -360,11 +365,9 @@ if (csb5) pci_write_config_word(dev, 0x4A, csb5_pio); -#ifdef CONFIG_BLK_DEV_IDEDMA pci_write_config_byte(dev, drive_pci2[drive->dn], dma_timing); pci_write_config_byte(dev, (0x56|hwif->channel), ultra_timing); pci_write_config_byte(dev, 0x54, ultra_enable); -#endif /* CONFIG_BLK_DEV_IDEDMA */ return (ide_config_drive_speed(drive, speed)); } @@ -412,7 +415,6 @@ (void) svwks_tune_chipset(drive, (XFER_PIO_0 + pio)); } -#ifdef CONFIG_BLK_DEV_IDEDMA static int config_chipset_for_dma (ide_drive_t *drive) { u8 speed = ide_dma_speed(drive, svwks_ratemask(drive)); @@ -470,6 +472,12 @@ static int svwks_ide_dma_end (ide_drive_t *drive) { + /* + * We never place the OSB4 into a UDMA mode with a disk + * medium, that means the UDMA "all my data is 4 byte shifted" + * problem cannot occur. + */ +#if 0 ide_hwif_t *hwif = HWIF(drive); u8 dma_stat = hwif->INB(hwif->dma_status); @@ -483,9 +491,9 @@ while(1) cpu_relax(); } +#endif return __ide_dma_end(drive); } -#endif /* CONFIG_BLK_DEV_IDEDMA */ static unsigned int __init init_chipset_svwks (struct pci_dev *dev, const char *name) { @@ -703,7 +711,6 @@ return; } -#ifdef CONFIG_BLK_DEV_IDEDMA hwif->ide_dma_check = &svwks_config_drive_xfer_rate; if (hwif->pci_dev->device == PCI_DEVICE_ID_SERVERWORKS_OSB4IDE) hwif->ide_dma_end = &svwks_ide_dma_end; @@ -719,7 +726,6 @@ hwif->drives[1].autotune = (!(dma_stat & 0x40)); // hwif->drives[0].autodma = hwif->autodma; // hwif->drives[1].autodma = hwif->autodma; -#endif /* !CONFIG_BLK_DEV_IDEDMA */ } /* diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/drivers/ide/pci/siimage.c linux.2.5.47-ac6/drivers/ide/pci/siimage.c --- linux.2.5.47/drivers/ide/pci/siimage.c 2002-10-31 15:05:01.000000000 +0000 +++ linux.2.5.47-ac6/drivers/ide/pci/siimage.c 2002-11-13 14:57:12.000000000 +0000 @@ -205,7 +205,6 @@ siimage_tuneproc(drive, (speed - XFER_PIO_0)); mode |= ((unit) ? 0x10 : 0x01); break; -#ifdef CONFIG_BLK_DEV_IDEDMA case XFER_MW_DMA_2: case XFER_MW_DMA_1: case XFER_MW_DMA_0: @@ -226,7 +225,6 @@ mode |= ((unit) ? 0x30 : 0x03); config_siimage_chipset_for_pio(drive, 0); break; -#endif /* CONFIG_BLK_DEV_IDEDMA */ default: return 1; } @@ -246,7 +244,6 @@ return (ide_config_drive_speed(drive, speed)); } -#ifdef CONFIG_BLK_DEV_IDEDMA static int config_chipset_for_dma (ide_drive_t *drive) { u8 speed = ide_dma_speed(drive, siimage_ratemask(drive)); @@ -256,7 +253,7 @@ if ((!(speed))) return 0; - if (HWIF(drive)->speedproc(drive, speed)) + if (ide_set_xfer_rate(drive, speed)) return 0; if (!drive->init_speed) @@ -392,7 +389,6 @@ #endif return temp; } -#endif /* CONFIG_BLK_DEV_IDEDMA */ static int siimage_busproc (ide_drive_t * drive, int state) { @@ -811,7 +807,6 @@ if (hwif->pci_dev->device != PCI_DEVICE_ID_SII_3112) hwif->atapi_dma = 1; -#ifdef CONFIG_BLK_DEV_IDEDMA hwif->ide_dma_check = &siimage_config_drive_for_dma; if (!(hwif->udma_four)) hwif->udma_four = ata66_siimage(hwif); @@ -827,7 +822,6 @@ hwif->autodma = 1; hwif->drives[0].autodma = hwif->autodma; hwif->drives[1].autodma = hwif->autodma; -#endif /* CONFIG_BLK_DEV_IDEDMA */ } static void __init init_dma_siimage (ide_hwif_t *hwif, unsigned long dmabase) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/drivers/ide/pci/siimage.h linux.2.5.47-ac6/drivers/ide/pci/siimage.h --- linux.2.5.47/drivers/ide/pci/siimage.h 2002-10-31 14:57:17.000000000 +0000 +++ linux.2.5.47-ac6/drivers/ide/pci/siimage.h 2002-11-12 15:30:00.000000000 +0000 @@ -62,14 +62,14 @@ // while (count--) { *(u32 *)addr = readl(port); addr += 4; } } -inline void sii_outb (u8 addr, u32 port) +inline void sii_outb (u8 value, u32 port) { - writeb(addr, port); + writeb(value, port); } -inline void sii_outw (u16 addr, u32 port) +inline void sii_outw (u16 value, u32 port) { - writew(addr, port); + writew(value, port); } inline void sii_outsw (u32 port, void *addr, u32 count) @@ -77,9 +77,9 @@ while (count--) { writew(*(u16 *)addr, port); addr += 2; } } -inline void sii_outl (u32 addr, u32 port) +inline void sii_outl (u32 value, u32 port) { - writel(addr, port); + writel(value, port); } inline void sii_outsl (u32 port, void *addr, u32 count) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/drivers/ide/pci/sis5513.c linux.2.5.47-ac6/drivers/ide/pci/sis5513.c --- linux.2.5.47/drivers/ide/pci/sis5513.c 2002-10-31 15:05:01.000000000 +0000 +++ linux.2.5.47-ac6/drivers/ide/pci/sis5513.c 2002-11-13 14:57:39.000000000 +0000 @@ -703,7 +703,6 @@ /* Config chip for mode */ switch(speed) { -#ifdef CONFIG_BLK_DEV_IDEDMA case XFER_UDMA_6: case XFER_UDMA_5: case XFER_UDMA_4: @@ -745,7 +744,6 @@ case XFER_SW_DMA_1: case XFER_SW_DMA_0: break; -#endif /* CONFIG_BLK_DEV_IDEDMA */ case XFER_PIO_4: return((int) config_chipset_for_pio(drive, 4)); case XFER_PIO_3: return((int) config_chipset_for_pio(drive, 3)); case XFER_PIO_2: return((int) config_chipset_for_pio(drive, 2)); @@ -764,7 +762,6 @@ (void) config_chipset_for_pio(drive, pio); } -#ifdef CONFIG_BLK_DEV_IDEDMA /* * ((id->hw_config & 0x4000|0x2000) && (HWIF(drive)->udma_four)) */ @@ -835,8 +832,6 @@ return sis5513_config_drive_xfer_rate(drive); } -#endif /* CONFIG_BLK_DEV_IDEDMA */ - /* Chip detection and general config */ static unsigned int __init init_chipset_sis5513 (struct pci_dev *dev, const char *name) { @@ -999,7 +994,6 @@ hwif->mwdma_mask = 0x07; hwif->swdma_mask = 0x07; -#ifdef CONFIG_BLK_DEV_IDEDMA if (!host_dev) return; @@ -1013,7 +1007,6 @@ } hwif->drives[0].autodma = hwif->autodma; hwif->drives[1].autodma = hwif->autodma; -#endif return; } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/drivers/ide/pci/trm290.c linux.2.5.47-ac6/drivers/ide/pci/trm290.c --- linux.2.5.47/drivers/ide/pci/trm290.c 2002-10-31 14:57:17.000000000 +0000 +++ linux.2.5.47-ac6/drivers/ide/pci/trm290.c 2002-11-13 14:58:02.000000000 +0000 @@ -176,7 +176,6 @@ trm290_prepare_drive(drive, drive->using_dma); } -#ifdef CONFIG_BLK_DEV_IDEDMA static int trm290_ide_dma_write (ide_drive_t *drive /*, struct request *rq */) { ide_hwif_t *hwif = HWIF(drive); @@ -297,7 +296,6 @@ status = hwif->INW(hwif->dma_status); return (status == 0x00ff); } -#endif /* CONFIG_BLK_DEV_IDEDMA */ /* * Invoked from ide-dma.c at boot time. @@ -344,13 +342,11 @@ ide_setup_dma(hwif, (hwif->config_data + 4) ^ (hwif->channel ? 0x0080 : 0x0000), 3); -#ifdef CONFIG_BLK_DEV_IDEDMA hwif->ide_dma_write = &trm290_ide_dma_write; hwif->ide_dma_read = &trm290_ide_dma_read; hwif->ide_dma_begin = &trm290_ide_dma_begin; hwif->ide_dma_end = &trm290_ide_dma_end; hwif->ide_dma_test_irq = &trm290_ide_dma_test_irq; -#endif /* CONFIG_BLK_DEV_IDEDMA */ hwif->selectproc = &trm290_selectproc; hwif->autodma = 0; /* play it safe for now */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/drivers/ide/pci/via82cxxx.c linux.2.5.47-ac6/drivers/ide/pci/via82cxxx.c --- linux.2.5.47/drivers/ide/pci/via82cxxx.c 2002-10-31 14:57:17.000000000 +0000 +++ linux.2.5.47-ac6/drivers/ide/pci/via82cxxx.c 2002-11-13 14:58:20.000000000 +0000 @@ -383,8 +383,6 @@ via_set_drive(drive, XFER_PIO_0 + MIN(pio, 5)); } -#ifdef CONFIG_BLK_DEV_IDEDMA - /** * via82cxxx_ide_dma_check - set up for DMA if possible * @drive: IDE drive to set up @@ -411,8 +409,6 @@ return HWIF(drive)->ide_dma_off_quietly(drive); } -#endif /* CONFIG_BLK_DEV_IDEDMA */ - /** * init_chipset_via82cxxx - initialization handler * @dev: PCI device @@ -608,7 +604,6 @@ hwif->mwdma_mask = 0x07; hwif->swdma_mask = 0x07; -#ifdef CONFIG_BLK_DEV_IDEDMA if (!(hwif->udma_four)) hwif->udma_four = ((via_enabled & via_80w) >> hwif->channel) & 1; hwif->ide_dma_check = &via82cxxx_ide_dma_check; @@ -616,7 +611,6 @@ hwif->autodma = 1; hwif->drives[0].autodma = hwif->autodma; hwif->drives[1].autodma = hwif->autodma; -#endif /* CONFIG_BLK_DEV_IDEDMA */ } /** diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/drivers/ide/setup-pci.c linux.2.5.47-ac6/drivers/ide/setup-pci.c --- linux.2.5.47/drivers/ide/setup-pci.c 2002-11-11 16:39:10.000000000 +0000 +++ linux.2.5.47-ac6/drivers/ide/setup-pci.c 2002-11-18 18:53:16.000000000 +0000 @@ -10,6 +10,7 @@ * Split the set up function into multiple functions * Use pci_set_master * Fix misreporting of I/O v MMIO problems + * Initial fixups for simplex devices */ /* @@ -42,6 +43,8 @@ * based on io_base port if possible. Return the matching hwif, * or a new hwif. If we find an error (clashing, out of devices, etc) * return NULL + * + * FIXME: we need to handle mmio matches here too */ static ide_hwif_t *ide_match_hwif(unsigned long io_base, u8 bootable, const char *name) @@ -144,34 +147,9 @@ return -EOPNOTSUPP; } } - -#if 0 - /* - * At this point we have enabled the device, but may previously - * have done a BAR4 enable alone. We should be prepared to assign - * resources here. - */ - - /* - * Setup base registers for IDE command/control - * spaces for each interface: - */ - for (reg = 0; reg < 4; reg++) { - struct resource *res = dev->resource + reg; - if ((res->flags & IORESOURCE_IO) == 0) - continue; - if (!res->start) { - if(pci_assign_resource(dev, reg)) { - printk(KERN_ERR "%s: Missing I/O address #%d\n", name, reg); - return -ENXIO; - } - } - } -#endif return 0; } -#ifdef CONFIG_BLK_DEV_IDEDMA #ifdef CONFIG_BLK_DEV_IDEDMA_FORCED /* * Long lost data from 2.0.34 that is now in 2.0.39 @@ -192,9 +170,6 @@ * Fetch the DMA Bus-Master-I/O-Base-Address (BMIBA) from PCI space: * If need be we set up the DMA base. Where a device has a partner that * is already in DMA mode we check and enforce IDE simplex rules. - * - * FIXME: currently we are sometimes enforicng simplex when it is not - * needed. We fail the safe way but why is it occurring ?? */ static unsigned long __init ide_get_or_set_dma_base (ide_hwif_t *hwif) @@ -274,7 +249,14 @@ simplex_stat = hwif->INB(dma_base + 2); if (simplex_stat & 0x80) { /* simplex device? */ - +#if 0 +/* + * At this point we haven't probed the drives so we can't make the + * appropriate decision. Really we should defer this problem + * until we tune the drive then try to grab DMA ownership if we want + * to be the DMA end. This has to be become dynamic to handle hot + * plug. + */ /* Don't enable DMA on a simplex channel with no drives */ if (!hwif->drives[0].present && !hwif->drives[1].present) { @@ -283,7 +265,9 @@ dma_base = 0; } /* If our other channel has DMA then we cannot */ - else if(hwif->mate && hwif->mate->dma_base) + else +#endif + if(hwif->mate && hwif->mate->dma_base) { printk(KERN_INFO "%s: simplex device: " "DMA disabled\n", @@ -295,9 +279,8 @@ } return dma_base; } -#endif /* CONFIG_BLK_DEV_IDEDMA */ -static void ide_setup_pci_noise (struct pci_dev *dev, ide_pci_device_t *d) +void ide_setup_pci_noise (struct pci_dev *dev, ide_pci_device_t *d) { if ((d->vendor != dev->vendor) && (d->device != dev->device)) { printk(KERN_INFO "%s: unknown IDE controller at PCI slot " @@ -309,6 +292,9 @@ } } +EXPORT_SYMBOL_GPL(ide_setup_pci_noise); + + /** * ide_pci_enable - do PCI enables * @dev: PCI device @@ -414,8 +400,7 @@ ".\n", d->name); return -EINVAL; } - - + /** * ide_hwif_configure - configure an IDE interface * @dev: PCI device holding interface @@ -434,16 +419,19 @@ unsigned long ctl = 0, base = 0; ide_hwif_t *hwif; - /* Possibly we should fail if these checks report true */ - ide_pci_check_iomem(dev, d, 2*port); - ide_pci_check_iomem(dev, d, 2*port+1); - - ctl = pci_resource_start(dev, 2*port+1); - base = pci_resource_start(dev, 2*port); - if ((ctl && !base) || (base && !ctl)) { - printk(KERN_ERR "%s: inconsistent baseregs (BIOS) " - "for port %d, skipping\n", d->name, port); - return NULL; + if(!d->isa_ports) + { + /* Possibly we should fail if these checks report true */ + ide_pci_check_iomem(dev, d, 2*port); + ide_pci_check_iomem(dev, d, 2*port+1); + + ctl = pci_resource_start(dev, 2*port+1); + base = pci_resource_start(dev, 2*port); + if ((ctl && !base) || (base && !ctl)) { + printk(KERN_ERR "%s: inconsistent baseregs (BIOS) " + "for port %d, skipping\n", d->name, port); + return NULL; + } } if (!ctl) { @@ -500,8 +488,9 @@ * Set up BM-DMA capability * (PnP BIOS should have done this) */ - if ((d->device != PCI_DEVICE_ID_CYRIX_5530_IDE) - && (d->vendor != PCI_VENDOR_ID_CYRIX)) { + if (!((d->device == PCI_DEVICE_ID_CYRIX_5530_IDE && d->vendor == PCI_VENDOR_ID_CYRIX) + ||(d->device == PCI_DEVICE_ID_NS_SCx200_IDE && d->vendor == PCI_VENDOR_ID_NS))) + { /* * default DMA off if we had to * configure it here @@ -575,75 +564,33 @@ return ret; } -/* - * ide_setup_pci_device() looks at the primary/secondary interfaces - * on a PCI IDE device and, if they are enabled, prepares the IDE driver - * for use with them. This generic code works for most PCI chipsets. +/** + * ide_pci_setup_ports - configure ports/devices on PCI IDE + * @dev: PCI device + * @d: IDE pci device info + * @autodma: Should we enable DMA + * @pciirq: IRQ line + * @index: ata index to update * - * One thing that is not standardized is the location of the - * primary/secondary interface "enable/disable" bits. For chipsets that - * we "know" about, this information is in the ide_pci_device_t struct; - * for all other chipsets, we just assume both interfaces are enabled. + * Scan the interfaces attached to this device and do any + * neccessary per port setup. Attach the devices and ask the + * generic DMA layer to do its work for us. + * + * Normally called automaticall from do_ide_pci_setup_device, + * but is also used directly as a helper function by some controllers + * where the chipset setup is not the default PCI IDE one. */ -static ata_index_t do_ide_setup_pci_device (struct pci_dev *dev, ide_pci_device_t *d, u8 noisy) + +void ide_pci_setup_ports(struct pci_dev *dev, ide_pci_device_t *d, int autodma, int pciirq, ata_index_t *index) { - u32 port, at_least_one_hwif_enabled = 0, autodma = 0; - int pciirq = 0; - int tried_config = 0; - int drive0_tune, drive1_tune; - ata_index_t index; - u8 tmp = 0; + int port; + int at_least_one_hwif_enabled = 0; ide_hwif_t *hwif, *mate = NULL; static int secondpdc = 0; + int drive0_tune, drive1_tune; + u8 tmp; - index.all = 0xf0f0; - - if((autodma = ide_setup_pci_controller(dev, d, noisy, &tried_config)) < 0) - return index; - - /* - * Can we trust the reported IRQ? - */ - pciirq = dev->irq; - - if ((dev->class & ~(0xfa)) != ((PCI_CLASS_STORAGE_IDE << 8) | 5)) { - if (noisy) - printk(KERN_INFO "%s: not 100%% native mode: " - "will probe irqs later\n", d->name); - /* - * This allows offboard ide-pci cards the enable a BIOS, - * verify interrupt settings of split-mirror pci-config - * space, place chipset into init-mode, and/or preserve - * an interrupt if the card is not native ide support. - */ - pciirq = (d->init_chipset) ? d->init_chipset(dev, d->name) : 0; - } else if (tried_config) { - if (noisy) - printk(KERN_INFO "%s: will probe irqs later\n", d->name); - pciirq = 0; - } else if (!pciirq) { - if (noisy) - printk(KERN_WARNING "%s: bad irq (%d): will probe later\n", - d->name, pciirq); - pciirq = 0; - } else { - if (d->init_chipset) - { - if(d->init_chipset(dev, d->name) < 0) - return index; - } - if (noisy) -#ifdef __sparc__ - printk(KERN_INFO "%s: 100%% native mode on irq %s\n", - d->name, __irq_itoa(pciirq)); -#else - printk(KERN_INFO "%s: 100%% native mode on irq %d\n", - d->name, pciirq); -#endif - } - - if(pciirq < 0) /* Error not an IRQ */ - return index; + index->all = 0xf0f0; /* * Set up the IDE ports @@ -671,7 +618,7 @@ controller_ok: if (d->channels <= port) - return index; + break; if ((hwif = ide_hwif_configure(dev, d, mate, port, pciirq)) == NULL) continue; @@ -680,25 +627,27 @@ hwif->gendev.parent = &dev->dev; if (hwif->channel) { - index.b.high = hwif->index; + index->b.high = hwif->index; } else { - index.b.low = hwif->index; + index->b.low = hwif->index; } if (d->init_iops) d->init_iops(hwif); -#ifdef CONFIG_BLK_DEV_IDEDMA if (d->autodma == NODMA) goto bypass_legacy_dma; if (d->autodma == NOAUTODMA) autodma = 0; if (autodma) hwif->autodma = 1; - ide_hwif_setup_dma(dev, d, hwif); + + if(d->init_setup_dma) + d->init_setup_dma(dev, d, hwif); + else + ide_hwif_setup_dma(dev, d, hwif); bypass_legacy_dma: -#endif /* CONFIG_BLK_DEV_IDEDMA */ drive0_tune = hwif->drives[0].autotune; drive1_tune = hwif->drives[1].autotune; @@ -708,7 +657,13 @@ * for each enabled hwif */ d->init_hwif(hwif); - + + /* + * This is in the wrong place. The driver may + * do set up based on the autotune value and this + * will then trash it. Torben please move it and + * propogate the fixes into the drivers + */ if (drive0_tune == IDE_TUNE_BIOS) /* biostimings */ hwif->drives[0].autotune = IDE_TUNE_BIOS; if (drive1_tune == IDE_TUNE_BIOS) @@ -719,6 +674,76 @@ } if (!at_least_one_hwif_enabled) printk(KERN_INFO "%s: neither IDE port enabled (BIOS)\n", d->name); +} + +EXPORT_SYMBOL_GPL(ide_pci_setup_ports); + +/* + * ide_setup_pci_device() looks at the primary/secondary interfaces + * on a PCI IDE device and, if they are enabled, prepares the IDE driver + * for use with them. This generic code works for most PCI chipsets. + * + * One thing that is not standardized is the location of the + * primary/secondary interface "enable/disable" bits. For chipsets that + * we "know" about, this information is in the ide_pci_device_t struct; + * for all other chipsets, we just assume both interfaces are enabled. + */ +static ata_index_t do_ide_setup_pci_device (struct pci_dev *dev, ide_pci_device_t *d, u8 noisy) +{ + int autodma = 0; + int pciirq = 0; + int tried_config = 0; + ata_index_t index; + + if((autodma = ide_setup_pci_controller(dev, d, noisy, &tried_config)) < 0) + return index; + + /* + * Can we trust the reported IRQ? + */ + pciirq = dev->irq; + + if ((dev->class & ~(0xfa)) != ((PCI_CLASS_STORAGE_IDE << 8) | 5)) { + if (noisy) + printk(KERN_INFO "%s: not 100%% native mode: " + "will probe irqs later\n", d->name); + /* + * This allows offboard ide-pci cards the enable a BIOS, + * verify interrupt settings of split-mirror pci-config + * space, place chipset into init-mode, and/or preserve + * an interrupt if the card is not native ide support. + */ + pciirq = (d->init_chipset) ? d->init_chipset(dev, d->name) : 0; + } else if (tried_config) { + if (noisy) + printk(KERN_INFO "%s: will probe irqs later\n", d->name); + pciirq = 0; + } else if (!pciirq) { + if (noisy) + printk(KERN_WARNING "%s: bad irq (%d): will probe later\n", + d->name, pciirq); + pciirq = 0; + } else { + if (d->init_chipset) + { + if(d->init_chipset(dev, d->name) < 0) + return index; + } + if (noisy) +#ifdef __sparc__ + printk(KERN_INFO "%s: 100%% native mode on irq %s\n", + d->name, __irq_itoa(pciirq)); +#else + printk(KERN_INFO "%s: 100%% native mode on irq %d\n", + d->name, pciirq); +#endif + } + + if(pciirq < 0) /* Error not an IRQ */ + return index; + + ide_pci_setup_ports(dev, d, autodma, pciirq, &index); + return index; } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/drivers/input/keyboard/98kbd.c linux.2.5.47-ac6/drivers/input/keyboard/98kbd.c --- linux.2.5.47/drivers/input/keyboard/98kbd.c 1970-01-01 01:00:00.000000000 +0100 +++ linux.2.5.47-ac6/drivers/input/keyboard/98kbd.c 2002-11-15 15:57:45.000000000 +0000 @@ -0,0 +1,379 @@ +/* + * drivers/input/keyboard/98kbd.c + * + * PC-9801 keyboard driver for Linux + * + * Based on atkbd.c and xtkbd.c written by Vojtech Pavlik + * + * Copyright (c) 2002 Osamu Tomita + * Copyright (c) 1999-2001 Vojtech Pavlik + */ + +/* + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include +#include +#include +#include +#include +#include + +#include +#include + +MODULE_AUTHOR("Osamu Tomita "); +MODULE_DESCRIPTION("PC-9801 keyboard driver"); +MODULE_LICENSE("GPL"); + +#define KBD98_KEY 0x7f +#define KBD98_RELEASE 0x80 + +static unsigned char kbd98_keycode[256] = { + 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 43, 14, 15, + 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 41, 26, 28, 30, 31, 32, + 33, 34, 35, 36, 37, 38, 39, 40, 27, 44, 45, 46, 47, 48, 49, 50, + 51, 52, 53, 12, 57,184,109,104,110,111,103,105,106,108,102,107, + 74, 98, 71, 72, 73, 55, 75, 76, 77, 78, 79, 80, 81,117, 82,124, + 83,185, 87, 88, 85, 89, 90, 0, 0, 0, 0, 0, 0, 0,102, 0, + 99,133, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 0, 0, 0, 0, + 54, 58, 42, 56, 29 +}; + +struct jis_kbd_conv { + unsigned char scancode; + struct { + unsigned char shift; + unsigned char keycode; + } emul[2]; +}; + +static struct jis_kbd_conv kbd98_jis[] = { + {0x02, {{0, 3}, {1, 40}}}, + {0x06, {{0, 7}, {1, 8}}}, + {0x07, {{0, 8}, {0, 40}}}, + {0x08, {{0, 9}, {1, 10}}}, + {0x09, {{0, 10}, {1, 11}}}, + {0x0a, {{0, 11}, {1, 255}}}, + {0x0b, {{0, 12}, {0, 13}}}, + {0x0c, {{1, 7}, {0, 41}}}, + {0x1a, {{1, 3}, {1, 41}}}, + {0x26, {{0, 39}, {1, 13}}}, + {0x27, {{1, 39}, {1, 9}}}, + {0x33, {{0, 255}, {1, 12}}}, + {0xff, {{0, 255}, {1, 255}}} /* terminater */ +}; + +#define KBD98_CMD_SETEXKEY 0x1095 /* Enable/Disable Windows, Appli key */ +#define KBD98_CMD_SETRATE 0x109c /* Set typematic rate */ +#define KBD98_CMD_SETLEDS 0x109d /* Set keyboard leds */ +#define KBD98_CMD_GETLEDS 0x119d /* Get keyboard leds */ +#define KBD98_CMD_GETID 0x019f + +#define KBD98_RET_ACK 0xfa +#define KBD98_RET_NAK 0xfc /* Command NACK, send the cmd again */ + +#define KBD98_KEY_JIS_EMUL 253 +#define KBD98_KEY_UNKNOWN 254 +#define KBD98_KEY_NULL 255 + +static char *kbd98_name = "PC-9801 Keyboard"; + +struct kbd98 { + unsigned char keycode[256]; + struct input_dev dev; + struct serio *serio; + char phys[32]; + unsigned char cmdbuf[4]; + unsigned char cmdcnt; + signed char ack; + unsigned char shift; + struct { + unsigned char scancode; + unsigned char keycode; + } emul; + struct jis_kbd_conv jis[16]; +}; + +void kbd98_interrupt(struct serio *serio, unsigned char data, unsigned int flags) +{ + struct kbd98 *kbd98 = serio->private; + unsigned char scancode, keycode; + int press, i; + + switch (data) { + case KBD98_RET_ACK: + kbd98->ack = 1; + return; + case KBD98_RET_NAK: + kbd98->ack = -1; + return; + } + + if (kbd98->cmdcnt) { + kbd98->cmdbuf[--kbd98->cmdcnt] = data; + return; + } + + scancode = data & KBD98_KEY; + keycode = kbd98->keycode[scancode]; + press = !(data & KBD98_RELEASE); + if (kbd98->emul.scancode != KBD98_KEY_UNKNOWN + && scancode != kbd98->emul.scancode) { + input_report_key(&kbd98->dev, kbd98->emul.keycode, 0); + kbd98->emul.scancode = KBD98_KEY_UNKNOWN; + } + + if (keycode == KEY_RIGHTSHIFT) + kbd98->shift = press; + + switch (keycode) { + case KEY_2: + case KEY_6: + case KEY_7: + case KEY_8: + case KEY_9: + case KEY_0: + case KEY_MINUS: + case KEY_EQUAL: + case KEY_GRAVE: + case KEY_SEMICOLON: + case KEY_APOSTROPHE: + /* emulation: JIS keyboard to US101 keyboard */ + i = 0; + while (kbd98->jis[i].scancode != 0xff) { + if (scancode == kbd98->jis[i].scancode) + break; + i ++; + } + + keycode = kbd98->jis[i].emul[kbd98->shift].keycode; + if (keycode == KBD98_KEY_NULL) + return; + + if (press) { + kbd98->emul.scancode = scancode; + kbd98->emul.keycode = keycode; + if (kbd98->jis[i].emul[kbd98->shift].shift + != kbd98->shift) + input_report_key(&kbd98->dev, + KEY_RIGHTSHIFT, + !(kbd98->shift)); + } + + input_report_key(&kbd98->dev, keycode, press); + if (!press) { + if (kbd98->jis[i].emul[kbd98->shift].shift + != kbd98->shift) + input_report_key(&kbd98->dev, + KEY_RIGHTSHIFT, + kbd98->shift); + kbd98->emul.scancode = KBD98_KEY_UNKNOWN; + } + + input_sync(&kbd98->dev); + return; + + case KBD98_KEY_NULL: + return; + + case 0: + printk(KERN_WARNING "kbd98.c: Unknown key (scancode %#x) %s.\n", + data & KBD98_KEY, data & KBD98_RELEASE ? "released" : "pressed"); + return; + + default: + input_report_key(&kbd98->dev, keycode, press); + input_sync(&kbd98->dev); + } +} + +/* + * kbd98_sendbyte() sends a byte to the keyboard, and waits for + * acknowledge. It doesn't handle resends according to the keyboard + * protocol specs, because if these are needed, the keyboard needs + * replacement anyway, and they only make a mess in the protocol. + */ + +static int kbd98_sendbyte(struct kbd98 *kbd98, unsigned char byte) +{ + int timeout = 10000; /* 100 msec */ + kbd98->ack = 0; + + if (serio_write(kbd98->serio, byte)) + return -1; + + while (!kbd98->ack && timeout--) udelay(10); + + return -(kbd98->ack <= 0); +} + +/* + * kbd98_command() sends a command, and its parameters to the keyboard, + * then waits for the response and puts it in the param array. + */ + +static int kbd98_command(struct kbd98 *kbd98, unsigned char *param, int command) +{ + int timeout = 50000; /* 500 msec */ + int send = (command >> 12) & 0xf; + int receive = (command >> 8) & 0xf; + int i; + + kbd98->cmdcnt = receive; + + if (command & 0xff) + if (kbd98_sendbyte(kbd98, command & 0xff)) + return (kbd98->cmdcnt = 0) - 1; + + for (i = 0; i < send; i++) + if (kbd98_sendbyte(kbd98, param[i])) + return (kbd98->cmdcnt = 0) - 1; + + while (kbd98->cmdcnt && timeout--) udelay(10); + + if (param) + for (i = 0; i < receive; i++) + param[i] = kbd98->cmdbuf[(receive - 1) - i]; + + if (kbd98->cmdcnt) + return (kbd98->cmdcnt = 0) - 1; + + return 0; +} + +/* + * Event callback from the input module. Events that change the state of + * the hardware are processed here. + */ + +static int kbd98_event(struct input_dev *dev, unsigned int type, unsigned int code, int value) +{ + struct kbd98 *kbd98 = dev->private; + char param[2]; + + switch (type) { + + case EV_LED: + + if (__PC9800SCA_TEST_BIT(0x481, 3)) { + /* 98note with Num Lock key */ + /* keep Num Lock status */ + *param = 0x60; + if (kbd98_command(kbd98, param, + KBD98_CMD_GETLEDS)) + printk(KERN_DEBUG + "kbd98: Get keyboard LED" + " status Error\n"); + + *param &= 1; + } else { + /* desktop PC-9801 */ + *param = 1; /* Allways set Num Lock */ + } + + *param |= 0x70 + | (test_bit(LED_CAPSL, dev->led) ? 4 : 0) + | (test_bit(LED_KANA, dev->led) ? 8 : 0); + kbd98_command(kbd98, param, KBD98_CMD_SETLEDS); + + return 0; + } + + return -1; +} + +void kbd98_connect(struct serio *serio, struct serio_dev *dev) +{ + struct kbd98 *kbd98; + int i; + + if ((serio->type & SERIO_TYPE) != SERIO_PC9800) + return; + + if (!(kbd98 = kmalloc(sizeof(struct kbd98), GFP_KERNEL))) + return; + + memset(kbd98, 0, sizeof(struct kbd98)); + kbd98->emul.scancode = KBD98_KEY_UNKNOWN; + + kbd98->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_LED) | BIT(EV_REP); + kbd98->dev.ledbit[0] = BIT(LED_NUML) | BIT(LED_CAPSL) | BIT(LED_KANA); + + kbd98->serio = serio; + + init_input_dev(&kbd98->dev); + kbd98->dev.keycode = kbd98->keycode; + kbd98->dev.keycodesize = sizeof(unsigned char); + kbd98->dev.keycodemax = ARRAY_SIZE(kbd98_keycode); + kbd98->dev.event = kbd98_event; + kbd98->dev.private = kbd98; + + serio->private = kbd98; + + if (serio_open(serio, dev)) { + kfree(kbd98); + return; + } + + memcpy(kbd98->jis, kbd98_jis, sizeof(kbd98_jis)); + memcpy(kbd98->keycode, kbd98_keycode, sizeof(kbd98->keycode)); + for (i = 0; i < 255; i++) + set_bit(kbd98->keycode[i], kbd98->dev.keybit); + clear_bit(0, kbd98->dev.keybit); + + sprintf(kbd98->phys, "%s/input0", serio->phys); + + kbd98->dev.name = kbd98_name; + kbd98->dev.phys = kbd98->phys; + kbd98->dev.id.bustype = BUS_XTKBD; + kbd98->dev.id.vendor = 0x0002; + kbd98->dev.id.product = 0x0001; + kbd98->dev.id.version = 0x0100; + + input_register_device(&kbd98->dev); + + printk(KERN_INFO "input: %s on %s\n", kbd98_name, serio->phys); +} + +void kbd98_disconnect(struct serio *serio) +{ + struct kbd98 *kbd98 = serio->private; + input_unregister_device(&kbd98->dev); + serio_close(serio); + kfree(kbd98); +} + +struct serio_dev kbd98_dev = { + .interrupt = kbd98_interrupt, + .connect = kbd98_connect, + .disconnect = kbd98_disconnect +}; + +int __init kbd98_init(void) +{ + serio_register_device(&kbd98_dev); + return 0; +} + +void __exit kbd98_exit(void) +{ + serio_unregister_device(&kbd98_dev); +} + +module_init(kbd98_init); +module_exit(kbd98_exit); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/drivers/input/keyboard/Kconfig linux.2.5.47-ac6/drivers/input/keyboard/Kconfig --- linux.2.5.47/drivers/input/keyboard/Kconfig 2002-10-31 15:05:01.000000000 +0000 +++ linux.2.5.47-ac6/drivers/input/keyboard/Kconfig 2002-11-15 15:57:45.000000000 +0000 @@ -88,3 +88,15 @@ The module will be called amikbd.o. If you want to compile it as a module, say M here and read . +config KEYBOARD_98KBD + tristate "NEC PC-9800 Keyboard support" + depends on PC9800 && INPUT && INPUT_KEYBOARD && SERIO + help + Say Y here if you want to use the NEC PC-9801/PC-9821 keyboard (or + compatible) on your system. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called xtkbd.o. If you want to compile it as a + module, say M here and read . + diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/drivers/input/keyboard/Makefile linux.2.5.47-ac6/drivers/input/keyboard/Makefile --- linux.2.5.47/drivers/input/keyboard/Makefile 2002-10-31 14:57:18.000000000 +0000 +++ linux.2.5.47-ac6/drivers/input/keyboard/Makefile 2002-11-15 15:57:45.000000000 +0000 @@ -10,6 +10,7 @@ obj-$(CONFIG_KEYBOARD_XTKBD) += xtkbd.o obj-$(CONFIG_KEYBOARD_AMIGA) += amikbd.o obj-$(CONFIG_KEYBOARD_NEWTON) += newtonkbd.o +obj-$(CONFIG_KEYBOARD_98KBD) += 98kbd.o # The global Rules.make. diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/drivers/input/mouse/98busmouse.c linux.2.5.47-ac6/drivers/input/mouse/98busmouse.c --- linux.2.5.47/drivers/input/mouse/98busmouse.c 1970-01-01 01:00:00.000000000 +0100 +++ linux.2.5.47-ac6/drivers/input/mouse/98busmouse.c 2002-11-15 15:58:41.000000000 +0000 @@ -0,0 +1,201 @@ +/* + * + * Copyright (c) 2002 Osamu Tomita + * + * Based on the work of: + * James Banks Matthew Dillon + * David Giller Nathan Laredo + * Linus Torvalds Johan Myreen + * Cliff Matthews Philip Blundell + * Russell King Vojtech Pavlik + */ + +/* + * NEC PC-9801 Bus Mouse Driver for Linux + */ + +/* + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include +#include + +#include +#include +#include +#include +#include +#include + +MODULE_AUTHOR("Osamu Tomita "); +MODULE_DESCRIPTION("PC-9801 busmouse driver"); +MODULE_LICENSE("GPL"); + +#define PC98BM_BASE 0x7fd9 +#define PC98BM_DATA_PORT PC98BM_BASE + 0 +/* PC98BM_SIGNATURE_PORT does not exist */ +#define PC98BM_CONTROL_PORT PC98BM_BASE + 4 +/* PC98BM_INTERRUPT_PORT does not exist */ +#define PC98BM_CONFIG_PORT PC98BM_BASE + 6 + +#define PC98BM_ENABLE_IRQ 0x00 +#define PC98BM_DISABLE_IRQ 0x10 +#define PC98BM_READ_X_LOW 0x80 +#define PC98BM_READ_X_HIGH 0xa0 +#define PC98BM_READ_Y_LOW 0xc0 +#define PC98BM_READ_Y_HIGH 0xe0 + +#define PC98BM_DEFAULT_MODE 0x93 +/* PC98BM_CONFIG_BYTE is not used */ +/* PC98BM_SIGNATURE_BYTE is not used */ + +#define PC98BM_TIMER_PORT 0xbfdb +#define PC98BM_DEFAULT_TIMER_VAL 0x00 + +#define PC98BM_IRQ 13 + +MODULE_PARM(pc98bm_irq, "i"); + +static int pc98bm_irq = PC98BM_IRQ; +static int pc98bm_used = 0; + +static void pc98bm_interrupt(int irq, void *dev_id, struct pt_regs *regs); + +static int pc98bm_open(struct input_dev *dev) +{ + if (pc98bm_used++) + return 0; + if (request_irq(pc98bm_irq, pc98bm_interrupt, 0, "98busmouse", NULL)) { + pc98bm_used--; + printk(KERN_ERR "98busmouse.c: Can't allocate irq %d\n", pc98bm_irq); + return -EBUSY; + } + outb(PC98BM_ENABLE_IRQ, PC98BM_CONTROL_PORT); + return 0; +} + +static void pc98bm_close(struct input_dev *dev) +{ + if (--pc98bm_used) + return; + outb(PC98BM_DISABLE_IRQ, PC98BM_CONTROL_PORT); + free_irq(pc98bm_irq, NULL); +} + +static struct input_dev pc98bm_dev = { + .evbit = { BIT(EV_KEY) | BIT(EV_REL) }, + .keybit = { [LONG(BTN_LEFT)] = BIT(BTN_LEFT) | BIT(BTN_MIDDLE) | BIT(BTN_RIGHT) }, + .relbit = { BIT(REL_X) | BIT(REL_Y) }, + .open = pc98bm_open, + .close = pc98bm_close, + .name = "PC-9801 bus mouse", + .phys = "isa7fd9/input0", + .id = { + .bustype = BUS_ISA, + .vendor = 0x0004, + .product = 0x0001, + .version = 0x0100, + }, +}; + +static void pc98bm_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + char dx, dy; + unsigned char buttons; + + outb(PC98BM_READ_X_LOW, PC98BM_CONTROL_PORT); + dx = (inb(PC98BM_DATA_PORT) & 0xf); + outb(PC98BM_READ_X_HIGH, PC98BM_CONTROL_PORT); + dx |= (inb(PC98BM_DATA_PORT) & 0xf) << 4; + outb(PC98BM_READ_Y_LOW, PC98BM_CONTROL_PORT); + dy = (inb(PC98BM_DATA_PORT) & 0xf); + outb(PC98BM_READ_Y_HIGH, PC98BM_CONTROL_PORT); + buttons = inb(PC98BM_DATA_PORT); + dy |= (buttons & 0xf) << 4; + buttons = ~buttons >> 5; + + input_report_rel(&pc98bm_dev, REL_X, dx); + input_report_rel(&pc98bm_dev, REL_Y, dy); + input_report_key(&pc98bm_dev, BTN_RIGHT, buttons & 1); + input_report_key(&pc98bm_dev, BTN_MIDDLE, buttons & 2); + input_report_key(&pc98bm_dev, BTN_LEFT, buttons & 4); + input_sync(&pc98bm_dev); + + outb(PC98BM_ENABLE_IRQ, PC98BM_CONTROL_PORT); +} + +#ifndef MODULE +static int __init pc98bm_setup(char *str) +{ + int ints[4]; + str = get_options(str, ARRAY_SIZE(ints), ints); + if (ints[0] > 0) pc98bm_irq = ints[1]; + return 1; +} +__setup("pc98bm_irq=", pc98bm_setup); +#endif + +static int __init pc98bm_init(void) +{ + int i; + + for (i = 0; i <= 6; i += 2) { + if (!request_region(PC98BM_BASE + i, 1, "98busmouse")) { + printk(KERN_ERR "98busmouse.c: Can't allocate ports at %#x\n", PC98BM_BASE + i); + while (i > 0) { + i -= 2; + release_region(PC98BM_BASE + i, 1); + } + + return -EBUSY; + } + + } + + if (!request_region(PC98BM_TIMER_PORT, 1, "98busmouse")) { + printk(KERN_ERR "98busmouse.c: Can't allocate ports at %#x\n", PC98BM_TIMER_PORT); + for (i = 0; i <= 6; i += 2) + release_region(PC98BM_BASE + i, 1); + + return -EBUSY; + } + + outb(PC98BM_DEFAULT_MODE, PC98BM_CONFIG_PORT); + outb(PC98BM_DISABLE_IRQ, PC98BM_CONTROL_PORT); + + outb(PC98BM_DEFAULT_TIMER_VAL, PC98BM_TIMER_PORT); + + input_register_device(&pc98bm_dev); + + printk(KERN_INFO "input: PC-9801 bus mouse at %#x irq %d\n", PC98BM_BASE, pc98bm_irq); + + return 0; +} + +static void __exit pc98bm_exit(void) +{ + int i; + + input_unregister_device(&pc98bm_dev); + for (i = 0; i <= 6; i += 2) + release_region(PC98BM_BASE + i, 1); + + release_region(PC98BM_TIMER_PORT, 1); +} + +module_init(pc98bm_init); +module_exit(pc98bm_exit); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/drivers/input/mouse/Kconfig linux.2.5.47-ac6/drivers/input/mouse/Kconfig --- linux.2.5.47/drivers/input/mouse/Kconfig 2002-11-11 16:39:10.000000000 +0000 +++ linux.2.5.47-ac6/drivers/input/mouse/Kconfig 2002-11-15 15:58:41.000000000 +0000 @@ -119,3 +119,15 @@ The module will be called rpcmouse.o. If you want to compile it as a module, say M here and read . +config MOUSE_PC9800 + tristate "NEC PC-9800 busmouse" + depends on PC9800 && INPUT && INPUT_MOUSE && ISA + help + Say Y here if you have NEC PC-9801/PC-9821 computer and want its + native mouse supported. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called logibm.o. If you want to compile it as a + module, say M here and read . + diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/drivers/input/mouse/Makefile linux.2.5.47-ac6/drivers/input/mouse/Makefile --- linux.2.5.47/drivers/input/mouse/Makefile 2002-11-11 16:39:10.000000000 +0000 +++ linux.2.5.47-ac6/drivers/input/mouse/Makefile 2002-11-15 15:58:41.000000000 +0000 @@ -10,6 +10,7 @@ obj-$(CONFIG_MOUSE_LOGIBM) += logibm.o obj-$(CONFIG_MOUSE_MAPLE) += maplemouse.o obj-$(CONFIG_MOUSE_PC110PAD) += pc110pad.o +obj-$(CONFIG_MOUSE_PC9800) += 98busmouse.o obj-$(CONFIG_MOUSE_PS2) += psmouse.o obj-$(CONFIG_MOUSE_SERIAL) += sermouse.o diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/drivers/input/mouse/psmouse.c linux.2.5.47-ac6/drivers/input/mouse/psmouse.c --- linux.2.5.47/drivers/input/mouse/psmouse.c 2002-10-31 14:57:18.000000000 +0000 +++ linux.2.5.47-ac6/drivers/input/mouse/psmouse.c 2002-10-31 15:05:42.000000000 +0000 @@ -312,6 +312,26 @@ return PSMOUSE_PS2; /* + * Try Synaptics TouchPad magic ID + */ + + param[0] = 0; + psmouse_command(psmouse, param, PSMOUSE_CMD_SETRES); + psmouse_command(psmouse, param, PSMOUSE_CMD_SETRES); + psmouse_command(psmouse, param, PSMOUSE_CMD_SETRES); + psmouse_command(psmouse, param, PSMOUSE_CMD_SETRES); + psmouse_command(psmouse, param, PSMOUSE_CMD_GETINFO); + + if (param[1] == 0x47) { + /* We could do more here. But it's sufficient just + to stop the subsequent probes from screwing the + thing up. */ + psmouse->vendor = "Synaptics"; + psmouse->name = "TouchPad"; + return PSMOUSE_PS2; + } + +/* * Try Genius NetMouse magic init. */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/drivers/input/serio/98kbd-io.c linux.2.5.47-ac6/drivers/input/serio/98kbd-io.c --- linux.2.5.47/drivers/input/serio/98kbd-io.c 1970-01-01 01:00:00.000000000 +0100 +++ linux.2.5.47-ac6/drivers/input/serio/98kbd-io.c 2002-11-15 15:58:41.000000000 +0000 @@ -0,0 +1,181 @@ +/* + * NEC PC-9801 keyboard controller driver for Linux + * + * Copyright (c) 1999-2002 Osamu Tomita + * Based on i8042.c written by Vojtech Pavlik + */ + +/* + * 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. + */ + +#include + +#include +#include +#include +#include +#include +#include +#include + +MODULE_AUTHOR("Osamu Tomita "); +MODULE_DESCRIPTION("NEC PC-9801 keyboard controller driver"); +MODULE_LICENSE("GPL"); + +/* + * Names. + */ + +#define KBD98_PHYS_DESC "isa0041/serio0" + +/* + * IRQs. + */ + +#define KBD98_IRQ 1 + +/* + * Register numbers. + */ + +#define KBD98_COMMAND_REG 0x43 +#define KBD98_STATUS_REG 0x43 +#define KBD98_DATA_REG 0x41 + +spinlock_t kbd98io_lock = SPIN_LOCK_UNLOCKED; + +static struct serio kbd98_port; +extern struct pt_regs *kbd_pt_regs; + +static void kbd98io_interrupt(int irq, void *dev_id, struct pt_regs *regs); + +/* + * kbd98_flush() flushes all data that may be in the keyboard buffers + */ + +static int kbd98_flush(void) +{ + unsigned long flags; + + spin_lock_irqsave(&kbd98io_lock, flags); + + while (inb(KBD98_STATUS_REG) & 0x02) /* RxRDY */ + inb(KBD98_DATA_REG); + + if (inb(KBD98_STATUS_REG) & 0x38) + printk("98kbd-io: Keyboard error!\n"); + + spin_unlock_irqrestore(&kbd98io_lock, flags); + + return 0; +} + +/* + * kbd98_write() sends a byte out through the keyboard interface. + */ + +static int kbd98_write(struct serio *port, unsigned char c) +{ + unsigned long flags; + + spin_lock_irqsave(&kbd98io_lock, flags); + + outb(0, 0x5f); /* wait */ + outb(0x17, KBD98_COMMAND_REG); /* enable send command */ + outb(0, 0x5f); /* wait */ + outb(c, KBD98_DATA_REG); + outb(0, 0x5f); /* wait */ + outb(0x16, KBD98_COMMAND_REG); /* disable send command */ + outb(0, 0x5f); /* wait */ + + spin_unlock_irqrestore(&kbd98io_lock, flags); + + return 0; +} + +/* + * kbd98_open() is called when a port is open by the higher layer. + * It allocates the interrupt and enables in in the chip. + */ + +static int kbd98_open(struct serio *port) +{ + kbd98_flush(); + + if (request_irq(KBD98_IRQ, kbd98io_interrupt, 0, "kbd98", NULL)) { + printk(KERN_ERR "98kbd-io.c: Can't get irq %d for %s, unregistering the port.\n", KBD98_IRQ, "KBD"); + serio_unregister_port(port); + return -1; + } + + return 0; +} + +static void kbd98_close(struct serio *port) +{ + free_irq(KBD98_IRQ, NULL); + + kbd98_flush(); +} + +/* + * Structures for registering the devices in the serio.c module. + */ + +static struct serio kbd98_port = +{ + .type = SERIO_PC9800, + .write = kbd98_write, + .open = kbd98_open, + .close = kbd98_close, + .driver = NULL, + .name = "PC-9801 Kbd Port", + .phys = KBD98_PHYS_DESC, +}; + +/* + * kbd98io_interrupt() is the most important function in this driver - + * it handles the interrupts from keyboard, and sends incoming bytes + * to the upper layers. + */ + +static void kbd98io_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + unsigned long flags; + unsigned char data; + +#ifdef CONFIG_VT + kbd_pt_regs = regs; +#endif + + spin_lock_irqsave(&kbd98io_lock, flags); + + data = inb(KBD98_DATA_REG); + spin_unlock_irqrestore(&kbd98io_lock, flags); + serio_interrupt(&kbd98_port, data, 0); + +} + +int __init kbd98io_init(void) +{ + serio_register_port(&kbd98_port); + + printk(KERN_INFO "serio: PC-9801 %s port at %#lx,%#lx irq %d\n", + "KBD", + (unsigned long) KBD98_DATA_REG, + (unsigned long) KBD98_COMMAND_REG, + KBD98_IRQ); + + return 0; +} + +void __exit kbd98io_exit(void) +{ + serio_unregister_port(&kbd98_port); +} + +module_init(kbd98io_init); +module_exit(kbd98io_exit); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/drivers/input/serio/Kconfig linux.2.5.47-ac6/drivers/input/serio/Kconfig --- linux.2.5.47/drivers/input/serio/Kconfig 2002-11-11 16:39:10.000000000 +0000 +++ linux.2.5.47-ac6/drivers/input/serio/Kconfig 2002-11-15 15:58:41.000000000 +0000 @@ -103,3 +103,15 @@ tristate "Intel SA1111 keyboard controller" depends on SA1111 && SERIO +config SERIO_98KBD + tristate "NEC PC-9800 keyboard controller" + depends on PC9800 && SERIO + help + Say Y here if you have the NEC PC-9801/PC-9821 and want to use its + standard keyboard connected to its keyboard controller. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called rpckbd.o. If you want to compile it as a + module, say M here and read . + diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/drivers/input/serio/Makefile linux.2.5.47-ac6/drivers/input/serio/Makefile --- linux.2.5.47/drivers/input/serio/Makefile 2002-10-31 14:57:18.000000000 +0000 +++ linux.2.5.47-ac6/drivers/input/serio/Makefile 2002-11-15 15:58:41.000000000 +0000 @@ -17,6 +17,7 @@ obj-$(CONFIG_SERIO_SA1111) += sa1111ps2.o obj-$(CONFIG_SERIO_AMBAKMI) += ambakmi.o obj-$(CONFIG_SERIO_Q40KBD) += q40kbd.o +obj-$(CONFIG_SERIO_98KBD) += 98kbd-io.o # The global Rules.make. diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/drivers/isdn/hisax/bkm_a8.c linux.2.5.47-ac6/drivers/isdn/hisax/bkm_a8.c --- linux.2.5.47/drivers/isdn/hisax/bkm_a8.c 2002-10-31 15:05:01.000000000 +0000 +++ linux.2.5.47-ac6/drivers/isdn/hisax/bkm_a8.c 2002-10-31 17:02:42.000000000 +0000 @@ -278,8 +278,6 @@ static struct pci_dev *dev_a8 __initdata = NULL; static u16 sub_vendor_id __initdata = 0; static u16 sub_sys_id __initdata = 0; -static u_char pci_bus __initdata = 0; -static u_char pci_device_fn __initdata = 0; static u_char pci_irq __initdata = 0; #endif /* CONFIG_PCI */ @@ -328,8 +326,6 @@ return(0); pci_ioaddr1 = pci_resource_start(dev_a8, 1); pci_irq = dev_a8->irq; - pci_bus = dev_a8->bus->number; - pci_device_fn = dev_a8->devfn; found = 1; break; } @@ -342,20 +338,17 @@ } #ifdef ATTEMPT_PCI_REMAPPING /* HACK: PLX revision 1 bug: PLX address bit 7 must not be set */ - pcibios_read_config_byte(pci_bus, pci_device_fn, - PCI_REVISION_ID, &pci_rev_id); + pci_read_config_byte(dev_a8, PCI_REVISION_ID, &pci_rev_id); if ((pci_ioaddr1 & 0x80) && (pci_rev_id == 1)) { printk(KERN_WARNING "HiSax: %s (%s): PLX rev 1, remapping required!\n", CardType[card->typ], sct_quadro_subtypes[cs->subtyp]); /* Restart PCI negotiation */ - pcibios_write_config_dword(pci_bus, pci_device_fn, - PCI_BASE_ADDRESS_1, (u_int) - 1); + pci_write_config_dword(dev_a8, PCI_BASE_ADDRESS_1, (u_int) - 1); /* Move up by 0x80 byte */ pci_ioaddr1 += 0x80; pci_ioaddr1 &= PCI_BASE_ADDRESS_IO_MASK; - pcibios_write_config_dword(pci_bus, pci_device_fn, - PCI_BASE_ADDRESS_1, pci_ioaddr1); + pci_write_config_dword(dev_a8, PCI_BASE_ADDRESS_1, pci_ioaddr1); dev_a8->resource[ 1].start = pci_ioaddr1; } #endif /* End HACK */ @@ -366,11 +359,11 @@ sct_quadro_subtypes[cs->subtyp]); return (0); } - pcibios_read_config_dword(pci_bus, pci_device_fn, PCI_BASE_ADDRESS_1, &pci_ioaddr1); - pcibios_read_config_dword(pci_bus, pci_device_fn, PCI_BASE_ADDRESS_2, &pci_ioaddr2); - pcibios_read_config_dword(pci_bus, pci_device_fn, PCI_BASE_ADDRESS_3, &pci_ioaddr3); - pcibios_read_config_dword(pci_bus, pci_device_fn, PCI_BASE_ADDRESS_4, &pci_ioaddr4); - pcibios_read_config_dword(pci_bus, pci_device_fn, PCI_BASE_ADDRESS_5, &pci_ioaddr5); + pci_read_config_dword(dev_a8, PCI_BASE_ADDRESS_1, &pci_ioaddr1); + pci_read_config_dword(dev_a8, PCI_BASE_ADDRESS_2, &pci_ioaddr2); + pci_read_config_dword(dev_a8, PCI_BASE_ADDRESS_3, &pci_ioaddr3); + pci_read_config_dword(dev_a8, PCI_BASE_ADDRESS_4, &pci_ioaddr4); + pci_read_config_dword(dev_a8, PCI_BASE_ADDRESS_5, &pci_ioaddr5); if (!pci_ioaddr1 || !pci_ioaddr2 || !pci_ioaddr3 || !pci_ioaddr4 || !pci_ioaddr5) { printk(KERN_WARNING "HiSax: %s (%s): No IO base address(es)\n", CardType[card->typ], diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/drivers/Makefile linux.2.5.47-ac6/drivers/Makefile --- linux.2.5.47/drivers/Makefile 2002-11-05 13:54:43.000000000 +0000 +++ linux.2.5.47-ac6/drivers/Makefile 2002-11-16 01:58:28.000000000 +0000 @@ -8,6 +8,9 @@ obj-$(CONFIG_PCI) += pci/ obj-$(CONFIG_PARISC) += parisc/ obj-$(CONFIG_ACPI) += acpi/ +# PnP must come after ACPI since it will eventually need to check if acpi +# was used and do nothing if so +obj-$(CONFIG_PNP) += pnp/ obj-y += serial/ obj-$(CONFIG_PARPORT) += parport/ obj-y += base/ char/ block/ misc/ net/ media/ @@ -26,7 +29,6 @@ obj-$(CONFIG_ZORRO) += zorro/ obj-$(CONFIG_ALL_PPC) += macintosh/ obj-$(CONFIG_MAC) += macintosh/ -obj-$(CONFIG_PNP) += pnp/ obj-$(CONFIG_SGI) += sgi/ obj-$(CONFIG_VT) += video/ obj-$(CONFIG_PARIDE) += block/paride/ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/drivers/md/dm.c linux.2.5.47-ac6/drivers/md/dm.c --- linux.2.5.47/drivers/md/dm.c 2002-10-31 15:05:01.000000000 +0000 +++ linux.2.5.47-ac6/drivers/md/dm.c 2002-11-13 01:15:07.000000000 +0000 @@ -15,7 +15,7 @@ #include static const char *_name = DM_NAME; -#define MAX_DEVICES 256 +#define MAX_DEVICES (1 << KDEV_MINOR_BITS) #define SECTOR_SHIFT 9 static int major = 0; @@ -41,8 +41,6 @@ struct mapped_device { struct rw_semaphore lock; - - kdev_t kdev; atomic_t holders; unsigned long flags; @@ -485,13 +483,25 @@ return 0; } +/*----------------------------------------------------------------- + * A bitset is used to keep track of allocated minor numbers. + *---------------------------------------------------------------*/ +static spinlock_t _minor_lock = SPIN_LOCK_UNLOCKED; +static unsigned long _minor_bits[MAX_DEVICES / BITS_PER_LONG]; + +static void free_minor(int minor) +{ + spin_lock(&_minor_lock); + clear_bit(minor, _minor_bits); + spin_unlock(&_minor_lock); +} + /* * See if the device with a specific minor # is free. */ -static int specific_dev(int minor, struct mapped_device *md) +static int specific_minor(int minor) { - struct gendisk *disk; - int part; + int r = -EBUSY; if (minor >= MAX_DEVICES) { DMWARN("request for a mapped_device beyond MAX_DEVICES (%d)", @@ -499,26 +509,27 @@ return -EINVAL; } - disk = get_gendisk(MKDEV(_major, minor), &part); - if (disk) { - put_disk(disk); - return -EBUSY; - } + spin_lock(&_minor_lock); + if (!test_and_set_bit(minor, _minor_bits)) + r = minor; + spin_unlock(&_minor_lock); - return minor; + return r; } -static int any_old_dev(struct mapped_device *md) +static int next_free_minor(void) { - int i; + int minor, r = -EBUSY; - for (i = 0; i < MAX_DEVICES; i++) - if (specific_dev(i, md) >= 0) { - DMWARN("allocating minor = %d", i); - return i; - } + spin_lock(&_minor_lock); + minor = find_first_zero_bit(_minor_bits, MAX_DEVICES); + if (minor != MAX_DEVICES) { + set_bit(minor, _minor_bits); + r = minor; + } + spin_unlock(&_minor_lock); - return -EBUSY; + return r; } /* @@ -534,15 +545,15 @@ } /* get a minor number for the dev */ - minor = (minor < 0) ? any_old_dev(md) : specific_dev(minor, md); + minor = (minor < 0) ? next_free_minor() : specific_minor(minor); if (minor < 0) { kfree(md); return NULL; } + DMWARN("allocating minor %d.", minor); memset(md, 0, sizeof(*md)); init_rwsem(&md->lock); - md->kdev = mk_kdev(_major, minor); atomic_set(&md->holders, 1); md->queue.queuedata = md; @@ -550,6 +561,7 @@ md->disk = alloc_disk(1); if (!md->disk) { + free_minor(md->disk->first_minor); kfree(md); return NULL; } @@ -569,6 +581,7 @@ static void free_dev(struct mapped_device *md) { + free_minor(md->disk->first_minor); del_gendisk(md->disk); put_disk(md->disk); kfree(md); @@ -749,15 +762,13 @@ return 0; } -kdev_t dm_kdev(struct mapped_device *md) +/* + * The gendisk is only valid as long as you have a reference + * count on 'md'. + */ +struct gendisk *dm_disk(struct mapped_device *md) { - kdev_t dev; - - down_read(&md->lock); - dev = md->kdev; - up_read(&md->lock); - - return dev; + return md->disk; } struct dm_table *dm_get_table(struct mapped_device *md) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/drivers/md/dm.h linux.2.5.47-ac6/drivers/md/dm.h --- linux.2.5.47/drivers/md/dm.h 2002-10-31 15:05:01.000000000 +0000 +++ linux.2.5.47-ac6/drivers/md/dm.h 2002-11-13 01:14:58.000000000 +0000 @@ -77,7 +77,7 @@ /* * Info functions. */ -kdev_t dm_kdev(struct mapped_device *md); +struct gendisk *dm_disk(struct mapped_device *md); int dm_suspended(struct mapped_device *md); /*----------------------------------------------------------------- diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/drivers/md/dm-ioctl.c linux.2.5.47-ac6/drivers/md/dm-ioctl.c --- linux.2.5.47/drivers/md/dm-ioctl.c 2002-10-31 15:05:01.000000000 +0000 +++ linux.2.5.47-ac6/drivers/md/dm-ioctl.c 2002-11-13 01:15:56.000000000 +0000 @@ -8,7 +8,6 @@ #include #include -#include #include #include #include @@ -16,6 +15,8 @@ #include #include +#include + #define DM_DRIVER_EMAIL "dm@uk.sistina.com" /*----------------------------------------------------------------- @@ -176,10 +177,11 @@ */ static int register_with_devfs(struct hash_cell *hc) { - kdev_t dev = dm_kdev(hc->md); + struct gendisk *disk = dm_disk(hc->md); + hc->devfs_entry = devfs_register(_dev_dir, hc->name, DEVFS_FL_CURRENT_OWNER, - major(dev), minor(dev), + disk->major, disk->first_minor, S_IFBLK | S_IRUSR | S_IWUSR | S_IRGRP, &dm_blk_dops, NULL); @@ -447,23 +449,24 @@ static int __info(struct mapped_device *md, struct dm_ioctl *param) { struct dm_table *table; + struct gendisk *disk = dm_disk(md); struct block_device *bdev; param->flags = DM_EXISTS_FLAG; if (dm_suspended(md)) param->flags |= DM_SUSPEND_FLAG; - param->dev = kdev_t_to_nr(dm_kdev(md)); + param->dev = MKDEV(disk->major, disk->first_minor); bdev = bdget(param->dev); if (!bdev) return -ENXIO; - if (bdev_read_only(bdev)) - param->flags |= DM_READONLY_FLAG; - param->open_count = bdev->bd_openers; bdput(bdev); + if (disk->policy) + param->flags |= DM_READONLY_FLAG; + table = dm_get_table(md); param->target_count = dm_table_get_num_targets(table); dm_table_put(table); @@ -558,6 +561,7 @@ { int r; struct dm_table *t; + struct gendisk *disk; struct mapped_device *md; int minor; @@ -585,7 +589,8 @@ } dm_table_put(t); /* md will have grabbed its own reference */ - set_device_ro(dm_kdev(md), (param->flags & DM_READONLY_FLAG)); + disk = dm_disk(md); + set_disk_ro(disk, (param->flags & DM_READONLY_FLAG)); r = dm_hash_insert(param->name, *param->uuid ? param->uuid : NULL, md); dm_put(md); @@ -845,6 +850,7 @@ static int reload(struct dm_ioctl *param, struct dm_ioctl *user) { int r; + struct gendisk *disk; struct mapped_device *md; struct dm_table *t; @@ -871,7 +877,8 @@ return r; } - set_device_ro(dm_kdev(md), (param->flags & DM_READONLY_FLAG)); + disk = dm_disk(md); + set_disk_ro(disk, (param->flags & DM_READONLY_FLAG)); dm_put(md); r = info(param, user); @@ -1077,7 +1084,6 @@ int __init dm_interface_init(void) { int r; - char rname[64]; r = dm_hash_init(); if (r) @@ -1090,25 +1096,12 @@ return r; } - r = devfs_generate_path(_dm_misc.devfs_handle, rname + 3, - sizeof rname - 3); - if (r == -ENOSYS) - return 0; /* devfs not present */ - - if (r < 0) { - DMERR("devfs_generate_path failed for control device"); - goto failed; - } - - strncpy(rname + r, "../", 3); - r = devfs_mk_symlink(NULL, DM_DIR "/control", - DEVFS_FL_DEFAULT, rname + r, &_ctl_handle, NULL); + r = devfs_mk_symlink(NULL, DM_DIR "/control", DEVFS_FL_DEFAULT, + "../misc/" DM_NAME, &_ctl_handle, NULL); if (r) { DMERR("devfs_mk_symlink failed for control device"); goto failed; } - devfs_auto_unregister(_dm_misc.devfs_handle, _ctl_handle); - DMINFO("%d.%d.%d%s initialised: %s", DM_VERSION_MAJOR, DM_VERSION_MINOR, DM_VERSION_PATCHLEVEL, DM_VERSION_EXTRA, DM_DRIVER_EMAIL); @@ -1124,6 +1117,8 @@ { dm_hash_exit(); + devfs_find_and_unregister(NULL, DM_DIR "/control", 0, 0, 0, 0); + if (misc_deregister(&_dm_misc) < 0) DMERR("misc_deregister failed for control device"); } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/drivers/md/dm-table.c linux.2.5.47-ac6/drivers/md/dm-table.c --- linux.2.5.47/drivers/md/dm-table.c 2002-10-31 15:05:01.000000000 +0000 +++ linux.2.5.47-ac6/drivers/md/dm-table.c 2002-11-13 01:14:13.000000000 +0000 @@ -146,6 +146,25 @@ return 0; } +static void *dm_vcalloc(unsigned long nmemb, unsigned long elem_size) +{ + unsigned long size; + void *addr; + + /* + * Check that we're not going to overflow. + */ + if (nmemb > (ULONG_MAX / elem_size)) + return NULL; + + size = nmemb * elem_size; + addr = vmalloc(size); + if (addr) + memset(addr, 0, size); + + return addr; +} + /* * highs, and targets are managed as dynamic arrays during a * table load. @@ -159,9 +178,8 @@ /* * Allocate both the target array and offset array at once. */ - n_highs = (sector_t *) vcalloc(sizeof(struct dm_target) + - sizeof(sector_t), - num); + n_highs = (sector_t *) dm_vcalloc(sizeof(struct dm_target) + + sizeof(sector_t), num); if (!n_highs) return -ENOMEM; @@ -624,7 +642,7 @@ total += t->counts[i]; } - indexes = (sector_t *) vcalloc(total, (unsigned long) NODE_SIZE); + indexes = (sector_t *) dm_vcalloc(total, (unsigned long) NODE_SIZE); if (!indexes) return -ENOMEM; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/drivers/media/dvb/av7110/av7110.c linux.2.5.47-ac6/drivers/media/dvb/av7110/av7110.c --- linux.2.5.47/drivers/media/dvb/av7110/av7110.c 2002-10-31 15:05:01.000000000 +0000 +++ linux.2.5.47-ac6/drivers/media/dvb/av7110/av7110.c 2002-11-13 01:26:41.000000000 +0000 @@ -89,7 +89,7 @@ static void SetMode(av7110_t *av7110, int mode); void pes_to_ts(u8 const *buf, long int length, u16 pid, p2t_t *p); -void p_to_t(u8 const *buf, long int length, u16 pid, u8 *counter, dvb_demux_feed_t *feed); +void p_to_t(u8 const *buf, long int length, u16 pid, u8 *counter, struct dvb_demux_feed *feed); static u32 vidmem = 0; static u32 vidlow = 0; @@ -392,9 +392,9 @@ static int -record_cb(pes2ts_t *p2t, u8 *buf, size_t len) +record_cb(dvb_filter_pes2ts_t *p2t, u8 *buf, size_t len) { - dvb_demux_feed_t *dvbdmxfeed=(dvb_demux_feed_t *) p2t->priv; + struct dvb_demux_feed *dvbdmxfeed=(struct dvb_demux_feed *) p2t->priv; if (!(dvbdmxfeed->ts_type & TS_PACKET)) return 0; @@ -404,13 +404,13 @@ return dvbdmxfeed->cb.ts(buf, len, 0, 0, &dvbdmxfeed->feed.ts, DMX_OK); else - return pes2ts(p2t, buf, len); + return dvb_filter_pes2ts(p2t, buf, len); } static int -pes2ts_cb(void *priv, unsigned char *data) +dvb_filter_pes2ts_cb(void *priv, unsigned char *data) { - dvb_demux_feed_t *dvbdmxfeed=(dvb_demux_feed_t *) priv; + struct dvb_demux_feed *dvbdmxfeed=(struct dvb_demux_feed *) priv; dvbdmxfeed->cb.ts(data, 188, 0, 0, &dvbdmxfeed->feed.ts, @@ -420,9 +420,9 @@ static int AV_StartRecord(av7110_t *av7110, int av, - dvb_demux_feed_t *dvbdmxfeed) + struct dvb_demux_feed *dvbdmxfeed) { - dvb_demux_t *dvbdmx=dvbdmxfeed->demux; + struct dvb_demux *dvbdmx=dvbdmxfeed->demux; if (av7110->playing||(av7110->rec_mode&av)) return -EBUSY; @@ -432,20 +432,30 @@ switch (av7110->rec_mode) { case RP_AUDIO: - pes2ts_init(&av7110->p2t[0], dvbdmx->pesfilter[0]->pid, - pes2ts_cb, (void *)dvbdmx->pesfilter[0]); + dvb_filter_pes2ts_init (&av7110->p2t[0], + dvbdmx->pesfilter[0]->pid, + dvb_filter_pes2ts_cb, + (void *)dvbdmx->pesfilter[0]); outcom(av7110, COMTYPE_REC_PLAY, __Record, 2, AudioPES, 0); break; + case RP_VIDEO: - pes2ts_init(&av7110->p2t[1], dvbdmx->pesfilter[1]->pid, - pes2ts_cb, (void *)dvbdmx->pesfilter[1]); + dvb_filter_pes2ts_init (&av7110->p2t[1], + dvbdmx->pesfilter[1]->pid, + dvb_filter_pes2ts_cb, + (void *)dvbdmx->pesfilter[1]); outcom(av7110, COMTYPE_REC_PLAY, __Record, 2, VideoPES, 0); break; + case RP_AV: - pes2ts_init(&av7110->p2t[0], dvbdmx->pesfilter[0]->pid, - pes2ts_cb, (void *)dvbdmx->pesfilter[0]); - pes2ts_init(&av7110->p2t[1], dvbdmx->pesfilter[1]->pid, - pes2ts_cb, (void *)dvbdmx->pesfilter[1]); + dvb_filter_pes2ts_init (&av7110->p2t[0], + dvbdmx->pesfilter[0]->pid, + dvb_filter_pes2ts_cb, + (void *)dvbdmx->pesfilter[0]); + dvb_filter_pes2ts_init (&av7110->p2t[1], + dvbdmx->pesfilter[1]->pid, + dvb_filter_pes2ts_cb, + (void *)dvbdmx->pesfilter[1]); outcom(av7110, COMTYPE_REC_PLAY, __Record, 2, AV_PES, 0); break; } @@ -463,8 +473,8 @@ outcom(av7110, COMTYPE_REC_PLAY, __Stop, 0); if (av7110->playing == RP_NONE) { - reset_ipack(&av7110->ipack[0]); - reset_ipack(&av7110->ipack[1]); + dvb_filter_ipack_reset(&av7110->ipack[0]); + dvb_filter_ipack_reset(&av7110->ipack[1]); } av7110->playing|=av; @@ -814,7 +824,7 @@ static inline int DvbDmxFilterCallback(u8 * buffer1, size_t buffer1_len, u8 * buffer2, size_t buffer2_len, - dvb_demux_filter_t *dvbdmxfilter, + struct dvb_demux_filter *dvbdmxfilter, dmx_success_t success, av7110_t *av7110) { @@ -896,7 +906,7 @@ // FIXME: use bottom half or tasklet if (av7110->feeding && mem[0]==0x47) - DvbDmxSWFilterPackets(&av7110->demux, mem, 512); + dvb_dmx_swfilter_packets(&av7110->demux, mem, 512); } #else static @@ -922,7 +932,7 @@ } else { if (av7110->ttbp>1000*188 && av7110->ttbp<1024*188) { if (av7110->feeding) - DvbDmxSWFilterPackets(&av7110->demux, + dvb_dmx_swfilter_packets(&av7110->demux, mem+av7110->ttbp, 1024- av7110->ttbp / 188); } @@ -937,7 +947,7 @@ // FIXME: use bottom half or tasklet if (av7110->feeding && mem[0]==0x47) - DvbDmxSWFilterPackets(&av7110->demux, mem, num); + dvb_dmx_swfilter_packets(&av7110->demux, mem, num); } #endif @@ -1001,7 +1011,7 @@ switch (type&0xff) { case DATA_TS_RECORD: - DvbDmxSWFilterPackets(&av7110->demux, + dvb_dmx_swfilter_packets(&av7110->demux, (const u8 *)av7110->debi_virt, av7110->debilen/188); spin_lock(&av7110->debilock); @@ -2008,8 +2018,8 @@ av7110->arm_app=(buf[6] << 16) + buf[7]; av7110->avtype=(buf[8] << 16) + buf[9]; - printk ("av7110 (%d): AV711%d - firm %08x, rtsl %08x, vid %08x, app %08x\n", - av7110->saa->dvb_adapter->num, av7110->avtype, av7110->arm_fw, + printk ("DVB: AV711%d(%d) - firm %08x, rtsl %08x, vid %08x, app %08x\n", + av7110->avtype, av7110->saa->dvb_adapter->num, av7110->arm_fw, av7110->arm_rtsl, av7110->arm_vid, av7110->arm_app); return; @@ -2483,9 +2493,12 @@ if (umem) { if (copy_from_user(av7110->kbuf[type], buf, n)) return -EFAULT; - instant_repack(av7110->kbuf[type], n, &av7110->ipack[type]); - } else - instant_repack((u8 *)buf, n, &av7110->ipack[type]); + dvb_filter_instant_repack(av7110->kbuf[type], n, + &av7110->ipack[type]); + } else { + dvb_filter_instant_repack((u8 *)buf, n, + &av7110->ipack[type]); + } todo -= n; buf += n; } @@ -2517,7 +2530,8 @@ n=IPACKS*2; if (copy_from_user(av7110->kbuf[type], buf, n)) return -EFAULT; - instant_repack(av7110->kbuf[type], n, &av7110->ipack[type]); + dvb_filter_instant_repack(av7110->kbuf[type], n, + &av7110->ipack[type]); // memcpy(dvb->kbuf[type], buf, n); todo -= n; buf += n; @@ -2525,7 +2539,7 @@ return count-todo; } -void init_p2t(p2t_t *p, dvb_demux_feed_t *feed) +void init_p2t(p2t_t *p, struct dvb_demux_feed *feed) { memset(p->pes,0,TS_SIZE); p->counter = 0; @@ -2721,7 +2735,7 @@ void p_to_t(u8 const *buf, long int length, u16 pid, u8 *counter, - dvb_demux_feed_t *feed) + struct dvb_demux_feed *feed) { int l, pes_start; @@ -3104,7 +3118,7 @@ static unsigned int dvb_audio_poll(struct file *file, poll_table *wait) { - dvb_device_t *dvbdev=(dvb_device_t *) file->private_data; + struct dvb_device *dvbdev=(struct dvb_device *) file->private_data; av7110_t *av7110=(av7110_t *) dvbdev->priv; unsigned int mask=0; @@ -3124,24 +3138,24 @@ static struct file_operations dvb_fops = { - ioctl: dvb_ioctl, - mmap: dvb_mmap, - llseek: no_llseek + .ioctl = dvb_ioctl, + .mmap = dvb_mmap, + .llseek = no_llseek }; /* template for video_device-structure */ static struct video_device dvb_template = { - owner: THIS_MODULE, - name: "DVB Board", - type: VID_TYPE_TUNER | + .owner = THIS_MODULE, + .name = "DVB Board", + .type = VID_TYPE_TUNER | VID_TYPE_CAPTURE | VID_TYPE_OVERLAY | VID_TYPE_CLIPPING | VID_TYPE_FRAMERAM | VID_TYPE_SCALES, - hardware: VID_HARDWARE_SAA7146, - fops: &dvb_fops + .hardware = VID_HARDWARE_SAA7146, + .fops = &dvb_fops }; @@ -3182,9 +3196,9 @@ ******************************************************************************/ static int -StartHWFilter(dvb_demux_filter_t *dvbdmxfilter) +StartHWFilter(struct dvb_demux_filter *dvbdmxfilter) { - dvb_demux_feed_t *dvbdmxfeed=dvbdmxfilter->feed; + struct dvb_demux_feed *dvbdmxfeed=dvbdmxfilter->feed; av7110_t *av7110=(av7110_t *) dvbdmxfeed->demux->priv; u16 buf[20]; int ret, i; @@ -3220,7 +3234,7 @@ } static int -StopHWFilter(dvb_demux_filter_t *dvbdmxfilter) +StopHWFilter(struct dvb_demux_filter *dvbdmxfilter) { av7110_t *av7110=(av7110_t *) dvbdmxfilter->feed->demux->priv; u16 buf[3]; @@ -3252,9 +3266,9 @@ static int -dvb_write_to_decoder(dvb_demux_feed_t *dvbdmxfeed, u8 *buf, size_t count) +dvb_write_to_decoder(struct dvb_demux_feed *dvbdmxfeed, u8 *buf, size_t count) { - dvb_demux_t *dvbdmx=dvbdmxfeed->demux; + struct dvb_demux *dvbdmx=dvbdmxfeed->demux; av7110_t *av7110=(av7110_t *) dvbdmx->priv; ipack *ipack=&av7110->ipack[dvbdmxfeed->pes_type]; @@ -3277,7 +3291,7 @@ return -1; } if (buf[1]&0x40) - send_ipack_rest(ipack); + dvb_filter_ipack_flush(ipack); if (buf[3]&0x20) { // adaptation field? count-=buf[4]+1; @@ -3287,14 +3301,15 @@ } } - instant_repack(buf+4, count-4, &av7110->ipack[dvbdmxfeed->pes_type]); + dvb_filter_instant_repack(buf+4, count-4, + &av7110->ipack[dvbdmxfeed->pes_type]); return 0; } static void -dvb_feed_start_pid(dvb_demux_feed_t *dvbdmxfeed) +dvb_feed_start_pid(struct dvb_demux_feed *dvbdmxfeed) { - dvb_demux_t *dvbdmx=dvbdmxfeed->demux; + struct dvb_demux *dvbdmx=dvbdmxfeed->demux; av7110_t *av7110=(av7110_t *) dvbdmx->priv; u16 *pid=dvbdmx->pids, npids[5]; int i; @@ -3329,9 +3344,9 @@ } static void -dvb_feed_stop_pid(dvb_demux_feed_t *dvbdmxfeed) +dvb_feed_stop_pid(struct dvb_demux_feed *dvbdmxfeed) { - dvb_demux_t *dvbdmx=dvbdmxfeed->demux; + struct dvb_demux *dvbdmx=dvbdmxfeed->demux; av7110_t *av7110=(av7110_t *) dvbdmx->priv; u16 *pid=dvbdmx->pids, npids[5]; int i; @@ -3365,9 +3380,9 @@ } static int -dvb_start_feed(dvb_demux_feed_t *dvbdmxfeed) +dvb_start_feed(struct dvb_demux_feed *dvbdmxfeed) { - dvb_demux_t *dvbdmx=dvbdmxfeed->demux; + struct dvb_demux *dvbdmx=dvbdmxfeed->demux; av7110_t *av7110=(av7110_t *) dvbdmx->priv; if (!dvbdmx->dmx.frontend) @@ -3425,9 +3440,9 @@ static int -dvb_stop_feed(dvb_demux_feed_t *dvbdmxfeed) +dvb_stop_feed(struct dvb_demux_feed *dvbdmxfeed) { - dvb_demux_t *dvbdmx=dvbdmxfeed->demux; + struct dvb_demux *dvbdmx=dvbdmxfeed->demux; av7110_t *av7110=(av7110_t *) dvbdmx->priv; if (av7110->saa->card_type>=DVB_CARD_TT_BUDGET) @@ -3468,8 +3483,8 @@ static void restart_feeds(av7110_t *av7110) { - dvb_demux_t *dvbdmx=&av7110->demux; - dvb_demux_feed_t *feed; + struct dvb_demux *dvbdmx=&av7110->demux; + struct dvb_demux_feed *feed; int mode; int i; @@ -3660,7 +3675,7 @@ static int dvb_ca_open(struct inode *inode, struct file *file) { - dvb_device_t *dvbdev=(dvb_device_t *) file->private_data; + struct dvb_device *dvbdev=(struct dvb_device *) file->private_data; av7110_t *av7110=(av7110_t *) dvbdev->priv; int err=dvb_generic_open(inode, file); @@ -3673,7 +3688,7 @@ static unsigned int dvb_ca_poll(struct file *file, poll_table *wait) { - dvb_device_t *dvbdev=(dvb_device_t *) file->private_data; + struct dvb_device *dvbdev=(struct dvb_device *) file->private_data; av7110_t *av7110=(av7110_t *) dvbdev->priv; unsigned int mask=0; @@ -3702,7 +3717,7 @@ dvb_ca_ioctl(struct inode *inode, struct file *file, unsigned int cmd, void *parg) { - dvb_device_t *dvbdev=(dvb_device_t *) file->private_data; + struct dvb_device *dvbdev=(struct dvb_device *) file->private_data; av7110_t *av7110=(av7110_t *) dvbdev->priv; unsigned long arg=(unsigned long) parg; @@ -3716,7 +3731,7 @@ case CA_GET_CAP: { - ca_cap_t cap; + ca_caps_t cap; cap.slot_num=2; #ifdef NEW_CI @@ -3788,7 +3803,7 @@ dvb_ca_write(struct file *file, const char *buf, size_t count, loff_t *ppos) { - dvb_device_t *dvbdev=(dvb_device_t *) file->private_data; + struct dvb_device *dvbdev=(struct dvb_device *) file->private_data; av7110_t *av7110=(av7110_t *) dvbdev->priv; return ci_ll_write(&av7110->ci_wbuffer, file, buf, count, ppos); @@ -3797,7 +3812,7 @@ static ssize_t dvb_ca_read(struct file *file, char *buf, size_t count, loff_t *ppos) { - dvb_device_t *dvbdev=(dvb_device_t *) file->private_data; + struct dvb_device *dvbdev=(struct dvb_device *) file->private_data; av7110_t *av7110=(av7110_t *) dvbdev->priv; return ci_ll_read(&av7110->ci_rbuffer, file, buf, count, ppos); @@ -3812,7 +3827,7 @@ static unsigned int dvb_video_poll(struct file *file, poll_table *wait) { - dvb_device_t *dvbdev=(dvb_device_t *) file->private_data; + struct dvb_device *dvbdev=(struct dvb_device *) file->private_data; av7110_t *av7110=(av7110_t *) dvbdev->priv; unsigned int mask=0; @@ -3834,7 +3849,7 @@ dvb_video_write(struct file *file, const char *buf, size_t count, loff_t *ppos) { - dvb_device_t *dvbdev=(dvb_device_t *) file->private_data; + struct dvb_device *dvbdev=(struct dvb_device *) file->private_data; av7110_t *av7110=(av7110_t *) dvbdev->priv; if (av7110->videostate.stream_source!=VIDEO_SOURCE_MEMORY) @@ -3847,7 +3862,7 @@ dvb_audio_write(struct file *file, const char *buf, size_t count, loff_t *ppos) { - dvb_device_t *dvbdev=(dvb_device_t *) file->private_data; + struct dvb_device *dvbdev=(struct dvb_device *) file->private_data; av7110_t *av7110=(av7110_t *) dvbdev->priv; if (av7110->audiostate.stream_source!=AUDIO_SOURCE_MEMORY) { @@ -3876,7 +3891,7 @@ for (i=0; iipack[1]); + dvb_filter_ipack_flush(&av7110->ipack[1]); } @@ -3884,7 +3899,7 @@ dvb_video_ioctl(struct inode *inode, struct file *file, unsigned int cmd, void *parg) { - dvb_device_t *dvbdev=(dvb_device_t *) file->private_data; + struct dvb_device *dvbdev=(struct dvb_device *) file->private_data; av7110_t *av7110=(av7110_t *) dvbdev->priv; unsigned long arg=(unsigned long) parg; int ret=0; @@ -4041,7 +4056,7 @@ case VIDEO_CLEAR_BUFFER: ring_buffer_flush(&av7110->avout); - reset_ipack(&av7110->ipack[1]); + dvb_filter_ipack_reset(&av7110->ipack[1]); if (av7110->playing==RP_AV) { outcom(av7110, COMTYPE_REC_PLAY, @@ -4073,7 +4088,7 @@ dvb_audio_ioctl(struct inode *inode, struct file *file, unsigned int cmd, void *parg) { - dvb_device_t *dvbdev=(dvb_device_t *) file->private_data; + struct dvb_device *dvbdev=(struct dvb_device *) file->private_data; av7110_t *av7110=(av7110_t *) dvbdev->priv; unsigned long arg=(unsigned long) parg; int ret=0; @@ -4164,7 +4179,7 @@ case AUDIO_CLEAR_BUFFER: ring_buffer_flush(&av7110->aout); - reset_ipack(&av7110->ipack[0]); + dvb_filter_ipack_reset(&av7110->ipack[0]); if (av7110->playing==RP_AV) outcom(av7110, COMTYPE_REC_PLAY, __Play, 2, AV_PES, 0); @@ -4192,7 +4207,7 @@ dvb_osd_ioctl(struct inode *inode, struct file *file, unsigned int cmd, void *parg) { - dvb_device_t *dvbdev=(dvb_device_t *) file->private_data; + struct dvb_device *dvbdev=(struct dvb_device *) file->private_data; av7110_t *av7110=(av7110_t *) dvbdev->priv; #ifdef CONFIG_DVB_AV7110_OSD @@ -4204,7 +4219,7 @@ static int dvb_video_open(struct inode *inode, struct file *file) { - dvb_device_t *dvbdev=(dvb_device_t *) file->private_data; + struct dvb_device *dvbdev=(struct dvb_device *) file->private_data; av7110_t *av7110=(av7110_t *) dvbdev->priv; int err; @@ -4220,7 +4235,7 @@ static int dvb_video_release(struct inode *inode, struct file *file) { - dvb_device_t *dvbdev=(dvb_device_t *) file->private_data; + struct dvb_device *dvbdev=(struct dvb_device *) file->private_data; av7110_t *av7110=(av7110_t *) dvbdev->priv; AV_Stop(av7110, RP_VIDEO); @@ -4229,7 +4244,7 @@ static int dvb_audio_open(struct inode *inode, struct file *file) { - dvb_device_t *dvbdev=(dvb_device_t *) file->private_data; + struct dvb_device *dvbdev=(struct dvb_device *) file->private_data; av7110_t *av7110=(av7110_t *) dvbdev->priv; int err=dvb_generic_open(inode, file); @@ -4242,7 +4257,7 @@ static int dvb_audio_release(struct inode *inode, struct file *file) { - dvb_device_t *dvbdev=(dvb_device_t *) file->private_data; + struct dvb_device *dvbdev=(struct dvb_device *) file->private_data; av7110_t *av7110=(av7110_t *) dvbdev->priv; AV_Stop(av7110, RP_AUDIO); @@ -4256,75 +4271,70 @@ ******************************************************************************/ static struct file_operations dvb_video_fops = { - owner: THIS_MODULE, - read: 0, - write: dvb_video_write, - ioctl: dvb_generic_ioctl, - open: dvb_video_open, - release: dvb_video_release, - poll: dvb_video_poll, + .owner = THIS_MODULE, + .write = dvb_video_write, + .ioctl = dvb_generic_ioctl, + .open = dvb_video_open, + .release = dvb_video_release, + .poll = dvb_video_poll, }; -static dvb_device_t dvbdev_video = { - priv: 0, - users: 1, - writers: 1, - fops: &dvb_video_fops, - kernel_ioctl: dvb_video_ioctl, +static struct dvb_device dvbdev_video = { + .priv = 0, + .users = 1, + .writers = 1, + .fops = &dvb_video_fops, + .kernel_ioctl = dvb_video_ioctl, }; static struct file_operations dvb_audio_fops = { - owner: THIS_MODULE, - read: 0, - write: dvb_audio_write, - ioctl: dvb_generic_ioctl, - open: dvb_audio_open, - release: dvb_audio_release, - poll: dvb_audio_poll, + .owner = THIS_MODULE, + .write = dvb_audio_write, + .ioctl = dvb_generic_ioctl, + .open = dvb_audio_open, + .release = dvb_audio_release, + .poll = dvb_audio_poll, }; -static dvb_device_t dvbdev_audio = { - priv: 0, - users: 1, - writers: 1, - fops: &dvb_audio_fops, - kernel_ioctl: dvb_audio_ioctl, +static struct dvb_device dvbdev_audio = { + .priv = 0, + .users = 1, + .writers = 1, + .fops = &dvb_audio_fops, + .kernel_ioctl = dvb_audio_ioctl, }; static struct file_operations dvb_ca_fops = { - owner: THIS_MODULE, - read: dvb_ca_read, - write: dvb_ca_write, - ioctl: dvb_generic_ioctl, - open: dvb_ca_open, - release: dvb_generic_release, - poll: dvb_ca_poll, + .owner = THIS_MODULE, + .read = dvb_ca_read, + .write = dvb_ca_write, + .ioctl = dvb_generic_ioctl, + .open = dvb_ca_open, + .release = dvb_generic_release, + .poll = dvb_ca_poll, }; -static dvb_device_t dvbdev_ca = { - priv: 0, - users: 1, - writers: 1, - fops: &dvb_ca_fops, - kernel_ioctl: dvb_ca_ioctl, +static struct dvb_device dvbdev_ca = { + .priv = 0, + .users = 1, + .writers = 1, + .fops = &dvb_ca_fops, + .kernel_ioctl = dvb_ca_ioctl, }; static struct file_operations dvb_osd_fops = { - owner: THIS_MODULE, - read: 0, - write: 0, - ioctl: dvb_generic_ioctl, - open: dvb_generic_open, - release: dvb_generic_release, - poll: 0, + .owner = THIS_MODULE, + .ioctl = dvb_generic_ioctl, + .open = dvb_generic_open, + .release = dvb_generic_release, }; -static dvb_device_t dvbdev_osd = { - priv: 0, - users: 1, - writers: 1, - fops: &dvb_osd_fops, - kernel_ioctl: dvb_osd_ioctl, +static struct dvb_device dvbdev_osd = { + .priv = 0, + .users = 1, + .writers = 1, + .fops = &dvb_osd_fops, + .kernel_ioctl = dvb_osd_ioctl, }; @@ -4359,7 +4369,7 @@ { int ret, i; dmx_frontend_t *dvbfront=&av7110->hw_frontend; - dvb_demux_t *dvbdemux=&av7110->demux; + struct dvb_demux *dvbdemux=&av7110->demux; if (av7110->registered) return -1; @@ -4414,7 +4424,7 @@ DMX_SECTION_FILTERING| DMX_MEMORY_BASED_FILTERING); - DvbDmxInit(&av7110->demux); + dvb_dmx_init(&av7110->demux); dvbfront->id="hw_frontend"; @@ -4426,7 +4436,7 @@ av7110->dmxdev.demux=&dvbdemux->dmx; av7110->dmxdev.capabilities=0; - DmxDevInit(&av7110->dmxdev, av7110->dvb_adapter); + dvb_dmxdev_init(&av7110->dmxdev, av7110->dvb_adapter); } if (av7110->saa->card_type>=DVB_CARD_TT_BUDGET) { @@ -4443,7 +4453,7 @@ DMX_SECTION_FILTERING| DMX_MEMORY_BASED_FILTERING); - DvbDmxInit(&av7110->demux); + dvb_dmx_init(&av7110->demux); dvbfront->id="hw_frontend"; dvbfront->vendor="VLSI"; @@ -4454,7 +4464,7 @@ av7110->dmxdev.demux=&dvbdemux->dmx; av7110->dmxdev.capabilities=0; - DmxDevInit(&av7110->dmxdev, av7110->dvb_adapter); + dvb_dmxdev_init(&av7110->dmxdev, av7110->dvb_adapter); } ret=dvbdemux->dmx.add_frontend(&dvbdemux->dmx, @@ -4505,7 +4515,7 @@ static void dvb_unregister(av7110_t *av7110) { - dvb_demux_t *dvbdemux=&av7110->demux; + struct dvb_demux *dvbdemux=&av7110->demux; if (!av7110->registered) return; @@ -4516,8 +4526,8 @@ dvbdemux->dmx.remove_frontend(&dvbdemux->dmx, &av7110->hw_frontend); dvbdemux->dmx.remove_frontend(&dvbdemux->dmx, &av7110->mem_frontend); - DmxDevRelease(&av7110->dmxdev); - DvbDmxRelease(&av7110->demux); + dvb_dmxdev_release(&av7110->dmxdev); + dvb_dmx_release(&av7110->demux); if (av7110->saa->card_type==DVB_CARD_TT_SIEMENS) dvb_remove_frontend_notifier (av7110->dvb_adapter, @@ -4584,9 +4594,9 @@ av7110->vidmode=VIDEO_MODE_PAL; - init_ipack(&av7110->ipack[0], IPACKS, play_audio_cb); + dvb_filter_ipack_init(&av7110->ipack[0], IPACKS, play_audio_cb); av7110->ipack[0].data=(void *) av7110; - init_ipack(&av7110->ipack[1], IPACKS, play_video_cb); + dvb_filter_ipack_init(&av7110->ipack[1], IPACKS, play_video_cb); av7110->ipack[1].data=(void *) av7110; @@ -4705,8 +4715,8 @@ saa7146_write(av7110->saa_mem, ISR,(MASK_19 | MASK_03)); ci_ll_release(&av7110->ci_rbuffer, &av7110->ci_wbuffer); - free_ipack(&av7110->ipack[0]); - free_ipack(&av7110->ipack[1]); + dvb_filter_ipack_free(&av7110->ipack[0]); + dvb_filter_ipack_free(&av7110->ipack[1]); vfree(av7110->iobuf); pci_free_consistent(av7110->saa->device, 8192, av7110->debi_virt, av7110->debi_bus); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/drivers/media/dvb/av7110/av7110.h linux.2.5.47-ac6/drivers/media/dvb/av7110/av7110.h --- linux.2.5.47/drivers/media/dvb/av7110/av7110.h 2002-10-31 15:05:01.000000000 +0000 +++ linux.2.5.47-ac6/drivers/media/dvb/av7110/av7110.h 2002-11-13 01:26:41.000000000 +0000 @@ -479,7 +479,7 @@ u8 counter; long int pos; int frags; - dvb_demux_feed_t *feed; + struct dvb_demux_feed *feed; } p2t_t; @@ -561,7 +561,7 @@ int vidmode; dmxdev_t dmxdev; - dvb_demux_t demux; + struct dvb_demux demux; char demux_id[16]; dmx_frontend_t hw_frontend; @@ -580,9 +580,9 @@ #define TRICK_FREEZE 3 struct audio_status audiostate; - dvb_demux_filter_t *handle2filter[32]; + struct dvb_demux_filter *handle2filter[32]; p2t_t p2t_filter[MAXFILT]; - pes2ts_t p2t[2]; + dvb_filter_pes2ts_t p2t[2]; struct ipack_s ipack[2]; u8 *kbuf[2]; @@ -621,11 +621,11 @@ ring_buffer_t ci_wbuffer; - dvb_adapter_t *dvb_adapter; - dvb_device_t *video_dev; - dvb_device_t *audio_dev; - dvb_device_t *ca_dev; - dvb_device_t *osd_dev; + struct dvb_adapter *dvb_adapter; + struct dvb_device *video_dev; + struct dvb_device *audio_dev; + struct dvb_device *ca_dev; + struct dvb_device *osd_dev; int dsp_dev; } av7110_t; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/drivers/media/dvb/av7110/Makefile linux.2.5.47-ac6/drivers/media/dvb/av7110/Makefile --- linux.2.5.47/drivers/media/dvb/av7110/Makefile 2002-10-31 15:05:01.000000000 +0000 +++ linux.2.5.47-ac6/drivers/media/dvb/av7110/Makefile 2002-11-13 01:26:41.000000000 +0000 @@ -6,5 +6,7 @@ obj-$(CONFIG_DVB_AV7110) += dvb-ttpci.o +EXTRA_CFLAGS = -Idrivers/media/dvb/dvb-core/ + include $(TOPDIR)/Rules.make diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/drivers/media/dvb/av7110/saa7146.c linux.2.5.47-ac6/drivers/media/dvb/av7110/saa7146.c --- linux.2.5.47/drivers/media/dvb/av7110/saa7146.c 2002-10-31 15:05:01.000000000 +0000 +++ linux.2.5.47-ac6/drivers/media/dvb/av7110/saa7146.c 2002-11-13 01:26:41.000000000 +0000 @@ -1399,7 +1399,7 @@ /* if any error is still present, a fatal error has occured ... */ if ( SAA7146_I2C_BBR != (status = i2c_status_check(saa)) ) { hprintk("saa7146: i2c_reset: fatal error, status:0x%08x\n",status); - return -1; + return -EIO; } return 0; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/drivers/media/dvb/av7110/saa7146_core.c linux.2.5.47-ac6/drivers/media/dvb/av7110/saa7146_core.c --- linux.2.5.47/drivers/media/dvb/av7110/saa7146_core.c 2002-10-31 15:05:01.000000000 +0000 +++ linux.2.5.47-ac6/drivers/media/dvb/av7110/saa7146_core.c 2002-11-13 01:26:41.000000000 +0000 @@ -33,8 +33,8 @@ #include "saa7146_core.h" #include "saa7146_v4l.h" #include "av7110.h" -#include "../dvb-core/compat.h" -#include "../dvb-core/dvb_i2c.h" +#include "compat.h" +#include "dvb_i2c.h" /* insmod parameter: here you can specify the number of video-buffers to be allocated. for simple capturing 2 buffers (double-buffering) @@ -197,23 +197,23 @@ int do_master_xfer (struct dvb_i2c_bus *i2c, struct i2c_msg msgs[], int num) { struct saa7146 *a = i2c->data; - int result, count; + int count; int i = 0; dprintk(KERN_ERR "saa7146_core.o: master_xfer called, num:%d\n",num); /* prepare the message(s), get number of u32s to transfer */ count = prepare(msgs, num, a->i2c); - if ( 0 > count ) { - hprintk(KERN_ERR "saa7146_core.o: master_xfer: could not prepare i2c-message\n"); + + if (count < 0) { + hprintk(KERN_ERR "saa7146_core.o: could not prepare i2c-message\n"); return -EIO; } /* reset the i2c-device if necessary */ - result = i2c_reset( a ); - if ( 0 > result ) { - hprintk(KERN_ERR "saa7146_core.o: master_xfer: could not reset i2c-bus\n"); - return result; + if (i2c_reset(a) < 0) { + hprintk(KERN_ERR "saa7146_core.o: could not reset i2c-bus\n"); + return -EIO; } for(i = 0; i < count; i++) { @@ -222,31 +222,17 @@ * we do not start the whole rps1-engine... */ - result = i2c_write_out( a, &a->i2c[i], - SAA7146_I2C_TIMEOUT ); - - if ( 0 != result) { /* if address-error occured, don't retry */ - if ( result == -EREMOTEIO ) - { - hprintk(KERN_ERR "saa7146_core.o: master_xfer: error in address phase\n"); - return result; - } - hprintk(KERN_ERR "saa7146_core.o: master_xfer: error transferring, trying again\n"); - break; - } + if (i2c_write_out(a, &a->i2c[i], SAA7146_I2C_TIMEOUT) < 0) { + hprintk (KERN_ERR "saa7146_core.o: " + "i2c error in address phase\n"); + return -EREMOTEIO; } - - /* see if an error occured & the last retry failed */ - if (0 != result) { - hprintk(KERN_ERR "saa7146_core.o: master_xfer: could not transfer i2c-message\n"); - return -EIO; } /* if any things had to be read, get the results */ - result = clean_up(msgs, num, a->i2c); - if ( 0 > result ) { - hprintk(KERN_ERR "saa7146_core.o: master_xfer: could not cleanup\n"); + if (clean_up(msgs, num, a->i2c) < 0) { + hprintk(KERN_ERR "saa7146_core.o: i2c cleanup failed!\n"); return -EIO; } @@ -259,13 +245,19 @@ static int master_xfer (struct dvb_i2c_bus *i2c, struct i2c_msg msgs[], int num) { + struct saa7146 *saa = i2c->data; int retries = SAA7146_I2C_RETRIES; int ret; + if (down_interruptible (&saa->i2c_sem)) + return -ERESTARTSYS; + do { ret = do_master_xfer (i2c, msgs, num); } while (ret != num && retries--); + up (&saa->i2c_sem); + return ret; } @@ -273,6 +265,8 @@ /* registering functions to load algorithms at runtime */ int i2c_saa7146_add_bus (struct saa7146 *saa) { + init_MUTEX(&saa->i2c_sem); + /* enable i2c-port pins */ saa7146_write (saa->mem, MC1, (MASK_08 | MASK_24)); @@ -389,9 +383,9 @@ struct saa7146_debi_transfer *dt = arg; - printk("saa7146_core.o: SAA7146_DEBI_TRANSFER\n"); - printk("saa7146_core.o: timeout:%d, swap:%d, slave16:%d, increment:%d, intel:%d, tien:%d\n", dt->timeout, dt->swap, dt->slave16, dt->increment, dt->intel, dt->tien); - printk("saa7146_core.o: address:0x%04x, num_bytes:%d, direction:%d, mem:0x%08x\n",dt->address,dt->address,dt->direction,dt->mem); + dprintk("saa7146_core.o: SAA7146_DEBI_TRANSFER\n"); + dprintk("saa7146_core.o: timeout:%d, swap:%d, slave16:%d, increment:%d, intel:%d, tien:%d\n", dt->timeout, dt->swap, dt->slave16, dt->increment, dt->intel, dt->tien); + dprintk("saa7146_core.o: address:0x%04x, num_bytes:%d, direction:%d, mem:0x%08x\n",dt->address,dt->address,dt->direction,dt->mem); debi_transfer(saa, dt); break; @@ -622,7 +616,7 @@ } /* print status message */ - printk(KERN_ERR "saa7146_core.o: %s: bus:%d, rev:%d, mem:0x%08x.\n", saa->name, saa->device->bus->number, saa->revision, (unsigned int) saa->mem); + dprintk("saa7146_core.o: %s: bus:%d, rev:%d, mem:0x%08x.\n", saa->name, saa->device->bus->number, saa->revision, (unsigned int) saa->mem); /* enable bus-mastering */ pci_set_master( saa->device ); @@ -827,7 +821,7 @@ int __devinit saa7146_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) { - struct dvb_adapter_s *adap; + struct dvb_adapter *adap; struct saa7146 *saa; int card_type; struct card_info *cinfo= (struct card_info *) ent->driver_data; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/drivers/media/dvb/av7110/saa7146_core.h linux.2.5.47-ac6/drivers/media/dvb/av7110/saa7146_core.h --- linux.2.5.47/drivers/media/dvb/av7110/saa7146_core.h 2002-10-31 15:05:01.000000000 +0000 +++ linux.2.5.47-ac6/drivers/media/dvb/av7110/saa7146_core.h 2002-11-13 01:26:41.000000000 +0000 @@ -1,17 +1,11 @@ #ifndef __SAA7146_CORE__ #define __SAA7146_CORE__ -#include /* definitions of u32 etc. */ -#include "../dvb-core/dvbdev.h" +#include +#include + +#include "dvbdev.h" -#if LINUX_VERSION_CODE < 0x020300 -#define DECLARE_MUTEX(foo) struct semaphore foo = MUTEX -#define DECLARE_MUTEX_LOCKED(foo) struct semaphore foo = MUTEX_LOCKED -#define WAIT_QUEUE struct wait_queue* -#define init_waitqueue_head(wq) *(wq) = NULL; -#else -#define WAIT_QUEUE wait_queue_head_t -#endif /* maximum number of capture frames we support */ #define SAA7146_MAX_BUF 5 @@ -37,12 +31,13 @@ char name[32]; /* give it a nice name */ struct list_head list_head; - - dvb_adapter_t *dvb_adapter; - struct dvb_i2c_bus *i2c_bus; struct pci_dev *device; int card_type; + struct dvb_adapter *dvb_adapter; + struct dvb_i2c_bus *i2c_bus; + struct semaphore i2c_sem; + void* data[SAA7146_MAX_EXTENSIONS]; /* data hooks for extensions */ int (*command) (struct dvb_i2c_bus *i, unsigned int cmd, void *arg); @@ -70,8 +65,8 @@ int grab_format[SAA7146_MAX_BUF]; /* video format of grabs */ int grab_port[SAA7146_MAX_BUF]; /* video port for grab */ - WAIT_QUEUE rps0_wq; /* rps0 interrupt queue (=> capture) */ - WAIT_QUEUE rps1_wq; /* rps1 interrupt queue (=> i2c, ...) */ + wait_queue_head_t rps0_wq; /* rps0 interrupt queue (=> capture) */ + wait_queue_head_t rps1_wq; /* rps1 interrupt queue (=> i2c, ...) */ }; #define SAA7146_IRQ_RPS0 diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/drivers/media/dvb/av7110/saa7146_v4l.c linux.2.5.47-ac6/drivers/media/dvb/av7110/saa7146_v4l.c --- linux.2.5.47/drivers/media/dvb/av7110/saa7146_v4l.c 2002-10-31 15:05:01.000000000 +0000 +++ linux.2.5.47-ac6/drivers/media/dvb/av7110/saa7146_v4l.c 2002-11-13 01:26:41.000000000 +0000 @@ -320,7 +320,6 @@ /* set corresponding buffer to ´unused´ */ saa->frame_stat[i] = GBUFFER_UNUSED; -printk ("saa7146_v4l.o: SAA7146_V4L_CSYNC, frame %i done.\n", i); break; } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/drivers/media/dvb/dvb-core/dmxdev.c linux.2.5.47-ac6/drivers/media/dvb/dvb-core/dmxdev.c --- linux.2.5.47/drivers/media/dvb/dvb-core/dmxdev.c 2002-10-31 15:05:01.000000000 +0000 +++ linux.2.5.47-ac6/drivers/media/dvb/dvb-core/dmxdev.c 2002-11-13 01:26:41.000000000 +0000 @@ -24,6 +24,7 @@ #include #include #include +#include #include #include "dmxdev.h" @@ -40,19 +41,19 @@ #define dprintk if (debug) printk inline dmxdev_filter_t * -DmxDevFile2Filter(struct file *file) +dvb_dmxdev_file_to_filter(struct file *file) { return (dmxdev_filter_t *) file->private_data; } inline dmxdev_dvr_t * -DmxDevFile2DVR(dmxdev_t *dmxdev, struct file *file) +dvb_dmxdev_file_to_dvr(dmxdev_t *dmxdev, struct file *file) { return (dmxdev_dvr_t *) file->private_data; } static inline void -DmxDevBufferInit(dmxdev_buffer_t *buffer) +dvb_dmxdev_buffer_init(dmxdev_buffer_t *buffer) { buffer->data=0; buffer->size=8192; @@ -63,7 +64,7 @@ } static inline int -DmxDevBufferWrite(dmxdev_buffer_t *buf, uint8_t *src, int len) +dvb_dmxdev_buffer_write(dmxdev_buffer_t *buf, uint8_t *src, int len) { int split; int free; @@ -98,7 +99,7 @@ } static ssize_t -DmxDevBufferRead(dmxdev_buffer_t *src, int non_blocking, +dvb_dmxdev_buffer_read(dmxdev_buffer_t *src, int non_blocking, char *buf, size_t count, loff_t *ppos) { unsigned long todo=count; @@ -108,6 +109,7 @@ return 0; if ((error=src->error)) { + src->pwrite=src->pread; src->error=0; return error; } @@ -125,6 +127,7 @@ return count-todo; if ((error=src->error)) { + src->pwrite=src->pread; src->error=0; return error; } @@ -172,7 +175,7 @@ } static inline void -DmxDevDVRStateSet(dmxdev_dvr_t *dmxdevdvr, int state) +dvb_dmxdev_dvr_state_set(dmxdev_dvr_t *dmxdevdvr, int state) { spin_lock_irq(&dmxdevdvr->dev->lock); dmxdevdvr->state=state; @@ -181,7 +184,7 @@ static int dvb_dvr_open(struct inode *inode, struct file *file) { - dvb_device_t *dvbdev=(dvb_device_t *) file->private_data; + struct dvb_device *dvbdev=(struct dvb_device *) file->private_data; dmxdev_t *dmxdev=(dmxdev_t *) dvbdev->priv; dmx_frontend_t *front; @@ -198,7 +201,7 @@ } if ((file->f_flags&O_ACCMODE)==O_RDONLY) { - DmxDevBufferInit(&dmxdev->dvr_buffer); + dvb_dmxdev_buffer_init(&dmxdev->dvr_buffer); dmxdev->dvr_buffer.size=DVR_BUFFER_SIZE; dmxdev->dvr_buffer.data=vmalloc(DVR_BUFFER_SIZE); if (!dmxdev->dvr_buffer.data) { @@ -230,7 +233,7 @@ static int dvb_dvr_release(struct inode *inode, struct file *file) { - dvb_device_t *dvbdev=(dvb_device_t *) file->private_data; + struct dvb_device *dvbdev=(struct dvb_device *) file->private_data; dmxdev_t *dmxdev=(dmxdev_t *) dvbdev->priv; if (down_interruptible (&dmxdev->mutex)) @@ -258,7 +261,7 @@ static ssize_t dvb_dvr_write(struct file *file, const char *buf, size_t count, loff_t *ppos) { - dvb_device_t *dvbdev=(dvb_device_t *) file->private_data; + struct dvb_device *dvbdev=(struct dvb_device *) file->private_data; dmxdev_t *dmxdev=(dmxdev_t *) dvbdev->priv; int ret; @@ -276,12 +279,12 @@ static ssize_t dvb_dvr_read(struct file *file, char *buf, size_t count, loff_t *ppos) { - dvb_device_t *dvbdev=(dvb_device_t *) file->private_data; + struct dvb_device *dvbdev=(struct dvb_device *) file->private_data; dmxdev_t *dmxdev=(dmxdev_t *) dvbdev->priv; int ret; //down(&dmxdev->mutex); - ret= DmxDevBufferRead(&dmxdev->dvr_buffer, + ret= dvb_dmxdev_buffer_read(&dmxdev->dvr_buffer, file->f_flags&O_NONBLOCK, buf, count, ppos); //up(&dmxdev->mutex); @@ -289,7 +292,7 @@ } static inline void -DmxDevFilterStateSet(dmxdev_filter_t *dmxdevfilter, int state) +dvb_dmxdev_filter_state_set(dmxdev_filter_t *dmxdevfilter, int state) { spin_lock_irq(&dmxdevfilter->dev->lock); dmxdevfilter->state=state; @@ -297,7 +300,7 @@ } static int -DmxDevSetBufferSize(dmxdev_filter_t *dmxdevfilter, unsigned long size) +dvb_dmxdev_set_buffer_size(dmxdev_filter_t *dmxdevfilter, unsigned long size) { dmxdev_buffer_t *buf=&dmxdevfilter->buffer; void *mem; @@ -327,7 +330,7 @@ } static void -DmxDevFilterTimeout(unsigned long data) +dvb_dmxdev_filter_timeout(unsigned long data) { dmxdev_filter_t *dmxdevfilter=(dmxdev_filter_t *)data; @@ -339,13 +342,13 @@ } static void -DmxDevFilterTimer(dmxdev_filter_t *dmxdevfilter) +dvb_dmxdev_filter_timer(dmxdev_filter_t *dmxdevfilter) { struct dmx_sct_filter_params *para=&dmxdevfilter->params.sec; del_timer(&dmxdevfilter->timer); if (para->timeout) { - dmxdevfilter->timer.function=DmxDevFilterTimeout; + dmxdevfilter->timer.function=dvb_dmxdev_filter_timeout; dmxdevfilter->timer.data=(unsigned long) dmxdevfilter; dmxdevfilter->timer.expires=jiffies+1+(HZ/2+HZ*para->timeout)/1000; add_timer(&dmxdevfilter->timer); @@ -353,7 +356,7 @@ } static int -DmxDevSectionCallback(u8 *buffer1, size_t buffer1_len, +dvb_dmxdev_section_callback(u8 *buffer1, size_t buffer1_len, u8 *buffer2, size_t buffer2_len, dmx_section_filter_t *filter, dmx_success_t success) @@ -375,9 +378,9 @@ buffer1[0], buffer1[1], buffer1[2], buffer1[3], buffer1[4], buffer1[5]); - ret=DmxDevBufferWrite(&dmxdevfilter->buffer, buffer1, buffer1_len); + ret=dvb_dmxdev_buffer_write(&dmxdevfilter->buffer, buffer1, buffer1_len); if (ret==buffer1_len) { - ret=DmxDevBufferWrite(&dmxdevfilter->buffer, buffer2, buffer2_len); + ret=dvb_dmxdev_buffer_write(&dmxdevfilter->buffer, buffer2, buffer2_len); } if (ret<0) { dmxdevfilter->buffer.pwrite=dmxdevfilter->buffer.pread; @@ -391,7 +394,7 @@ } static int -DmxDevTSCallback(u8 *buffer1, size_t buffer1_len, +dvb_dmxdev_ts_callback(u8 *buffer1, size_t buffer1_len, u8 *buffer2, size_t buffer2_len, dmx_ts_feed_t *feed, dmx_success_t success) @@ -415,9 +418,9 @@ wake_up(&buffer->queue); return 0; } - ret=DmxDevBufferWrite(buffer, buffer1, buffer1_len); + ret=dvb_dmxdev_buffer_write(buffer, buffer1, buffer1_len); if (ret==buffer1_len) - ret=DmxDevBufferWrite(buffer, buffer2, buffer2_len); + ret=dvb_dmxdev_buffer_write(buffer, buffer2, buffer2_len); if (ret<0) { buffer->pwrite=buffer->pread; buffer->error=-EOVERFLOW; @@ -431,9 +434,9 @@ /* stop feed but only mark the specified filter as stopped (state set) */ static int -DmxDevFeedStop(dmxdev_filter_t *dmxdevfilter) +dvb_dmxdev_feed_stop(dmxdev_filter_t *dmxdevfilter) { - DmxDevFilterStateSet(dmxdevfilter, DMXDEV_STATE_SET); + dvb_dmxdev_filter_state_set(dmxdevfilter, DMXDEV_STATE_SET); switch (dmxdevfilter->type) { case DMXDEV_TYPE_SEC: @@ -453,9 +456,9 @@ /* start feed associated with the specified filter */ static int -DmxDevFeedStart(dmxdev_filter_t *dmxdevfilter) +dvb_dmxdev_feed_start(dmxdev_filter_t *dmxdevfilter) { - DmxDevFilterStateSet(dmxdevfilter, DMXDEV_STATE_GO); + dvb_dmxdev_filter_state_set(dmxdevfilter, DMXDEV_STATE_GO); switch (dmxdevfilter->type) { case DMXDEV_TYPE_SEC: @@ -475,7 +478,7 @@ otherwise release the feed */ static int -DmxDevFeedRestart(dmxdev_filter_t *dmxdevfilter) +dvb_dmxdev_feed_restart(dmxdev_filter_t *dmxdevfilter) { int i; dmxdev_t *dmxdev=dmxdevfilter->dev; @@ -485,7 +488,7 @@ if (dmxdev->filter[i].state>=DMXDEV_STATE_GO && dmxdev->filter[i].type==DMXDEV_TYPE_SEC && dmxdev->filter[i].pid==pid) { - DmxDevFeedStart(&dmxdev->filter[i]); + dvb_dmxdev_feed_start(&dmxdev->filter[i]); return 0; } @@ -497,7 +500,7 @@ } static int -DmxDevFilterStop(dmxdev_filter_t *dmxdevfilter) +dvb_dmxdev_filter_stop(dmxdev_filter_t *dmxdevfilter) { if (dmxdevfilter->statefeed.sec) break; - DmxDevFeedStop(dmxdevfilter); + dvb_dmxdev_feed_stop(dmxdevfilter); if (dmxdevfilter->filter.sec) dmxdevfilter->feed.sec-> release_filter(dmxdevfilter->feed.sec, dmxdevfilter->filter.sec); - DmxDevFeedRestart(dmxdevfilter); + dvb_dmxdev_feed_restart(dmxdevfilter); dmxdevfilter->feed.sec=0; break; case DMXDEV_TYPE_PES: if (!dmxdevfilter->feed.ts) break; - DmxDevFeedStop(dmxdevfilter); + dvb_dmxdev_feed_stop(dmxdevfilter); dmxdevfilter->dev->demux-> release_ts_feed(dmxdevfilter->dev->demux, dmxdevfilter->feed.ts); @@ -533,19 +536,19 @@ } static inline int -DmxDevFilterReset(dmxdev_filter_t *dmxdevfilter) +dvb_dmxdev_filter_reset(dmxdev_filter_t *dmxdevfilter) { if (dmxdevfilter->statetype=DMXDEV_TYPE_NONE; dmxdevfilter->pid=0xffff; - DmxDevFilterStateSet(dmxdevfilter, DMXDEV_STATE_ALLOCATED); + dvb_dmxdev_filter_state_set(dmxdevfilter, DMXDEV_STATE_ALLOCATED); return 0; } static int -DmxDevFilterStart(dmxdev_filter_t *dmxdevfilter) +dvb_dmxdev_filter_start(dmxdev_filter_t *dmxdevfilter) { dmxdev_t *dmxdev=dmxdevfilter->dev; void *mem; @@ -554,7 +557,7 @@ if (dmxdevfilter->statestate>=DMXDEV_STATE_GO) - DmxDevFilterStop(dmxdevfilter); + dvb_dmxdev_filter_stop(dmxdevfilter); mem=dmxdevfilter->buffer.data; if (!mem) { @@ -566,6 +569,8 @@ return -ENOMEM; } + dmxdevfilter->buffer.pwrite=dmxdevfilter->buffer.pread=0; + switch (dmxdevfilter->type) { case DMXDEV_TYPE_SEC: { @@ -588,10 +593,9 @@ /* if no feed found, try to allocate new one */ if (!*secfeed) { - ret=dmxdev->demux-> - allocate_section_feed(dmxdev->demux, + ret=dmxdev->demux->allocate_section_feed(dmxdev->demux, secfeed, - DmxDevSectionCallback); + dvb_dmxdev_section_callback); if (ret<0) { printk ("DVB (%s): could not alloc feed\n", __FUNCTION__); @@ -604,18 +608,17 @@ if (ret<0) { printk ("DVB (%s): could not set feed\n", __FUNCTION__); - DmxDevFeedRestart(dmxdevfilter); + dvb_dmxdev_feed_restart(dmxdevfilter); return ret; } } else - DmxDevFeedStop(dmxdevfilter); + dvb_dmxdev_feed_stop(dmxdevfilter); ret=(*secfeed)->allocate_filter(*secfeed, secfilter); if (ret<0) { - DmxDevFeedRestart(dmxdevfilter); - dmxdevfilter->feed.sec-> - start_filtering(*secfeed); + dvb_dmxdev_feed_restart(dmxdevfilter); + dmxdevfilter->feed.sec->start_filtering(*secfeed); dprintk ("could not get filter\n"); return ret; } @@ -636,15 +639,14 @@ (*secfilter)->filter_mask[2]=0; dmxdevfilter->todo=0; - dmxdevfilter->feed.sec-> - start_filtering(dmxdevfilter->feed.sec); - DmxDevFilterTimer(dmxdevfilter); + dmxdevfilter->feed.sec->start_filtering(dmxdevfilter->feed.sec); + dvb_dmxdev_filter_timer(dmxdevfilter); break; } case DMXDEV_TYPE_PES: { - struct timespec timeout = {0 }; + struct timespec timeout = { 0 }; struct dmx_pes_filter_params *para=&dmxdevfilter->params.pes; dmx_output_t otype; int ret; @@ -670,31 +672,29 @@ ret=dmxdev->demux->allocate_ts_feed(dmxdev->demux, tsfeed, - DmxDevTSCallback); + dvb_dmxdev_ts_callback); if (ret<0) return ret; (*tsfeed)->priv=(void *) dmxdevfilter; ret=(*tsfeed)->set(*tsfeed, para->pid, ts_type, ts_pes, 188, 32768, 0, timeout); if (ret<0) { - dmxdev->demux-> - release_ts_feed(dmxdev->demux, *tsfeed); + dmxdev->demux->release_ts_feed(dmxdev->demux, *tsfeed); return ret; } - dmxdevfilter->feed.ts-> - start_filtering(dmxdevfilter->feed.ts); + dmxdevfilter->feed.ts->start_filtering(dmxdevfilter->feed.ts); break; } default: return -EINVAL; } - DmxDevFilterStateSet(dmxdevfilter, DMXDEV_STATE_GO); + dvb_dmxdev_filter_state_set(dmxdevfilter, DMXDEV_STATE_GO); return 0; } static int dvb_demux_open(struct inode *inode, struct file *file) { - dvb_device_t *dvbdev=(dvb_device_t *) file->private_data; + struct dvb_device *dvbdev=(struct dvb_device *) file->private_data; dmxdev_t *dmxdev=(dmxdev_t *) dvbdev->priv; int i; dmxdev_filter_t *dmxdevfilter; @@ -714,9 +714,9 @@ dmxdevfilter->dvbdev=dmxdev->dvbdev; file->private_data=dmxdevfilter; - DmxDevBufferInit(&dmxdevfilter->buffer); + dvb_dmxdev_buffer_init(&dmxdevfilter->buffer); dmxdevfilter->type=DMXDEV_TYPE_NONE; - DmxDevFilterStateSet(dmxdevfilter, DMXDEV_STATE_ALLOCATED); + dvb_dmxdev_filter_state_set(dmxdevfilter, DMXDEV_STATE_ALLOCATED); dmxdevfilter->feed.ts=0; init_timer(&dmxdevfilter->timer); @@ -725,13 +725,13 @@ } int -DmxDevFilterFree(dmxdev_t *dmxdev, dmxdev_filter_t *dmxdevfilter) +dvb_dmxdev_filter_free(dmxdev_t *dmxdev, dmxdev_filter_t *dmxdevfilter) { if (down_interruptible(&dmxdev->mutex)) return -ERESTARTSYS; - DmxDevFilterStop(dmxdevfilter); - DmxDevFilterReset(dmxdevfilter); + dvb_dmxdev_filter_stop(dmxdevfilter); + dvb_dmxdev_filter_reset(dmxdevfilter); if (dmxdevfilter->buffer.data) { void *mem=dmxdevfilter->buffer.data; @@ -741,7 +741,7 @@ spin_unlock_irq(&dmxdev->lock); vfree(mem); } - DmxDevFilterStateSet(dmxdevfilter, DMXDEV_STATE_FREE); + dvb_dmxdev_filter_state_set(dmxdevfilter, DMXDEV_STATE_FREE); wake_up(&dmxdevfilter->buffer.queue); up(&dmxdev->mutex); return 0; @@ -758,33 +758,33 @@ static int -DmxDevFilterSet(dmxdev_t *dmxdev, +dvb_dmxdev_filter_set(dmxdev_t *dmxdev, dmxdev_filter_t *dmxdevfilter, struct dmx_sct_filter_params *params) { dprintk ("function : %s\n", __FUNCTION__); - DmxDevFilterStop(dmxdevfilter); + dvb_dmxdev_filter_stop(dmxdevfilter); dmxdevfilter->type=DMXDEV_TYPE_SEC; dmxdevfilter->pid=params->pid; memcpy(&dmxdevfilter->params.sec, params, sizeof(struct dmx_sct_filter_params)); invert_mode(&dmxdevfilter->params.sec.filter); - DmxDevFilterStateSet(dmxdevfilter, DMXDEV_STATE_SET); + dvb_dmxdev_filter_state_set(dmxdevfilter, DMXDEV_STATE_SET); if (params->flags&DMX_IMMEDIATE_START) - return DmxDevFilterStart(dmxdevfilter); + return dvb_dmxdev_filter_start(dmxdevfilter); return 0; } static int -DmxDevPesFilterSet(dmxdev_t *dmxdev, +dvb_dmxdev_pes_filter_set(dmxdev_t *dmxdev, dmxdev_filter_t *dmxdevfilter, struct dmx_pes_filter_params *params) { - DmxDevFilterStop(dmxdevfilter); + dvb_dmxdev_filter_stop(dmxdevfilter); if (params->pes_type>DMX_PES_OTHER || params->pes_type<0) return -EINVAL; @@ -793,16 +793,16 @@ dmxdevfilter->pid=params->pid; memcpy(&dmxdevfilter->params, params, sizeof(struct dmx_pes_filter_params)); - DmxDevFilterStateSet(dmxdevfilter, DMXDEV_STATE_SET); + dvb_dmxdev_filter_state_set(dmxdevfilter, DMXDEV_STATE_SET); if (params->flags&DMX_IMMEDIATE_START) - return DmxDevFilterStart(dmxdevfilter); + return dvb_dmxdev_filter_start(dmxdevfilter); return 0; } static ssize_t -DmxDevReadSec(dmxdev_filter_t *dfil, struct file *file, +dvb_dmxdev_read_sec(dmxdev_filter_t *dfil, struct file *file, char *buf, size_t count, loff_t *ppos) { int result, hcount; @@ -812,7 +812,7 @@ hcount=3+dfil->todo; if (hcount>count) hcount=count; - result=DmxDevBufferRead(&dfil->buffer, file->f_flags&O_NONBLOCK, + result=dvb_dmxdev_buffer_read(&dfil->buffer, file->f_flags&O_NONBLOCK, buf, hcount, ppos); if (result<0) { dfil->todo=0; @@ -832,7 +832,7 @@ } if (count>dfil->todo) count=dfil->todo; - result=DmxDevBufferRead(&dfil->buffer, file->f_flags&O_NONBLOCK, + result=dvb_dmxdev_buffer_read(&dfil->buffer, file->f_flags&O_NONBLOCK, buf, count, ppos); if (result<0) return result; @@ -844,16 +844,16 @@ ssize_t dvb_demux_read(struct file *file, char *buf, size_t count, loff_t *ppos) { - dmxdev_filter_t *dmxdevfilter=DmxDevFile2Filter(file); + dmxdev_filter_t *dmxdevfilter=dvb_dmxdev_file_to_filter(file); //dmxdev_t *dmxdev=dmxdevfilter->dev; int ret=0; // semaphore should not be necessary (I hope ...) //down(&dmxdev->mutex); if (dmxdevfilter->type==DMXDEV_TYPE_SEC) - ret=DmxDevReadSec(dmxdevfilter, file, buf, count, ppos); + ret=dvb_dmxdev_read_sec(dmxdevfilter, file, buf, count, ppos); else - ret=DmxDevBufferRead(&dmxdevfilter->buffer, + ret=dvb_dmxdev_buffer_read(&dmxdevfilter->buffer, file->f_flags&O_NONBLOCK, buf, count, ppos); //up(&dmxdev->mutex); @@ -864,7 +864,7 @@ static int dvb_demux_do_ioctl(struct inode *inode, struct file *file, unsigned int cmd, void *parg) { - dmxdev_filter_t *dmxdevfilter=DmxDevFile2Filter(file); + dmxdev_filter_t *dmxdevfilter=dvb_dmxdev_file_to_filter(file); dmxdev_t *dmxdev=dmxdevfilter->dev; unsigned long arg=(unsigned long) parg; int ret=0; @@ -877,25 +877,25 @@ if (dmxdevfilter->statedev; - return DmxDevFilterFree(dmxdev, dmxdevfilter); + return dvb_dmxdev_filter_free(dmxdev, dmxdevfilter); } static struct file_operations dvb_demux_fops = { - owner: THIS_MODULE, - read: dvb_demux_read, - write: 0, - ioctl: dvb_demux_ioctl, - open: dvb_demux_open, - release: dvb_demux_release, - poll: dvb_demux_poll, + .owner = THIS_MODULE, + .read = dvb_demux_read, + .ioctl = dvb_demux_ioctl, + .open = dvb_demux_open, + .release = dvb_demux_release, + .poll = dvb_demux_poll, }; -static dvb_device_t dvbdev_demux = { - priv: 0, - users: 1, - writers: 1, - fops: &dvb_demux_fops +static struct dvb_device dvbdev_demux = { + .priv = 0, + .users = 1, + .writers = 1, + .fops = &dvb_demux_fops }; static int dvb_dvr_do_ioctl(struct inode *inode, struct file *file, unsigned int cmd, void *parg) { - dvb_device_t *dvbdev=(dvb_device_t *) file->private_data; + struct dvb_device *dvbdev=(struct dvb_device *) file->private_data; dmxdev_t *dmxdev=(dmxdev_t *) dvbdev->priv; int ret=0; @@ -1008,13 +1007,13 @@ static int dvb_dvr_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { - return generic_usercopy(inode, file, cmd, arg, dvb_dvr_do_ioctl); + return video_usercopy(inode, file, cmd, arg, dvb_dvr_do_ioctl); } static unsigned int dvb_dvr_poll(struct file *file, poll_table *wait) { - dvb_device_t *dvbdev=(dvb_device_t *) file->private_data; + struct dvb_device *dvbdev=(struct dvb_device *) file->private_data; dmxdev_t *dmxdev=(dmxdev_t *) dvbdev->priv; dprintk ("function : %s\n", __FUNCTION__); @@ -1040,24 +1039,24 @@ } static struct file_operations dvb_dvr_fops = { - owner: THIS_MODULE, - read: dvb_dvr_read, - write: dvb_dvr_write, - ioctl: dvb_dvr_ioctl, - open: dvb_dvr_open, - release: dvb_dvr_release, - poll: dvb_dvr_poll, + .owner = THIS_MODULE, + .read = dvb_dvr_read, + .write = dvb_dvr_write, + .ioctl = dvb_dvr_ioctl, + .open = dvb_dvr_open, + .release = dvb_dvr_release, + .poll =dvb_dvr_poll, }; -static dvb_device_t dvbdev_dvr = { - priv: 0, - users: 1, - writers: 1, - fops: &dvb_dvr_fops +static struct dvb_device dvbdev_dvr = { + .priv = 0, + .users = 1, + .writers = 1, + .fops = &dvb_dvr_fops }; int -DmxDevInit(dmxdev_t *dmxdev, dvb_adapter_t *dvb_adapter) +dvb_dmxdev_init(dmxdev_t *dmxdev, struct dvb_adapter *dvb_adapter) { int i; @@ -1079,22 +1078,22 @@ for (i=0; ifilternum; i++) { dmxdev->filter[i].dev=dmxdev; dmxdev->filter[i].buffer.data=0; - DmxDevFilterStateSet(&dmxdev->filter[i], DMXDEV_STATE_FREE); + dvb_dmxdev_filter_state_set(&dmxdev->filter[i], DMXDEV_STATE_FREE); dmxdev->dvr[i].dev=dmxdev; dmxdev->dvr[i].buffer.data=0; - DmxDevFilterStateSet(&dmxdev->filter[i], DMXDEV_STATE_FREE); - DmxDevDVRStateSet(&dmxdev->dvr[i], DMXDEV_STATE_FREE); + dvb_dmxdev_filter_state_set(&dmxdev->filter[i], DMXDEV_STATE_FREE); + dvb_dmxdev_dvr_state_set(&dmxdev->dvr[i], DMXDEV_STATE_FREE); } dvb_register_device(dvb_adapter, &dmxdev->dvbdev, &dvbdev_demux, dmxdev, DVB_DEVICE_DEMUX); dvb_register_device(dvb_adapter, &dmxdev->dvr_dvbdev, &dvbdev_dvr, dmxdev, DVB_DEVICE_DVR); - DmxDevBufferInit(&dmxdev->dvr_buffer); + dvb_dmxdev_buffer_init(&dmxdev->dvr_buffer); MOD_INC_USE_COUNT; return 0; } void -DmxDevRelease(dmxdev_t *dmxdev) +dvb_dmxdev_release(dmxdev_t *dmxdev) { dvb_unregister_device(dmxdev->dvbdev); dvb_unregister_device(dmxdev->dvr_dvbdev); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/drivers/media/dvb/dvb-core/dmxdev.h linux.2.5.47-ac6/drivers/media/dvb/dvb-core/dmxdev.h --- linux.2.5.47/drivers/media/dvb/dvb-core/dmxdev.h 2002-10-31 15:05:01.000000000 +0000 +++ linux.2.5.47-ac6/drivers/media/dvb/dvb-core/dmxdev.h 2002-11-13 01:26:41.000000000 +0000 @@ -64,7 +64,7 @@ typedef struct dmxdev_filter_s { - dvb_device_t *dvbdev; + struct dvb_device *dvbdev; union { dmx_section_filter_t *sec; @@ -102,8 +102,8 @@ typedef struct dmxdev_s { - dvb_device_t *dvbdev; - dvb_device_t *dvr_dvbdev; + struct dvb_device *dvbdev; + struct dvb_device *dvr_dvbdev; dmxdev_filter_t *filter; dmxdev_dvr_t *dvr; @@ -122,7 +122,7 @@ } dmxdev_t; -int DmxDevInit(dmxdev_t *dmxdev, dvb_adapter_t *); -void DmxDevRelease(dmxdev_t *dmxdev); +int dvb_dmxdev_init(dmxdev_t *dmxdev, struct dvb_adapter *); +void dvb_dmxdev_release(dmxdev_t *dmxdev); #endif /* _DMXDEV_H_ */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/drivers/media/dvb/dvb-core/dvb_demux.c linux.2.5.47-ac6/drivers/media/dvb/dvb-core/dvb_demux.c --- linux.2.5.47/drivers/media/dvb/dvb-core/dvb_demux.c 2002-10-31 15:05:01.000000000 +0000 +++ linux.2.5.47-ac6/drivers/media/dvb/dvb-core/dvb_demux.c 2002-11-13 01:26:41.000000000 +0000 @@ -182,7 +182,7 @@ ******************************************************************************/ static inline int -DvbDmxSWFilterPayload(dvb_demux_feed_t *dvbdmxfeed, const u8 *buf) +dvb_dmx_swfilter_payload(struct dvb_demux_feed *dvbdmxfeed, const u8 *buf) { int p, count; //int ccok; @@ -208,8 +208,8 @@ static int -DvbDmxSWFilterSectionFilter(dvb_demux_feed_t *dvbdmxfeed, - dvb_demux_filter_t *f) +dvb_dmx_swfilter_sectionfilter(struct dvb_demux_feed *dvbdmxfeed, + struct dvb_demux_filter *f) { dmx_section_filter_t *filter=&f->filter; int i; @@ -229,10 +229,10 @@ } static inline int -DvbDmxSWFilterSectionFeed(dvb_demux_feed_t *dvbdmxfeed) +dvb_dmx_swfilter_section_feed(struct dvb_demux_feed *dvbdmxfeed) { u8 *buf=dvbdmxfeed->secbuf; - dvb_demux_filter_t *f; + struct dvb_demux_filter *f; if (dvbdmxfeed->secbufp!=dvbdmxfeed->seclen) return -1; @@ -241,7 +241,7 @@ if (!(f=dvbdmxfeed->filter)) return 0; do - if (DvbDmxSWFilterSectionFilter(dvbdmxfeed, f)<0) + if (dvb_dmx_swfilter_sectionfilter(dvbdmxfeed, f)<0) return -1; while ((f=f->next) && dvbdmxfeed->feed.sec.is_filtering); @@ -251,7 +251,7 @@ } static inline int -DvbDmxSWFilterSectionPacket(dvb_demux_feed_t *dvbdmxfeed, const u8 *buf) +dvb_dmx_swfilter_section_packet(struct dvb_demux_feed *dvbdmxfeed, const u8 *buf) { int p, count; int ccok, rest; @@ -286,7 +286,7 @@ memcpy(dvbdmxfeed->secbuf+dvbdmxfeed->secbufp, buf+p+1, buf[p]); dvbdmxfeed->secbufp+=buf[p]; - DvbDmxSWFilterSectionFeed(dvbdmxfeed); + dvb_dmx_swfilter_section_feed(dvbdmxfeed); } } p+=buf[p]+1; // skip rest of last section @@ -301,7 +301,7 @@ dvbdmxfeed->secbufp=dvbdmxfeed->seclen; p+=dvbdmxfeed->seclen; count=188-p; - DvbDmxSWFilterSectionFeed(dvbdmxfeed); + dvb_dmx_swfilter_section_feed(dvbdmxfeed); // filling bytes until packet end? if (count && buf[p]==0xff) @@ -337,7 +337,7 @@ if (rest<=count) { // section completed in this TS packet memcpy(dvbdmxfeed->secbuf+dvbdmxfeed->secbufp, buf+p, rest); dvbdmxfeed->secbufp+=rest; - DvbDmxSWFilterSectionFeed(dvbdmxfeed); + dvb_dmx_swfilter_section_feed(dvbdmxfeed); } else { // section continues in following ts packet memcpy(dvbdmxfeed->secbuf+dvbdmxfeed->secbufp, buf+p, count); dvbdmxfeed->secbufp+=count; @@ -346,7 +346,7 @@ } static inline void -DvbDmxSWFilterPacketType(dvb_demux_feed_t *dvbdmxfeed, const u8 *buf) +dvb_dmx_swfilter_packet_type(struct dvb_demux_feed *dvbdmxfeed, const u8 *buf) { switch(dvbdmxfeed->type) { case DMX_TYPE_TS: @@ -354,7 +354,7 @@ break; if (dvbdmxfeed->ts_type & TS_PACKET) { if (dvbdmxfeed->ts_type & TS_PAYLOAD_ONLY) - DvbDmxSWFilterPayload(dvbdmxfeed, buf); + dvb_dmx_swfilter_payload(dvbdmxfeed, buf); else dvbdmxfeed->cb.ts((u8 *)buf, 188, 0, 0, &dvbdmxfeed->feed.ts, DMX_OK); @@ -368,7 +368,7 @@ case DMX_TYPE_SEC: if (!dvbdmxfeed->feed.sec.is_filtering) break; - if (DvbDmxSWFilterSectionPacket(dvbdmxfeed, buf)<0) + if (dvb_dmx_swfilter_section_packet(dvbdmxfeed, buf)<0) dvbdmxfeed->seclen=dvbdmxfeed->secbufp=0; break; @@ -377,27 +377,27 @@ } } -void inline -DvbDmxSWFilterPacket(dvb_demux_t *dvbdmx, const u8 *buf) +void +dvb_dmx_swfilter_packet(struct dvb_demux *dvbdmx, const u8 *buf) { - dvb_demux_feed_t *dvbdmxfeed; + struct dvb_demux_feed *dvbdmxfeed; if (!(dvbdmxfeed=dvbdmx->pid2feed[ts_pid(buf)])) return; - DvbDmxSWFilterPacketType(dvbdmxfeed, buf); + dvb_dmx_swfilter_packet_type(dvbdmxfeed, buf); } void -DvbDmxSWFilterPackets(dvb_demux_t *dvbdmx, const u8 *buf, int count) +dvb_dmx_swfilter_packets(struct dvb_demux *dvbdmx, const u8 *buf, int count) { - dvb_demux_feed_t *dvbdmxfeed; + struct dvb_demux_feed *dvbdmxfeed; spin_lock(&dvbdmx->lock); if ((dvbdmxfeed=dvbdmx->pid2feed[0x2000])) dvbdmxfeed->cb.ts((u8 *)buf, count*188, 0, 0, &dvbdmxfeed->feed.ts, DMX_OK); while (count) { - DvbDmxSWFilterPacket(dvbdmx, buf); + dvb_dmx_swfilter_packet(dvbdmx, buf); count--; buf+=188; } @@ -405,7 +405,7 @@ } static inline void -DvbDmxSWFilter(dvb_demux_t *dvbdmx, const u8 *buf, size_t count) +dvb_dmx_swfilter(struct dvb_demux *dvbdmx, const u8 *buf, size_t count) { int p=0,i, j; @@ -416,7 +416,7 @@ return; } memcpy(&dvbdmx->tsbuf[i], buf, j); - DvbDmxSWFilterPacket(dvbdmx, dvbdmx->tsbuf); + dvb_dmx_swfilter_packet(dvbdmx, dvbdmx->tsbuf); dvbdmx->tsbufp=0; p+=j; } @@ -424,7 +424,7 @@ while (p=188) { - DvbDmxSWFilterPacket(dvbdmx, buf+p); + dvb_dmx_swfilter_packet(dvbdmx, buf+p); p+=188; } else { i=count-p; @@ -444,8 +444,8 @@ ****************************************************************************** ******************************************************************************/ -static dvb_demux_filter_t * -DvbDmxFilterAlloc(dvb_demux_t *dvbdmx) +static struct dvb_demux_filter * +dvb_dmx_filter_alloc(struct dvb_demux *dvbdmx) { int i; @@ -458,8 +458,8 @@ return &dvbdmx->filter[i]; } -static dvb_demux_feed_t * -DvbDmxFeedAlloc(dvb_demux_t *dvbdmx) +static struct dvb_demux_feed * +dvb_dmx_feed_alloc(struct dvb_demux *dvbdmx) { int i; @@ -478,10 +478,10 @@ ******************************************************************************/ static int -dmx_pid_set(u16 pid, dvb_demux_feed_t *dvbdmxfeed) +dmx_pid_set(u16 pid, struct dvb_demux_feed *dvbdmxfeed) { - dvb_demux_t *dvbdmx=dvbdmxfeed->demux; - dvb_demux_feed_t **pid2feed=dvbdmx->pid2feed; + struct dvb_demux *dvbdmx=dvbdmxfeed->demux; + struct dvb_demux_feed **pid2feed=dvbdmx->pid2feed; if (pid>DMX_MAX_PID) return -EINVAL; @@ -510,8 +510,8 @@ struct timespec timeout ) { - dvb_demux_feed_t *dvbdmxfeed=(dvb_demux_feed_t *) feed; - dvb_demux_t *dvbdmx=dvbdmxfeed->demux; + struct dvb_demux_feed *dvbdmxfeed=(struct dvb_demux_feed *) feed; + struct dvb_demux *dvbdmx=dvbdmxfeed->demux; int ret; if (down_interruptible (&dvbdmx->mutex)) @@ -576,8 +576,8 @@ static int dmx_ts_feed_start_filtering(struct dmx_ts_feed_s* feed) { - dvb_demux_feed_t *dvbdmxfeed=(dvb_demux_feed_t *) feed; - dvb_demux_t *dvbdmx=dvbdmxfeed->demux; + struct dvb_demux_feed *dvbdmxfeed=(struct dvb_demux_feed *) feed; + struct dvb_demux *dvbdmx=dvbdmxfeed->demux; int ret; if (down_interruptible (&dvbdmx->mutex)) @@ -608,8 +608,8 @@ static int dmx_ts_feed_stop_filtering(struct dmx_ts_feed_s* feed) { - dvb_demux_feed_t *dvbdmxfeed=(dvb_demux_feed_t *) feed; - dvb_demux_t *dvbdmx=dvbdmxfeed->demux; + struct dvb_demux_feed *dvbdmxfeed=(struct dvb_demux_feed *) feed; + struct dvb_demux *dvbdmx=dvbdmxfeed->demux; int ret; if (down_interruptible (&dvbdmx->mutex)) @@ -637,13 +637,13 @@ dmx_ts_feed_t **feed, dmx_ts_cb callback) { - dvb_demux_t *dvbdmx=(dvb_demux_t *) demux; - dvb_demux_feed_t *dvbdmxfeed; + struct dvb_demux *dvbdmx=(struct dvb_demux *) demux; + struct dvb_demux_feed *dvbdmxfeed; if (down_interruptible (&dvbdmx->mutex)) return -ERESTARTSYS; - if (!(dvbdmxfeed=DvbDmxFeedAlloc(dvbdmx))) { + if (!(dvbdmxfeed=dvb_dmx_feed_alloc(dvbdmx))) { up(&dvbdmx->mutex); return -EBUSY; } @@ -663,7 +663,7 @@ (*feed)->stop_filtering=dmx_ts_feed_stop_filtering; - if (!(dvbdmxfeed->filter=DvbDmxFilterAlloc(dvbdmx))) { + if (!(dvbdmxfeed->filter=dvb_dmx_filter_alloc(dvbdmx))) { dvbdmxfeed->state=DMX_STATE_FREE; up(&dvbdmx->mutex); return -EBUSY; @@ -679,8 +679,8 @@ static int dvbdmx_release_ts_feed(dmx_demux_t *demux, dmx_ts_feed_t *feed) { - dvb_demux_t *dvbdmx=(dvb_demux_t *) demux; - dvb_demux_feed_t *dvbdmxfeed=(dvb_demux_feed_t *) feed; + struct dvb_demux *dvbdmx=(struct dvb_demux *) demux; + struct dvb_demux_feed *dvbdmxfeed=(struct dvb_demux_feed *) feed; if (down_interruptible (&dvbdmx->mutex)) return -ERESTARTSYS; @@ -715,14 +715,14 @@ dmx_section_feed_allocate_filter(struct dmx_section_feed_s* feed, dmx_section_filter_t** filter) { - dvb_demux_feed_t *dvbdmxfeed=(dvb_demux_feed_t *) feed; - dvb_demux_t *dvbdemux=dvbdmxfeed->demux; - dvb_demux_filter_t *dvbdmxfilter; + struct dvb_demux_feed *dvbdmxfeed=(struct dvb_demux_feed *) feed; + struct dvb_demux *dvbdemux=dvbdmxfeed->demux; + struct dvb_demux_filter *dvbdmxfilter; if (down_interruptible (&dvbdemux->mutex)) return -ERESTARTSYS; - dvbdmxfilter=DvbDmxFilterAlloc(dvbdemux); + dvbdmxfilter=dvb_dmx_filter_alloc(dvbdemux); if (!dvbdmxfilter) { up(&dvbdemux->mutex); return -ENOSPC; @@ -747,8 +747,8 @@ u16 pid, size_t circular_buffer_size, int descramble, int check_crc) { - dvb_demux_feed_t *dvbdmxfeed=(dvb_demux_feed_t *) feed; - dvb_demux_t *dvbdmx=dvbdmxfeed->demux; + struct dvb_demux_feed *dvbdmxfeed=(struct dvb_demux_feed *) feed; + struct dvb_demux *dvbdmx=dvbdmxfeed->demux; if (pid>0x1fff) return -EINVAL; @@ -789,11 +789,11 @@ return 0; } -static void prepare_secfilters(dvb_demux_feed_t *dvbdmxfeed) +static void prepare_secfilters(struct dvb_demux_feed *dvbdmxfeed) { int i; dmx_section_filter_t *sf; - dvb_demux_filter_t *f; + struct dvb_demux_filter *f; u8 mask, mode, doneq; if (!(f=dvbdmxfeed->filter)) @@ -815,8 +815,8 @@ static int dmx_section_feed_start_filtering(dmx_section_feed_t *feed) { - dvb_demux_feed_t *dvbdmxfeed=(dvb_demux_feed_t *) feed; - dvb_demux_t *dvbdmx=dvbdmxfeed->demux; + struct dvb_demux_feed *dvbdmxfeed=(struct dvb_demux_feed *) feed; + struct dvb_demux *dvbdmx=dvbdmxfeed->demux; int ret; if (down_interruptible (&dvbdmx->mutex)) @@ -854,8 +854,8 @@ static int dmx_section_feed_stop_filtering(struct dmx_section_feed_s* feed) { - dvb_demux_feed_t *dvbdmxfeed=(dvb_demux_feed_t *) feed; - dvb_demux_t *dvbdmx=dvbdmxfeed->demux; + struct dvb_demux_feed *dvbdmxfeed=(struct dvb_demux_feed *) feed; + struct dvb_demux *dvbdmx=dvbdmxfeed->demux; int ret; if (down_interruptible (&dvbdmx->mutex)) @@ -878,9 +878,9 @@ dmx_section_feed_release_filter(dmx_section_feed_t *feed, dmx_section_filter_t* filter) { - dvb_demux_filter_t *dvbdmxfilter=(dvb_demux_filter_t *) filter, *f; - dvb_demux_feed_t *dvbdmxfeed=(dvb_demux_feed_t *) feed; - dvb_demux_t *dvbdmx=dvbdmxfeed->demux; + struct dvb_demux_filter *dvbdmxfilter=(struct dvb_demux_filter *) filter, *f; + struct dvb_demux_feed *dvbdmxfeed=(struct dvb_demux_feed *) feed; + struct dvb_demux *dvbdmx=dvbdmxfeed->demux; if (down_interruptible (&dvbdmx->mutex)) return -ERESTARTSYS; @@ -911,13 +911,13 @@ dmx_section_feed_t **feed, dmx_section_cb callback) { - dvb_demux_t *dvbdmx=(dvb_demux_t *) demux; - dvb_demux_feed_t *dvbdmxfeed; + struct dvb_demux *dvbdmx=(struct dvb_demux *) demux; + struct dvb_demux_feed *dvbdmxfeed; if (down_interruptible (&dvbdmx->mutex)) return -ERESTARTSYS; - if (!(dvbdmxfeed=DvbDmxFeedAlloc(dvbdmx))) { + if (!(dvbdmxfeed=dvb_dmx_feed_alloc(dvbdmx))) { up(&dvbdmx->mutex); return -EBUSY; } @@ -946,8 +946,8 @@ static int dvbdmx_release_section_feed(dmx_demux_t *demux, dmx_section_feed_t *feed) { - dvb_demux_feed_t *dvbdmxfeed=(dvb_demux_feed_t *) feed; - dvb_demux_t *dvbdmx=(dvb_demux_t *) demux; + struct dvb_demux_feed *dvbdmxfeed=(struct dvb_demux_feed *) feed; + struct dvb_demux *dvbdmx=(struct dvb_demux *) demux; if (down_interruptible (&dvbdmx->mutex)) return -ERESTARTSYS; @@ -977,7 +977,7 @@ static int dvbdmx_open(dmx_demux_t *demux) { - dvb_demux_t *dvbdemux=(dvb_demux_t *) demux; + struct dvb_demux *dvbdemux=(struct dvb_demux *) demux; if (dvbdemux->users>=MAX_DVB_DEMUX_USERS) return -EUSERS; @@ -987,7 +987,7 @@ static int dvbdmx_close(struct dmx_demux_s *demux) { - dvb_demux_t *dvbdemux=(dvb_demux_t *) demux; + struct dvb_demux *dvbdemux=(struct dvb_demux *) demux; if (dvbdemux->users==0) return -ENODEV; @@ -998,7 +998,7 @@ static int dvbdmx_write(dmx_demux_t *demux, const char *buf, size_t count) { - dvb_demux_t *dvbdemux=(dvb_demux_t *) demux; + struct dvb_demux *dvbdemux=(struct dvb_demux *) demux; if ((!demux->frontend) || (demux->frontend->source!=DMX_MEMORY_FE)) @@ -1007,7 +1007,7 @@ if (down_interruptible (&dvbdemux->mutex)) return -ERESTARTSYS; - DvbDmxSWFilter(dvbdemux, buf, count); + dvb_dmx_swfilter(dvbdemux, buf, count); up(&dvbdemux->mutex); return count; } @@ -1016,7 +1016,7 @@ static int dvbdmx_add_frontend(dmx_demux_t *demux, dmx_frontend_t *frontend) { - dvb_demux_t *dvbdemux=(dvb_demux_t *) demux; + struct dvb_demux *dvbdemux=(struct dvb_demux *) demux; struct list_head *pos, *head=&dvbdemux->frontend_list; if (!(frontend->id && frontend->vendor && frontend->model)) @@ -1035,7 +1035,7 @@ dvbdmx_remove_frontend(dmx_demux_t *demux, dmx_frontend_t *frontend) { - dvb_demux_t *dvbdemux=(dvb_demux_t *) demux; + struct dvb_demux *dvbdemux=(struct dvb_demux *) demux; struct list_head *pos, *n, *head=&dvbdemux->frontend_list; list_for_each_safe (pos, n, head) @@ -1052,7 +1052,7 @@ static struct list_head * dvbdmx_get_frontends(dmx_demux_t *demux) { - dvb_demux_t *dvbdemux=(dvb_demux_t *) demux; + struct dvb_demux *dvbdemux=(struct dvb_demux *) demux; if (list_empty(&dvbdemux->frontend_list)) return NULL; @@ -1062,7 +1062,7 @@ static int dvbdmx_connect_frontend(dmx_demux_t *demux, dmx_frontend_t *frontend) { - dvb_demux_t *dvbdemux=(dvb_demux_t *) demux; + struct dvb_demux *dvbdemux=(struct dvb_demux *) demux; if (demux->frontend) return -EINVAL; @@ -1077,7 +1077,7 @@ static int dvbdmx_disconnect_frontend(dmx_demux_t *demux) { - dvb_demux_t *dvbdemux=(dvb_demux_t *) demux; + struct dvb_demux *dvbdemux=(struct dvb_demux *) demux; if (down_interruptible (&dvbdemux->mutex)) return -ERESTARTSYS; @@ -1089,24 +1089,24 @@ static int dvbdmx_get_pes_pids(dmx_demux_t *demux, u16 *pids) { - dvb_demux_t *dvbdemux=(dvb_demux_t *) demux; + struct dvb_demux *dvbdemux=(struct dvb_demux *) demux; memcpy(pids, dvbdemux->pids, 5*sizeof(u16)); return 0; } int -DvbDmxInit(dvb_demux_t *dvbdemux) +dvb_dmx_init(struct dvb_demux *dvbdemux) { int i; dmx_demux_t *dmx=&dvbdemux->dmx; dvbdemux->users=0; - dvbdemux->filter=vmalloc(dvbdemux->filternum*sizeof(dvb_demux_filter_t)); + dvbdemux->filter=vmalloc(dvbdemux->filternum*sizeof(struct dvb_demux_filter)); if (!dvbdemux->filter) return -ENOMEM; - dvbdemux->feed=vmalloc(dvbdemux->feednum*sizeof(dvb_demux_feed_t)); + dvbdemux->feed=vmalloc(dvbdemux->feednum*sizeof(struct dvb_demux_feed)); if (!dvbdemux->feed) { vfree(dvbdemux->filter); return -ENOMEM; @@ -1125,7 +1125,7 @@ dvbdemux->pids[i]=0xffff; } dvbdemux->playing=dvbdemux->recording=0; - memset(dvbdemux->pid2feed, 0, (DMX_MAX_PID+1)*sizeof(dvb_demux_feed_t *)); + memset(dvbdemux->pid2feed, 0, (DMX_MAX_PID+1)*sizeof(struct dvb_demux_feed *)); dvbdemux->tsbufp=0; dmx->frontend=0; @@ -1159,7 +1159,7 @@ } int -DvbDmxRelease(dvb_demux_t *dvbdemux) +dvb_dmx_release(struct dvb_demux *dvbdemux) { dmx_demux_t *dmx=&dvbdemux->dmx; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/drivers/media/dvb/dvb-core/dvb_demux.h linux.2.5.47-ac6/drivers/media/dvb/dvb-core/dvb_demux.h --- linux.2.5.47/drivers/media/dvb/dvb-core/dvb_demux.h 2002-10-31 15:05:01.000000000 +0000 +++ linux.2.5.47-ac6/drivers/media/dvb/dvb-core/dvb_demux.h 2002-11-13 01:26:41.000000000 +0000 @@ -39,14 +39,14 @@ #define DVB_DEMUX_MASK_MAX 18 -typedef struct dvb_demux_filter_s { +struct dvb_demux_filter { dmx_section_filter_t filter; u8 maskandmode [DMX_MAX_FILTER_SIZE]; u8 maskandnotmode [DMX_MAX_FILTER_SIZE]; int doneq; - struct dvb_demux_filter_s *next; - struct dvb_demux_feed_s *feed; + struct dvb_demux_filter *next; + struct dvb_demux_feed *feed; int index; int state; int type; @@ -56,11 +56,10 @@ u16 hw_handle; struct timer_list timer; int ts_state; +}; - //u16 pid; //to be removed -} dvb_demux_filter_t; -typedef struct dvb_demux_feed_s { +struct dvb_demux_feed { union { dmx_ts_feed_t ts; dmx_section_feed_t sec; @@ -71,7 +70,7 @@ dmx_section_cb sec; } cb; - struct dvb_demux_s *demux; + struct dvb_demux *demux; int type; int state; u16 pid; @@ -81,7 +80,7 @@ int check_crc; struct timespec timeout; - dvb_demux_filter_t *filter; + struct dvb_demux_filter *filter; int cb_length; int ts_type; @@ -93,42 +92,43 @@ int cc; u16 peslen; -} dvb_demux_feed_t; +}; -typedef struct dvb_demux_s { +struct dvb_demux { dmx_demux_t dmx; void *priv; int filternum; int feednum; - int (*start_feed)(dvb_demux_feed_t *); - int (*stop_feed)(dvb_demux_feed_t *); - int (*write_to_decoder)(dvb_demux_feed_t *, u8 *, size_t); + int (*start_feed)(struct dvb_demux_feed *); + int (*stop_feed)(struct dvb_demux_feed *); + int (*write_to_decoder)(struct dvb_demux_feed *, u8 *, size_t); int users; #define MAX_DVB_DEMUX_USERS 10 - dvb_demux_filter_t *filter; - dvb_demux_feed_t *feed; + struct dvb_demux_filter *filter; + struct dvb_demux_feed *feed; struct list_head frontend_list; - dvb_demux_feed_t *pesfilter[DMX_TS_PES_OTHER]; + struct dvb_demux_feed *pesfilter[DMX_TS_PES_OTHER]; u16 pids[DMX_TS_PES_OTHER]; int playing; int recording; #define DMX_MAX_PID 0x2000 - dvb_demux_feed_t *pid2feed[DMX_MAX_PID+1]; + struct dvb_demux_feed *pid2feed[DMX_MAX_PID+1]; u8 tsbuf[188]; int tsbufp; struct semaphore mutex; spinlock_t lock; -} dvb_demux_t; +}; -int DvbDmxInit(dvb_demux_t *dvbdemux); -int DvbDmxRelease(dvb_demux_t *dvbdemux); -void DvbDmxSWFilterPackets(dvb_demux_t *dvbdmx, const u8 *buf, int count); +int dvb_dmx_init(struct dvb_demux *dvbdemux); +int dvb_dmx_release(struct dvb_demux *dvbdemux); +void dvb_dmx_swfilter_packet(struct dvb_demux *dvbdmx, const u8 *buf); +void dvb_dmx_swfilter_packets(struct dvb_demux *dvbdmx, const u8 *buf, int count); #endif /* _DVB_DEMUX_H_ */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/drivers/media/dvb/dvb-core/dvbdev.c linux.2.5.47-ac6/drivers/media/dvb/dvb-core/dvbdev.c --- linux.2.5.47/drivers/media/dvb/dvb-core/dvbdev.c 2002-10-31 15:05:01.000000000 +0000 +++ linux.2.5.47-ac6/drivers/media/dvb/dvb-core/dvbdev.c 2002-11-13 01:26:41.000000000 +0000 @@ -37,6 +37,7 @@ #include #include #include +#include #include "compat.h" #include "dvbdev.h" @@ -69,17 +70,17 @@ static -dvb_device_t* dvbdev_find_device (int minor) +struct dvb_device* dvbdev_find_device (int minor) { struct list_head *entry; list_for_each (entry, &dvb_adapter_list) { struct list_head *entry0; - dvb_adapter_t *adap; - adap = list_entry (entry, dvb_adapter_t, list_head); + struct dvb_adapter *adap; + adap = list_entry (entry, struct dvb_adapter, list_head); list_for_each (entry0, &adap->device_list) { - dvb_device_t *dev; - dev = list_entry (entry0, dvb_device_t, list_head); + struct dvb_device *dev; + dev = list_entry (entry0, struct dvb_device, list_head); if (nums2minor(adap->num, dev->type, dev->id) == minor) return dev; } @@ -92,7 +93,7 @@ static int dvb_device_open(struct inode *inode, struct file *file) { - dvb_device_t *dvbdev; + struct dvb_device *dvbdev; dvbdev = dvbdev_find_device (minor(inode->i_rdev)); @@ -118,13 +119,8 @@ static struct file_operations dvb_device_fops = { - owner: THIS_MODULE, - read: NULL, - write: NULL, - ioctl: NULL, - open: dvb_device_open, - release: NULL, - poll: NULL, + .owner = THIS_MODULE, + .open = dvb_device_open, }; #endif /* CONFIG_DVB_DEVFS_ONLY */ @@ -132,7 +128,7 @@ int dvb_generic_open(struct inode *inode, struct file *file) { - dvb_device_t *dvbdev = file->private_data; + struct dvb_device *dvbdev = file->private_data; if (!dvbdev) return -ENODEV; @@ -153,7 +149,7 @@ int dvb_generic_release(struct inode *inode, struct file *file) { - dvb_device_t *dvbdev = file->private_data; + struct dvb_device *dvbdev = file->private_data; if (!dvbdev) return -ENODEV; @@ -166,73 +162,10 @@ } -/* - * helper function -- handles userspace copying for ioctl arguments - */ -int -generic_usercopy(struct inode *inode, struct file *file, - unsigned int cmd, unsigned long arg, - int (*func)(struct inode *inode, struct file *file, - unsigned int cmd, void *arg)) -{ - char sbuf[128]; - void *mbuf = NULL; - void *parg = NULL; - int err = -EINVAL; - - /* Copy arguments into temp kernel buffer */ - switch (_IOC_DIR(cmd)) { - case _IOC_NONE: - parg = (void *)arg; - break; - case _IOC_READ: /* some v4l ioctls are marked wrong ... */ - case _IOC_WRITE: - case (_IOC_WRITE | _IOC_READ): - if (_IOC_SIZE(cmd) <= sizeof(sbuf)) { - parg = sbuf; - } else { - /* too big to allocate from stack */ - mbuf = kmalloc(_IOC_SIZE(cmd),GFP_KERNEL); - if (NULL == mbuf) - return -ENOMEM; - parg = mbuf; - } - - err = -EFAULT; - if (copy_from_user(parg, (void *)arg, _IOC_SIZE(cmd))) - goto out; - break; - } - - /* call driver */ - if ((err = func(inode, file, cmd, parg)) == -ENOIOCTLCMD) - err = -EINVAL; - - if (err < 0) - goto out; - - /* Copy results into user buffer */ - switch (_IOC_DIR(cmd)) - { - case _IOC_READ: - case (_IOC_WRITE | _IOC_READ): - if (copy_to_user((void *)arg, parg, _IOC_SIZE(cmd))) - err = -EFAULT; - break; - } - -out: - if (mbuf) - kfree(mbuf); - - return err; -} - - int dvb_generic_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { - dvb_device_t *dvbdev = file->private_data; + struct dvb_device *dvbdev = file->private_data; if (!dvbdev) return -ENODEV; @@ -240,20 +173,20 @@ if (!dvbdev->kernel_ioctl) return -EINVAL; - return generic_usercopy (inode, file, cmd, arg, dvbdev->kernel_ioctl); + return video_usercopy (inode, file, cmd, arg, dvbdev->kernel_ioctl); } static -int dvbdev_get_free_id (struct dvb_adapter_s *adap, int type) +int dvbdev_get_free_id (struct dvb_adapter *adap, int type) { u32 id = 0; while (id < DVB_MAX_IDS) { struct list_head *entry; list_for_each (entry, &adap->device_list) { - dvb_device_t *dev; - dev = list_entry (entry, dvb_device_t, list_head); + struct dvb_device *dev; + dev = list_entry (entry, struct dvb_device, list_head); if (dev->type == type && dev->id == id) goto skip; } @@ -265,12 +198,12 @@ } -int dvb_register_device(dvb_adapter_t *adap, dvb_device_t **pdvbdev, - dvb_device_t *template, void *priv, int type) +int dvb_register_device(struct dvb_adapter *adap, struct dvb_device **pdvbdev, + const struct dvb_device *template, void *priv, int type) { u32 id; char name [20]; - dvb_device_t *dvbdev; + struct dvb_device *dvbdev; if (down_interruptible (&dvbdev_register_lock)) return -ERESTARTSYS; @@ -282,7 +215,7 @@ return -ENFILE; } - *pdvbdev = dvbdev = kmalloc(sizeof(dvb_device_t), GFP_KERNEL); + *pdvbdev = dvbdev = kmalloc(sizeof(struct dvb_device), GFP_KERNEL); if (!dvbdev) { up(&dvbdev_register_lock); @@ -291,7 +224,7 @@ up (&dvbdev_register_lock); - memcpy(dvbdev, template, sizeof(dvb_device_t)); + memcpy(dvbdev, template, sizeof(struct dvb_device)); dvbdev->type = type; dvbdev->id = id; dvbdev->adapter = adap; @@ -307,15 +240,15 @@ S_IFCHR | S_IRUSR | S_IWUSR, dvbdev->fops, dvbdev); - dprintk("%s: register adapter%d/%s @ minor: %i (0x%02x) - dvbdev: %p\n", - __FUNCTION__, adap->num, name, nums2minor(adap->num, type, id), - nums2minor(adap->num, type, id), dvbdev); + dprintk("DVB: register adapter%d/%s @ minor: %i (0x%02x)\n", + adap->num, name, nums2minor(adap->num, type, id), + nums2minor(adap->num, type, id)); return 0; } -void dvb_unregister_device(dvb_device_t *dvbdev) +void dvb_unregister_device(struct dvb_device *dvbdev) { if (!dvbdev) return; @@ -334,8 +267,8 @@ while (1) { struct list_head *entry; list_for_each (entry, &dvb_adapter_list) { - dvb_adapter_t *adap; - adap = list_entry (entry, dvb_adapter_t, list_head); + struct dvb_adapter *adap; + adap = list_entry (entry, struct dvb_adapter, list_head); if (adap->num == num) goto skip; } @@ -348,10 +281,10 @@ } -int dvb_register_adapter(dvb_adapter_t **padap, char *name) +int dvb_register_adapter(struct dvb_adapter **padap, char *name) { char dirname[10]; - dvb_adapter_t *adap; + struct dvb_adapter *adap; int num; if (down_interruptible (&dvbdev_register_lock)) @@ -362,17 +295,17 @@ return -ENFILE; } - if (!(*padap = adap = kmalloc(sizeof(dvb_adapter_t), GFP_KERNEL))) { + if (!(*padap = adap = kmalloc(sizeof(struct dvb_adapter), GFP_KERNEL))) { up(&dvbdev_register_lock); return -ENOMEM; } - memset (adap, 0, sizeof(dvb_adapter_t)); + memset (adap, 0, sizeof(struct dvb_adapter)); INIT_LIST_HEAD (&adap->device_list); MOD_INC_USE_COUNT; - printk ("%s: registering new adapter (%s).\n", __FUNCTION__, name); + printk ("DVB: registering new adapter (%s).\n", name); sprintf(dirname, "adapter%d", num); adap->devfs_handle = devfs_mk_dir(dvb_devfs_handle, dirname, NULL); @@ -386,7 +319,7 @@ } -int dvb_unregister_adapter(dvb_adapter_t *adap) +int dvb_unregister_adapter(struct dvb_adapter *adap) { devfs_unregister (adap->devfs_handle); if (down_interruptible (&dvbdev_register_lock)) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/drivers/media/dvb/dvb-core/dvbdev.h linux.2.5.47-ac6/drivers/media/dvb/dvb-core/dvbdev.h --- linux.2.5.47/drivers/media/dvb/dvb-core/dvbdev.h 2002-10-31 15:05:01.000000000 +0000 +++ linux.2.5.47-ac6/drivers/media/dvb/dvb-core/dvbdev.h 2002-11-13 01:26:41.000000000 +0000 @@ -43,49 +43,48 @@ #define DVB_DEVICE_OSD 8 -typedef struct dvb_adapter_s -{ +struct dvb_adapter { int num; devfs_handle_t devfs_handle; struct list_head list_head; struct list_head device_list; -} dvb_adapter_t; +}; -typedef struct dvb_device -{ +struct dvb_device { struct list_head list_head; struct file_operations *fops; devfs_handle_t devfs_handle; - dvb_adapter_t *adapter; + struct dvb_adapter *adapter; int type; u32 id; int users; int writers; - /* don't really need those !? */ + /* don't really need those !? -- FIXME: use video_usercopy */ int (*kernel_ioctl)(struct inode *inode, struct file *file, - unsigned int cmd, void *arg); // FIXME: use generic_usercopy() + unsigned int cmd, void *arg); void *priv; -} dvb_device_t; +}; -int dvb_register_device(dvb_adapter_t *adap, dvb_device_t **pdvbdev, - dvb_device_t *template, void *priv, int type); -void dvb_unregister_device(struct dvb_device *dvbdev); +extern int dvb_register_adapter (struct dvb_adapter **padap, char *name); +extern int dvb_unregister_adapter (struct dvb_adapter *adap); -int dvb_register_adapter(dvb_adapter_t **padap, char *name); -int dvb_unregister_adapter(dvb_adapter_t *adap); +extern int dvb_register_device (struct dvb_adapter *adap, + struct dvb_device **pdvbdev, + const struct dvb_device *template, + void *priv, + int type); -int dvb_generic_ioctl(struct inode *inode, struct file *file, +extern void dvb_unregister_device (struct dvb_device *dvbdev); + +extern int dvb_generic_open (struct inode *inode, struct file *file); +extern int dvb_generic_release (struct inode *inode, struct file *file); +extern int dvb_generic_ioctl (struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg); -int dvb_generic_open(struct inode *inode, struct file *file); -int dvb_generic_release(struct inode *inode, struct file *file); -int generic_usercopy(struct inode *inode, struct file *file, - unsigned int cmd, unsigned long arg, - int (*func)(struct inode *inode, struct file *file, - unsigned int cmd, void *arg)); -#endif /* #ifndef __DVBDEV_H */ +#endif /* #ifndef _DVBDEV_H_ */ + diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/drivers/media/dvb/dvb-core/dvb_filter.c linux.2.5.47-ac6/drivers/media/dvb/dvb-core/dvb_filter.c --- linux.2.5.47/drivers/media/dvb/dvb-core/dvb_filter.c 2002-10-31 15:05:01.000000000 +0000 +++ linux.2.5.47-ac6/drivers/media/dvb/dvb-core/dvb_filter.c 2002-11-13 01:26:41.000000000 +0000 @@ -24,939 +24,978 @@ -void pes2ts_init(pes2ts_t *p2ts, unsigned short pid, - pes2ts_cb_t *cb, void *priv) +#if 0 +static +void setup_ts2pes(ipack *pa, ipack *pv, u16 *pida, u16 *pidv, + void (*pes_write)(u8 *buf, int count, void *data), + void *priv) { - unsigned char *buf=p2ts->buf; - - buf[0]=0x47; - buf[1]=(pid>>8); - buf[2]=pid&0xff; - p2ts->cc=0; - p2ts->cb=cb; - p2ts->priv=priv; + dvb_filter_ipack_init(pa, IPACKS, pes_write); + dvb_filter_ipack_init(pv, IPACKS, pes_write); + pa->pid = pida; + pv->pid = pidv; + pa->data = priv; + pv->data = priv; } +#endif -int pes2ts(pes2ts_t *p2ts, unsigned char *pes, int len) +#if 0 +static +void ts_to_pes(ipack *p, u8 *buf) // don't need count (=188) { - unsigned char *buf=p2ts->buf; - int ret=0, rest; - - //len=6+((pes[4]<<8)|pes[5]); + u8 off = 0; - buf[1]|=0x40; - while (len>=184) { - buf[3]=0x10|((p2ts->cc++)&0x0f); - memcpy(buf+4, pes, 184); - if ((ret=p2ts->cb(p2ts->priv, buf))) - return ret; - len-=184; pes+=184; - buf[1]&=~0x40; - } - if (!len) - return 0; - buf[3]=0x30|((p2ts->cc++)&0x0f); - rest=183-len; - if (rest) { - buf[5]=0x00; - if (rest-1) - memset(buf+6, 0xff, rest-1); + if (!buf || !p ){ + printk("NULL POINTER IDIOT\n"); + return; } - buf[4]=rest; - memcpy(buf+5+rest, pes, len); - return p2ts->cb(p2ts->priv, buf); -} - -void reset_ipack(ipack *p) -{ + if (buf[1]&PAY_START) { + if (p->plength == MMAX_PLENGTH-6 && p->found>6){ + p->plength = p->found-6; p->found = 0; - p->cid = 0; - p->plength = 0; - p->flag1 = 0; - p->flag2 = 0; - p->hlength = 0; - p->mpeg = 0; - p->check = 0; - p->which = 0; - p->done = 0; - p->count = 0; -} - -void init_ipack(ipack *p, int size, - void (*func)(u8 *buf, int size, void *priv)) -{ - if ( !(p->buf = vmalloc(size*sizeof(u8))) ){ - printk ("Couldn't allocate memory for ipack\n"); + send_ipack(p); + dvb_filter_ipack_reset(p); } - p->size = size; - p->func = func; - p->repack_subids = 0; - reset_ipack(p); -} - -void free_ipack(ipack * p) -{ - if (p->buf) vfree(p->buf); + } + if (buf[3] & ADAPT_FIELD) { // adaptation field? + off = buf[4] + 1; + if (off+4 > 187) return; + } + dvb_filter_instant_repack(buf+4+off, TS_SIZE-4-off, p); } +#endif -void send_ipack(ipack *p) +#if 0 +/* needs 5 byte input, returns picture coding type*/ +static +int read_picture_header(uint8_t *headr, mpg_picture *pic, int field, int pr) { - int off; - AudioInfo ai; - int ac3_off = 0; - int streamid=0; - int nframes= 0; - int f=0; - - switch ( p->mpeg ){ - case 2: - if (p->count < 10) return; - p->buf[3] = p->cid; - - p->buf[4] = (u8)(((p->count-6) & 0xFF00) >> 8); - p->buf[5] = (u8)((p->count-6) & 0x00FF); - if (p->repack_subids && p->cid == PRIVATE_STREAM1){ + uint8_t pct; - off = 9+p->buf[8]; - streamid = p->buf[off]; - if ((streamid & 0xF8) == 0x80){ - ai.off = 0; - ac3_off = ((p->buf[off+2] << 8)| - p->buf[off+3]); - if (ac3_off < p->count) - f=get_ac3info(p->buf+off+3+ac3_off, - p->count-ac3_off, &ai,0); - if ( !f ){ - nframes = (p->count-off-3-ac3_off)/ - ai.framesize + 1; - p->buf[off+2] = (ac3_off >> 8)& 0xFF; - p->buf[off+3] = (ac3_off)& 0xFF; - p->buf[off+1] = nframes; + if (pr) printk( "Pic header: "); + pic->temporal_reference[field] = (( headr[0] << 2 ) | + (headr[1] & 0x03) )& 0x03ff; + if (pr) printk( " temp ref: 0x%04x", pic->temporal_reference[field]); - ac3_off += nframes * ai.framesize - - p->count; - } + pct = ( headr[1] >> 2 ) & 0x07; + pic->picture_coding_type[field] = pct; + if (pr) { + switch(pct){ + case I_FRAME: + printk( " I-FRAME"); + break; + case B_FRAME: + printk( " B-FRAME"); + break; + case P_FRAME: + printk( " P-FRAME"); + break; } } - p->func(p->buf, p->count, p->data); - p->buf[6] = 0x80; - p->buf[7] = 0x00; - p->buf[8] = 0x00; - p->count = 9; - if (p->repack_subids && p->cid == PRIVATE_STREAM1 - && (streamid & 0xF8)==0x80 ){ - p->count += 4; - p->buf[9] = streamid; - p->buf[10] = (ac3_off >> 8)& 0xFF; - p->buf[11] = (ac3_off)& 0xFF; - p->buf[12] = 0; - } - break; - case 1: - if (p->count < 8) return; - p->buf[3] = p->cid; + pic->vinfo.vbv_delay = (( headr[1] >> 5 ) | ( headr[2] << 3) | + ( (headr[3] & 0x1F) << 11) ) & 0xffff; - p->buf[4] = (u8)(((p->count-6) & 0xFF00) >> 8); - p->buf[5] = (u8)((p->count-6) & 0x00FF); - p->func(p->buf, p->count, p->data); + if (pr) printk( " vbv delay: 0x%04x", pic->vinfo.vbv_delay); - p->buf[6] = 0x0F; - p->count = 7; - break; + pic->picture_header_parameter = ( headr[3] & 0xe0 ) | + ((headr[4] & 0x80) >> 3); + + if ( pct == B_FRAME ){ + pic->picture_header_parameter |= ( headr[4] >> 3 ) & 0x0f; } -} + if (pr) printk( " pic head param: 0x%x", + pic->picture_header_parameter); -void send_ipack_rest(ipack *p) -{ - if (p->plength != MMAX_PLENGTH-6 || p->found<=6) - return; - p->plength = p->found-6; - p->found = 0; - send_ipack(p); - reset_ipack(p); + return pct; } +#endif -static void write_ipack(ipack *p, u8 *data, int count) +#if 0 +/* needs 4 byte input */ +static +int read_gop_header(uint8_t *headr, mpg_picture *pic, int pr) { - u8 headr[3] = { 0x00, 0x00, 0x01} ; + if (pr) printk("GOP header: "); - if (p->count < 6){ - memcpy(p->buf, headr, 3); - p->count = 6; + pic->time_code = (( headr[0] << 17 ) | ( headr[1] << 9) | + ( headr[2] << 1 ) | (headr[3] &0x01)) & 0x1ffffff; + + if (pr) printk(" time: %d:%d.%d ", (headr[0]>>2)& 0x1F, + ((headr[0]<<4)& 0x30)| ((headr[1]>>4)& 0x0F), + ((headr[1]<<3)& 0x38)| ((headr[2]>>5)& 0x0F)); + + if ( ( headr[3] & 0x40 ) != 0 ){ + pic->closed_gop = 1; + } else { + pic->closed_gop = 0; } + if (pr) printk("closed: %d", pic->closed_gop); - if (p->count + count < p->size){ - memcpy(p->buf+p->count, data, count); - p->count += count; + if ( ( headr[3] & 0x20 ) != 0 ){ + pic->broken_link = 1; } else { - int rest = p->size - p->count; - memcpy(p->buf+p->count, data, rest); - p->count += rest; - send_ipack(p); - if (count - rest > 0) - write_ipack(p, data+rest, count-rest); + pic->broken_link = 0; } + if (pr) printk(" broken: %d\n", pic->broken_link); + + return 0; } +#endif -int instant_repack(u8 *buf, int count, ipack *p) +#if 0 +/* needs 8 byte input */ +static +int read_sequence_header(uint8_t *headr, VideoInfo *vi, int pr) { - int l; - int c=0; + int sw; + int form = -1; - while (c < count && (p->mpeg == 0 || - (p->mpeg == 1 && p->found < 7) || - (p->mpeg == 2 && p->found < 9)) - && (p->found < 5 || !p->done)){ - switch ( p->found ){ - case 0: + if (pr) printk("Reading sequence header\n"); + + vi->horizontal_size = ((headr[1] &0xF0) >> 4) | (headr[0] << 4); + vi->vertical_size = ((headr[1] &0x0F) << 8) | (headr[2]); + + sw = (int)((headr[3]&0xF0) >> 4) ; + + switch( sw ){ case 1: - if (buf[c] == 0x00) p->found++; - else p->found = 0; - c++; + if (pr) + printk("Videostream: ASPECT: 1:1"); + vi->aspect_ratio = 100; break; case 2: - if (buf[c] == 0x01) p->found++; - else if (buf[c] == 0) { - p->found = 2; - } else p->found = 0; - c++; + if (pr) + printk("Videostream: ASPECT: 4:3"); + vi->aspect_ratio = 133; break; case 3: - p->cid = 0; - switch (buf[c]){ - case PROG_STREAM_MAP: - case PRIVATE_STREAM2: - case PROG_STREAM_DIR: - case ECM_STREAM : - case EMM_STREAM : - case PADDING_STREAM : - case DSM_CC_STREAM : - case ISO13522_STREAM: - p->done = 1; - case PRIVATE_STREAM1: - case VIDEO_STREAM_S ... VIDEO_STREAM_E: - case AUDIO_STREAM_S ... AUDIO_STREAM_E: - p->found++; - p->cid = buf[c]; - c++; + if (pr) + printk("Videostream: ASPECT: 16:9"); + vi->aspect_ratio = 177; break; - default: - p->found = 0; + case 4: + if (pr) + printk("Videostream: ASPECT: 2.21:1"); + vi->aspect_ratio = 221; break; - } + + case 5 ... 15: + if (pr) + printk("Videostream: ASPECT: reserved"); + vi->aspect_ratio = 0; break; - case 4: - if (count-c > 1){ - p->plen[0] = buf[c]; - c++; - p->plen[1] = buf[c]; - c++; - p->found+=2; - p->plength=(p->plen[0]<<8)|p->plen[1]; - } else { - p->plen[0] = buf[c]; - p->found++; - return count; + default: + vi->aspect_ratio = 0; + return -1; } + + if (pr) + printk(" Size = %dx%d",vi->horizontal_size,vi->vertical_size); + + sw = (int)(headr[3]&0x0F); + + switch ( sw ) { + case 1: + if (pr) + printk(" FRate: 23.976 fps"); + vi->framerate = 23976; + form = -1; + break; + case 2: + if (pr) + printk(" FRate: 24 fps"); + vi->framerate = 24000; + form = -1; + break; + case 3: + if (pr) + printk(" FRate: 25 fps"); + vi->framerate = 25000; + form = VIDEO_MODE_PAL; + break; + case 4: + if (pr) + printk(" FRate: 29.97 fps"); + vi->framerate = 29970; + form = VIDEO_MODE_NTSC; break; case 5: - p->plen[1] = buf[c]; - c++; - p->found++; - p->plength=(p->plen[0]<<8)|p->plen[1]; + if (pr) + printk(" FRate: 30 fps"); + vi->framerate = 30000; + form = VIDEO_MODE_NTSC; break; case 6: - if (!p->done){ - p->flag1 = buf[c]; - c++; - p->found++; - if ( (p->flag1 & 0xC0) == 0x80 ) p->mpeg = 2; - else { - p->hlength = 0; - p->which = 0; - p->mpeg = 1; - p->flag2 = 0; - } - } + if (pr) + printk(" FRate: 50 fps"); + vi->framerate = 50000; + form = VIDEO_MODE_PAL; break; - case 7: - if ( !p->done && p->mpeg == 2) { - p->flag2 = buf[c]; - c++; - p->found++; - } + if (pr) + printk(" FRate: 60 fps"); + vi->framerate = 60000; + form = VIDEO_MODE_NTSC; break; - - case 8: - if ( !p->done && p->mpeg == 2) { - p->hlength = buf[c]; - c++; - p->found++; } - break; - default: + vi->bit_rate = (headr[4] << 10) | (headr[5] << 2) | (headr[6] & 0x03); - break; - } + vi->vbv_buffer_size + = (( headr[6] & 0xF8) >> 3 ) | (( headr[7] & 0x1F )<< 5); + + if (pr){ + printk(" BRate: %d Mbit/s",4*(vi->bit_rate)/10000); + printk(" vbvbuffer %d",16*1024*(vi->vbv_buffer_size)); + printk("\n"); } - if (c == count) return count; + vi->video_format = form; - if (!p->plength) p->plength = MMAX_PLENGTH-6; + return 0; +} +#endif - if ( p->done || ((p->mpeg == 2 && p->found >= 9) || - (p->mpeg == 1 && p->found >= 7)) ){ - switch (p->cid){ - case AUDIO_STREAM_S ... AUDIO_STREAM_E: - case VIDEO_STREAM_S ... VIDEO_STREAM_E: - case PRIVATE_STREAM1: +#if 0 +static +int get_vinfo(uint8_t *mbuf, int count, VideoInfo *vi, int pr) +{ + uint8_t *headr; + int found = 0; + int c = 0; - if (p->mpeg == 2 && p->found == 9) { - write_ipack(p, &p->flag1, 1); - write_ipack(p, &p->flag2, 1); - write_ipack(p, &p->hlength, 1); + while (found < 4 && c+4 < count){ + uint8_t *b; + + b = mbuf+c; + if ( b[0] == 0x00 && b[1] == 0x00 && b[2] == 0x01 + && b[3] == 0xb3) found = 4; + else { + c++; + } } - if (p->mpeg == 1 && p->found == 7) - write_ipack(p, &p->flag1, 1); + if (! found) return -1; + c += 4; + if (c+12 >= count) return -1; + headr = mbuf+c; + if (read_sequence_header(headr, vi, pr) < 0) return -1; + vi->off = c-4; + return 0; +} +#endif - if (p->mpeg == 2 && (p->flag2 & PTS_ONLY) && - p->found < 14) { - while (c < count && p->found < 14) { - p->pts[p->found-9] = buf[c]; - write_ipack(p, buf+c, 1); + +#if 0 +static +int get_ainfo(uint8_t *mbuf, int count, AudioInfo *ai, int pr) +{ + uint8_t *headr; + int found = 0; + int c = 0; + int fr = 0; + + while (found < 2 && c < count){ + uint8_t b[2]; + memcpy( b, mbuf+c, 2); + + if ( b[0] == 0xff && (b[1] & 0xf8) == 0xf8) + found = 2; + else { c++; - p->found++; } - if (c == count) return count; } - if (p->mpeg == 1 && p->which < 2000) { + if (!found) return -1; - if (p->found == 7) { - p->check = p->flag1; - p->hlength = 1; + if (c+3 >= count) return -1; + headr = mbuf+c; + + ai->layer = (headr[1] & 0x06) >> 1; + + if (pr) + printk("Audiostream: Layer: %d", 4-ai->layer); + + + ai->bit_rate = bitrates[(3-ai->layer)][(headr[2] >> 4 )]*1000; + + if (pr){ + if (ai->bit_rate == 0) + printk(" Bit rate: free"); + else if (ai->bit_rate == 0xf) + printk(" BRate: reserved"); + else + printk(" BRate: %d kb/s", ai->bit_rate/1000); } - while (!p->which && c < count && - p->check == 0xFF){ - p->check = buf[c]; - write_ipack(p, buf+c, 1); - c++; - p->found++; - p->hlength++; + fr = (headr[2] & 0x0c ) >> 2; + ai->frequency = freq[fr]*100; + if (pr){ + if (ai->frequency == 3) + printk(" Freq: reserved\n"); + else + printk(" Freq: %d kHz\n",ai->frequency); + } + ai->off = c; + return 0; +} +#endif - if ( c == count) return count; +static +int get_ac3info(uint8_t *mbuf, int count, AudioInfo *ai, int pr) +{ + uint8_t *headr; + int found = 0; + int c = 0; + uint8_t frame = 0; + int fr = 0; - if ( (p->check & 0xC0) == 0x40 && !p->which){ - p->check = buf[c]; - write_ipack(p, buf+c, 1); - c++; - p->found++; - p->hlength++; + while ( !found && c < count){ + uint8_t *b = mbuf+c; - p->which = 1; - if ( c == count) return count; - p->check = buf[c]; - write_ipack(p, buf+c, 1); + if ( b[0] == 0x0b && b[1] == 0x77 ) + found = 1; + else { c++; - p->found++; - p->hlength++; - p->which = 2; - if ( c == count) return count; } - - if (p->which == 1){ - p->check = buf[c]; - write_ipack(p, buf+c, 1); - c++; - p->found++; - p->hlength++; - p->which = 2; - if ( c == count) return count; } - if ( (p->check & 0x30) && p->check != 0xFF){ - p->flag2 = (p->check & 0xF0) << 2; - p->pts[0] = p->check; - p->which = 3; - } - - if ( c == count) return count; - if (p->which > 2){ - if ((p->flag2 & PTS_DTS_FLAGS) - == PTS_ONLY){ - while (c < count && - p->which < 7){ - p->pts[p->which-2] = - buf[c]; - write_ipack(p,buf+c,1); - c++; - p->found++; - p->which++; - p->hlength++; - } - if ( c == count) return count; - } else if ((p->flag2 & PTS_DTS_FLAGS) - == PTS_DTS){ - while (c < count && - p->which< 12){ - if (p->which< 7) - p->pts[p->which - -2] = - buf[c]; - write_ipack(p,buf+c,1); - c++; - p->found++; - p->which++; - p->hlength++; - } - if ( c == count) return count; - } - p->which = 2000; - } + if (!found) return -1; + if (pr) + printk("Audiostream: AC3"); - } + ai->off = c; + if (c+5 >= count) return -1; - while (c < count && p->found < p->plength+6){ - l = count -c; - if (l+p->found > p->plength+6) - l = p->plength+6-p->found; - write_ipack(p, buf+c, l); - p->found += l; - c += l; - } + ai->layer = 0; // 0 for AC3 + headr = mbuf+c+2; - break; - } + frame = (headr[2]&0x3f); + ai->bit_rate = ac3_bitrates[frame >> 1]*1000; + if (pr) + printk(" BRate: %d kb/s", ai->bit_rate/1000); - if ( p->done ){ - if( p->found + count - c < p->plength+6){ - p->found += count-c; - c = count; - } else { - c += p->plength+6 - p->found; - p->found = p->plength+6; - } - } + ai->frequency = (headr[2] & 0xc0 ) >> 6; + fr = (headr[2] & 0xc0 ) >> 6; + ai->frequency = freq[fr]*100; + if (pr) printk (" Freq: %d Hz\n", ai->frequency); - if (p->plength && p->found == p->plength+6) { - send_ipack(p); - reset_ipack(p); - if (c < count) - instant_repack(buf+c, count-c, p); - } - } - return count; -} + ai->framesize = ac3_frames[fr][frame >> 1]; + if ((frame & 1) && (fr == 1)) ai->framesize++; + ai->framesize = ai->framesize << 1; + if (pr) printk (" Framesize %d\n", ai->framesize); -void setup_ts2pes(ipack *pa, ipack *pv, u16 *pida, u16 *pidv, - void (*pes_write)(u8 *buf, int count, void *data), - void *priv) -{ - init_ipack(pa, IPACKS, pes_write); - init_ipack(pv, IPACKS, pes_write); - pa->pid = pida; - pv->pid = pidv; - pa->data = priv; - pv->data = priv; + return 0; } -void ts_to_pes(ipack *p, u8 *buf) // don't need count (=188) -{ - u8 off = 0; - - if (!buf || !p ){ - printk("NULL POINTER IDIOT\n"); - return; - } - if (buf[1]&PAY_START) { - if (p->plength == MMAX_PLENGTH-6 && p->found>6){ - p->plength = p->found-6; - p->found = 0; - send_ipack(p); - reset_ipack(p); - } - } - if (buf[3] & ADAPT_FIELD) { // adaptation field? - off = buf[4] + 1; - if (off+4 > 187) return; - } - instant_repack(buf+4+off, TS_SIZE-4-off, p); -} -/* needs 5 byte input, returns picture coding type*/ -int read_picture_header(uint8_t *headr, mpg_picture *pic, int field, int pr) +#if 0 +static +uint8_t *skip_pes_header(uint8_t **bufp) { - uint8_t pct; + uint8_t *inbuf = *bufp; + uint8_t *buf = inbuf; + uint8_t *pts = NULL; + int skip = 0; - if (pr) printk( "Pic header: "); - pic->temporal_reference[field] = (( headr[0] << 2 ) | - (headr[1] & 0x03) )& 0x03ff; - if (pr) printk( " temp ref: 0x%04x", pic->temporal_reference[field]); + static const int mpeg1_skip_table[16] = { + 1, 0xffff, 5, 10, 0xffff, 0xffff, 0xffff, 0xffff, + 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff + }; - pct = ( headr[1] >> 2 ) & 0x07; - pic->picture_coding_type[field] = pct; - if (pr) { - switch(pct){ - case I_FRAME: - printk( " I-FRAME"); - break; - case B_FRAME: - printk( " B-FRAME"); - break; - case P_FRAME: - printk( " P-FRAME"); + + if ((inbuf[6] & 0xc0) == 0x80){ /* mpeg2 */ + if (buf[7] & PTS_ONLY) + pts = buf+9; + else pts = NULL; + buf = inbuf + 9 + inbuf[8]; + } else { /* mpeg1 */ + for (buf = inbuf + 6; *buf == 0xff; buf++) + if (buf == inbuf + 6 + 16) { break; } - } - - - pic->vinfo.vbv_delay = (( headr[1] >> 5 ) | ( headr[2] << 3) | - ( (headr[3] & 0x1F) << 11) ) & 0xffff; - - if (pr) printk( " vbv delay: 0x%04x", pic->vinfo.vbv_delay); - - pic->picture_header_parameter = ( headr[3] & 0xe0 ) | - ((headr[4] & 0x80) >> 3); + if ((*buf & 0xc0) == 0x40) + buf += 2; + skip = mpeg1_skip_table [*buf >> 4]; + if (skip == 5 || skip == 10) pts = buf; + else pts = NULL; - if ( pct == B_FRAME ){ - pic->picture_header_parameter |= ( headr[4] >> 3 ) & 0x0f; + buf += mpeg1_skip_table [*buf >> 4]; } - if (pr) printk( " pic head param: 0x%x", - pic->picture_header_parameter); - return pct; + *bufp = buf; + return pts; } +#endif - -/* needs 4 byte input */ -int read_gop_header(uint8_t *headr, mpg_picture *pic, int pr) +#if 0 +static +void initialize_quant_matrix( uint32_t *matrix ) { - if (pr) printk("GOP header: "); + int i; - pic->time_code = (( headr[0] << 17 ) | ( headr[1] << 9) | - ( headr[2] << 1 ) | (headr[3] &0x01)) & 0x1ffffff; + matrix[0] = 0x08101013; + matrix[1] = 0x10131616; + matrix[2] = 0x16161616; + matrix[3] = 0x1a181a1b; + matrix[4] = 0x1b1b1a1a; + matrix[5] = 0x1a1a1b1b; + matrix[6] = 0x1b1d1d1d; + matrix[7] = 0x2222221d; + matrix[8] = 0x1d1d1b1b; + matrix[9] = 0x1d1d2020; + matrix[10] = 0x22222526; + matrix[11] = 0x25232322; + matrix[12] = 0x23262628; + matrix[13] = 0x28283030; + matrix[14] = 0x2e2e3838; + matrix[15] = 0x3a454553; - if (pr) printk(" time: %d:%d.%d ", (headr[0]>>2)& 0x1F, - ((headr[0]<<4)& 0x30)| ((headr[1]>>4)& 0x0F), - ((headr[1]<<3)& 0x38)| ((headr[2]>>5)& 0x0F)); + for ( i = 16 ; i < 32 ; i++ ) + matrix[i] = 0x10101010; +} +#endif - if ( ( headr[3] & 0x40 ) != 0 ){ - pic->closed_gop = 1; - } else { - pic->closed_gop = 0; - } - if (pr) printk("closed: %d", pic->closed_gop); +#if 0 +static +void initialize_mpg_picture(mpg_picture *pic) +{ + int i; - if ( ( headr[3] & 0x20 ) != 0 ){ - pic->broken_link = 1; - } else { - pic->broken_link = 0; + /* set MPEG1 */ + pic->mpeg1_flag = 1; + pic->profile_and_level = 0x4A ; /* MP@LL */ + pic->progressive_sequence = 1; + pic->low_delay = 0; + + pic->sequence_display_extension_flag = 0; + for ( i = 0 ; i < 4 ; i++ ){ + pic->frame_centre_horizontal_offset[i] = 0; + pic->frame_centre_vertical_offset[i] = 0; } - if (pr) printk(" broken: %d\n", pic->broken_link); + pic->last_frame_centre_horizontal_offset = 0; + pic->last_frame_centre_vertical_offset = 0; - return 0; + pic->picture_display_extension_flag[0] = 0; + pic->picture_display_extension_flag[1] = 0; + pic->sequence_header_flag = 0; + pic->gop_flag = 0; + pic->sequence_end_flag = 0; } +#endif -/* needs 8 byte input */ -int read_sequence_header(uint8_t *headr, VideoInfo *vi, int pr) +#if 0 +static +void mpg_set_picture_parameter( int32_t field_type, mpg_picture *pic ) { - int sw; - int form = -1; + int16_t last_h_offset; + int16_t last_v_offset; - if (pr) printk("Reading sequence header\n"); + int16_t *p_h_offset; + int16_t *p_v_offset; - vi->horizontal_size = ((headr[1] &0xF0) >> 4) | (headr[0] << 4); - vi->vertical_size = ((headr[1] &0x0F) << 8) | (headr[2]); + if ( pic->mpeg1_flag ){ + pic->picture_structure[field_type] = VIDEO_FRAME_PICTURE; + pic->top_field_first = 0; + pic->repeat_first_field = 0; + pic->progressive_frame = 1; + pic->picture_coding_parameter = 0x000010; + } - sw = (int)((headr[3]&0xF0) >> 4) ; + /* Reset flag */ + pic->picture_display_extension_flag[field_type] = 0; - switch( sw ){ - case 1: - if (pr) - printk("Videostream: ASPECT: 1:1"); - vi->aspect_ratio = 100; - break; - case 2: - if (pr) - printk("Videostream: ASPECT: 4:3"); - vi->aspect_ratio = 133; - break; - case 3: - if (pr) - printk("Videostream: ASPECT: 16:9"); - vi->aspect_ratio = 177; - break; - case 4: - if (pr) - printk("Videostream: ASPECT: 2.21:1"); - vi->aspect_ratio = 221; - break; - - case 5 ... 15: - if (pr) - printk("Videostream: ASPECT: reserved"); - vi->aspect_ratio = 0; - break; - - default: - vi->aspect_ratio = 0; - return -1; + last_h_offset = pic->last_frame_centre_horizontal_offset; + last_v_offset = pic->last_frame_centre_vertical_offset; + if ( field_type == FIRST_FIELD ){ + p_h_offset = pic->frame_centre_horizontal_offset; + p_v_offset = pic->frame_centre_vertical_offset; + *p_h_offset = last_h_offset; + *(p_h_offset + 1) = last_h_offset; + *(p_h_offset + 2) = last_h_offset; + *p_v_offset = last_v_offset; + *(p_v_offset + 1) = last_v_offset; + *(p_v_offset + 2) = last_v_offset; + } else { + pic->frame_centre_horizontal_offset[3] = last_h_offset; + pic->frame_centre_vertical_offset[3] = last_v_offset; } +} +#endif - if (pr) - printk(" Size = %dx%d",vi->horizontal_size,vi->vertical_size); - - sw = (int)(headr[3]&0x0F); +#if 0 +static +void init_mpg_picture( mpg_picture *pic, int chan, int32_t field_type) +{ + pic->picture_header = 0; + pic->sequence_header_data + = ( INIT_HORIZONTAL_SIZE << 20 ) + | ( INIT_VERTICAL_SIZE << 8 ) + | ( INIT_ASPECT_RATIO << 4 ) + | ( INIT_FRAME_RATE ); + pic->mpeg1_flag = 0; + pic->vinfo.horizontal_size + = INIT_DISP_HORIZONTAL_SIZE; + pic->vinfo.vertical_size + = INIT_DISP_VERTICAL_SIZE; + pic->picture_display_extension_flag[field_type] + = 0; + pic->pts_flag[field_type] = 0; - switch ( sw ) { - case 1: - if (pr) - printk(" FRate: 23.976 fps"); - vi->framerate = 23976; - form = -1; - break; - case 2: - if (pr) - printk(" FRate: 24 fps"); - vi->framerate = 24000; - form = -1; - break; - case 3: - if (pr) - printk(" FRate: 25 fps"); - vi->framerate = 25000; - form = VIDEO_MODE_PAL; - break; - case 4: - if (pr) - printk(" FRate: 29.97 fps"); - vi->framerate = 29970; - form = VIDEO_MODE_NTSC; - break; - case 5: - if (pr) - printk(" FRate: 30 fps"); - vi->framerate = 30000; - form = VIDEO_MODE_NTSC; - break; - case 6: - if (pr) - printk(" FRate: 50 fps"); - vi->framerate = 50000; - form = VIDEO_MODE_PAL; - break; - case 7: - if (pr) - printk(" FRate: 60 fps"); - vi->framerate = 60000; - form = VIDEO_MODE_NTSC; - break; - } + pic->sequence_gop_header = 0; + pic->picture_header = 0; + pic->sequence_header_flag = 0; + pic->gop_flag = 0; + pic->sequence_end_flag = 0; + pic->sequence_display_extension_flag = 0; + pic->last_frame_centre_horizontal_offset = 0; + pic->last_frame_centre_vertical_offset = 0; + pic->channel = chan; +} +#endif - vi->bit_rate = (headr[4] << 10) | (headr[5] << 2) | (headr[6] & 0x03); +void dvb_filter_pes2ts_init(dvb_filter_pes2ts_t *p2ts, unsigned short pid, + dvb_filter_pes2ts_cb_t *cb, void *priv) +{ + unsigned char *buf=p2ts->buf; - vi->vbv_buffer_size - = (( headr[6] & 0xF8) >> 3 ) | (( headr[7] & 0x1F )<< 5); + buf[0]=0x47; + buf[1]=(pid>>8); + buf[2]=pid&0xff; + p2ts->cc=0; + p2ts->cb=cb; + p2ts->priv=priv; +} - if (pr){ - printk(" BRate: %d Mbit/s",4*(vi->bit_rate)/10000); - printk(" vbvbuffer %d",16*1024*(vi->vbv_buffer_size)); - printk("\n"); - } +int dvb_filter_pes2ts(dvb_filter_pes2ts_t *p2ts, unsigned char *pes, int len) +{ + unsigned char *buf=p2ts->buf; + int ret=0, rest; - vi->video_format = form; + //len=6+((pes[4]<<8)|pes[5]); + buf[1]|=0x40; + while (len>=184) { + buf[3]=0x10|((p2ts->cc++)&0x0f); + memcpy(buf+4, pes, 184); + if ((ret=p2ts->cb(p2ts->priv, buf))) + return ret; + len-=184; pes+=184; + buf[1]&=~0x40; + } + if (!len) return 0; + buf[3]=0x30|((p2ts->cc++)&0x0f); + rest=183-len; + if (rest) { + buf[5]=0x00; + if (rest-1) + memset(buf+6, 0xff, rest-1); + } + buf[4]=rest; + memcpy(buf+5+rest, pes, len); + return p2ts->cb(p2ts->priv, buf); } -int get_vinfo(uint8_t *mbuf, int count, VideoInfo *vi, int pr) +void dvb_filter_ipack_reset(ipack *p) { - uint8_t *headr; - int found = 0; - int c = 0; - - while (found < 4 && c+4 < count){ - uint8_t *b; + p->found = 0; + p->cid = 0; + p->plength = 0; + p->flag1 = 0; + p->flag2 = 0; + p->hlength = 0; + p->mpeg = 0; + p->check = 0; + p->which = 0; + p->done = 0; + p->count = 0; +} - b = mbuf+c; - if ( b[0] == 0x00 && b[1] == 0x00 && b[2] == 0x01 - && b[3] == 0xb3) found = 4; - else { - c++; - } +void dvb_filter_ipack_init(ipack *p, int size, + void (*func)(u8 *buf, int size, void *priv)) +{ + if ( !(p->buf = vmalloc(size*sizeof(u8))) ){ + printk ("Couldn't allocate memory for ipack\n"); } + p->size = size; + p->func = func; + p->repack_subids = 0; + dvb_filter_ipack_reset(p); +} - if (! found) return -1; - c += 4; - if (c+12 >= count) return -1; - headr = mbuf+c; - if (read_sequence_header(headr, vi, pr) < 0) return -1; - vi->off = c-4; - return 0; +void dvb_filter_ipack_free(ipack * p) +{ + if (p->buf) vfree(p->buf); } -int get_ainfo(uint8_t *mbuf, int count, AudioInfo *ai, int pr) +static +void send_ipack(ipack *p) { - uint8_t *headr; - int found = 0; - int c = 0; - int fr = 0; + int off; + AudioInfo ai; + int ac3_off = 0; + int streamid=0; + int nframes= 0; + int f=0; - while (found < 2 && c < count){ - uint8_t b[2]; - memcpy( b, mbuf+c, 2); + switch ( p->mpeg ){ + case 2: + if (p->count < 10) return; + p->buf[3] = p->cid; - if ( b[0] == 0xff && (b[1] & 0xf8) == 0xf8) - found = 2; - else { - c++; + p->buf[4] = (u8)(((p->count-6) & 0xFF00) >> 8); + p->buf[5] = (u8)((p->count-6) & 0x00FF); + if (p->repack_subids && p->cid == PRIVATE_STREAM1){ + + off = 9+p->buf[8]; + streamid = p->buf[off]; + if ((streamid & 0xF8) == 0x80){ + ai.off = 0; + ac3_off = ((p->buf[off+2] << 8)| + p->buf[off+3]); + if (ac3_off < p->count) + f=get_ac3info(p->buf+off+3+ac3_off, + p->count-ac3_off, &ai,0); + if ( !f ){ + nframes = (p->count-off-3-ac3_off)/ + ai.framesize + 1; + p->buf[off+2] = (ac3_off >> 8)& 0xFF; + p->buf[off+3] = (ac3_off)& 0xFF; + p->buf[off+1] = nframes; + + ac3_off += nframes * ai.framesize - + p->count; + } } } + p->func(p->buf, p->count, p->data); - if (!found) return -1; + p->buf[6] = 0x80; + p->buf[7] = 0x00; + p->buf[8] = 0x00; + p->count = 9; + if (p->repack_subids && p->cid == PRIVATE_STREAM1 + && (streamid & 0xF8)==0x80 ){ + p->count += 4; + p->buf[9] = streamid; + p->buf[10] = (ac3_off >> 8)& 0xFF; + p->buf[11] = (ac3_off)& 0xFF; + p->buf[12] = 0; + } - if (c+3 >= count) return -1; - headr = mbuf+c; + break; + case 1: + if (p->count < 8) return; + p->buf[3] = p->cid; - ai->layer = (headr[1] & 0x06) >> 1; + p->buf[4] = (u8)(((p->count-6) & 0xFF00) >> 8); + p->buf[5] = (u8)((p->count-6) & 0x00FF); + p->func(p->buf, p->count, p->data); - if (pr) - printk("Audiostream: Layer: %d", 4-ai->layer); + p->buf[6] = 0x0F; + p->count = 7; + break; + } +} +void dvb_filter_ipack_flush(ipack *p) +{ + if (p->plength != MMAX_PLENGTH-6 || p->found<=6) + return; + p->plength = p->found-6; + p->found = 0; + send_ipack(p); + dvb_filter_ipack_reset(p); +} - ai->bit_rate = bitrates[(3-ai->layer)][(headr[2] >> 4 )]*1000; +static +void write_ipack(ipack *p, u8 *data, int count) +{ + u8 headr[3] = { 0x00, 0x00, 0x01} ; - if (pr){ - if (ai->bit_rate == 0) - printk(" Bit rate: free"); - else if (ai->bit_rate == 0xf) - printk(" BRate: reserved"); - else - printk(" BRate: %d kb/s", ai->bit_rate/1000); + if (p->count < 6){ + memcpy(p->buf, headr, 3); + p->count = 6; } - fr = (headr[2] & 0x0c ) >> 2; - ai->frequency = freq[fr]*100; - if (pr){ - if (ai->frequency == 3) - printk(" Freq: reserved\n"); - else - printk(" Freq: %d kHz\n",ai->frequency); - + if (p->count + count < p->size){ + memcpy(p->buf+p->count, data, count); + p->count += count; + } else { + int rest = p->size - p->count; + memcpy(p->buf+p->count, data, rest); + p->count += rest; + send_ipack(p); + if (count - rest > 0) + write_ipack(p, data+rest, count-rest); } - ai->off = c; - return 0; } -int get_ac3info(uint8_t *mbuf, int count, AudioInfo *ai, int pr) + +int dvb_filter_instant_repack(u8 *buf, int count, ipack *p) { - uint8_t *headr; - int found = 0; - int c = 0; - uint8_t frame = 0; - int fr = 0; + int l; + int c=0; - while ( !found && c < count){ - uint8_t *b = mbuf+c; + while (c < count && (p->mpeg == 0 || + (p->mpeg == 1 && p->found < 7) || + (p->mpeg == 2 && p->found < 9)) + && (p->found < 5 || !p->done)){ + switch ( p->found ){ + case 0: + case 1: + if (buf[c] == 0x00) p->found++; + else p->found = 0; + c++; + break; + case 2: + if (buf[c] == 0x01) p->found++; + else if (buf[c] == 0) { + p->found = 2; + } else p->found = 0; + c++; + break; + case 3: + p->cid = 0; + switch (buf[c]){ + case PROG_STREAM_MAP: + case PRIVATE_STREAM2: + case PROG_STREAM_DIR: + case ECM_STREAM : + case EMM_STREAM : + case PADDING_STREAM : + case DSM_CC_STREAM : + case ISO13522_STREAM: + p->done = 1; + case PRIVATE_STREAM1: + case VIDEO_STREAM_S ... VIDEO_STREAM_E: + case AUDIO_STREAM_S ... AUDIO_STREAM_E: + p->found++; + p->cid = buf[c]; + c++; + break; + default: + p->found = 0; + break; + } + break; - if ( b[0] == 0x0b && b[1] == 0x77 ) - found = 1; - else { + case 4: + if (count-c > 1){ + p->plen[0] = buf[c]; c++; + p->plen[1] = buf[c]; + c++; + p->found+=2; + p->plength=(p->plen[0]<<8)|p->plen[1]; + } else { + p->plen[0] = buf[c]; + p->found++; + return count; } + break; + case 5: + p->plen[1] = buf[c]; + c++; + p->found++; + p->plength=(p->plen[0]<<8)|p->plen[1]; + break; + case 6: + if (!p->done){ + p->flag1 = buf[c]; + c++; + p->found++; + if ( (p->flag1 & 0xC0) == 0x80 ) p->mpeg = 2; + else { + p->hlength = 0; + p->which = 0; + p->mpeg = 1; + p->flag2 = 0; } + } + break; - if (!found) return -1; - if (pr) - printk("Audiostream: AC3"); - - ai->off = c; - if (c+5 >= count) return -1; - - ai->layer = 0; // 0 for AC3 - headr = mbuf+c+2; - - frame = (headr[2]&0x3f); - ai->bit_rate = ac3_bitrates[frame >> 1]*1000; - - if (pr) - printk(" BRate: %d kb/s", ai->bit_rate/1000); + case 7: + if ( !p->done && p->mpeg == 2) { + p->flag2 = buf[c]; + c++; + p->found++; + } + break; - ai->frequency = (headr[2] & 0xc0 ) >> 6; - fr = (headr[2] & 0xc0 ) >> 6; - ai->frequency = freq[fr]*100; - if (pr) printk (" Freq: %d Hz\n", ai->frequency); + case 8: + if ( !p->done && p->mpeg == 2) { + p->hlength = buf[c]; + c++; + p->found++; + } + break; + default: - ai->framesize = ac3_frames[fr][frame >> 1]; - if ((frame & 1) && (fr == 1)) ai->framesize++; - ai->framesize = ai->framesize << 1; - if (pr) printk (" Framesize %d\n", ai->framesize); + break; + } + } + if (c == count) return count; - return 0; -} + if (!p->plength) p->plength = MMAX_PLENGTH-6; -uint8_t *skip_pes_header(uint8_t **bufp) -{ - uint8_t *inbuf = *bufp; - uint8_t *buf = inbuf; - uint8_t *pts = NULL; - int skip = 0; + if ( p->done || ((p->mpeg == 2 && p->found >= 9) || + (p->mpeg == 1 && p->found >= 7)) ){ + switch (p->cid){ -int mpeg1_skip_table[16] = { - 1, 0xffff, 5, 10, 0xffff, 0xffff, 0xffff, 0xffff, - 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff -}; + case AUDIO_STREAM_S ... AUDIO_STREAM_E: + case VIDEO_STREAM_S ... VIDEO_STREAM_E: + case PRIVATE_STREAM1: + if (p->mpeg == 2 && p->found == 9) { + write_ipack(p, &p->flag1, 1); + write_ipack(p, &p->flag2, 1); + write_ipack(p, &p->hlength, 1); + } - if ((inbuf[6] & 0xc0) == 0x80){ /* mpeg2 */ - if (buf[7] & PTS_ONLY) - pts = buf+9; - else pts = NULL; - buf = inbuf + 9 + inbuf[8]; - } else { /* mpeg1 */ - for (buf = inbuf + 6; *buf == 0xff; buf++) - if (buf == inbuf + 6 + 16) { - break; - } - if ((*buf & 0xc0) == 0x40) - buf += 2; - skip = mpeg1_skip_table [*buf >> 4]; - if (skip == 5 || skip == 10) pts = buf; - else pts = NULL; + if (p->mpeg == 1 && p->found == 7) + write_ipack(p, &p->flag1, 1); - buf += mpeg1_skip_table [*buf >> 4]; + if (p->mpeg == 2 && (p->flag2 & PTS_ONLY) && + p->found < 14) { + while (c < count && p->found < 14) { + p->pts[p->found-9] = buf[c]; + write_ipack(p, buf+c, 1); + c++; + p->found++; + } + if (c == count) return count; } - *bufp = buf; - return pts; -} - + if (p->mpeg == 1 && p->which < 2000) { -void initialize_quant_matrix( uint32_t *matrix ) -{ - int i; + if (p->found == 7) { + p->check = p->flag1; + p->hlength = 1; + } - matrix[0] = 0x08101013; - matrix[1] = 0x10131616; - matrix[2] = 0x16161616; - matrix[3] = 0x1a181a1b; - matrix[4] = 0x1b1b1a1a; - matrix[5] = 0x1a1a1b1b; - matrix[6] = 0x1b1d1d1d; - matrix[7] = 0x2222221d; - matrix[8] = 0x1d1d1b1b; - matrix[9] = 0x1d1d2020; - matrix[10] = 0x22222526; - matrix[11] = 0x25232322; - matrix[12] = 0x23262628; - matrix[13] = 0x28283030; - matrix[14] = 0x2e2e3838; - matrix[15] = 0x3a454553; + while (!p->which && c < count && + p->check == 0xFF){ + p->check = buf[c]; + write_ipack(p, buf+c, 1); + c++; + p->found++; + p->hlength++; + } - for ( i = 16 ; i < 32 ; i++ ) - matrix[i] = 0x10101010; -} + if ( c == count) return count; -void initialize_mpg_picture(mpg_picture *pic) -{ - int i; + if ( (p->check & 0xC0) == 0x40 && !p->which){ + p->check = buf[c]; + write_ipack(p, buf+c, 1); + c++; + p->found++; + p->hlength++; - /* set MPEG1 */ - pic->mpeg1_flag = 1; - pic->profile_and_level = 0x4A ; /* MP@LL */ - pic->progressive_sequence = 1; - pic->low_delay = 0; + p->which = 1; + if ( c == count) return count; + p->check = buf[c]; + write_ipack(p, buf+c, 1); + c++; + p->found++; + p->hlength++; + p->which = 2; + if ( c == count) return count; + } - pic->sequence_display_extension_flag = 0; - for ( i = 0 ; i < 4 ; i++ ){ - pic->frame_centre_horizontal_offset[i] = 0; - pic->frame_centre_vertical_offset[i] = 0; + if (p->which == 1){ + p->check = buf[c]; + write_ipack(p, buf+c, 1); + c++; + p->found++; + p->hlength++; + p->which = 2; + if ( c == count) return count; } - pic->last_frame_centre_horizontal_offset = 0; - pic->last_frame_centre_vertical_offset = 0; - pic->picture_display_extension_flag[0] = 0; - pic->picture_display_extension_flag[1] = 0; - pic->sequence_header_flag = 0; - pic->gop_flag = 0; - pic->sequence_end_flag = 0; -} + if ( (p->check & 0x30) && p->check != 0xFF){ + p->flag2 = (p->check & 0xF0) << 2; + p->pts[0] = p->check; + p->which = 3; + } + if ( c == count) return count; + if (p->which > 2){ + if ((p->flag2 & PTS_DTS_FLAGS) + == PTS_ONLY){ + while (c < count && + p->which < 7){ + p->pts[p->which-2] = + buf[c]; + write_ipack(p,buf+c,1); + c++; + p->found++; + p->which++; + p->hlength++; + } + if ( c == count) return count; + } else if ((p->flag2 & PTS_DTS_FLAGS) + == PTS_DTS){ + while (c < count && + p->which< 12){ + if (p->which< 7) + p->pts[p->which + -2] = + buf[c]; + write_ipack(p,buf+c,1); + c++; + p->found++; + p->which++; + p->hlength++; + } + if ( c == count) return count; + } + p->which = 2000; + } -void mpg_set_picture_parameter( int32_t field_type, mpg_picture *pic ) -{ - int16_t last_h_offset; - int16_t last_v_offset; + } - int16_t *p_h_offset; - int16_t *p_v_offset; + while (c < count && p->found < p->plength+6){ + l = count -c; + if (l+p->found > p->plength+6) + l = p->plength+6-p->found; + write_ipack(p, buf+c, l); + p->found += l; + c += l; + } - if ( pic->mpeg1_flag ){ - pic->picture_structure[field_type] = VIDEO_FRAME_PICTURE; - pic->top_field_first = 0; - pic->repeat_first_field = 0; - pic->progressive_frame = 1; - pic->picture_coding_parameter = 0x000010; + break; } - /* Reset flag */ - pic->picture_display_extension_flag[field_type] = 0; - last_h_offset = pic->last_frame_centre_horizontal_offset; - last_v_offset = pic->last_frame_centre_vertical_offset; - if ( field_type == FIRST_FIELD ){ - p_h_offset = pic->frame_centre_horizontal_offset; - p_v_offset = pic->frame_centre_vertical_offset; - *p_h_offset = last_h_offset; - *(p_h_offset + 1) = last_h_offset; - *(p_h_offset + 2) = last_h_offset; - *p_v_offset = last_v_offset; - *(p_v_offset + 1) = last_v_offset; - *(p_v_offset + 2) = last_v_offset; + if ( p->done ){ + if( p->found + count - c < p->plength+6){ + p->found += count-c; + c = count; } else { - pic->frame_centre_horizontal_offset[3] = last_h_offset; - pic->frame_centre_vertical_offset[3] = last_v_offset; + c += p->plength+6 - p->found; + p->found = p->plength+6; + } } -} - -void init_mpg_picture( mpg_picture *pic, int chan, int32_t field_type) -{ - pic->picture_header = 0; - pic->sequence_header_data - = ( INIT_HORIZONTAL_SIZE << 20 ) - | ( INIT_VERTICAL_SIZE << 8 ) - | ( INIT_ASPECT_RATIO << 4 ) - | ( INIT_FRAME_RATE ); - pic->mpeg1_flag = 0; - pic->vinfo.horizontal_size - = INIT_DISP_HORIZONTAL_SIZE; - pic->vinfo.vertical_size - = INIT_DISP_VERTICAL_SIZE; - pic->picture_display_extension_flag[field_type] - = 0; - pic->pts_flag[field_type] = 0; - pic->sequence_gop_header = 0; - pic->picture_header = 0; - pic->sequence_header_flag = 0; - pic->gop_flag = 0; - pic->sequence_end_flag = 0; - pic->sequence_display_extension_flag = 0; - pic->last_frame_centre_horizontal_offset = 0; - pic->last_frame_centre_vertical_offset = 0; - pic->channel = chan; + if (p->plength && p->found == p->plength+6) { + send_ipack(p); + dvb_filter_ipack_reset(p); + if (c < count) + dvb_filter_instant_repack(buf+c, count-c, p); + } + } + return count; } + diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/drivers/media/dvb/dvb-core/dvb_filter.h linux.2.5.47-ac6/drivers/media/dvb/dvb-core/dvb_filter.h --- linux.2.5.47/drivers/media/dvb/dvb-core/dvb_filter.h 2002-10-31 15:05:01.000000000 +0000 +++ linux.2.5.47-ac6/drivers/media/dvb/dvb-core/dvb_filter.h 2002-11-13 01:26:41.000000000 +0000 @@ -6,18 +6,18 @@ #include "demux.h" -typedef int (pes2ts_cb_t) (void *, unsigned char *); +typedef int (dvb_filter_pes2ts_cb_t) (void *, unsigned char *); -typedef struct pes2ts_s { +typedef struct dvb_filter_pes2ts_s { unsigned char buf[188]; unsigned char cc; - pes2ts_cb_t *cb; + dvb_filter_pes2ts_cb_t *cb; void *priv; -} pes2ts_t; +} dvb_filter_pes2ts_t; -void pes2ts_init(pes2ts_t *p2ts, unsigned short pid, - pes2ts_cb_t *cb, void *priv); -int pes2ts(pes2ts_t *p2ts, unsigned char *pes, int len); +void dvb_filter_pes2ts_init(dvb_filter_pes2ts_t *p2ts, unsigned short pid, + dvb_filter_pes2ts_cb_t *cb, void *priv); +int dvb_filter_pes2ts(dvb_filter_pes2ts_t *p2ts, unsigned char *pes, int len); #define PROG_STREAM_MAP 0xBC @@ -224,26 +224,11 @@ } AudioInfo; -void reset_ipack(ipack *p); -int instant_repack(u8 *buf, int count, ipack *p); -void init_ipack(ipack *p, int size, +void dvb_filter_ipack_reset(ipack *p); +int dvb_filter_instant_repack(u8 *buf, int count, ipack *p); +void dvb_filter_ipack_init(ipack *p, int size, void (*func)(u8 *buf, int size, void *priv)); -void free_ipack(ipack * p); -void setup_ts2pes(ipack *pa, ipack *pv, u16 *pida, u16 *pidv, - void (*pes_write)(u8 *buf, int count, void *data), - void *priv); -void ts_to_pes(ipack *p, u8 *buf); -void send_ipack(ipack *p); -void send_ipack_rest(ipack *p); -int get_ainfo(uint8_t *mbuf, int count, AudioInfo *ai, int pr); -int get_ac3info(uint8_t *mbuf, int count, AudioInfo *ai, int pr); -int get_vinfo(uint8_t *mbuf, int count, VideoInfo *vi, int pr); -uint8_t *skip_pes_header(uint8_t **bufp); -void initialize_quant_matrix( uint32_t *matrix ); -void initialize_mpg_picture(mpg_picture *pic); -void init_mpg_picture( mpg_picture *pic, int chan, int32_t field_type); -void mpg_set_picture_parameter( int32_t field_type, mpg_picture *pic ); -int read_sequence_header(uint8_t *headr, VideoInfo *vi, int pr); -int read_gop_header(uint8_t *headr, mpg_picture *pic, int pr); -int read_picture_header(uint8_t *headr, mpg_picture *pic, int field, int pr); +void dvb_filter_ipack_free(ipack * p); +void dvb_filter_ipack_flush(ipack *p); + #endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/drivers/media/dvb/dvb-core/dvb_frontend.c linux.2.5.47-ac6/drivers/media/dvb/dvb-core/dvb_frontend.c --- linux.2.5.47/drivers/media/dvb/dvb-core/dvb_frontend.c 2002-10-31 15:05:01.000000000 +0000 +++ linux.2.5.47-ac6/drivers/media/dvb/dvb-core/dvb_frontend.c 2002-11-13 01:26:41.000000000 +0000 @@ -83,7 +83,7 @@ struct dvb_frontend_ioctl_data { struct list_head list_head; - struct dvb_adapter_s *adapter; + struct dvb_adapter *adapter; int (*before_ioctl) (struct dvb_frontend *frontend, unsigned int cmd, void *arg); int (*after_ioctl) (struct dvb_frontend *frontend, @@ -336,9 +336,6 @@ struct dvb_frontend *frontend = &fe->frontend; int err; - dprintk ("%s: f == %i, drift == %i\n", - __FUNCTION__, param->frequency, fe->lnb_drift); - dvb_bend_frequency (fe, 0); if (first_trial) { @@ -352,6 +349,9 @@ sizeof (struct dvb_frontend_parameters)); } + dprintk ("%s: f == %i, drift == %i\n", + __FUNCTION__, param->frequency, fe->lnb_drift); + param->frequency += fe->lnb_drift + fe->bending; err = dvb_frontend_internal_ioctl (frontend, FE_SET_FRONTEND, param); param->frequency -= fe->lnb_drift + fe->bending; @@ -367,9 +367,8 @@ struct dvb_frontend *frontend = &fe->frontend; struct dvb_frontend_parameters *init_param; - printk ("%s: initialising frontend %i:%i (%s)...\n", __FUNCTION__, - frontend->i2c->adapter->num, frontend->i2c->id, - fe->info->name); + printk ("DVB: initialising frontend %i:%i (%s)...\n", + frontend->i2c->adapter->num, frontend->i2c->id, fe->info->name); dvb_frontend_internal_ioctl (frontend, FE_INIT, NULL); @@ -436,15 +435,20 @@ */ { int j = fe->lost_sync_count; - int stepsize = fe->info->frequency_stepsize; - - if (j % 32 == 0) - fe->lnb_drift = 0; + int stepsize; - if (j % 2) - fe->lnb_drift += stepsize * ((j+1)/2); + if (fe->info->type == FE_QPSK) + stepsize = fe->parameters.u.qpsk.symbol_rate / 16000; else + stepsize = fe->info->frequency_stepsize * 2; + + if (j % 32 == 0) { + fe->lnb_drift = 0; + } else { fe->lnb_drift = -fe->lnb_drift; + if (j % 2) + fe->lnb_drift += stepsize; + } dvb_frontend_set_parameters (fe, &fe->parameters, 0); } @@ -511,7 +515,8 @@ fe->lost_sync_count = 0; } else { fe->lost_sync_count++; - + if (fe->lost_sync_count < 10) /* XXX FIXME CHECKME! */ + continue; dvb_frontend_recover (fe); delay = HZ/5; if (jiffies - fe->lost_sync_jiffies > TIMEOUT) { @@ -627,7 +632,7 @@ static int dvb_frontend_open (struct inode *inode, struct file *file) { - dvb_device_t *dvbdev = file->private_data; + struct dvb_device *dvbdev = file->private_data; struct dvb_frontend_data *fe = dvbdev->priv; int ret; @@ -648,7 +653,7 @@ static int dvb_frontend_release (struct inode *inode, struct file *file) { - dvb_device_t *dvbdev = file->private_data; + struct dvb_device *dvbdev = file->private_data; struct dvb_frontend_data *fe = dvbdev->priv; dprintk ("%s\n", __FUNCTION__); @@ -661,7 +666,7 @@ int -dvb_add_frontend_ioctls (struct dvb_adapter_s *adapter, +dvb_add_frontend_ioctls (struct dvb_adapter *adapter, int (*before_ioctl) (struct dvb_frontend *frontend, unsigned int cmd, void *arg), int (*after_ioctl) (struct dvb_frontend *frontend, @@ -715,7 +720,7 @@ void -dvb_remove_frontend_ioctls (struct dvb_adapter_s *adapter, +dvb_remove_frontend_ioctls (struct dvb_adapter *adapter, int (*before_ioctl) (struct dvb_frontend *frontend, unsigned int cmd, void *arg), int (*after_ioctl) (struct dvb_frontend *frontend, @@ -748,7 +753,7 @@ int -dvb_add_frontend_notifier (struct dvb_adapter_s *adapter, +dvb_add_frontend_notifier (struct dvb_adapter *adapter, void (*callback) (fe_status_t s, void *data), void *data) { @@ -791,7 +796,7 @@ void -dvb_remove_frontend_notifier (struct dvb_adapter_s *adapter, +dvb_remove_frontend_notifier (struct dvb_adapter *adapter, void (*callback) (fe_status_t s, void *data)) { struct list_head *entry; @@ -827,11 +832,11 @@ static struct file_operations dvb_frontend_fops = { - owner: THIS_MODULE, - ioctl: dvb_generic_ioctl, - poll: dvb_frontend_poll, - open: dvb_frontend_open, - release: dvb_frontend_release + .owner = THIS_MODULE, + .ioctl = dvb_generic_ioctl, + .poll = dvb_frontend_poll, + .open = dvb_frontend_open, + .release = dvb_frontend_release }; @@ -845,9 +850,11 @@ { struct list_head *entry; struct dvb_frontend_data *fe; - dvb_device_t dvbdev_template = { users: 1, writers: 1, - fops: &dvb_frontend_fops, - kernel_ioctl: dvb_frontend_ioctl + static const struct dvb_device dvbdev_template = { + .users = 1, + .writers = 1, + .fops = &dvb_frontend_fops, + .kernel_ioctl = dvb_frontend_ioctl }; dprintk ("%s\n", __FUNCTION__); @@ -878,7 +885,9 @@ list_for_each (entry, &frontend_ioctl_list) { struct dvb_frontend_ioctl_data *ioctl; - ioctl = list_entry (entry, struct dvb_frontend_ioctl_data, list_head); + ioctl = list_entry (entry, + struct dvb_frontend_ioctl_data, + list_head); if (ioctl->adapter == i2c->adapter) { fe->frontend.before_ioctl = ioctl->before_ioctl; @@ -936,3 +945,4 @@ MODULE_PARM(dvb_shutdown_timeout,"i"); MODULE_PARM_DESC(dvb_frontend_debug, "enable verbose debug messages"); MODULE_PARM_DESC(dvb_shutdown_timeout, "wait seconds after close() before suspending hardware"); + diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/drivers/media/dvb/dvb-core/dvb_frontend.h linux.2.5.47-ac6/drivers/media/dvb/dvb-core/dvb_frontend.h --- linux.2.5.47/drivers/media/dvb/dvb-core/dvb_frontend.h 2002-10-31 15:05:01.000000000 +0000 +++ linux.2.5.47-ac6/drivers/media/dvb/dvb-core/dvb_frontend.h 2002-11-13 01:26:41.000000000 +0000 @@ -90,7 +90,7 @@ * Return value: number of frontends where the ioctl's were applied. */ extern int -dvb_add_frontend_ioctls (struct dvb_adapter_s *adapter, +dvb_add_frontend_ioctls (struct dvb_adapter *adapter, int (*before_ioctl) (struct dvb_frontend *frontend, unsigned int cmd, void *arg), int (*after_ioctl) (struct dvb_frontend *frontend, @@ -99,18 +99,18 @@ extern void -dvb_remove_frontend_ioctls (struct dvb_adapter_s *adapter, +dvb_remove_frontend_ioctls (struct dvb_adapter *adapter, int (*before_ioctl) (struct dvb_frontend *frontend, unsigned int cmd, void *arg), int (*after_ioctl) (struct dvb_frontend *frontend, unsigned int cmd, void *arg)); extern int -dvb_add_frontend_notifier (struct dvb_adapter_s *adapter, +dvb_add_frontend_notifier (struct dvb_adapter *adapter, void (*callback) (fe_status_t s, void *data), void *data); extern void -dvb_remove_frontend_notifier (struct dvb_adapter_s *adapter, +dvb_remove_frontend_notifier (struct dvb_adapter *adapter, void (*callback) (fe_status_t s, void *data)); #endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/drivers/media/dvb/dvb-core/dvb_i2c.c linux.2.5.47-ac6/drivers/media/dvb/dvb-core/dvb_i2c.c --- linux.2.5.47/drivers/media/dvb/dvb-core/dvb_i2c.c 2002-10-31 15:05:01.000000000 +0000 +++ linux.2.5.47-ac6/drivers/media/dvb/dvb-core/dvb_i2c.c 2002-11-13 01:26:41.000000000 +0000 @@ -173,7 +173,7 @@ dvb_register_i2c_bus (int (*xfer) (struct dvb_i2c_bus *i2c, struct i2c_msg msgs[], int num), void *data, - struct dvb_adapter_s *adapter, + struct dvb_adapter *adapter, int id) { struct dvb_i2c_bus *i2c; @@ -200,7 +200,7 @@ struct dvb_i2c_bus* dvb_find_i2c_bus (int (*xfer) (struct dvb_i2c_bus *i2c, struct i2c_msg msgs[], int num), - struct dvb_adapter_s *adapter, + struct dvb_adapter *adapter, int id) { struct list_head *entry; @@ -231,7 +231,7 @@ void dvb_unregister_i2c_bus (int (*xfer) (struct dvb_i2c_bus *i2c, struct i2c_msg msgs[], int num), - struct dvb_adapter_s *adapter, + struct dvb_adapter *adapter, int id) { struct dvb_i2c_bus *i2c = dvb_find_i2c_bus (xfer, adapter, id); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/drivers/media/dvb/dvb-core/dvb_i2c.h linux.2.5.47-ac6/drivers/media/dvb/dvb-core/dvb_i2c.h --- linux.2.5.47/drivers/media/dvb/dvb-core/dvb_i2c.h 2002-10-31 15:05:01.000000000 +0000 +++ linux.2.5.47-ac6/drivers/media/dvb/dvb-core/dvb_i2c.h 2002-11-13 01:26:41.000000000 +0000 @@ -32,7 +32,7 @@ struct list_head list_head; int (*xfer) (struct dvb_i2c_bus *i2c, struct i2c_msg msgs[], int num); void *data; - struct dvb_adapter_s *adapter; + struct dvb_adapter *adapter; int id; struct list_head client_list; }; @@ -43,13 +43,13 @@ struct i2c_msg msgs[], int num), void *data, - struct dvb_adapter_s *adapter, + struct dvb_adapter *adapter, int id); extern void dvb_unregister_i2c_bus (int (*xfer) (struct dvb_i2c_bus *i2c, struct i2c_msg msgs[], int num), - struct dvb_adapter_s *adapter, + struct dvb_adapter *adapter, int id); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/drivers/media/dvb/dvb-core/dvb_ksyms.c linux.2.5.47-ac6/drivers/media/dvb/dvb-core/dvb_ksyms.c --- linux.2.5.47/drivers/media/dvb/dvb-core/dvb_ksyms.c 2002-10-31 15:05:01.000000000 +0000 +++ linux.2.5.47-ac6/drivers/media/dvb/dvb-core/dvb_ksyms.c 2002-11-13 01:26:41.000000000 +0000 @@ -9,11 +9,12 @@ #include "dvb_net.h" -EXPORT_SYMBOL(DmxDevInit); -EXPORT_SYMBOL(DmxDevRelease); -EXPORT_SYMBOL(DvbDmxInit); -EXPORT_SYMBOL(DvbDmxRelease); -EXPORT_SYMBOL(DvbDmxSWFilterPackets); +EXPORT_SYMBOL(dvb_dmxdev_init); +EXPORT_SYMBOL(dvb_dmxdev_release); +EXPORT_SYMBOL(dvb_dmx_init); +EXPORT_SYMBOL(dvb_dmx_release); +EXPORT_SYMBOL(dvb_dmx_swfilter_packet); +EXPORT_SYMBOL(dvb_dmx_swfilter_packets); EXPORT_SYMBOL(dvb_register_frontend); EXPORT_SYMBOL(dvb_unregister_frontend); @@ -37,13 +38,12 @@ EXPORT_SYMBOL(dvb_generic_ioctl); EXPORT_SYMBOL(dvb_generic_open); EXPORT_SYMBOL(dvb_generic_release); -EXPORT_SYMBOL(generic_usercopy); -EXPORT_SYMBOL(init_ipack); -EXPORT_SYMBOL(reset_ipack); -EXPORT_SYMBOL(free_ipack); -EXPORT_SYMBOL(send_ipack_rest); -EXPORT_SYMBOL(instant_repack); -EXPORT_SYMBOL(pes2ts_init); -EXPORT_SYMBOL(pes2ts); +EXPORT_SYMBOL(dvb_filter_ipack_init); +EXPORT_SYMBOL(dvb_filter_ipack_reset); +EXPORT_SYMBOL(dvb_filter_ipack_free); +EXPORT_SYMBOL(dvb_filter_ipack_flush); +EXPORT_SYMBOL(dvb_filter_instant_repack); +EXPORT_SYMBOL(dvb_filter_pes2ts_init); +EXPORT_SYMBOL(dvb_filter_pes2ts); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/drivers/media/dvb/dvb-core/dvb_net.c linux.2.5.47-ac6/drivers/media/dvb/dvb-core/dvb_net.c --- linux.2.5.47/drivers/media/dvb/dvb-core/dvb_net.c 2002-10-31 15:05:01.000000000 +0000 +++ linux.2.5.47-ac6/drivers/media/dvb/dvb-core/dvb_net.c 2002-11-13 01:26:41.000000000 +0000 @@ -435,7 +435,7 @@ int dvb_net_ioctl(struct inode *inode, struct file *file, unsigned int cmd, void *parg) { - dvb_device_t *dvbdev=(dvb_device_t *) file->private_data; + struct dvb_device *dvbdev=(struct dvb_device *) file->private_data; dvb_net_t *dvbnet=(dvb_net_t *) dvbdev->priv; if (((file->f_flags&O_ACCMODE)==O_RDONLY)) @@ -462,21 +462,18 @@ } static struct file_operations dvb_net_fops = { - owner: THIS_MODULE, - read: 0, - write: 0, - ioctl: dvb_generic_ioctl, - open: dvb_generic_open, - release: dvb_generic_release, - poll: 0, + .owner = THIS_MODULE, + .ioctl = dvb_generic_ioctl, + .open = dvb_generic_open, + .release = dvb_generic_release, }; -static dvb_device_t dvbdev_net = { - priv: 0, - users: 1, - writers: 1, - fops: &dvb_net_fops, - kernel_ioctl: dvb_net_ioctl, +static struct dvb_device dvbdev_net = { + .priv = 0, + .users = 1, + .writers = 1, + .fops = &dvb_net_fops, + .kernel_ioctl = dvb_net_ioctl, }; void @@ -493,7 +490,7 @@ } int -dvb_net_init(dvb_adapter_t *adap, dvb_net_t *dvbnet, dmx_demux_t *demux) +dvb_net_init(struct dvb_adapter *adap, dvb_net_t *dvbnet, dmx_demux_t *demux) { int i; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/drivers/media/dvb/dvb-core/dvb_net.h linux.2.5.47-ac6/drivers/media/dvb/dvb-core/dvb_net.h --- linux.2.5.47/drivers/media/dvb/dvb-core/dvb_net.h 2002-10-31 15:05:01.000000000 +0000 +++ linux.2.5.47-ac6/drivers/media/dvb/dvb-core/dvb_net.h 2002-11-13 01:26:41.000000000 +0000 @@ -47,7 +47,7 @@ } dvb_net_priv_t; typedef struct dvb_net_s { - dvb_device_t *dvbdev; + struct dvb_device *dvbdev; int card_num; int dev_num; @@ -58,6 +58,6 @@ void dvb_net_release(dvb_net_t *); -int dvb_net_init(dvb_adapter_t *, dvb_net_t *, dmx_demux_t *); +int dvb_net_init(struct dvb_adapter *, dvb_net_t *, dmx_demux_t *); #endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/drivers/media/dvb/frontends/alps_bsru6.c linux.2.5.47-ac6/drivers/media/dvb/frontends/alps_bsru6.c --- linux.2.5.47/drivers/media/dvb/frontends/alps_bsru6.c 2002-10-31 15:05:01.000000000 +0000 +++ linux.2.5.47-ac6/drivers/media/dvb/frontends/alps_bsru6.c 2002-11-13 01:26:51.000000000 +0000 @@ -1,8 +1,9 @@ /* - Alps BSRU6 DVB QPSK frontend driver + Alps BSRU6 and LG TDQB-S00x DVB QPSK frontend driver Copyright (C) 2001-2002 Convergence Integrated Media GmbH - , + , , + 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 @@ -32,12 +33,16 @@ #define M_CLK (88000000UL) - /* M=21, K=0, P=0, f_VCO = 4MHz*4*(M+1)/(K+1) = 352 MHz */ + static struct dvb_frontend_info bsru6_info = { +#ifdef CONFIG_ALPS_BSRU6_IS_LG_TDQBS00X + name: "LG TDQB-S00x", +#else name: "Alps BSRU6", +#endif type: FE_QPSK, frequency_min: 950000, frequency_max: 2150000, @@ -63,7 +68,8 @@ 0x05, 0x35, // SDAT:0 SCLT:0 I2CT:1 0x06, 0x00, // DAC mode and MSB 0x07, 0x00, // DAC LSB - 0x08, 0x43, // DiSEqC +// 0x08, 0x43, // DiSEqC + 0x08, 0x03, // DiSEqC 0x09, 0x00, 0x0a, 0x42, 0x0c, 0x51, // QPSK reverse:1 Nyquist:0 OP0 val:1 OP0 con:1 OP1 val:1 OP1 con:1 @@ -79,17 +85,20 @@ 0x15, 0xc9, // lock detector threshold 0x16, 0x1d, - 0x17, 0x0, + 0x17, 0x00, 0x18, 0x14, 0x19, 0xf2, 0x1a, 0x11, 0x1b, 0x9c, - 0x1c, 0x0, - 0x1d, 0x0, - 0x1e, 0xb, + 0x1c, 0x00, + 0x1d, 0x00, + 0x1e, 0x0b, + 0x1f, 0x50, + 0x20, 0x00, + 0x21, 0x00, 0x22, 0x00, 0x23, 0x00, 0x24, 0xff, @@ -110,16 +119,37 @@ 0x33, 0xfc, // rs control 0x34, 0x93, // error control - 0x0b, 0x00, - 0x27, 0x00, 0x2f, 0x00, 0x30, 0x00, - 0x35, 0x00, 0x36, 0x00, 0x37, 0x00, - 0x38, 0x00, 0x39, 0x00, 0x3a, 0x00, 0x3b, 0x00, - 0x3c, 0x00, 0x3d, 0x00, 0x3e, 0x00, 0x3f, 0x00, - 0x40, 0x00, 0x41, 0x00, 0x42, 0x00, 0x43, 0x00, - 0x44, 0x00, 0x45, 0x00, 0x46, 0x00, 0x47, 0x00, - 0x48, 0x00, 0x49, 0x00, 0x4a, 0x00, 0x4b, 0x00, - 0x4c, 0x00, 0x4d, 0x00, 0x4e, 0x00, 0x4f, 0x00 + 0x27, 0x00, + 0x2f, 0x00, + 0x30, 0x00, + 0x35, 0x00, + 0x36, 0x00, + 0x37, 0x00, + 0x38, 0x00, + 0x39, 0x00, + 0x3a, 0x00, + 0x3b, 0x00, + 0x3c, 0x00, + 0x3d, 0x00, + 0x3e, 0x00, + 0x3f, 0x00, + 0x40, 0x00, + 0x41, 0x00, + 0x42, 0x00, + 0x43, 0x00, + 0x44, 0x00, + 0x45, 0x00, + 0x46, 0x00, + 0x47, 0x00, + 0x48, 0x00, + 0x49, 0x00, + 0x4a, 0x00, + 0x4b, 0x00, + 0x4c, 0x00, + 0x4d, 0x00, + 0x4e, 0x00, + 0x4f, 0x00 }; @@ -231,12 +261,27 @@ static -int stv0299_set_inversion (struct dvb_i2c_bus *i2c, int inversion) +int stv0299_set_inversion (struct dvb_i2c_bus *i2c, + fe_spectral_inversion_t inversion) { u8 val; dprintk ("%s\n", __FUNCTION__); +#ifdef CONFIG_ALPS_BSRU6_IS_LG_TDQBS00X /* reversed I/Q pins */ + switch (inversion) { + case INVERSION_AUTO: + return -EOPNOTSUPP; + case INVERSION_OFF: + val = stv0299_readreg (i2c, 0x0c); + return stv0299_writereg (i2c, 0x0c, val & 0xfe); + case INVERSION_ON: + val = stv0299_readreg (i2c, 0x0c); + return stv0299_writereg (i2c, 0x0c, val | 0x01); + default: + return -EINVAL; + }; +#else switch (inversion) { case INVERSION_AUTO: return -EOPNOTSUPP; @@ -248,7 +293,8 @@ return stv0299_writereg (i2c, 0x0c, val & 0xfe); default: return -EINVAL; - } + }; +#endif } @@ -277,9 +323,10 @@ static -fe_code_rate_t stv0299_get_FEC (struct dvb_i2c_bus *i2c) +fe_code_rate_t stv0299_get_fec (struct dvb_i2c_bus *i2c) { - static fe_code_rate_t fec_tab [] = { FEC_2_3, FEC_3_4, FEC_5_6, FEC_7_8, FEC_1_2 }; + static fe_code_rate_t fec_tab [] = { FEC_2_3, FEC_3_4, FEC_5_6, + FEC_7_8, FEC_1_2 }; u8 index; dprintk ("%s\n", __FUNCTION__); @@ -343,6 +390,9 @@ dprintk ("%s\n", __FUNCTION__); + if (stv0299_wait_diseqc_idle (i2c, 100) < 0) + return -ETIMEDOUT; + val = stv0299_readreg (i2c, 0x08); if (stv0299_writereg (i2c, 0x08, (val & ~0x7) | 0x6)) /* DiSEqC mode */ @@ -356,12 +406,7 @@ return -EREMOTEIO; } - /* Shouldn't we wait for idle state (FE=1, FF=0) here to - make certain all bytes have been sent ? - Hmm, actually we should do that before all mode changes too ... - if (stv0299_wait_diseqc_idle (i2c, 100) < 0) */ - - if (stv0299_wait_diseqc_fifo (i2c, 100) < 0) + if (stv0299_wait_diseqc_idle (i2c, 100) < 0) return -ETIMEDOUT; return 0; @@ -375,18 +420,18 @@ dprintk ("%s\n", __FUNCTION__); - val = stv0299_readreg (i2c, 0x08); - - if (stv0299_wait_diseqc_fifo (i2c, 100) < 0) + if (stv0299_wait_diseqc_idle (i2c, 100) < 0) return -ETIMEDOUT; + val = stv0299_readreg (i2c, 0x08); + if (stv0299_writereg (i2c, 0x08, (val & ~0x7) | 0x2)) /* burst mode */ return -EREMOTEIO; if (stv0299_writereg (i2c, 0x09, burst == SEC_MINI_A ? 0x00 : 0xff)) return -EREMOTEIO; - if (stv0299_wait_diseqc_fifo (i2c, 100) < 0) + if (stv0299_wait_diseqc_idle (i2c, 100) < 0) return -ETIMEDOUT; if (stv0299_writereg (i2c, 0x08, val)) @@ -403,6 +448,9 @@ dprintk ("%s\n", __FUNCTION__); + if (stv0299_wait_diseqc_idle (i2c, 100) < 0) + return -ETIMEDOUT; + val = stv0299_readreg (i2c, 0x08); switch (tone) { @@ -445,8 +493,6 @@ u32 tmp; u8 aclk = 0xb4, bclk = 0x51; - dprintk ("%s\n", __FUNCTION__); - if (srate > M_CLK) srate = M_CLK; if (srate < 500000) @@ -479,7 +525,6 @@ } - static int stv0299_get_symbolrate (struct dvb_i2c_bus *i2c) { @@ -608,7 +653,7 @@ p->frequency += derot_freq; p->inversion = (stv0299_readreg (i2c, 0x0c) & 1) ? INVERSION_OFF : INVERSION_ON; - p->u.qpsk.fec_inner = stv0299_get_FEC (i2c); + p->u.qpsk.fec_inner = stv0299_get_fec (i2c); p->u.qpsk.symbol_rate = stv0299_get_symbolrate (i2c); break; } @@ -694,7 +739,7 @@ MODULE_PARM(debug,"i"); MODULE_PARM_DESC(debug, "enable verbose debug messages"); -MODULE_DESCRIPTION("BSRU6 DVB Frontend driver"); +MODULE_DESCRIPTION("Alps BSRU6/LG TDQB-S00x DVB Frontend driver"); MODULE_AUTHOR("Ralph Metzler, Holger Waechtler"); MODULE_LICENSE("GPL"); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/drivers/media/dvb/frontends/alps_bsrv2.c linux.2.5.47-ac6/drivers/media/dvb/frontends/alps_bsrv2.c --- linux.2.5.47/drivers/media/dvb/frontends/alps_bsrv2.c 2002-10-31 15:05:01.000000000 +0000 +++ linux.2.5.47-ac6/drivers/media/dvb/frontends/alps_bsrv2.c 2002-11-13 01:26:51.000000000 +0000 @@ -342,7 +342,7 @@ *ber = ves1893_readreg (i2c, 0x15); *ber |= (ves1893_readreg (i2c, 0x16) << 8); - *ber |= (ves1893_readreg (i2c, 0x17) << 16); + *ber |= ((ves1893_readreg (i2c, 0x17) & 0x0f) << 16); *ber *= 10; break; } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/drivers/media/dvb/frontends/alps_tdlb7.c linux.2.5.47-ac6/drivers/media/dvb/frontends/alps_tdlb7.c --- linux.2.5.47/drivers/media/dvb/frontends/alps_tdlb7.c 1970-01-01 01:00:00.000000000 +0100 +++ linux.2.5.47-ac6/drivers/media/dvb/frontends/alps_tdlb7.c 2002-11-13 01:26:51.000000000 +0000 @@ -0,0 +1,437 @@ +/* + Driver for Alps TDLB7 Frontend + + Copyright (C) 1999 Juergen Peitz + + 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. + +*/ + + +/* + + Wrote this code mainly to get my own card running. It's working for me, but I + hope somebody who knows more about linux programming and the DVB driver can + improve it. + + Reused a lot from the existing driver and tuner code. + Thanks to everybody who worked on it! + + This driver needs a copy of the microcode file 'Sc_main.mc' from the Haupauge + windows driver in the 'usr/lib/DVB/driver/frontends' directory. + You can also pass the complete file name with the module parameter 'mcfile'. + + The code only needs to be loaded once after a power on. Because loading the + microcode to the card takes some time, you can use the 'loadcode=0' module + parameter, if you only want to reload the dvb driver. + + Juergen Peitz + +*/ + + + +#define __KERNEL_SYSCALLS__ +#include +#include +#include +#include +#include + +#include "compat.h" +#include "dvb_frontend.h" + +static int debug = 0; + +static int loadcode = 1; + +static char * mcfile = "/usr/lib/DVB/driver/frontends/Sc_main.mc"; + +#define dprintk if (debug) printk + +/* microcode size for sp8870 */ +#define SP8870_CODE_SIZE 16384 + +/* starting point for microcode in file 'Sc_main.mc' */ +#define SP8870_CODE_OFFSET 0x0A + + +static int errno; + +static +struct dvb_frontend_info tdlb7_info = { + name: "Alps TDLB7", + type: FE_OFDM, + frequency_min: 470000000, + frequency_max: 860000000, + frequency_stepsize: 166666, +#if 0 + frequency_tolerance: ???, + symbol_rate_min: ???, + symbol_rate_max: ???, + symbol_rate_tolerance: ???, + notifier_delay: 0, +#endif + caps: FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | + FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO | + FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 +}; + + +static +int sp8870_writereg (struct dvb_i2c_bus *i2c, u16 reg, u16 data) +{ + u8 buf [] = { reg >> 8, reg & 0xff, data >> 8, data & 0xff }; + struct i2c_msg msg = { addr: 0x71, flags: 0, buf: buf, len: 4 }; + int err; + + if ((err = i2c->xfer (i2c, &msg, 1)) != 1) { + dprintk ("%s: writereg error (err == %i, reg == 0x%02x, data == 0x%02x)\n", __FUNCTION__, err, reg, data); + return -EREMOTEIO; + } + + return 0; +} + + +static +u16 sp8870_readreg (struct dvb_i2c_bus *i2c, u16 reg) +{ + int ret; + u8 b0 [] = { reg >> 8 , reg & 0xff }; + u8 b1 [] = { 0, 0 }; + struct i2c_msg msg [] = { { addr: 0x71, flags: 0, buf: b0, len: 2 }, + { addr: 0x71, flags: I2C_M_RD, buf: b1, len: 2 } }; + + ret = i2c->xfer (i2c, msg, 2); + + if (ret != 2) + dprintk("%s: readreg error (ret == %i)\n", __FUNCTION__, ret); + + return (b1[0] << 8 | b1[1]); +} + + +static +int sp5659_write (struct dvb_i2c_bus *i2c, u8 data [4]) +{ + int ret; + struct i2c_msg msg = { addr: 0x60, flags: 0, buf: data, len: 4 }; + + ret = i2c->xfer (i2c, &msg, 1); + + if (ret != 1) + printk("%s: i/o error (ret == %i)\n", __FUNCTION__, ret); + + return (ret != 1) ? -1 : 0; +} + + +static +int sp5659_set_tv_freq (struct dvb_i2c_bus *i2c, u32 freq, u8 pwr) +{ + u32 div = (freq + 36200000) / 166666; + u8 buf [4] = { (div >> 8) & 0x7f, div & 0xff, 0x85, (pwr << 5) | 0x30 }; + + return sp5659_write (i2c, buf); +} + + +static +int sp8870_read_code(const char *fn, char **fp) +{ + int fd; + loff_t l; + char *dp; + + fd = open(fn, 0, 0); + if (fd == -1) { + printk(KERN_INFO "%s: Unable to load '%s'.\n", __FUNCTION__, fn); + return -1; + } + l = lseek(fd, 0L, 2); + if (l <= 0 || l < SP8870_CODE_OFFSET+SP8870_CODE_SIZE) { + printk(KERN_INFO "%s: code file too small '%s'\n", __FUNCTION__, fn); + sys_close(fd); + return -1; + } + lseek(fd, SP8870_CODE_OFFSET, 0); + *fp= dp = vmalloc(SP8870_CODE_SIZE); + if (dp == NULL) { + printk(KERN_INFO "%s: Out of memory loading '%s'.\n", __FUNCTION__, fn); + sys_close(fd); + return -1; + } + if (read(fd, dp, SP8870_CODE_SIZE) != SP8870_CODE_SIZE) { + printk(KERN_INFO "%s: Failed to read '%s'.\n",__FUNCTION__, fn); + vfree(dp); + sys_close(fd); + return -1; + } + sys_close(fd); + *fp = dp; + return 0; +} + + +static +int sp8870_load_code(struct dvb_i2c_bus *i2c) +{ + /* this takes a long time. is there a way to do it faster? */ + char *lcode; + struct i2c_msg msg; + unsigned char buf[255]; + int err; + int p=0; + int c; + mm_segment_t fs = get_fs(); + + sp8870_writereg(i2c,0x8F08,0x1FFF); + sp8870_writereg(i2c,0x8F0A,0x0000); + + set_fs(get_ds()); + if (sp8870_read_code(mcfile,(char**) &lcode)<0) return -1; + set_fs(fs); + while (pxfer (i2c, &msg, 1)) != 1) { + dprintk ("%s: i2c error (err == %i)\n", __FUNCTION__, err); + vfree(lcode); + return -EREMOTEIO; + } + + p+=252; + } + vfree(lcode); + return 0; +}; + + +static +int sp8870_init (struct dvb_i2c_bus *i2c) +{ + + dprintk ("%s\n", __FUNCTION__); + + sp8870_readreg(i2c,0x200); + sp8870_readreg(i2c,0x200); + sp8870_readreg(i2c,0x0F00); /* system controller stop */ + sp8870_readreg(i2c,0x0301); /* ???????? */ + sp8870_readreg(i2c,0x0309); /* integer carrier offset */ + sp8870_readreg(i2c,0x030A); /* fractional carrier offset */ + sp8870_readreg(i2c,0x0311); /* filter for 8 Mhz channel */ + sp8870_readreg(i2c,0x0319); /* sample rate correction bit [23..17] */ + sp8870_readreg(i2c,0x031A); /* sample rate correction bit [16..0] */ + sp8870_readreg(i2c,0x0338); /* ???????? */ + sp8870_readreg(i2c,0x0F00); + sp8870_readreg(i2c,0x0200); + + if (loadcode) { + dprintk("%s: loading mcfile '%s' !\n", __FUNCTION__, mcfile); + if (sp8870_load_code(i2c)==0) + dprintk("%s: microcode loaded!\n", __FUNCTION__); + }else{ + dprintk("%s: without loading mcfile!\n", __FUNCTION__); + } + + return 0; +} + + +static +int sp8870_reset (struct dvb_i2c_bus *i2c) +{ + dprintk("%s\n", __FUNCTION__); + sp8870_writereg(i2c,0x0F00,0x0000); /* system controller stop */ + sp8870_writereg(i2c,0x0301,0x0003); /* ???????? */ + sp8870_writereg(i2c,0x0309,0x0400); /* integer carrier offset */ + sp8870_writereg(i2c,0x030A,0x0000); /* fractional carrier offset */ + sp8870_writereg(i2c,0x0311,0x0000); /* filter for 8 Mhz channel */ + sp8870_writereg(i2c,0x0319,0x000A); /* sample rate correction bit [23..17] */ + sp8870_writereg(i2c,0x031A,0x0AAB); /* sample rate correction bit [16..0] */ + sp8870_writereg(i2c,0x0338,0x0000); /* ???????? */ + sp8870_writereg(i2c,0x0201,0x0000); /* interrupts for change of lock or tuner adjustment disabled */ + sp8870_writereg(i2c,0x0F00,0x0001); /* system controller start */ + + return 0; +} + +static +int tdlb7_ioctl (struct dvb_frontend *fe, unsigned int cmd, void *arg) +{ + struct dvb_i2c_bus *i2c = fe->i2c; + + switch (cmd) { + case FE_GET_INFO: + memcpy (arg, &tdlb7_info, sizeof(struct dvb_frontend_info)); + break; + + case FE_READ_STATUS: + { + fe_status_t *status = arg; + int sync = sp8870_readreg (i2c, 0x0200); + + *status=0; + + if (sync&0x04) // FIXME: find criteria for having signal + *status |= FE_HAS_SIGNAL; + + if (sync&0x04) // FIXME: find criteria + *status |= FE_HAS_CARRIER; + + if (sync&0x04) // FIXME + *status |= FE_HAS_VITERBI; + + if (sync&0x08) // FIXME + *status |= FE_HAS_SYNC; + + if (sync&0x04) + *status |= FE_HAS_LOCK; + break; + + } + + case FE_READ_BER: + { + u32 *ber=(u32 *) arg; + *ber=sp8870_readreg(i2c,0x0C07); // bit error rate before Viterbi + break; + + } + + case FE_READ_SIGNAL_STRENGTH: // not supported by hardware? + { + s32 *signal=(s32 *) arg; + *signal=0; + break; + } + + case FE_READ_SNR: // not supported by hardware? + { + s32 *snr=(s32 *) arg; + *snr=0; + break; + } + + case FE_READ_UNCORRECTED_BLOCKS: // not supported by hardware? + { + u32 *ublocks=(u32 *) arg; + *ublocks=0; + break; + } + + case FE_SET_FRONTEND: + { + struct dvb_frontend_parameters *p = arg; + sp5659_set_tv_freq (i2c, p->frequency, 0); + // all other parameters are set by the on card + // system controller. Don't know how to pass + // distinct values to the card. + break; + } + + case FE_GET_FRONTEND: // how to do this? + { + break; + } + + case FE_SLEEP: // is this supported by hardware? + return -EOPNOTSUPP; + + case FE_INIT: + return sp8870_init (i2c); + + case FE_RESET: + return sp8870_reset (i2c); + + default: + return -EOPNOTSUPP; + }; + + return 0; +} + + +static +int tdlb7_attach (struct dvb_i2c_bus *i2c) +{ + + struct i2c_msg msg = { addr: 0x71, flags: 0, buf: NULL, len: 0 }; + + dprintk ("%s\n", __FUNCTION__); + + if (i2c->xfer (i2c, &msg, 1) != 1) + return -ENODEV; + + dvb_register_frontend (tdlb7_ioctl, i2c, NULL, &tdlb7_info); + + return 0; +} + + +static +void tdlb7_detach (struct dvb_i2c_bus *i2c) +{ + dprintk ("%s\n", __FUNCTION__); + + dvb_unregister_frontend (tdlb7_ioctl, i2c); +} + + +static +int __init init_tdlb7 (void) +{ + dprintk ("%s\n", __FUNCTION__); + + return dvb_register_i2c_device (THIS_MODULE, tdlb7_attach, tdlb7_detach); +} + + +static +void __exit exit_tdlb7 (void) +{ + dprintk ("%s\n", __FUNCTION__); + + dvb_unregister_i2c_device (tdlb7_attach); +} + + +module_init(init_tdlb7); +module_exit(exit_tdlb7); + + +MODULE_PARM(debug,"i"); +MODULE_PARM_DESC(debug, "enable verbose debug messages"); + +MODULE_PARM(loadcode,"i"); +MODULE_PARM_DESC(loadcode, "load tuner microcode"); + +MODULE_PARM(mcfile,"s"); +MODULE_PARM_DESC(mcfile, "where to find the microcode file"); + +MODULE_DESCRIPTION("TDLB7 DVB-T Frontend"); +MODULE_AUTHOR("Juergen Peitz"); +MODULE_LICENSE("GPL"); + + diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/drivers/media/dvb/frontends/alps_tdmb7.c linux.2.5.47-ac6/drivers/media/dvb/frontends/alps_tdmb7.c --- linux.2.5.47/drivers/media/dvb/frontends/alps_tdmb7.c 1970-01-01 01:00:00.000000000 +0100 +++ linux.2.5.47-ac6/drivers/media/dvb/frontends/alps_tdmb7.c 2002-11-13 01:26:51.000000000 +0000 @@ -0,0 +1,468 @@ +/* + Alps TDMB7 DVB OFDM frontend driver + + Copyright (C) 2001-2002 Convergence Integrated Media GmbH + Holger Waechtler + + 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. + +*/ + +#include +#include + +#include "compat.h" +#include "dvb_frontend.h" + + +static int debug = 0; +#define dprintk if (debug) printk + + +static +struct dvb_frontend_info tdmb7_info = { + name: "Alps TDMB7", + type: FE_OFDM, + frequency_min: 470000000, + frequency_max: 860000000, + frequency_stepsize: 166667, +#if 0 + frequency_tolerance: ???, + symbol_rate_min: ???, + symbol_rate_max: ???, + symbol_rate_tolerance: 500, /* ppm */ + notifier_delay: 0, +#endif + caps: FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | + FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO | + FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 +}; + + +static +inline void ddelay (int timeout) +{ + current->state=TASK_INTERRUPTIBLE; + schedule_timeout(timeout); +} + + +static +u8 init_tab [] = { + 0x04, 0x10, + 0x05, 0x09, + 0x06, 0x00, + 0x08, 0x04, + 0x09, 0x00, + 0x0a, 0x01, + 0x15, 0x40, + 0x16, 0x10, + 0x17, 0x87, + 0x18, 0x17, + 0x1a, 0x10, + 0x25, 0x04, + 0x2e, 0x00, + 0x39, 0x00, + 0x3a, 0x04, + 0x45, 0x08, + 0x46, 0x02, + 0x47, 0x05, +}; + + +static +int cx22700_writereg (struct dvb_i2c_bus *i2c, u8 reg, u8 data) +{ + int ret; + u8 buf [] = { reg, data }; + struct i2c_msg msg = { addr: 0x43, flags: 0, buf: buf, len: 2 }; + + dprintk ("%s\n", __FUNCTION__); + + ret = i2c->xfer (i2c, &msg, 1); + + if (ret != 1) + printk("%s: writereg error (reg == 0x%02x, val == 0x%02x, ret == %i)\n", + __FUNCTION__, reg, data, ret); + + return (ret != 1) ? -1 : 0; +} + + +static +u8 cx22700_readreg (struct dvb_i2c_bus *i2c, u8 reg) +{ + int ret; + u8 b0 [] = { reg }; + u8 b1 [] = { 0 }; + struct i2c_msg msg [] = { { addr: 0x43, flags: 0, buf: b0, len: 1 }, + { addr: 0x43, flags: I2C_M_RD, buf: b1, len: 1 } }; + + dprintk ("%s\n", __FUNCTION__); + + ret = i2c->xfer (i2c, msg, 2); + + if (ret != 2) + printk("%s: readreg error (ret == %i)\n", __FUNCTION__, ret); + + return b1[0]; +} + + +static +int pll_write (struct dvb_i2c_bus *i2c, u8 data [4]) +{ + struct i2c_msg msg = { addr: 0x61, flags: 0, buf: data, len: 4 }; + int ret; + + cx22700_writereg (i2c, 0x0a, 0x00); /* open i2c bus switch */ + ret = i2c->xfer (i2c, &msg, 1); + cx22700_writereg (i2c, 0x0a, 0x01); /* close i2c bus switch */ + + if (ret != 1) + printk("%s: i/o error (addr == 0x%02x, ret == %i)\n", __FUNCTION__, msg.addr, ret); + + return (ret != 1) ? -1 : 0; +} + + +/** + * set up the downconverter frequency divisor for a + * reference clock comparision frequency of 125 kHz. + */ +static +int pll_set_tv_freq (struct dvb_i2c_bus *i2c, u32 freq) +{ + u32 div = (freq + 36166667) / 166667; +#if 1 //ALPS_SETTINGS + u8 buf [4] = { (div >> 8) & 0x7f, div & 0xff, ((div >> 10) & 0x60) | 0x85, + freq < 592000000 ? 0x40 : 0x80 }; +#else + u8 buf [4] = { (div >> 8) & 0x7f, div & 0xff, ((div >> 10) & 0x60) | 0x85, + freq < 470000000 ? 0x42 : freq < 862000000 ? 0x41 : 0x81 }; +#endif + + dprintk ("%s: freq == %i, div == %i\n", __FUNCTION__, freq, div); + + return pll_write (i2c, buf); +} + + +static +int cx22700_init (struct dvb_i2c_bus *i2c) +{ + int i; + + dprintk("cx22700_init: init chip\n"); + + cx22700_writereg (i2c, 0x00, 0x02); /* soft reset */ + cx22700_writereg (i2c, 0x00, 0x00); + + ddelay (HZ/100); + + for (i=0; icode_rate_HP < FEC_1_2 || p->code_rate_HP > FEC_7_8) + return -EINVAL; + + if (p->code_rate_LP < FEC_1_2 || p->code_rate_LP > FEC_7_8) + + if (p->code_rate_HP == FEC_4_5 || p->code_rate_LP == FEC_4_5) + return -EINVAL; + + if (p->guard_interval < GUARD_INTERVAL_1_32 || + p->guard_interval > GUARD_INTERVAL_1_4) + return -EINVAL; + + if (p->transmission_mode != TRANSMISSION_MODE_2K && + p->transmission_mode != TRANSMISSION_MODE_8K) + return -EINVAL; + + if (p->constellation != QPSK && + p->constellation != QAM_16 && + p->constellation != QAM_64) + return -EINVAL; + + if (p->hierarchy_information < HIERARCHY_NONE || + p->hierarchy_information > HIERARCHY_4) + return -EINVAL; + + if (p->bandwidth < BANDWIDTH_8_MHZ && p->bandwidth > BANDWIDTH_6_MHZ) + return -EINVAL; + + if (p->bandwidth == BANDWIDTH_7_MHZ) + cx22700_writereg (i2c, 0x09, cx22700_readreg (i2c, 0x09 | 0x10)); + else + cx22700_writereg (i2c, 0x09, cx22700_readreg (i2c, 0x09 & ~0x10)); + + val = qam_tab[p->constellation - QPSK]; + val |= p->hierarchy_information - HIERARCHY_NONE; + + cx22700_writereg (i2c, 0x04, val); + + val = fec_tab[p->code_rate_HP - FEC_1_2] << 3; + val |= fec_tab[p->code_rate_LP - FEC_1_2]; + + cx22700_writereg (i2c, 0x05, val); + + val = (p->guard_interval - GUARD_INTERVAL_1_32) << 2; + val |= p->transmission_mode - TRANSMISSION_MODE_2K; + + cx22700_writereg (i2c, 0x06, val); + + cx22700_writereg (i2c, 0x08, 0x04 | 0x02); /* use user tps parameters */ + cx22700_writereg (i2c, 0x08, 0x04); /* restart aquisition */ + + return 0; +} + + +static +int cx22700_get_tps (struct dvb_i2c_bus *i2c, struct dvb_ofdm_parameters *p) +{ + static const fe_modulation_t qam_tab [3] = { QPSK, QAM_16, QAM_64 }; + static const fe_code_rate_t fec_tab [5] = { FEC_1_2, FEC_2_3, FEC_3_4, + FEC_5_6, FEC_7_8 }; + u8 val; + + dprintk ("%s\n", __FUNCTION__); + + if (!(cx22700_readreg(i2c, 0x07) & 0x20)) /* tps valid? */ + return -EAGAIN; + + val = cx22700_readreg (i2c, 0x01); + + if ((val & 0x7) > 4) + p->hierarchy_information = HIERARCHY_AUTO; + else + p->hierarchy_information = HIERARCHY_NONE + (val & 0x7); + + if (((val >> 3) & 0x3) > 2) + p->constellation = QAM_AUTO; + else + p->constellation = qam_tab[(val >> 3) & 0x3]; + + + val = cx22700_readreg (i2c, 0x02); + + if ((val >> 3) > 4) + p->code_rate_HP = FEC_AUTO; + else + p->code_rate_HP = fec_tab[val >> 3]; + + if ((val & 0x7) > 4) + p->code_rate_LP = FEC_AUTO; + else + p->code_rate_LP = fec_tab[val >> 3]; + + + val = cx22700_readreg (i2c, 0x03); + + p->guard_interval = GUARD_INTERVAL_1_32 + ((val >> 6) & 0x3); + p->transmission_mode = TRANSMISSION_MODE_2K + ((val >> 5) & 0x1); + + return 0; +} + + +static +int tdmb7_ioctl (struct dvb_frontend *fe, unsigned int cmd, void *arg) +{ + struct dvb_i2c_bus *i2c = fe->i2c; + + dprintk ("%s\n", __FUNCTION__); + + switch (cmd) { + case FE_GET_INFO: + memcpy (arg, &tdmb7_info, sizeof(struct dvb_frontend_info)); + break; + + case FE_READ_STATUS: + { + fe_status_t *status = (fe_status_t *) arg; + u16 rs_ber = (cx22700_readreg (i2c, 0x0d) << 9) + | (cx22700_readreg (i2c, 0x0e) << 1); + u8 sync = cx22700_readreg (i2c, 0x07); + + *status = 0; + + if (rs_ber < 0xff00) + *status |= FE_HAS_SIGNAL; + + if (sync & 0x20) + *status |= FE_HAS_CARRIER; + + if (sync & 0x10) + *status |= FE_HAS_VITERBI; + + if (sync & 0x10) + *status |= FE_HAS_SYNC; + + if (sync & 0x10) + *status |= FE_HAS_LOCK; + + break; + } + + case FE_READ_BER: + *((uint32_t*) arg) = cx22700_readreg (i2c, 0x0c) & 0x7f; + break; + + case FE_READ_SIGNAL_STRENGTH: + { + u16 rs_ber = (cx22700_readreg (i2c, 0x0d) << 9) + | (cx22700_readreg (i2c, 0x0e) << 1); + *((uint16_t*) arg) = ~rs_ber; + break; + } + case FE_READ_SNR: + { + u16 rs_ber = (cx22700_readreg (i2c, 0x0d) << 9) + | (cx22700_readreg (i2c, 0x0e) << 1); + *((uint16_t*) arg) = ~rs_ber; + break; + } + case FE_READ_UNCORRECTED_BLOCKS: + *((uint32_t*) arg) = cx22700_readreg (i2c, 0x0f); + break; + + case FE_SET_FRONTEND: + { + struct dvb_frontend_parameters *p = arg; + + cx22700_writereg (i2c, 0x00, 0x02); /* XXX CHECKME: soft reset*/ + cx22700_writereg (i2c, 0x00, 0x00); + + pll_set_tv_freq (i2c, p->frequency); + cx22700_set_inversion (i2c, p->inversion); + cx22700_set_tps (i2c, &p->u.ofdm); + cx22700_writereg (i2c, 0x37, 0x01); /* PAL loop filter off */ + cx22700_writereg (i2c, 0x00, 0x01); /* restart aquire */ + break; + } + + case FE_GET_FRONTEND: + { + struct dvb_frontend_parameters *p = arg; + u8 reg09 = cx22700_readreg (i2c, 0x09); + + p->inversion = reg09 & 0x1 ? INVERSION_ON : INVERSION_OFF; + return cx22700_get_tps (i2c, &p->u.ofdm); + } + + case FE_INIT: + return cx22700_init (i2c); + + case FE_RESET: + break; + + default: + return -EOPNOTSUPP; + }; + + return 0; +} + + + +static +int tdmb7_attach (struct dvb_i2c_bus *i2c) +{ + struct i2c_msg msg = { addr: 0x43, flags: 0, buf: NULL, len: 0 }; + + dprintk ("%s\n", __FUNCTION__); + + if (i2c->xfer (i2c, &msg, 1) != 1) + return -ENODEV; + + dvb_register_frontend (tdmb7_ioctl, i2c, NULL, &tdmb7_info); + + return 0; +} + + +static +void tdmb7_detach (struct dvb_i2c_bus *i2c) +{ + dprintk ("%s\n", __FUNCTION__); + + dvb_unregister_frontend (tdmb7_ioctl, i2c); +} + + +static +int __init init_tdmb7 (void) +{ + dprintk ("%s\n", __FUNCTION__); + + return dvb_register_i2c_device (THIS_MODULE, tdmb7_attach, tdmb7_detach); +} + + +static +void __exit exit_tdmb7 (void) +{ + dprintk ("%s\n", __FUNCTION__); + + dvb_unregister_i2c_device (tdmb7_attach); +} + +module_init (init_tdmb7); +module_exit (exit_tdmb7); + +MODULE_PARM(debug,"i"); +MODULE_PARM_DESC(debug, "enable verbose debug messages"); +MODULE_DESCRIPTION("TDMB7 DVB Frontend driver"); +MODULE_AUTHOR("Holger Waechtler"); +MODULE_LICENSE("GPL"); + diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/drivers/media/dvb/frontends/Kconfig linux.2.5.47-ac6/drivers/media/dvb/frontends/Kconfig --- linux.2.5.47/drivers/media/dvb/frontends/Kconfig 2002-10-31 15:05:01.000000000 +0000 +++ linux.2.5.47-ac6/drivers/media/dvb/frontends/Kconfig 2002-11-13 01:29:47.000000000 +0000 @@ -23,6 +23,30 @@ DVB adapter simply enable all supported frontends, the right one will get autodetected. +config DVB_ALPS_TDLB7 + tristate "Alps TDLB7 (OFDM)" + depends on DVB_CORE + help + A DVB-T tuner module. Say Y when you want to support this frontend. + + This tuner module needs some microcode located in a file called + "Sc_main.mc" in the windows driver. Please pass the module parameter + mcfile="/PATH/FILENAME" when loading alps_tdlb7.o. + + If you don't know what tuner module is soldered on your + DVB adapter simply enable all supported frontends, the + right one will get autodetected. + +config DVB_ALPS_TDMB7 + tristate "Alps BSRV2 (OFDM)" + depends on DVB_CORE + help + A DVB-S tuner module. Say Y when you want to support this frontend. + + If you don't know what tuner module is soldered on your + DVB adapter simply enable all supported frontends, the + right one will get autodetected. + config DVB_GRUNDIG_29504_491 tristate "Grundig 29504-491 (QPSK)" depends on DVB_CORE diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/drivers/media/dvb/frontends/Makefile linux.2.5.47-ac6/drivers/media/dvb/frontends/Makefile --- linux.2.5.47/drivers/media/dvb/frontends/Makefile 2002-10-31 15:05:01.000000000 +0000 +++ linux.2.5.47-ac6/drivers/media/dvb/frontends/Makefile 2002-11-13 01:26:51.000000000 +0000 @@ -6,6 +6,8 @@ obj-$(CONFIG_DVB_ALPS_BSRU6) += alps_bsru6.o obj-$(CONFIG_DVB_ALPS_BSRV2) += alps_bsrv2.o +obj-$(CONFIG_DVB_ALPS_TDLB7) += alps_tdlb7.o +obj-$(CONFIG_DVB_ALPS_TDMB7) += alps_tdmb7.o obj-$(CONFIG_DVB_GRUNDIG_29504_491) += grundig_29504-491.o obj-$(CONFIG_DVB_GRUNDIG_29504_401) += grundig_29504-401.o obj-$(CONFIG_DVB_VES1820) += ves1820.o diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/drivers/media/dvb/frontends/ves1820.c linux.2.5.47-ac6/drivers/media/dvb/frontends/ves1820.c --- linux.2.5.47/drivers/media/dvb/frontends/ves1820.c 2002-10-31 15:05:01.000000000 +0000 +++ linux.2.5.47-ac6/drivers/media/dvb/frontends/ves1820.c 2002-11-13 01:26:51.000000000 +0000 @@ -199,8 +199,8 @@ u8 b0 [] = { 0xff }; u8 pwm; int i; - struct i2c_msg msg [] = { { addr: 0x28, flags: 0, buf: b0, len: 1 }, - { addr: 0x28, flags: I2C_M_RD, buf: &pwm, len: 1 } }; + struct i2c_msg msg [] = { { addr: 0x50, flags: 0, buf: b0, len: 1 }, + { addr: 0x50, flags: I2C_M_RD, buf: &pwm, len: 1 } }; dprintk("VES1820: init chip\n"); @@ -433,12 +433,13 @@ } case FE_READ_BER: - *((u32*) arg) = ves1820_readreg(frontend->i2c, 0x14) | + { + u32 ber = ves1820_readreg(frontend->i2c, 0x14) | (ves1820_readreg(frontend->i2c, 0x15) << 8) | - (ves1820_readreg(frontend->i2c, 0x16) << 16); - /* XXX FIXME: scale!!*/ + ((ves1820_readreg(frontend->i2c, 0x16) & 0x0f) << 16); + *((u32*) arg) = 10 * ber; break; - + } case FE_READ_SIGNAL_STRENGTH: { u8 gain = ves1820_readreg(frontend->i2c, 0x17); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/drivers/media/video/audiochip.h linux.2.5.47-ac6/drivers/media/video/audiochip.h --- linux.2.5.47/drivers/media/video/audiochip.h 2002-10-31 14:57:08.000000000 +0000 +++ linux.2.5.47-ac6/drivers/media/video/audiochip.h 2002-11-11 20:24:45.000000000 +0000 @@ -67,4 +67,7 @@ #define AUDC_SWITCH_MUTE _IO('m',16) /* turn on mute */ #endif +/* misc stuff to pass around config info to i2c chips */ +#define AUDC_CONFIG_PINNACLE _IOW('m',32,int) + #endif /* AUDIOCHIP_H */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/drivers/media/video/bttv-driver.c linux.2.5.47-ac6/drivers/media/video/bttv-driver.c --- linux.2.5.47/drivers/media/video/bttv-driver.c 2002-11-05 13:54:43.000000000 +0000 +++ linux.2.5.47-ac6/drivers/media/video/bttv-driver.c 2002-11-12 15:28:58.000000000 +0000 @@ -833,11 +833,9 @@ i2c_mux = mux = (btv->audio & AUDIO_MUTE) ? AUDIO_OFF : btv->audio; if (btv->opt_automute && !signal && !btv->radio_user) mux = AUDIO_OFF; -#if 0 - printk("bttv%d: amux: mode=%d audio=%d signal=%s mux=%d/%d irq=%s\n", + dprintk(KERN_DEBUG "bttv%d: amux: mode=%d audio=%d signal=%s mux=%d/%d irq=%s\n", btv->nr, mode, btv->audio, signal ? "yes" : "no", mux, i2c_mux, in_interrupt() ? "yes" : "no"); -#endif val = bttv_tvcards[btv->type].audiomux[mux]; btaor(val,~bttv_tvcards[btv->type].gpiomask, BT848_GPIO_DATA); @@ -3225,6 +3223,7 @@ INIT_LIST_HEAD(&btv->capture); INIT_LIST_HEAD(&btv->vcapture); + init_timer(&btv->timeout); btv->timeout.function = bttv_irq_timeout; btv->timeout.data = (unsigned long)btv; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/drivers/media/video/Makefile linux.2.5.47-ac6/drivers/media/video/Makefile --- linux.2.5.47/drivers/media/video/Makefile 2002-11-05 13:54:43.000000000 +0000 +++ linux.2.5.47-ac6/drivers/media/video/Makefile 2002-11-11 19:39:54.000000000 +0000 @@ -35,7 +35,7 @@ obj-$(CONFIG_VIDEO_CPIA_PP) += cpia_pp.o obj-$(CONFIG_VIDEO_CPIA_USB) += cpia_usb.o obj-$(CONFIG_VIDEO_MEYE) += meye.o -obj-$(CONFIG_VIDEO_SAA7134) += saa7134/ tuner.o tda9887.o +obj-$(CONFIG_VIDEO_SAA7134) += saa7134/ tuner.o #tda9887.o obj-$(CONFIG_TUNER_3036) += tuner-3036.o include $(TOPDIR)/Rules.make diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/drivers/media/video/meye.c linux.2.5.47-ac6/drivers/media/video/meye.c --- linux.2.5.47/drivers/media/video/meye.c 2002-10-31 14:57:08.000000000 +0000 +++ linux.2.5.47-ac6/drivers/media/video/meye.c 2002-11-11 19:39:31.000000000 +0000 @@ -861,7 +861,7 @@ mchip_free_frame(); } -out: +out: ; } /****************************************************************************/ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/drivers/message/fusion/mptbase.c linux.2.5.47-ac6/drivers/message/fusion/mptbase.c --- linux.2.5.47/drivers/message/fusion/mptbase.c 2002-10-31 14:57:19.000000000 +0000 +++ linux.2.5.47-ac6/drivers/message/fusion/mptbase.c 2002-11-13 01:12:10.000000000 +0000 @@ -49,7 +49,7 @@ * (mailto:sjralston1@netscape.net) * (mailto:Pam.Delaney@lsil.com) * - * $Id: mptbase.c,v 1.122 2002/10/03 13:10:11 pdelaney Exp $ + * $Id: mptbase.c,v 1.123 2002/10/17 20:15:56 pdelaney Exp $ */ /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /* @@ -1156,7 +1156,7 @@ dprintk((KERN_INFO MYNAM ": Checking for MPT adapters...\n")); /* - * NOTE: The 929, 929X and 1030 will appear as 2 separate PCI devices, + * NOTE: The 929, 929X, 1030 and 1035 will appear as 2 separate PCI devices, * one for each channel. */ pci_for_each_dev(pdev) { @@ -1170,18 +1170,14 @@ (pdev->device != MPI_MANUFACTPAGE_DEVICEID_FC929X) && (pdev->device != MPI_MANUFACTPAGE_DEVICEID_FC919X) && (pdev->device != MPI_MANUFACTPAGE_DEVID_53C1030) && -#if 0 - /* FIXME! C103x family */ - (pdev->device != MPI_MANUFACTPAGE_DEVID_53C1030_ZC) && - (pdev->device != MPI_MANUFACTPAGE_DEVID_53C1035) && -#endif + (pdev->device != MPI_MANUFACTPAGE_DEVID_1030_53C1035) && 1) { dprintk((KERN_INFO MYNAM ": Skipping LSI device=%04xh\n", pdev->device)); continue; } /* GRRRRR - * dual function devices (929, 929X, 1030) may be presented in Func 1,0 order, + * dual function devices (929, 929X, 1030, 1035) may be presented in Func 1,0 order, * but we'd really really rather have them in Func 0,1 order. * Do some kind of look ahead here... */ @@ -1445,15 +1441,24 @@ ioc->chip_type = C1030; ioc->prod_name = "LSI53C1030"; { + u8 revision; + /* 1030 Chip Fix. Disable Split transactions - * for PCIX. Set bits 4 - 6 to zero. + * for PCIX. Set bits 4 - 6 to zero if Rev < C0( = 8) */ - u16 pcixcmd = 0; - pci_read_config_word(pdev, 0x6a, &pcixcmd); - pcixcmd &= 0xFF8F; - pci_write_config_word(pdev, 0x6a, pcixcmd); + pci_read_config_byte(pdev, PCI_CLASS_REVISION, &revision); + if (revision < 0x08) { + u16 pcixcmd = 0; + pci_read_config_word(pdev, 0x6a, &pcixcmd); + pcixcmd &= 0xFF8F; + pci_write_config_word(pdev, 0x6a, pcixcmd); + } } } + else if (pdev->device == MPI_MANUFACTPAGE_DEVID_1030_53C1035) { + ioc->chip_type = C1035; + ioc->prod_name = "LSI53C1035"; + } sprintf(ioc->name, "ioc%d", ioc->id); @@ -1500,9 +1505,10 @@ mpt_adapters[ioc->id] = ioc; /* NEW! 20010220 -sralston - * Check for "bound ports" (929, 929X, 1030) to reduce redundant resets. + * Check for "bound ports" (929, 929X, 1030, 1035) to reduce redundant resets. */ - if ((ioc->chip_type == FC929) || (ioc->chip_type == C1030) || (ioc->chip_type == FC929X)) + if ((ioc->chip_type == FC929) || (ioc->chip_type == C1030) + || (ioc->chip_type == C1035) || (ioc->chip_type == FC929X)) mpt_detect_bound_ports(ioc, pdev); if ((r = mpt_do_ioc_recovery(ioc, MPT_HOSTEVENT_IOC_BRINGUP, CAN_SLEEP)) != 0) { @@ -1746,7 +1752,7 @@ /* * mpt_detect_bound_ports - Search for PCI bus/dev_function * which matches PCI bus/dev_function (+/-1) for newly discovered 929, - * 929X or 1030. + * 929X, 1030 or 1035. * @ioc: Pointer to MPT adapter structure * @pdev: Pointer to (struct pci_dev) structure * @@ -1806,8 +1812,7 @@ /* Disable the FW */ state = mpt_GetIocState(this, 1); if (state == MPI_IOC_STATE_OPERATIONAL) { - if (SendIocReset(this, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, NO_SLEEP) != 0) - (void) KickStart(this, 1, NO_SLEEP); + SendIocReset(this, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, NO_SLEEP); } if (this->cached_fw != NULL) { @@ -1819,7 +1824,6 @@ } } - /* Disable adapter interrupts! */ CHIPREG_WRITE32(&this->chip->IntMask, 0xFFFFFFFF); this->active = 0; @@ -2291,9 +2295,6 @@ ioc->reply_sz = ioc->req_sz; ioc->reply_depth = MIN(MPT_DEFAULT_REPLY_DEPTH, facts->ReplyQueueDepth); - /* 1030 - should we use a smaller DEFAULT_REPLY_DEPTH? - * FIX - */ dprintk((MYIOC_s_INFO_FMT "reply_sz=%3d, reply_depth=%4d\n", ioc->name, ioc->reply_sz, ioc->reply_depth)); dprintk((MYIOC_s_INFO_FMT "req_sz =%3d, req_depth =%4d\n", @@ -2891,6 +2892,7 @@ */ diag0val = CHIPREG_READ32(&ioc->chip->Diagnostic); while ((diag0val & MPI_DIAG_DRWE) == 0) { + CHIPREG_WRITE32(&ioc->chip->WriteSequence, 0xFF); CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_1ST_KEY_VALUE); CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_2ND_KEY_VALUE); CHIPREG_WRITE32(&ioc->chip->WriteSequence, MPI_WRSEQ_3RD_KEY_VALUE); @@ -3126,6 +3128,18 @@ int cnt = 0; dprintk((KERN_WARNING MYNAM ": KickStarting %s!\n", ioc->name)); + if ((int)ioc->chip_type > (int)FC929) { + /* Always issue a Msg Unit Reset first. This will clear some + * SCSI bus hang conditions. + */ + SendIocReset(ioc, MPI_FUNCTION_IOC_MESSAGE_UNIT_RESET, sleepFlag); + + if (sleepFlag == CAN_SLEEP) { + schedule_timeout(HZ); + } else { + mdelay (1000); + } + } hard_reset_done = mpt_diag_reset(ioc, force, sleepFlag); if (hard_reset_done < 0) @@ -5841,6 +5855,15 @@ while (! Q_IS_EMPTY(&MptAdapters)) { this = MptAdapters.head; + + /* Disable interrupts! */ + CHIPREG_WRITE32(&this->chip->IntMask, 0xFFFFFFFF); + + this->active = 0; + + /* Clear any lingering interrupt */ + CHIPREG_WRITE32(&this->chip->IntStatus, 0); + Q_DEL_ITEM(this); mpt_adapter_dispose(this); } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/drivers/message/fusion/mptbase.h linux.2.5.47-ac6/drivers/message/fusion/mptbase.h --- linux.2.5.47/drivers/message/fusion/mptbase.h 2002-10-31 14:57:19.000000000 +0000 +++ linux.2.5.47-ac6/drivers/message/fusion/mptbase.h 2002-11-17 00:27:50.000000000 +0000 @@ -13,7 +13,7 @@ * (mailto:sjralston1@netscape.net) * (mailto:Pam.Delaney@lsil.com) * - * $Id: mptbase.h,v 1.134 2002/10/03 13:10:12 pdelaney Exp $ + * $Id: mptbase.h,v 1.136 2002/10/21 13:51:54 pdelaney Exp $ */ /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /* @@ -80,8 +80,8 @@ #define COPYRIGHT "Copyright (c) 1999-2002 " MODULEAUTHOR #endif -#define MPT_LINUX_VERSION_COMMON "2.02.01.07" -#define MPT_LINUX_PACKAGE_NAME "@(#)mptlinux-2.02.01.07" +#define MPT_LINUX_VERSION_COMMON "2.03.00.02" +#define MPT_LINUX_PACKAGE_NAME "@(#)mptlinux-2.03.00.02" #define WHAT_MAGIC_STRING "@" "(" "#" ")" #define show_mptmod_ver(s,ver) \ @@ -301,6 +301,7 @@ FC919 = 0x0919, FC929 = 0x0929, C1030 = 0x1030, + C1035 = 0x1035, FCUNK = 0xFBAD } CHIP_TYPE; @@ -368,6 +369,7 @@ typedef struct _VirtDevice { struct _VirtDevice *forw; struct _VirtDevice *back; + struct scsi_device *device; rwlock_t VdevLock; int ref_cnt; u8 tflags; @@ -912,6 +914,10 @@ MPT_FRAME_HDR *cmdPtr; /* Ptr to nonOS request */ struct scsi_cmnd *abortSCpnt; MPT_LOCAL_REPLY localReply; /* internal cmd reply struct */ + unsigned long hard_resets; /* driver forced bus resets count */ + unsigned long soft_resets; /* fw/external bus resets count */ + unsigned long timeouts; /* cmd timeouts */ + ushort sel_timeout[MPT_MAX_FC_DEVICES]; } MPT_SCSI_HOST; /* diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/drivers/message/fusion/mptctl.c linux.2.5.47-ac6/drivers/message/fusion/mptctl.c --- linux.2.5.47/drivers/message/fusion/mptctl.c 2002-10-31 14:57:19.000000000 +0000 +++ linux.2.5.47-ac6/drivers/message/fusion/mptctl.c 2002-11-13 01:12:10.000000000 +0000 @@ -34,7 +34,7 @@ * (mailto:sjralston1@netscape.net) * (mailto:Pam.Delaney@lsil.com) * - * $Id: mptctl.c,v 1.60 2002/10/03 13:10:13 pdelaney Exp $ + * $Id: mptctl.c,v 1.61 2002/10/17 20:15:57 pdelaney Exp $ */ /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /* @@ -136,14 +136,8 @@ static int mptctl_replace_fw (unsigned long arg); static int mptctl_do_reset(unsigned long arg); - -static int mptctl_compaq_ioctl(struct file *file, unsigned int cmd, unsigned long arg); -static int mptctl_cpq_getpciinfo(unsigned long arg); -static int mptctl_cpq_getdriver(unsigned long arg); -static int mptctl_cpq_ctlr_status(unsigned long arg); -static int mptctl_cpq_target_address(unsigned long arg); -static int mptctl_cpq_passthru(unsigned long arg); -static int mptctl_compaq_scsiio(VENDOR_IOCTL_REQ *pVenReq, cpqfc_passthru_t *pPass); +static int mptctl_hp_hostinfo(unsigned long arg); +static int mptctl_hp_targetinfo(unsigned long arg); /* * Private function calls. @@ -415,7 +409,7 @@ /* Send request */ if ((mf = mpt_get_msg_frame(mptctl_id, ioctl->ioc->id)) == NULL) { - dtmprintk((MYIOC_s_WARN_FMT "IssueTaskMgmt, no msg frames!!\n", + dctlprintk((MYIOC_s_WARN_FMT "IssueTaskMgmt, no msg frames!!\n", ioctl->ioc->name)); mptctl_free_tm_flags(ioctl->ioc); @@ -623,21 +617,13 @@ } ret = -ENXIO; /* (-6) No such device or address */ - - /* Test for Compaq-specific IOCTL's. - */ - if ((cmd == CPQFCTS_GETPCIINFO) || (cmd == CPQFCTS_CTLR_STATUS) || - (cmd == CPQFCTS_GETDRIVVER) || (cmd == CPQFCTS_SCSI_PASSTHRU) || - (cmd == CPQFCTS_SCSI_IOCTL_FC_TARGET_ADDRESS)) - return mptctl_compaq_ioctl(file, cmd, arg); - /* Verify intended MPT adapter - set iocnum and the adapter * pointer (iocp) */ iocnumX = khdr.iocnum & 0xFF; if (((iocnum = mpt_verify_adapter(iocnumX, &iocp)) < 0) || (iocp == NULL)) { - dtmprintk((KERN_ERR "%s::mptctl_ioctl() @%d - ioc%d not found!\n", + dctlprintk((KERN_ERR "%s::mptctl_ioctl() @%d - ioc%d not found!\n", __FILE__, __LINE__, iocnumX)); return -ENODEV; } @@ -683,6 +669,12 @@ case MPTHARDRESET: ret = mptctl_do_reset(arg); break; + case HP_GETHOSTINFO: + ret = mptctl_hp_hostinfo(arg); + break; + case HP_GETTARGETINFO: + ret = mptctl_hp_targetinfo(arg); + break; default: ret = -EINVAL; } @@ -708,7 +700,7 @@ } if (mpt_verify_adapter(krinfo.hdr.iocnum, &iocp) < 0) { - dtmprintk((KERN_ERR "%s@%d::mptctl_do_reset - ioc%d not found!\n", + dctlprintk((KERN_ERR "%s@%d::mptctl_do_reset - ioc%d not found!\n", __FILE__, __LINE__, krinfo.hdr.iocnum)); return -ENODEV; /* (-6) No such device or address */ } @@ -816,7 +808,7 @@ dctlprintk((KERN_INFO "DbG: kfwdl.ioc = %04xh\n", ioc)); if ((ioc = mpt_verify_adapter(ioc, &iocp)) < 0) { - dtmprintk(("%s@%d::_ioctl_fwdl - ioc%d not found!\n", + dctlprintk(("%s@%d::_ioctl_fwdl - ioc%d not found!\n", __FILE__, __LINE__, ioc)); return -ENODEV; /* (-6) No such device or address */ } @@ -1252,7 +1244,7 @@ if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) || (ioc == NULL)) { - dtmprintk((KERN_ERR "%s::mptctl_getiocinfo() @%d - ioc%d not found!\n", + dctlprintk((KERN_ERR "%s::mptctl_getiocinfo() @%d - ioc%d not found!\n", __FILE__, __LINE__, iocnum)); return -ENODEV; } @@ -1379,7 +1371,7 @@ if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) || (ioc == NULL)) { - dtmprintk((KERN_ERR "%s::mptctl_gettargetinfo() @%d - ioc%d not found!\n", + dctlprintk((KERN_ERR "%s::mptctl_gettargetinfo() @%d - ioc%d not found!\n", __FILE__, __LINE__, iocnum)); return -ENODEV; } @@ -1510,7 +1502,7 @@ if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) || (ioc == NULL)) { - dtmprintk((KERN_ERR "%s::mptctl_readtest() @%d - ioc%d not found!\n", + dctlprintk((KERN_ERR "%s::mptctl_readtest() @%d - ioc%d not found!\n", __FILE__, __LINE__, iocnum)); return -ENODEV; } @@ -1568,7 +1560,7 @@ if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) || (ioc == NULL)) { - dtmprintk((KERN_ERR "%s::mptctl_eventquery() @%d - ioc%d not found!\n", + dctlprintk((KERN_ERR "%s::mptctl_eventquery() @%d - ioc%d not found!\n", __FILE__, __LINE__, iocnum)); return -ENODEV; } @@ -1606,7 +1598,7 @@ if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) || (ioc == NULL)) { - dtmprintk((KERN_ERR "%s::mptctl_eventenable() @%d - ioc%d not found!\n", + dctlprintk((KERN_ERR "%s::mptctl_eventenable() @%d - ioc%d not found!\n", __FILE__, __LINE__, iocnum)); return -ENODEV; } @@ -1654,7 +1646,7 @@ if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) || (ioc == NULL)) { - dtmprintk((KERN_ERR "%s::mptctl_eventreport() @%d - ioc%d not found!\n", + dctlprintk((KERN_ERR "%s::mptctl_eventreport() @%d - ioc%d not found!\n", __FILE__, __LINE__, iocnum)); return -ENODEV; } @@ -1708,7 +1700,7 @@ if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) || (ioc == NULL)) { - dtmprintk((KERN_ERR "%s::mptctl_replace_fw() @%d - ioc%d not found!\n", + dctlprintk((KERN_ERR "%s::mptctl_replace_fw() @%d - ioc%d not found!\n", __FILE__, __LINE__, iocnum)); return -ENODEV; } @@ -1794,7 +1786,7 @@ if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) || (ioc == NULL)) { - dtmprintk((KERN_ERR "%s::mptctl_mpt_command() @%d - ioc%d not found!\n", + dctlprintk((KERN_ERR "%s::mptctl_mpt_command() @%d - ioc%d not found!\n", __FILE__, __LINE__, iocnum)); return -ENODEV; } @@ -1842,7 +1834,7 @@ if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) || (ioc == NULL)) { - dtmprintk((KERN_ERR "%s::mptctl_do_mpt_command() @%d - ioc%d not found!\n", + dctlprintk((KERN_ERR "%s::mptctl_do_mpt_command() @%d - ioc%d not found!\n", __FILE__, __LINE__, iocnum)); return -ENODEV; } @@ -1926,6 +1918,14 @@ int target = (int) pScsiReq->TargetID; int dataSize; + if ((target < 0) || (target >= ioc->sh->max_id)) { + printk(KERN_ERR "%s@%d::mptctl_do_mpt_command - " + "Target ID out of bounds. \n", + __FILE__, __LINE__); + rc = -ENODEV; + goto done_free_mem; + } + pScsiReq->MsgFlags = mpt_msg_flags(); /* verify that app has not requested @@ -2049,9 +2049,37 @@ } break; + case MPI_FUNCTION_IOC_INIT: + { + IOCInit_t *pInit = (IOCInit_t *) mf; + u32 high_addr, sense_high; + + /* Verify that all entries in the IOC INIT match + * existing setup (and in LE format). + */ + if (sizeof(dma_addr_t) == sizeof(u64)) { + high_addr = cpu_to_le32((u32)((u64)ioc->req_frames_dma >> 32)); + sense_high= cpu_to_le32((u32)((u64)ioc->sense_buf_pool_dma >> 32)); + } else { + high_addr = 0; + sense_high= 0; + } + + if ((pInit->Flags != 0) || (pInit->MaxDevices != ioc->facts.MaxDevices) || + (pInit->MaxBuses != ioc->facts.MaxBuses) || + (pInit->ReplyFrameSize != cpu_to_le16(ioc->reply_sz)) || + (pInit->HostMfaHighAddr != high_addr) || + (pInit->SenseBufferHighAddr != sense_high)) { + printk(KERN_ERR "%s@%d::mptctl_do_mpt_command - " + "IOC_INIT issued with 1 or more incorrect parameters. Rejected.\n", + __FILE__, __LINE__); + rc = -EFAULT; + goto done_free_mem; + } + } + break; default: /* - * MPI_FUNCTION_IOC_INIT * MPI_FUNCTION_PORT_ENABLE * MPI_FUNCTION_TARGET_CMD_BUFFER_POST * MPI_FUNCTION_TARGET_ASSIST @@ -2357,131 +2385,85 @@ } /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ -/* Routine for the Compaq IOCTL commands. +/* Prototype Routine for the HP HOST INFO command. * * Outputs: None. * Return: 0 if successful - * -EBUSY if previous command timout and IOC reset is not complete. * -EFAULT if data unavailable - * -ENODEV if no such device/adapter - * -ETIME if timer expires - * -ENOMEM if memory allocation error - */ -static int -mptctl_compaq_ioctl(struct file *file, unsigned int cmd, unsigned long arg) -{ - int iocnum = 0; - unsigned iocnumX = 0; - int ret; - int nonblock = (file->f_flags & O_NONBLOCK); - MPT_ADAPTER *iocp = NULL; - - if (cmd == CPQFCTS_SCSI_PASSTHRU) { - /* Update the iocnum */ - if (copy_from_user(&iocnumX, (int *)arg, sizeof(int))) { - printk(KERN_ERR "%s::mptctl_compaq_ioctl() @%d - " - "Unable to read controller number @ %p\n", - __FILE__, __LINE__, (void*)arg); - return -EFAULT; - } - iocnumX &= 0xFF; - } - - if (((iocnum = mpt_verify_adapter(iocnumX, &iocp)) < 0) || - (iocp == NULL)) { - dtmprintk((KERN_ERR "%s::mptctl_compaq_ioctl() @%d - ioc%d not found!\n", - __FILE__, __LINE__, iocnumX)); - return -ENODEV; - } - - /* All of these commands require an interrupt or - * are unknown/illegal. - */ - if ((ret = mptctl_syscall_down(iocp, nonblock)) != 0) - return ret; - - dctlprintk((MYIOC_s_INFO_FMT ": mptctl_compaq_ioctl()\n", iocp->name)); - - switch(cmd) { - case CPQFCTS_GETPCIINFO: - ret = mptctl_cpq_getpciinfo(arg); - break; - case CPQFCTS_GETDRIVVER: - ret = mptctl_cpq_getdriver(arg); - break; - case CPQFCTS_CTLR_STATUS: - ret = mptctl_cpq_ctlr_status(arg); - break; - case CPQFCTS_SCSI_IOCTL_FC_TARGET_ADDRESS: - ret = mptctl_cpq_target_address(arg); - break; - case CPQFCTS_SCSI_PASSTHRU: - ret = mptctl_cpq_passthru(arg); - break; - default: - ret = -EINVAL; - } - - up(&mptctl_syscall_sem_ioc[iocp->id]); - - return ret; - -} - -/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ -/* mptctl_cpq_getpciinfo - Get PCI Information in format desired by Compaq - * - * Outputs: None. - * Return: 0 if successful * -EBUSY if previous command timout and IOC reset is not complete. - * -EFAULT if data unavailable * -ENODEV if no such device/adapter * -ETIME if timer expires + * -ENOMEM if memory allocation error */ static int -mptctl_cpq_getpciinfo(unsigned long arg) +mptctl_hp_hostinfo(unsigned long arg) { - cpqfc_pci_info_struct *uarg = (cpqfc_pci_info_struct *) arg; - cpqfc_pci_info_struct karg; + hp_host_info_t *uarg = (hp_host_info_t *) arg; MPT_ADAPTER *ioc; struct pci_dev *pdev; + char *pbuf; + dma_addr_t buf_dma; + hp_host_info_t karg; CONFIGPARMS cfg; ConfigPageHeader_t hdr; - int iocnum = 0, iocnumX = 0; - dma_addr_t buf_dma; - u8 *pbuf = NULL; - int failed; + int iocnum; + int rc; - dctlprintk((": mptctl_cpq_pciinfo called.\n")); - if (copy_from_user(&karg, uarg, sizeof(cpqfc_pci_info_struct))) { - printk(KERN_ERR "%s@%d::mptctl_cpq_pciinfo - " - "Unable to read in cpqfc_pci_info_struct @ %p\n", + dctlprintk((": mptctl_hp_hostinfo called.\n")); + if (copy_from_user(&karg, uarg, sizeof(hp_host_info_t))) { + printk(KERN_ERR "%s@%d::mptctl_hp_host_info - " + "Unable to read in hp_host_info struct @ %p\n", __FILE__, __LINE__, (void*)uarg); - return -EINVAL; + return -EFAULT; } - if (((iocnum = mpt_verify_adapter(iocnumX, &ioc)) < 0) || + if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) || (ioc == NULL)) { - dtmprintk((KERN_ERR "%s::mptctl_pciinfo() @%d - ioc%d not found!\n", + dctlprintk((KERN_ERR "%s::mptctl_hp_hostinfo() @%d - ioc%d not found!\n", __FILE__, __LINE__, iocnum)); return -ENODEV; } + /* Fill in the data and return the structure to the calling + * program + */ pdev = (struct pci_dev *) ioc->pcidev; - /* Populate the structure. */ - karg.bus = pdev->bus->number; - karg.bus_type = 1; /* 1 = PCI; 4 = unknown */ - karg.device_fn = PCI_FUNC(pdev->devfn); - karg.slot_number = PCI_SLOT(pdev->devfn); - karg.vendor_id = pdev->vendor; - karg.device_id = pdev->device; - karg.board_id = (karg.device_id | (karg.vendor_id << 16)); - karg.class_code = pdev->class; + karg.vendor = pdev->vendor; + karg.device = pdev->device; #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) - karg.sub_vendor_id = pdev->subsystem_vendor; - karg.sub_device_id = pdev->subsystem_device; + karg.subsystem_id = pdev->subsystem_device; + karg.subsystem_vendor = pdev->subsystem_vendor; #endif + karg.devfn = pdev->devfn; + karg.bus = pdev->bus->number; + + /* Save the SCSI host no. if + * SCSI driver loaded + */ + if (ioc->sh != NULL) + karg.host_no = ioc->sh->host_no; + else + karg.host_no = -1; + + /* Reformat the fw_version into a string + */ + karg.fw_version[0] = ioc->facts.FWVersion.Struct.Major >= 10 ? + ((ioc->facts.FWVersion.Struct.Major / 10) + '0') : '0'; + karg.fw_version[1] = (ioc->facts.FWVersion.Struct.Major % 10 ) + '0'; + karg.fw_version[2] = '.'; + karg.fw_version[3] = ioc->facts.FWVersion.Struct.Minor >= 10 ? + ((ioc->facts.FWVersion.Struct.Minor / 10) + '0') : '0'; + karg.fw_version[4] = (ioc->facts.FWVersion.Struct.Minor % 10 ) + '0'; + karg.fw_version[5] = '.'; + karg.fw_version[6] = ioc->facts.FWVersion.Struct.Unit >= 10 ? + ((ioc->facts.FWVersion.Struct.Unit / 10) + '0') : '0'; + karg.fw_version[7] = (ioc->facts.FWVersion.Struct.Unit % 10 ) + '0'; + karg.fw_version[8] = '.'; + karg.fw_version[9] = ioc->facts.FWVersion.Struct.Dev >= 10 ? + ((ioc->facts.FWVersion.Struct.Dev / 10) + '0') : '0'; + karg.fw_version[10] = (ioc->facts.FWVersion.Struct.Dev % 10 ) + '0'; + karg.fw_version[11] = '\0'; /* Issue a config request to get the device serial number */ @@ -2496,8 +2478,7 @@ cfg.dir = 0; /* read */ cfg.timeout = 10; - failed = 1; - + strncpy(karg.serial_number, " ", 24); if (mpt_config(ioc, &cfg) == 0) { if (cfg.hdr->PageLength > 0) { /* Issue the second config page request */ @@ -2508,242 +2489,207 @@ cfg.physAddr = buf_dma; if (mpt_config(ioc, &cfg) == 0) { ManufacturingPage0_t *pdata = (ManufacturingPage0_t *) pbuf; - strncpy(karg.serial_number, pdata->BoardTracerNumber, 17); - failed = 0; + if (strlen(pdata->BoardTracerNumber) > 1) + strncpy(karg.serial_number, pdata->BoardTracerNumber, 24); } pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, pbuf, buf_dma); pbuf = NULL; } } } - if (failed) - strncpy(karg.serial_number, " ", 17); - - /* Copy the data from kernel memory to user memory - */ - if (copy_to_user((char *)arg, &karg, - sizeof(cpqfc_pci_info_struct))) { - printk(KERN_ERR "%s@%d::mptctl_cpq_pciinfo - " - "Unable to write out cpqfc_pci_info_struct @ %p\n", - __FILE__, __LINE__, (void*)uarg); - return -EFAULT; - } + rc = mpt_GetIocState(ioc, 1); + switch (rc) { + case MPI_IOC_STATE_OPERATIONAL: + karg.ioc_status = HP_STATUS_OK; + break; - return 0; -} + case MPI_IOC_STATE_FAULT: + karg.ioc_status = HP_STATUS_FAILED; + break; -/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ -/* mptctl_cpq_getdriver - Get Driver Version in format desired by Compaq - * - * Outputs: None. - * Return: 0 if successful - * -EFAULT if data unavailable - * -ENODEV if no such device/adapter - */ -static int -mptctl_cpq_getdriver(unsigned long arg) -{ - int *uarg = (int *)arg; - int karg; - MPT_ADAPTER *ioc = NULL; - int iocnum = 0, iocnumX = 0; - int ii, jj; - char version[10]; - char val; - char *vptr = NULL; - char *pptr = NULL; - - dctlprintk((": mptctl_cpq_getdriver called.\n")); - if (copy_from_user(&karg, uarg, sizeof(int))) { - printk(KERN_ERR "%s@%d::mptctl_cpq_getdriver - " - "Unable to read in struct @ %p\n", - __FILE__, __LINE__, (void*)uarg); - return -EFAULT; + case MPI_IOC_STATE_RESET: + case MPI_IOC_STATE_READY: + default: + karg.ioc_status = HP_STATUS_OTHER; + break; } - if (((iocnum = mpt_verify_adapter(iocnumX, &ioc)) < 0) || - (ioc == NULL)) { - dtmprintk((KERN_ERR "%s::mptctl_cpq_getdriver() @%d - ioc%d not found!\n", - __FILE__, __LINE__, iocnum)); - return -ENODEV; - } + karg.base_io_addr = pdev->PCI_BASEADDR_START(0); - strncpy(version, MPT_LINUX_VERSION_COMMON, 8); + if ((int)ioc->chip_type <= (int) FC929) + karg.bus_phys_width = HP_BUS_WIDTH_UNK; + else + karg.bus_phys_width = HP_BUS_WIDTH_16; - karg = 0; - vptr = version; - ii = 3; - while (ii > 0) { - pptr = strchr(vptr, '.'); - if (pptr) { - *pptr = '\0'; - val = 0; - for (jj=0; vptr[jj]>='0' && vptr[jj]<='9'; jj++) - val = 10 * val + (vptr[jj] - '0'); - karg |= (val << (8*ii)); - pptr++; - vptr = pptr; - } else - break; - ii--; + karg.hard_resets = 0; + karg.soft_resets = 0; + karg.timeouts = 0; + if (ioc->sh != NULL) { + MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)ioc->sh->hostdata; + + if (hd) { + karg.hard_resets = hd->hard_resets; + karg.soft_resets = hd->soft_resets; + karg.timeouts = hd->timeouts; + } } /* Copy the data from kernel memory to user memory */ if (copy_to_user((char *)arg, &karg, - sizeof(int))) { - printk(KERN_ERR "%s@%d::mptctl_cpq_getdriver - " - "Unable to write out stuct @ %p\n", + sizeof(hp_host_info_t))) { + printk(KERN_ERR "%s@%d::mptctl_hpgethostinfo - " + "Unable to write out hp_host_info @ %p\n", __FILE__, __LINE__, (void*)uarg); return -EFAULT; } return 0; + } /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ -/* mptctl_cpq_ctlr_status - Get controller status in format desired by Compaq +/* Prototype Routine for the HP TARGET INFO command. * * Outputs: None. * Return: 0 if successful * -EFAULT if data unavailable + * -EBUSY if previous command timout and IOC reset is not complete. * -ENODEV if no such device/adapter + * -ETIME if timer expires + * -ENOMEM if memory allocation error */ static int -mptctl_cpq_ctlr_status(unsigned long arg) +mptctl_hp_targetinfo(unsigned long arg) { - cpqfc_ctlr_status *uarg = (cpqfc_ctlr_status *) arg; - cpqfc_ctlr_status karg; + hp_target_info_t *uarg = (hp_target_info_t *) arg; + SCSIDevicePage0_t *pg0_alloc; + SCSIDevicePage3_t *pg3_alloc; MPT_ADAPTER *ioc; - int iocnum = 0, iocnumX = 0; + MPT_SCSI_HOST *hd = NULL; + hp_target_info_t karg; + int iocnum; + int data_sz; + dma_addr_t page_dma; + CONFIGPARMS cfg; + ConfigPageHeader_t hdr; + int tmp, np, rc = 0; - dctlprintk((": mptctl_cpq_pciinfo called.\n")); - if (copy_from_user(&karg, uarg, sizeof(cpqfc_ctlr_status))) { - printk(KERN_ERR "%s@%d::mptctl_cpq_ctlr_status - " - "Unable to read in cpqfc_ctlr_status @ %p\n", + dctlprintk((": mptctl_hp_targetinfo called.\n")); + if (copy_from_user(&karg, uarg, sizeof(hp_target_info_t))) { + printk(KERN_ERR "%s@%d::mptctl_hp_targetinfo - " + "Unable to read in hp_host_targetinfo struct @ %p\n", __FILE__, __LINE__, (void*)uarg); return -EFAULT; } - - if (((iocnum = mpt_verify_adapter(iocnumX, &ioc)) < 0) || - (ioc == NULL)) { - dtmprintk((KERN_ERR "%s::mptctl_cpq_ctlr_status() @%d - ioc%d not found!\n", + + if (((iocnum = mpt_verify_adapter(karg.hdr.iocnum, &ioc)) < 0) || + (ioc == NULL)) { + dctlprintk((KERN_ERR "%s::mptctl_hp_targetinfo() @%d - ioc%d not found!\n", __FILE__, __LINE__, iocnum)); return -ENODEV; } - karg.status = ioc->last_state; - karg.offline_reason = 0; - - /* Copy the data from kernel memory to user memory + /* There is nothing to do for FCP parts. */ - if (copy_to_user((char *)arg, &karg, - sizeof(cpqfc_ctlr_status))) { - printk(KERN_ERR "%s@%d::mptctl_cpq_ctlr_status - " - "Unable to write out cpqfc_ctlr_status @ %p\n", - __FILE__, __LINE__, (void*)uarg); - return -EFAULT; - } - - return 0; -} + if ((int) ioc->chip_type <= (int) FC929) + return 0; -/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ -/* mptctl_cpq_target_address - Get WWN Information in format desired by Compaq - * - * Outputs: None. - * Return: 0 if successful - * -EBUSY if previous command timout and IOC reset is not complete. - * -EFAULT if data unavailable - * -ENODEV if no such device/adapter - * -ETIME if timer expires - */ -static int -mptctl_cpq_target_address(unsigned long arg) -{ - Scsi_FCTargAddress *uarg = (Scsi_FCTargAddress *) arg; - Scsi_FCTargAddress karg; - MPT_ADAPTER *ioc; - int iocnum = 0, iocnumX = 0; - CONFIGPARMS cfg; - ConfigPageHeader_t hdr; - dma_addr_t buf_dma; - u8 *pbuf = NULL; - FCPortPage0_t *ppp0; - int ii, failed; - u32 low, high; - - dctlprintk((": mptctl_cpq_target_address called.\n")); - if (copy_from_user(&karg, uarg, sizeof(Scsi_FCTargAddress))) { - printk(KERN_ERR "%s@%d::mptctl_cpq_target_address - " - "Unable to read in Scsi_FCTargAddress @ %p\n", - __FILE__, __LINE__, (void*)uarg); - return -EFAULT; - } + if ((ioc->spi_data.sdp0length == 0) || (ioc->sh == NULL)) + return 0; - if (((iocnum = mpt_verify_adapter(iocnumX, &ioc)) < 0) || - (ioc == NULL)) { - dtmprintk((KERN_ERR "%s::mptctl_cpq_target_address() @%d - ioc%d not found!\n", - __FILE__, __LINE__, iocnum)); + if (ioc->sh->host_no != karg.hdr.host) return -ENODEV; - } - - karg.host_port_id = 0; + + /* Get the data transfer speeds + */ + data_sz = ioc->spi_data.sdp0length * 4; + pg0_alloc = (SCSIDevicePage0_t *) pci_alloc_consistent(ioc->pcidev, data_sz, &page_dma); + if (pg0_alloc) { + hdr.PageVersion = ioc->spi_data.sdp0version; + hdr.PageLength = data_sz; + hdr.PageNumber = 0; + hdr.PageType = MPI_CONFIG_PAGETYPE_SCSI_DEVICE; + + cfg.hdr = &hdr; + cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT; + cfg.dir = 0; + cfg.timeout = 0; + cfg.physAddr = page_dma; + + cfg.pageAddr = (karg.hdr.channel << 8) | karg.hdr.id; + + if ((rc = mpt_config(ioc, &cfg)) == 0) { + np = le32_to_cpu(pg0_alloc->NegotiatedParameters); + karg.negotiated_width = np & MPI_SCSIDEVPAGE0_NP_WIDE ? + HP_BUS_WIDTH_16 : HP_BUS_WIDTH_8; + + if (np & MPI_SCSIDEVPAGE0_NP_NEG_SYNC_OFFSET_MASK) { + tmp = (np & MPI_SCSIDEVPAGE0_NP_NEG_SYNC_PERIOD_MASK) >> 8; + if (tmp < 0x09) + karg.negotiated_speed = HP_DEV_SPEED_ULTRA320; + else if (tmp <= 0x09) + karg.negotiated_speed = HP_DEV_SPEED_ULTRA160; + else if (tmp <= 0x0A) + karg.negotiated_speed = HP_DEV_SPEED_ULTRA2; + else if (tmp <= 0x0C) + karg.negotiated_speed = HP_DEV_SPEED_ULTRA; + else if (tmp <= 0x25) + karg.negotiated_speed = HP_DEV_SPEED_FAST; + else + karg.negotiated_speed = HP_DEV_SPEED_ASYNC; + } else + karg.negotiated_speed = HP_DEV_SPEED_ASYNC; + } + + pci_free_consistent(ioc->pcidev, data_sz, (u8 *) pg0_alloc, page_dma); + } + + /* Set defaults + */ + karg.message_rejects = -1; + karg.phase_errors = -1; + karg.parity_errors = -1; + karg.select_timeouts = -1; - /* Issue a config request to get the device wwn + /* Get the target error parameters */ hdr.PageVersion = 0; hdr.PageLength = 0; - hdr.PageNumber = 0; - hdr.PageType = MPI_CONFIG_PAGETYPE_FC_PORT; + hdr.PageNumber = 3; + hdr.PageType = MPI_CONFIG_PAGETYPE_SCSI_DEVICE; + cfg.hdr = &hdr; - cfg.physAddr = -1; - cfg.pageAddr = 0; cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER; - cfg.dir = 0; /* read */ - cfg.timeout = 10; - - failed = 1; - - if (mpt_config(ioc, &cfg) == 0) { - if (cfg.hdr->PageLength > 0) { - /* Issue the second config page request */ - cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT; - - pbuf = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4, &buf_dma); - if (pbuf) { - cfg.physAddr = buf_dma; - if (mpt_config(ioc, &cfg) == 0) { - ppp0 = (FCPortPage0_t *) pbuf; - - low = le32_to_cpu(ppp0->WWNN.Low); - high = le32_to_cpu(ppp0->WWNN.High); - - for (ii = 0; ii < 4; ii++) { - karg.host_wwn[7-ii] = low & 0xFF; - karg.host_wwn[3-ii] = high & 0xFF; - low = (low >> 8); - high = (high >> 8); - } - failed = 0; - } - pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, pbuf, buf_dma); - pbuf = NULL; + cfg.dir = 0; + cfg.timeout = 0; + cfg.physAddr = -1; + if ((mpt_config(ioc, &cfg) == 0) && (cfg.hdr->PageLength > 0)) { + /* Issue the second config page request */ + cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT; + data_sz = (int) cfg.hdr->PageLength * 4; + pg3_alloc = (SCSIDevicePage3_t *) pci_alloc_consistent( + ioc->pcidev, data_sz, &page_dma); + if (pg3_alloc) { + cfg.physAddr = page_dma; + cfg.pageAddr = (karg.hdr.channel << 8) | karg.hdr.id; + if ((rc = mpt_config(ioc, &cfg)) == 0) { + karg.message_rejects = (u32) le16_to_cpu(pg3_alloc->MsgRejectCount); + karg.phase_errors = (u32) le16_to_cpu(pg3_alloc->PhaseErrorCount); + karg.parity_errors = (u32) le16_to_cpu(pg3_alloc->ParityErrorCount); } + pci_free_consistent(ioc->pcidev, data_sz, (u8 *) pg3_alloc, page_dma); } } - - if (failed) { - for (ii = 7; ii >= 0; ii--) - karg.host_wwn[ii] = 0; - } + hd = (MPT_SCSI_HOST *) ioc->sh->hostdata; + if (hd != NULL) + karg.select_timeouts = hd->sel_timeout[karg.hdr.id]; /* Copy the data from kernel memory to user memory */ - if (copy_to_user((char *)arg, &karg, - sizeof(Scsi_FCTargAddress))) { - printk(KERN_ERR "%s@%d::mptctl_cpq_target_address - " - "Unable to write out Scsi_FCTargAddress @ %p\n", + if (copy_to_user((char *)arg, &karg, sizeof(hp_target_info_t))) { + printk(KERN_ERR "%s@%d::mptctl_hp_target_info - " + "Unable to write out mpt_ioctl_targetinfo struct @ %p\n", __FILE__, __LINE__, (void*)uarg); return -EFAULT; } @@ -2752,161 +2698,6 @@ } /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ -/* mptctl_cpq_passthru - Construct and issue a SCSI IO Passthru - * - * Requires the SCSI host driver to be loaded. - * I386 version. - * - * Outputs: None. - * Return: 0 if successful - * -EBUSY if previous command timout and IOC reset is not complete. - * -EFAULT if data unavailable - * -ENODEV if no such device/adapter - * -ETIME if timer expires - */ -static int -mptctl_cpq_passthru(unsigned long arg) -{ - VENDOR_IOCTL_REQ *uarg = (VENDOR_IOCTL_REQ *) arg; - VENDOR_IOCTL_REQ karg; - cpqfc_passthru_t kpass; - MPT_ADAPTER *ioc; - int iocnum = 0, iocnumX = 0; - int rc; - - dctlprintk((": mptctl_cpq_passthru called.\n")); - if (copy_from_user(&karg, uarg, sizeof(VENDOR_IOCTL_REQ))) { - printk(KERN_ERR "%s@%d::mptctl_cpq_passthru - " - "Unable to read in VENDOR_IOCTL_REQ @ %p\n", - __FILE__, __LINE__, (void*)uarg); - return -EFAULT; - } - - /* Set the IOC number */ - iocnumX = karg.lc & 0xFF; - if (((iocnum = mpt_verify_adapter(iocnumX, &ioc)) < 0) || - (ioc == NULL)) { - dtmprintk((KERN_ERR "%s::mptctl_cpq_passthru() @%d - ioc%d not found!\n", - __FILE__, __LINE__, iocnum)); - return -ENODEV; - } - - if (ioc->sh == NULL) { - printk(KERN_ERR "%s::mptctl_cpq_passthru() @%d - SCSI Host driver not loaded!\n", - __FILE__, __LINE__); - return -EFAULT; - } - - /* Read in the second buffer */ - if (copy_from_user(&kpass, uarg->argp, sizeof(cpqfc_passthru_t))) { - printk(KERN_ERR "%s@%d::mptctl_cpq_passthru - " - "Unable to read in cpqfc_passthru_t @ %p\n", - __FILE__, __LINE__, (void*)uarg); - return -EFAULT; - } - - - /* Generate the SCSI IO command and issue */ - rc = mptctl_compaq_scsiio(&karg, &kpass); - return rc; -} - -/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ -/* mptctl_compaq_scsiio - Reformat Compaq structures into driver structures - * Call the generic _do_mpt_command function. - * - * Requires the SCSI host driver to be loaded. - * I386 version. - * - * Outputs: None. - * Return: 0 if successful - * -EBUSY if previous command timout and IOC reset is not complete. - * -EFAULT if data unavailable - * -ENODEV if no such device/adapter - * -ETIME if timer expires - */ -static int -mptctl_compaq_scsiio(VENDOR_IOCTL_REQ *pVenReq, cpqfc_passthru_t *pPass) -{ - struct mpt_ioctl_command karg; - SCSIIORequest_t request ; - SCSIIORequest_t *pMf; - int ii, rc; - u8 opcode; - - /* Fill in parameters to karg */ - karg.hdr.iocnum = pVenReq->lc; - karg.hdr.port = 0; - karg.hdr.maxDataSize = 0; /* not used */ - karg.timeout = 0; /* use default */ - - karg.replyFrameBufPtr = NULL; /* no reply data */ - karg.maxReplyBytes = 0; - - karg.senseDataPtr = pPass->sense_data; - karg.maxSenseBytes = pPass->sense_len; /* max is 40 */ - - if (pPass->rw_flag == MPT_COMPAQ_WRITE) { - karg.dataOutBufPtr = pPass->bufp; - karg.dataOutSize = pPass->len; - karg.dataInBufPtr = NULL; - karg.dataInSize = 0; - } else { - karg.dataInBufPtr = pPass->bufp; - karg.dataInSize = pPass->len; - karg.dataOutBufPtr = NULL; - karg.dataOutSize = 0; - } - - karg.dataSgeOffset = (sizeof(SCSIIORequest_t) - sizeof(SGE_IO_UNION))/4; - - /* Construct the Message frame */ - pMf = &request; - - pMf->TargetID = (u8) pVenReq->ld; /* ???? FIXME */ - pMf->Bus = (u8) pPass->bus; - pMf->ChainOffset = 0; - pMf->Function = MPI_FUNCTION_SCSI_IO_REQUEST; - - /* May need some tweaking here */ - opcode = (u8) pPass->cdb[0]; - if (opcode < 0x20) - pMf->CDBLength = 6; - else if (opcode < 0x60) - pMf->CDBLength = 10; - else if ((opcode < 0xC0) && (opcode >= 0xA0)) - pMf->CDBLength = 12; - else - pMf->CDBLength = 16; - - pMf->SenseBufferLength = karg.maxSenseBytes; /* max is 40 */ - pMf->Reserved = 0; - pMf->MsgFlags = 0; /* set later */ - pMf->MsgContext = 0; /* set later */ - - for (ii = 0; ii < 8; ii++) - pMf->LUN[ii] = 0; - pMf->LUN[1] = 0; /* ???? FIXME */ - - /* Tag values set by _do_mpt_command */ - if (pPass->rw_flag == MPT_COMPAQ_WRITE) - pMf->Control = MPI_SCSIIO_CONTROL_WRITE; - else - pMf->Control = MPI_SCSIIO_CONTROL_READ; - - for (ii = 0; ii < 16; ii++) - pMf->CDB[ii] = pPass->cdb[ii]; - - pMf->DataLength = pPass->len; - - /* All remaining fields are set by the next function - */ - rc = mptctl_do_mpt_command (karg, (char *)pMf, 1); - return rc; -} - - -/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,51) #define owner_THIS_MODULE owner: THIS_MODULE, @@ -2971,7 +2762,7 @@ iocnumX = kfw32.iocnum & 0xFF; if (((iocnum = mpt_verify_adapter(iocnumX, &iocp)) < 0) || (iocp == NULL)) { - dtmprintk((KERN_ERR MYNAM "::sparc32_mptfwxfer_ioctl @%d - ioc%d not found!\n", + dctlprintk((KERN_ERR MYNAM "::sparc32_mptfwxfer_ioctl @%d - ioc%d not found!\n", __LINE__, iocnumX)); return -ENODEV; } @@ -3011,7 +2802,7 @@ iocnumX = karg32.hdr.iocnum & 0xFF; if (((iocnum = mpt_verify_adapter(iocnumX, &iocp)) < 0) || (iocp == NULL)) { - dtmprintk((KERN_ERR MYNAM "::sparc32_mpt_command @%d - ioc%d not found!\n", + dctlprintk((KERN_ERR MYNAM "::sparc32_mpt_command @%d - ioc%d not found!\n", __LINE__, iocnumX)); return -ENODEV; } @@ -3044,70 +2835,6 @@ return ret; } -static int -sparc32_mptctl_cpq_passthru(unsigned int fd, unsigned int cmd, - unsigned long arg, struct file *filp) -{ - VENDOR_IOCTL_REQ32 *uarg = (VENDOR_IOCTL_REQ32 *) arg; - VENDOR_IOCTL_REQ32 karg32; - VENDOR_IOCTL_REQ karg; - cpqfc_passthru32_t kpass32; - cpqfc_passthru_t kpass; - MPT_ADAPTER *ioc; - int nonblock = (filp->f_flags & O_NONBLOCK); - int iocnum = 0, iocnumX = 0; - int rc; - int ii; - - dctlprintk((KERN_INFO MYNAM "::sparc32_mptctl_cpq_passthru() called\n")); - - if (copy_from_user(&karg32, (char *)arg, sizeof(karg32))) - return -EFAULT; - - /* Verify intended MPT adapter */ - iocnumX = karg32.lc & 0xFF; - if (((iocnum = mpt_verify_adapter(iocnumX, &ioc)) < 0) || - (ioc == NULL)) { - dtmprintk((KERN_ERR MYNAM "::sparc32_mpt_command @%d - ioc%d not found!\n", - __LINE__, iocnumX)); - return -ENODEV; - } - - if ((rc = mptctl_syscall_down(ioc, nonblock)) != 0) - return rc; - - /* Copy data to karg */ - karg.ld = karg32.ld; - karg.node = karg32.node; - karg.lc = karg32.lc; - karg.nexus = karg32.nexus; - karg.argp = (void *)(unsigned long)karg32.argp; - - /* Read in the second buffer */ - if (copy_from_user(&kpass32, karg.argp, sizeof(cpqfc_passthru32_t))) { - printk(KERN_ERR "%s@%d::sparc32_mptctl_cpq_passthru - " - "Unable to read in cpqfc_passthru_t @ %p\n", - __FILE__, __LINE__, (void*)uarg); - return -EFAULT; - } - - /* Copy the 32bit buffer to kpass */ - for (ii = 0; ii < 16; ii++) - kpass.cdb[ii] = kpass32.cdb[ii]; - kpass.bus = kpass32.bus; - kpass.pdrive = kpass32.pdrive; - kpass.len = kpass32.len; - kpass.sense_len = kpass32.sense_len; - kpass.bufp = (void *)(unsigned long)kpass32.bufp; - kpass.rw_flag = kpass32.rw_flag; - - /* Generate the SCSI IO command and issue */ - rc = mptctl_compaq_scsiio(&karg, &kpass); - - up(&mptctl_syscall_sem_ioc[ioc->id]); - return rc; -} - #endif /*} linux >= 2.3.x */ #endif /*} sparc */ @@ -3176,15 +2903,9 @@ err = register_ioctl32_conversion(MPTFWDOWNLOAD32, sparc32_mptfwxfer_ioctl); if (++where && err) goto out_fail; - err = register_ioctl32_conversion(CPQFCTS_GETPCIINFO, NULL); - if (++where && err) goto out_fail; - err = register_ioctl32_conversion(CPQFCTS_CTLR_STATUS, NULL); - if (++where && err) goto out_fail; - err = register_ioctl32_conversion(CPQFCTS_GETDRIVVER, NULL); - if (++where && err) goto out_fail; - err = register_ioctl32_conversion(CPQFCTS_SCSI_IOCTL_FC_TARGET_ADDRESS, NULL); + err = register_ioctl32_conversion(HP_GETHOSTINFO, NULL); if (++where && err) goto out_fail; - err = register_ioctl32_conversion(CPQFCTS_SCSI_PASSTHRU32, sparc32_mptctl_cpq_passthru); + err = register_ioctl32_conversion(HP_GETTARGETINFO, NULL); if (++where && err) goto out_fail; #endif /*} linux >= 2.3.x */ #endif /*} sparc */ @@ -3233,11 +2954,8 @@ unregister_ioctl32_conversion(MPTHARDRESET); unregister_ioctl32_conversion(MPTCOMMAND32); unregister_ioctl32_conversion(MPTFWDOWNLOAD32); - unregister_ioctl32_conversion(CPQFCTS_GETPCIINFO); - unregister_ioctl32_conversion(CPQFCTS_GETDRIVVER); - unregister_ioctl32_conversion(CPQFCTS_CTLR_STATUS); - unregister_ioctl32_conversion(CPQFCTS_SCSI_IOCTL_FC_TARGET_ADDRESS); - unregister_ioctl32_conversion(CPQFCTS_SCSI_PASSTHRU32); + unregister_ioctl32_conversion(HP_GETHOSTINFO); + unregister_ioctl32_conversion(HP_GETTARGETINFO); #endif /*} linux >= 2.3.x */ #endif /*} sparc */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/drivers/message/fusion/mptctl.h linux.2.5.47-ac6/drivers/message/fusion/mptctl.h --- linux.2.5.47/drivers/message/fusion/mptctl.h 2002-10-31 14:57:19.000000000 +0000 +++ linux.2.5.47-ac6/drivers/message/fusion/mptctl.h 2002-11-13 01:12:10.000000000 +0000 @@ -20,7 +20,7 @@ * (mailto:sjralston1@netscape.net) * (mailto:Pam.Delaney@lsil.com) * - * $Id: mptctl.h,v 1.11 2002/10/03 13:10:13 pdelaney Exp $ + * $Id: mptctl.h,v 1.12 2002/10/17 20:15:58 pdelaney Exp $ */ /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /* @@ -310,95 +310,91 @@ #endif /*}*/ - /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ - /* - * COMPAQ Specific IOCTL Defines and Structures - */ +/* + * HP Specific IOCTL Defines and Structures + */ #define CPQFCTS_IOC_MAGIC 'Z' +#define HP_IOC_MAGIC 'Z' +#define HP_GETHOSTINFO _IOR(HP_IOC_MAGIC, 20, hp_host_info_t) +#define HP_GETTARGETINFO _IOR(HP_IOC_MAGIC, 21, hp_target_info_t) -#define CPQFCTS_GETPCIINFO _IOR(CPQFCTS_IOC_MAGIC, 1, cpqfc_pci_info_struct) -#define CPQFCTS_GETDRIVVER _IOR(CPQFCTS_IOC_MAGIC, 9, int) -#define CPQFCTS_CTLR_STATUS _IOR(CPQFCTS_IOC_MAGIC, 3, struct _cpqfc_ctlr_status) -#define CPQFCTS_SCSI_IOCTL_FC_TARGET_ADDRESS _IOR(CPQFCTS_IOC_MAGIC, 13, struct scsi_fctargaddress) -#define CPQFCTS_SCSI_PASSTHRU _IOWR(CPQFCTS_IOC_MAGIC, 11, VENDOR_IOCTL_REQ) -#if defined(__sparc__) && defined(__sparc_v9__) -#define CPQFCTS_SCSI_PASSTHRU32 _IOWR(CPQFCTS_IOC_MAGIC, 11, VENDOR_IOCTL_REQ32) -#endif - -typedef struct { - unsigned short bus; - unsigned short bus_type; - unsigned short device_fn; - u32 board_id; - u32 slot_number; - unsigned short vendor_id; - unsigned short device_id; - unsigned short class_code; - unsigned short sub_vendor_id; - unsigned short sub_device_id; - u8 serial_number[81]; -} cpqfc_pci_info_struct; - - -typedef struct scsi_fctargaddress { - unsigned int host_port_id; - u8 host_wwn[8]; /* WW Network Name */ -} Scsi_FCTargAddress; - -typedef struct _cpqfc_ctlr_status { - u32 status; - u32 offline_reason; -} cpqfc_ctlr_status; - - -/* Compaq SCSI I/O Passthru structures. +/* All HP IOCTLs must include this header */ -#define MPT_COMPAQ_READ 0x26 -#define MPT_COMPAQ_WRITE 0x27 - -typedef struct { - int lc; /* controller number */ - int node; /* node number */ - int ld; /* target logical id */ - u32 nexus; - void *argp; -} VENDOR_IOCTL_REQ; - -#if defined(__KERNEL__) && defined(__sparc__) && defined(__sparc_v9__) /*{*/ -typedef struct { - int lc; /* controller number */ - int node; /* node number */ - int ld; /* target logical id */ - u32 nexus; - u32 argp; -} VENDOR_IOCTL_REQ32; -#endif - -typedef struct { - char cdb[16]; /* cdb */ - unsigned short bus; /* bus number */ - unsigned short pdrive; /* physical drive */ - int len; /* data area size */ - int sense_len; /* sense size */ - char sense_data[40]; /* sense buffer */ - void *bufp; /* data buffer pointer */ - char rw_flag; -} cpqfc_passthru_t; - -#if defined(__KERNEL__) && defined(__sparc__) && defined(__sparc_v9__) /*{*/ -typedef struct { - char cdb[16]; /* cdb */ - unsigned short bus; /* bus number */ - unsigned short pdrive; /* physical drive */ - int len; /* data area size */ - int sense_len; /* sense size */ - char sense_data[40]; /* sense buffer */ - u32 bufp; /* data buffer pointer */ - char rw_flag; -} cpqfc_passthru32_t; -#endif +typedef struct _hp_header { + unsigned int iocnum; + unsigned int host; + unsigned int channel; + unsigned int id; + unsigned int lun; +} hp_header_t; + +/* + * Header: + * iocnum required (input) + * host ignored + * channe ignored + * id ignored + * lun ignored + */ +typedef struct _hp_host_info { + hp_header_t hdr; + u16 vendor; + u16 device; + u16 subsystem_vendor; + u16 subsystem_id; + u8 devfn; + u8 bus; + ushort host_no; /* SCSI Host number, if scsi driver not loaded*/ + u8 fw_version[16]; /* string */ + u8 serial_number[24]; /* string */ + u32 ioc_status; + u32 bus_phys_width; + u32 base_io_addr; + u32 rsvd; + unsigned long hard_resets; /* driver initiated resets */ + unsigned long soft_resets; /* ioc, external resets */ + unsigned long timeouts; /* num timeouts */ +} hp_host_info_t; + +/* + * Header: + * iocnum required (input) + * host required + * channel required (bus number) + * id required + * lun ignored + * + * All error values between 0 and 0xFFFF in size. + */ +typedef struct _hp_target_info { + hp_header_t hdr; + u32 parity_errors; + u32 phase_errors; + u32 select_timeouts; + u32 message_rejects; + u32 negotiated_speed; + u8 negotiated_width; + u8 rsvd[7]; /* 8 byte alignment */ +} hp_target_info_t; + +#define HP_STATUS_OTHER 1 +#define HP_STATUS_OK 2 +#define HP_STATUS_FAILED 3 + +#define HP_BUS_WIDTH_UNK 1 +#define HP_BUS_WIDTH_8 2 +#define HP_BUS_WIDTH_16 3 +#define HP_BUS_WIDTH_32 4 + +#define HP_DEV_SPEED_ASYNC 2 +#define HP_DEV_SPEED_FAST 3 +#define HP_DEV_SPEED_ULTRA 4 +#define HP_DEV_SPEED_ULTRA2 5 +#define HP_DEV_SPEED_ULTRA160 6 +#define HP_DEV_SPEED_SCSI1 7 +#define HP_DEV_SPEED_ULTRA320 8 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/drivers/message/fusion/mptlan.c linux.2.5.47-ac6/drivers/message/fusion/mptlan.c --- linux.2.5.47/drivers/message/fusion/mptlan.c 2002-10-31 14:57:19.000000000 +0000 +++ linux.2.5.47-ac6/drivers/message/fusion/mptlan.c 2002-11-13 01:12:10.000000000 +0000 @@ -26,7 +26,7 @@ * Copyright (c) 2000-2002 LSI Logic Corporation * Originally By: Noah Romer * - * $Id: mptlan.c,v 1.52 2002/05/06 13:45:07 sshirron Exp $ + * $Id: mptlan.c,v 1.53 2002/10/17 20:15:58 pdelaney Exp $ */ /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /* diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/drivers/message/fusion/mptlan.h linux.2.5.47-ac6/drivers/message/fusion/mptlan.h --- linux.2.5.47/drivers/message/fusion/mptlan.h 2002-10-31 15:05:01.000000000 +0000 +++ linux.2.5.47-ac6/drivers/message/fusion/mptlan.h 2002-11-13 01:12:10.000000000 +0000 @@ -8,7 +8,6 @@ #include #endif -#include #include #include // #include diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/drivers/message/fusion/mptscsih.c linux.2.5.47-ac6/drivers/message/fusion/mptscsih.c --- linux.2.5.47/drivers/message/fusion/mptscsih.c 2002-10-31 15:05:01.000000000 +0000 +++ linux.2.5.47-ac6/drivers/message/fusion/mptscsih.c 2002-11-17 00:27:50.000000000 +0000 @@ -26,7 +26,7 @@ * (mailto:sjralston1@netscape.net) * (mailto:Pam.Delaney@lsil.com) * - * $Id: mptscsih.c,v 1.102 2002/10/03 13:10:14 pdelaney Exp $ + * $Id: mptscsih.c,v 1.103 2002/10/17 20:15:59 pdelaney Exp $ */ /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /* @@ -78,6 +78,9 @@ #include /* notifier code */ #include "../../scsi/scsi.h" #include "../../scsi/hosts.h" +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,45) +#include "../../scsi/sd.h" +#endif #include "mptbase.h" #include "mptscsih.h" @@ -198,7 +201,7 @@ static int mptscsih_do_raid(MPT_SCSI_HOST *hd, u8 action, INTERNAL_CMD *io); static void mptscsih_domainValidation(void *hd); static int mptscsih_is_phys_disk(MPT_ADAPTER *ioc, int id); -static void mptscsih_qas_check(MPT_SCSI_HOST *hd); +static void mptscsih_qas_check(MPT_SCSI_HOST *hd, int id); static int mptscsih_doDv(MPT_SCSI_HOST *hd, int portnum, int target); static void mptscsih_dv_parms(MPT_SCSI_HOST *hd, DVPARAMETERS *dv,void *pPage); static void mptscsih_fillbuf(char *buffer, int size, int index, int width); @@ -399,6 +402,9 @@ case MPI_IOCSTATUS_SCSI_DEVICE_NOT_THERE: /* 0x0043 */ /* Spoof to SCSI Selection Timeout! */ sc->result = DID_NO_CONNECT << 16; + + if (hd->sel_timeout[pScsiReq->TargetID] < 0xFFFF) + hd->sel_timeout[pScsiReq->TargetID]++; break; case MPI_IOCSTATUS_SCSI_TASK_TERMINATED: /* 0x0048 */ @@ -1289,11 +1295,17 @@ #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,7) sh->max_sectors = MPT_SCSI_MAX_SECTORS; #endif -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,1) +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,1) || defined CONFIG_HIGHIO sh->highmem_io = 1; #endif sh->this_id = this->pfacts[portnum].PortSCSIID; +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,44) + /* OS entry to allow host drivers to force + * a queue depth on a per device basis. + */ + sh->select_queue_depths = mptscsih_select_queue_depths; +#endif /* Required entry. */ sh->unique_id = this->id; @@ -2546,14 +2558,13 @@ /* Isse the Task Mgmt request. */ + if (hd->hard_resets < -1) + hd->hard_resets++; rc = mptscsih_IssueTaskMgmt(hd, type, target, lun, ctx2abort, sleepFlag); if (rc) { -#ifdef MPT_SCSI_USE_NEW_EH - hd->tmState = TM_STATE_ERROR; -#endif printk(MYIOC_s_INFO_FMT "Issue of TaskMgmt failed!\n", hd->ioc->name); } else { - printk(MYIOC_s_INFO_FMT "Issue of TaskMgmt Successful!\n", hd->ioc->name); + dtmprintk((MYIOC_s_INFO_FMT "Issue of TaskMgmt Successful!\n", hd->ioc->name)); } } #ifdef DROP_TEST @@ -2681,7 +2692,6 @@ { MPT_SCSI_HOST *hd; MPT_FRAME_HDR *mf; - unsigned long flags; u32 ctx2abort; int scpnt_idx; @@ -2696,10 +2706,11 @@ return FAILED; } - printk(KERN_WARNING MYNAM ": %s: >> Attempting task abort! (sc=%p)\n", - hd->ioc->name, SCpnt); - printk(KERN_WARNING MYNAM ": %s: IOs outstanding = %d\n", - hd->ioc->name, atomic_read(&queue_depth)); + printk(KERN_WARNING MYNAM ": %s: >> Attempting task abort! (sc=%p, numIOs=%d)\n", + hd->ioc->name, SCpnt, atomic_read(&queue_depth)); + + if (hd->timeouts < -1) + hd->timeouts++; /* Find this command */ @@ -2753,11 +2764,9 @@ ctx2abort = mf->u.frame.hwhdr.msgctxu.MsgContext; hd->abortSCpnt = SCpnt; - if (mptscsih_TMHandler(hd, MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK, - SCpnt->target, SCpnt->lun, ctx2abort, CAN_SLEEP) - < 0 - || hd->tmState == TM_STATE_ERROR) { + SCpnt->target, SCpnt->lun, ctx2abort, NO_SLEEP) + < 0) { /* The TM request failed and the subsequent FW-reload failed! * Fatal error case. @@ -2765,14 +2774,6 @@ printk(MYIOC_s_WARN_FMT "Error issuing abort task! (sc=%p)\n", hd->ioc->name, SCpnt); - /* If command not found, do not do callback, - * just return failed. CHECKME - */ - if (hd->ScsiLookup[scpnt_idx] != NULL) { - SCpnt->result = STS_BUSY; - SCpnt->scsi_done(SCpnt); - } - /* We must clear our pending flag before clearing our state. */ hd->tmPending = 0; @@ -2780,34 +2781,8 @@ return FAILED; } + return FAILED; - /* Our task management request will either complete or time out. So we - * spin until tmPending is != 1. If tmState is set to TM_STATE_ERROR, - * we encountered an error executing the task management request. - */ - while (hd->tmPending == 1){ - set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(HZ/4); - } - spin_lock_irqsave(&hd->ioc->FreeQlock, flags); - if (hd->tmState == TM_STATE_ERROR){ - hd->tmState = TM_STATE_NONE; - spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags); - nehprintk((KERN_WARNING MYNAM ": %s: mptscsih_abort: " - "TM timeout error! (sc=%p)\n", - hd->ioc->name, - SCpnt)); - return FAILED; - } - hd->tmState = TM_STATE_NONE; - spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags); - - nehprintk((KERN_WARNING MYNAM ": %s: mptscsih_abort: " - "Abort was successful! (sc=%p)\n", - hd->ioc->name, - SCpnt)); - - return SUCCESS; } /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ @@ -2823,7 +2798,6 @@ mptscsih_dev_reset(Scsi_Cmnd * SCpnt) { MPT_SCSI_HOST *hd; - unsigned long flags; /* If we can't locate our host adapter structure, return FAILED status. */ @@ -2834,10 +2808,13 @@ return FAILED; } - printk(KERN_WARNING MYNAM ": %s: >> Attempting target reset! (sc=%p)\n", - hd->ioc->name, SCpnt); - printk(KERN_WARNING MYNAM ": %s: IOs outstanding = %d\n", - hd->ioc->name, atomic_read(&queue_depth)); + printk(KERN_WARNING MYNAM ": %s: >> Attempting target reset! (sc=%p, numIOs=%d)\n", + hd->ioc->name, SCpnt, atomic_read(&queue_depth)); + + /* Unsupported for SCSI. Suppored for FCP + */ + if (hd->is_spi) + return FAILED; /* Wait a fixed amount of time for the TM pending flag to be cleared. * If we time out, then we return a FAILED status to the caller. This @@ -2853,7 +2830,7 @@ } if (mptscsih_TMHandler(hd, MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET, - SCpnt->target, 0, 0, CAN_SLEEP) + SCpnt->target, 0, 0, NO_SLEEP) < 0){ /* The TM request failed and the subsequent FW-reload failed! * Fatal error case. @@ -2864,34 +2841,8 @@ hd->tmState = TM_STATE_NONE; return FAILED; } - - /* Our task management request will either complete or time out. So we - * spin until tmPending is != 1. If tmState is set to TM_STATE_ERROR, - * we encountered an error executing the task management request. - */ - while (hd->tmPending == 1){ - set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(HZ/4); - } - spin_lock_irqsave(&hd->ioc->FreeQlock, flags); - if (hd->tmState == TM_STATE_ERROR){ - hd->tmState = TM_STATE_NONE; - spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags); - nehprintk((KERN_WARNING MYNAM ": %s: mptscsih_dev_reset: " - "TM timeout error! (sc=%p)\n", - hd->ioc->name, - SCpnt)); - return FAILED; - } - hd->tmState = TM_STATE_NONE; - spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags); - - nehprintk((KERN_WARNING MYNAM ": %s: mptscsih_dev_reset: " - "Device reset was successful! (sc=%p)\n", - hd->ioc->name, - SCpnt)); - return SUCCESS; + } /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ @@ -2907,7 +2858,6 @@ mptscsih_bus_reset(Scsi_Cmnd * SCpnt) { MPT_SCSI_HOST *hd; - unsigned long flags; /* If we can't locate our host adapter structure, return FAILED status. */ @@ -2918,10 +2868,11 @@ return FAILED; } - printk(KERN_WARNING MYNAM ": %s: >> Attempting bus reset! (sc=%p)\n", - hd->ioc->name, SCpnt); - printk(KERN_WARNING MYNAM ": %s: IOs outstanding = %d\n", - hd->ioc->name, atomic_read(&queue_depth)); + printk(KERN_WARNING MYNAM ": %s: >> Attempting bus reset! (sc=%p, numIOs=%d)\n", + hd->ioc->name, SCpnt, atomic_read(&queue_depth)); + + if (hd->timeouts < -1) + hd->timeouts++; /* Wait a fixed amount of time for the TM pending flag to be cleared. * If we time out, then we return a FAILED status to the caller. This @@ -2932,13 +2883,13 @@ nehprintk((KERN_WARNING MYNAM ": %s: mptscsih_bus_reset: " "Timed out waiting for previous TM to complete! " "(sc = %p)\n", - hd->ioc->name, SCpnt ) ); + hd->ioc->name, SCpnt)); return FAILED; } /* We are now ready to execute the task management request. */ if (mptscsih_TMHandler(hd, MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS, - 0, 0, 0, CAN_SLEEP) + 0, 0, 0, NO_SLEEP) < 0){ /* The TM request failed and the subsequent FW-reload failed! @@ -2952,32 +2903,6 @@ return FAILED; } - /* Our task management request will either complete or time out. So we - * spin until tmPending is != 1. If tmState is set to TM_STATE_ERROR, - * we encountered an error executing the task management request. - */ - while (hd->tmPending == 1){ - set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(HZ/4); - } - spin_lock_irqsave(&hd->ioc->FreeQlock, flags); - if (hd->tmState == TM_STATE_ERROR){ - hd->tmState = TM_STATE_NONE; - spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags); - nehprintk((KERN_WARNING MYNAM ": %s: mptscsih_bus_reset: " - "TM timeout error! (sc=%p)\n", - hd->ioc->name, - SCpnt)); - return FAILED; - } - hd->tmState = TM_STATE_NONE; - spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags); - - nehprintk((KERN_WARNING MYNAM ": %s: mptscsih_bus_reset: " - "Bus reset was successful! (sc=%p)\n", - hd->ioc->name, - SCpnt)); - return SUCCESS; } @@ -3013,7 +2938,7 @@ /* If our attempts to reset the host failed, then return a failed * status. The host will be taken off line by the SCSI mid-layer. */ - if (mpt_HardResetHandler(hd->ioc, CAN_SLEEP) < 0){ + if (mpt_HardResetHandler(hd->ioc, NO_SLEEP) < 0){ status = FAILED; } else { /* Make sure TM pending is cleared and TM state is set to @@ -3056,9 +2981,7 @@ break; } spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags); - set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(HZ/4); - + mdelay(250); } while (--loop_count); return status; @@ -3093,6 +3016,9 @@ return SCSI_ABORT_NOT_RUNNING; } + if (hd->timeouts < -1) + hd->timeouts++; + if ((scpnt_idx = SCPNT_TO_LOOKUP_IDX(SCpnt)) < 0) { /* Cmd not found in ScsiLookup. * If found in doneQ, delete from Q. @@ -3166,7 +3092,7 @@ SCpnt->host_scribble = (u8 *) MPT_INDEX_2_MFPTR (hd->ioc, scpnt_idx); /* For the time being, force bus reset on any abort - * requests for the 1030 FW. + * requests for the 1030/1035 FW. */ if (hd->is_spi) mf->u.frame.linkage.arg1 = MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS; @@ -3226,6 +3152,9 @@ return SCSI_RESET_SUCCESS; } + if (hd->timeouts < -1) + hd->timeouts++; + if ((scpnt_idx = SCPNT_TO_LOOKUP_IDX(SCpnt)) < 0) { /* Cmd not found in ScsiLookup. * If found in doneQ, delete from Q. @@ -3583,9 +3512,6 @@ } } } -#ifdef MPT_SCSI_USE_NEW_EH - hd->tmState = TM_STATE_ERROR; -#endif } else { dtmprintk((KERN_INFO " SCSI TaskMgmt SUCCESS!\n")); @@ -3629,6 +3555,9 @@ spin_lock_irqsave(&ioc->FreeQlock, flags); hd->tmPending = 0; spin_unlock_irqrestore(&ioc->FreeQlock, flags); +#ifdef MPT_SCSI_USE_NEW_EH + hd->tmState = TM_STATE_NONE; +#endif return 1; } @@ -3638,14 +3567,18 @@ * This is anyones guess quite frankly. */ int -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,44) +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,45) mptscsih_bios_param(struct scsi_device * sdev, struct block_device *bdev, sector_t capacity, int *ip) { +#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,28) +mptscsih_bios_param(Disk * disk, struct block_device *bdev, int *ip) +{ + sector_t capacity = disk->capacity; #else mptscsih_bios_param(Disk * disk, kdev_t dev, int *ip) { - sector_t capacity = disk->capacity; + unsigned capacity = disk->capacity; #endif int size; @@ -3666,20 +3599,63 @@ * Called once per device the bus scan. Use it to force the queue_depth * member to 1 if a device does not support Q tags. */ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,44) int mptscsih_slave_attach(Scsi_Device *device) { + struct Scsi_Host *host = device->host; VirtDevice *pTarget; - pTarget = device->hostdata; - if (!device->tagged_supported || - !(pTarget->tflags & MPT_TARGET_FLAGS_Q_YES)) { - scsi_adjust_queue_depth(device, 0, 1); - } else { - scsi_adjust_queue_depth(device, MSG_SIMPLE_TAG, - device->host->can_queue >> 1); + MPT_SCSI_HOST *hd; + + hd = (MPT_SCSI_HOST *)host->hostdata; + if (hd && (hd->Targets != NULL)) { + pTarget = hd->Targets[device->id]; + if (pTarget) { + if (!device->tagged_supported || + !(pTarget->tflags & MPT_TARGET_FLAGS_Q_YES)) { + scsi_adjust_queue_depth(device, 0, 1); + } else { + scsi_adjust_queue_depth(device, MSG_SIMPLE_TAG, + device->host->can_queue >> 1); + } + } } return 0; } +#else /* LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,44) */ +void +mptscsih_select_queue_depths(struct Scsi_Host *sh, Scsi_Device *sdList) +{ + struct scsi_device *device; + VirtDevice *pTarget; + MPT_SCSI_HOST *hd; + int ii, max; + + for (device = sdList; device != NULL; device = device->next) { + + if (device->host != sh) + continue; + + hd = (MPT_SCSI_HOST *) sh->hostdata; + if (hd == NULL) + continue; + + if (hd->Targets != NULL) { + if (hd->is_spi) + max = MPT_MAX_SCSI_DEVICES; + else + max = MPT_MAX_FC_DEVICES<256 ? MPT_MAX_FC_DEVICES : 255; + + for (ii=0; ii < max; ii++) { + pTarget = hd->Targets[ii]; + if (pTarget && !(pTarget->tflags & MPT_TARGET_FLAGS_Q_YES)) { + device->queue_depth = 1; + } + } + } + } +} +#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,44) */ /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /* @@ -4126,6 +4102,9 @@ spin_unlock_irqrestore(&ioc->FreeQlock, flags); hd->resetPending = 0; hd->numTMrequests = 0; +#ifdef MPT_SCSI_USE_NEW_EH + hd->tmState = TM_STATE_NONE; +#endif /* 6. If there was an internal command, * wake this process up. @@ -4167,10 +4146,13 @@ /* FIXME! */ break; case MPI_EVENT_IOC_BUS_RESET: /* 04 */ - /* FIXME! */ - break; case MPI_EVENT_EXT_BUS_RESET: /* 05 */ - /* FIXME! */ + hd = NULL; + if (ioc->sh) { + hd = (MPT_SCSI_HOST *) ioc->sh->hostdata; + if (hd && (hd->is_spi) && (hd->soft_resets < -1)) + hd->soft_resets++; + } break; case MPI_EVENT_LOGOUT: /* 09 */ /* FIXME! */ @@ -4804,9 +4786,10 @@ } if (vdev) { - if (hd->ioc->spi_data.isRaid & (1 << target_id)) + if (hd->ioc->spi_data.isRaid & (1 << target_id)) { vdev->raidVolume = 1; - else + ddvtprintk((KERN_INFO "RAID Volume @ id %d\n", target_id)); + } else vdev->raidVolume = 0; } @@ -4868,6 +4851,8 @@ u8 version, nfactor; u8 noQas = 1; + ddvtprintk((KERN_INFO "set Target: (id %d) byte56 0x%x\n", id, byte56)); + /* Set flags based on Inquiry data */ if (target->tflags & MPT_TARGET_FLAGS_VALID_INQUIRY) { @@ -4886,12 +4871,18 @@ */ if ((byte56 & 0x04) == 0) factor = MPT_ULTRA2; + else if ((byte56 & 0x03) == 0) + factor = MPT_ULTRA160; else factor = MPT_ULTRA320; - /* bit 1 QAS support, non-raid only + /* If RAID, never disable QAS + * else if non RAID, do not disable + * QAS if bit 1 is set + * bit 1 QAS support, non-raid only + * bit 0 IU support */ - if ((target->raidVolume == 0) && (byte56 & 0x02) != 0) + if ((target->raidVolume == 1) || ((byte56 & 0x02) != 0)) noQas = 0; offset = pspi_data->maxSyncOffset; @@ -4976,6 +4967,7 @@ VirtDevice *vdev; int ii; + ddvtprintk((KERN_INFO "Disabling QAS!\n")); pspi_data->noQas = MPT_TARGET_NO_NEGO_QAS; for (ii = 0; ii < id; ii++) { vdev = hd->Targets[id]; @@ -5204,6 +5196,17 @@ //negoFlags = MPT_TARGET_NO_NEGO_SYNC; } +#ifndef MPTSCSIH_DISABLE_DOMAIN_VALIDATION + /* Force to async and narrow if DV has not been executed + * for this ID + */ + if ((hd->ioc->spi_data.dvStatus[id] & MPT_SCSICFG_DV_NOT_DONE) != 0) { + width = 0; + factor = MPT_ASYNC; + offset = 0; + } +#endif + /* If id is not a raid volume, get the updated * transmission settings from the target structure. */ @@ -5313,13 +5316,6 @@ */ del_timer(&hd->TMtimer); -#ifdef MPT_SCSI_USE_NEW_EH - /* Set the error flag to 1 so that the function that started the - * task management request knows it timed out. - */ - hd->tmState = TM_STATE_ERROR; -#endif - /* Call the reset handler. Already had a TM request * timeout - so issue a diagnostic reset */ @@ -5853,6 +5849,12 @@ else pScsiReq->Control = cpu_to_le32(dir | MPI_SCSIIO_CONTROL_UNTAGGED); + if (cmd == CMD_RequestSense) { + pScsiReq->Control = cpu_to_le32(dir | MPI_SCSIIO_CONTROL_UNTAGGED); + ddvprintk((MYIOC_s_INFO_FMT "Untagged! 0x%2x\n", + hd->ioc->name, cmd)); + } + for (ii=0; ii < 16; ii++) pScsiReq->CDB[ii] = CDB[ii]; @@ -6184,7 +6186,7 @@ post_pendingQ_commands(hd); if (hd->ioc->spi_data.noQas) - mptscsih_qas_check(hd); + mptscsih_qas_check(hd, id); } } } @@ -6218,7 +6220,7 @@ /* Write SDP1 if no QAS has been enabled */ -static void mptscsih_qas_check(MPT_SCSI_HOST *hd) +static void mptscsih_qas_check(MPT_SCSI_HOST *hd, int id) { VirtDevice *pTarget = NULL; int ii; @@ -6227,6 +6229,9 @@ return; for (ii=0; ii < MPT_MAX_SCSI_DEVICES; ii++) { + if (ii == id) + continue; + if ((hd->ioc->spi_data.dvStatus[ii] & MPT_SCSICFG_DV_NOT_DONE) != 0) continue; @@ -6510,6 +6515,7 @@ rc = hd->pLocal->completion; if ((rc == MPT_SCANDV_GOOD) || (rc == MPT_SCANDV_SENSE)) { dv.max.width = 0; + doFallback = 0; } else goto target_done; } @@ -7059,6 +7065,10 @@ dv.cmd = MPT_SAVE; mptscsih_dv_parms(hd, &dv, (void *)pcfg1Data); +#if 0 + /* Double writes to SDP1 can cause problems, + * skip here since unnecessary + */ /* Save the final negotiated settings to * SCSI device page 1. */ @@ -7067,13 +7077,14 @@ cfg.action = MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT; cfg.dir = 1; mpt_config(hd->ioc, &cfg); +#endif } /* If this is a RAID Passthrough, enable internal IOs */ if (iocmd.flags & MPT_ICFLAG_PHYS_DISK) { if (mptscsih_do_raid(hd, MPI_RAID_ACTION_ENABLE_PHYS_IO, &iocmd) < 0) - ddvprintk((MYIOC_s_ERR_FMT "RAID Queisce FAILED!\n", ioc->name)); + ddvprintk((MYIOC_s_ERR_FMT "RAID Enable FAILED!\n", ioc->name)); } /* Done with the DV scan of the current target @@ -7227,8 +7238,7 @@ pPage1->Configuration = le32_to_cpu(configuration); } ddvprintk(("width %d, factor %x, offset %x request %x config %x\n", - dv->now.width, dv->now.factor, - dv->now.offset, val, configuration)); + width, factor, offset, val, configuration)); break; case MPT_FALLBACK: diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/drivers/message/fusion/mptscsih.h linux.2.5.47-ac6/drivers/message/fusion/mptscsih.h --- linux.2.5.47/drivers/message/fusion/mptscsih.h 2002-10-31 15:05:01.000000000 +0000 +++ linux.2.5.47-ac6/drivers/message/fusion/mptscsih.h 2002-11-17 00:27:50.000000000 +0000 @@ -20,7 +20,7 @@ * (mailto:netscape.net) * (mailto:Pam.Delaney@lsil.com) * - * $Id: mptscsih.h,v 1.19 2002/10/03 13:10:15 pdelaney Exp $ + * $Id: mptscsih.h,v 1.20 2002/10/17 20:16:00 pdelaney Exp $ */ /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /* @@ -206,12 +206,15 @@ #define x_scsi_dev_reset mptscsih_dev_reset #define x_scsi_host_reset mptscsih_host_reset #define x_scsi_bios_param mptscsih_bios_param -#define x_scsi_slave_attach mptscsih_slave_attach #define x_scsi_taskmgmt_bh mptscsih_taskmgmt_bh #define x_scsi_old_abort mptscsih_old_abort #define x_scsi_old_reset mptscsih_old_reset +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,44) #define x_scsi_slave_attach mptscsih_slave_attach +#else +#define x_scsi_select_queue_depths mptscsih_select_queue_depths +#endif /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ /* @@ -230,14 +233,20 @@ extern int x_scsi_old_abort(Scsi_Cmnd *); extern int x_scsi_old_reset(Scsi_Cmnd *, unsigned int); #endif -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,28) +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,45) +extern int x_scsi_bios_param(struct scsi_device * sdev, struct block_device *bdev, + sector_t capacity, int *ip); +#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,28) extern int x_scsi_bios_param(Disk *, struct block_device *, int *); #else extern int x_scsi_bios_param(Disk *, kdev_t, int *); #endif -extern int x_scsi_slave_attach(Scsi_Device *); extern void x_scsi_taskmgmt_bh(void *); +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,44) extern int x_scsi_slave_attach(Scsi_Device *); +#else +extern void x_scsi_select_queue_depths(struct Scsi_Host *, Scsi_Device *); +#endif #if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0) #define PROC_SCSI_DECL @@ -247,7 +256,7 @@ #ifdef MPT_SCSI_USE_NEW_EH -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,1) +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,44) #define MPT_SCSIHOST { \ PROC_SCSI_DECL \ @@ -255,8 +264,35 @@ .detect = x_scsi_detect, \ .release = x_scsi_release, \ .info = x_scsi_info, \ + .command = NULL, \ .queuecommand = x_scsi_queuecommand, \ .slave_attach = x_scsi_slave_attach, \ + .eh_strategy_handler = NULL, \ + .eh_abort_handler = x_scsi_abort, \ + .eh_device_reset_handler = x_scsi_dev_reset, \ + .eh_bus_reset_handler = x_scsi_bus_reset, \ + .eh_host_reset_handler = x_scsi_host_reset, \ + .bios_param = x_scsi_bios_param, \ + .can_queue = MPT_SCSI_CAN_QUEUE, \ + .this_id = -1, \ + .sg_tablesize = MPT_SCSI_SG_DEPTH, \ + .max_sectors = MPT_SCSI_MAX_SECTORS, \ + .cmd_per_lun = MPT_SCSI_CMD_PER_LUN, \ + .unchecked_isa_dma = 0, \ + .use_clustering = ENABLE_CLUSTERING, \ +} + +#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,1) + +#define MPT_SCSIHOST { \ + PROC_SCSI_DECL \ + .name = "MPT SCSI Host", \ + .detect = x_scsi_detect, \ + .release = x_scsi_release, \ + .info = x_scsi_info, \ + .command = NULL, \ + .queuecommand = x_scsi_queuecommand, \ + .eh_strategy_handler = NULL, \ .eh_abort_handler = x_scsi_abort, \ .eh_device_reset_handler = x_scsi_dev_reset, \ .eh_bus_reset_handler = x_scsi_bus_reset, \ @@ -267,27 +303,32 @@ .sg_tablesize = MPT_SCSI_SG_DEPTH, \ .max_sectors = MPT_SCSI_MAX_SECTORS, \ .cmd_per_lun = MPT_SCSI_CMD_PER_LUN, \ + .unchecked_isa_dma = 0, \ .use_clustering = ENABLE_CLUSTERING, \ - .slave_attach x_scsi_slave_attach, \ } #else /* LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,1) */ #define MPT_SCSIHOST { \ + .next = NULL, \ PROC_SCSI_DECL \ .name = "MPT SCSI Host", \ .detect = x_scsi_detect, \ .release = x_scsi_release, \ .info = x_scsi_info, \ + .command = NULL, \ .queuecommand = x_scsi_queuecommand, \ + .eh_strategy_handler = NULL, \ .eh_abort_handler = x_scsi_abort, \ .eh_device_reset_handler = x_scsi_dev_reset, \ .eh_bus_reset_handler = x_scsi_bus_reset, \ + .eh_host_reset_handler = NULL, \ .bios_param = x_scsi_bios_param, \ .can_queue = MPT_SCSI_CAN_QUEUE, \ .this_id = -1, \ .sg_tablesize = MPT_SCSI_SG_DEPTH, \ .cmd_per_lun = MPT_SCSI_CMD_PER_LUN, \ + .unchecked_isa_dma = 0, \ .use_clustering = ENABLE_CLUSTERING, \ .use_new_eh_code = 1 \ } @@ -297,11 +338,13 @@ #else /* MPT_SCSI_USE_NEW_EH */ #define MPT_SCSIHOST { \ + .next = NULL, \ PROC_SCSI_DECL \ .name = "MPT SCSI Host", \ .detect = x_scsi_detect, \ .release = x_scsi_release, \ .info = x_scsi_info, \ + .command = NULL, \ .queuecommand = x_scsi_queuecommand, \ .abort = x_scsi_old_abort, \ .reset = x_scsi_old_reset, \ @@ -310,6 +353,7 @@ .this_id = -1, \ .sg_tablesize = MPT_SCSI_SG_DEPTH, \ .cmd_per_lun = MPT_SCSI_CMD_PER_LUN, \ + .unchecked_isa_dma = 0, \ .use_clustering = ENABLE_CLUSTERING \ } #endif /* MPT_SCSI_USE_NEW_EH */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/drivers/message/i2o/i2o_block.c linux.2.5.47-ac6/drivers/message/i2o/i2o_block.c --- linux.2.5.47/drivers/message/i2o/i2o_block.c 2002-10-31 15:05:01.000000000 +0000 +++ linux.2.5.47-ac6/drivers/message/i2o/i2o_block.c 2002-11-02 21:48:00.000000000 +0000 @@ -1669,7 +1669,6 @@ if(i2o_install_handler(&i2o_block_handler)<0) { unregister_blkdev(MAJOR_NR, "i2o_block"); - blk_cleanup_queue(BLK_DEFAULT_QUEUE(MAJOR_NR)); printk(KERN_ERR "i2o_block: unable to register OSM.\n"); return -EINVAL; } @@ -1682,8 +1681,7 @@ evt_pid = kernel_thread(i2ob_evt, NULL, CLONE_SIGHAND); if(evt_pid < 0) { - printk(KERN_ERR - "i2o_block: Could not initialize event thread. Aborting\n"); + printk(KERN_ERR "i2o_block: Could not initialize event thread. Aborting\n"); i2o_remove_handler(&i2o_block_handler); return 0; } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/drivers/message/i2o/i2o_scsi.c linux.2.5.47-ac6/drivers/message/i2o/i2o_scsi.c --- linux.2.5.47/drivers/message/i2o/i2o_scsi.c 2002-10-31 15:05:01.000000000 +0000 +++ linux.2.5.47-ac6/drivers/message/i2o/i2o_scsi.c 2002-11-02 23:58:17.000000000 +0000 @@ -57,7 +57,6 @@ #include #include "../../scsi/scsi.h" #include "../../scsi/hosts.h" -#include "../../scsi/sd.h" #if BITS_PER_LONG == 64 #error FIXME: driver does not support 64-bit platforms @@ -918,6 +917,7 @@ unsigned long msg; u32 m; int tid; + unsigned long timeout; printk(KERN_WARNING "i2o_scsi: Aborting command block.\n"); @@ -930,21 +930,21 @@ return FAILED; } c = hostdata->controller; - - /* - * Obtain an I2O message. Right now we _have_ to obtain one - * until the scsi layer stuff is cleaned up. - * - * FIXME: we are in error context so we could sleep retry - * a bit and then bail in the improved scsi layer. - */ - + + spin_unlock_irq(host->host_lock); + + timeout = jiffies+2*HZ; do { - mb(); m = le32_to_cpu(I2O_POST_READ32(c)); + if(m != 0xFFFFFFFF) + break; + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout(1); + mb(); } - while(m==0xFFFFFFFF); + while(time_before(jiffies, timeout)); + msg = c->mem_offset + m; i2o_raw_writel(FIVE_WORD_MSG_SIZE, msg); @@ -955,6 +955,8 @@ wmb(); i2o_post_message(c,m); wmb(); + + spin_lock_irq(host->host_lock); return SUCCESS; } @@ -977,14 +979,20 @@ struct i2o_scsi_host *hostdata; u32 m; unsigned long msg; + unsigned long timeout; + /* * Find the TID for the bus */ - printk(KERN_WARNING "i2o_scsi: Attempting to reset the bus.\n"); host = SCpnt->host; + + spin_unlock_irq(host->host_lock); + + printk(KERN_WARNING "i2o_scsi: Attempting to reset the bus.\n"); + hostdata = (struct i2o_scsi_host *)host->hostdata; tid = hostdata->bus_task; c = hostdata->controller; @@ -994,15 +1002,19 @@ * will be aborted by the IOP. We need to catch the reply * possibly ? */ - - m = le32_to_cpu(I2O_POST_READ32(c)); + + timeout = jiffies+2*HZ; + do + { + m = le32_to_cpu(I2O_POST_READ32(c)); + if(m != 0xFFFFFFFF) + break; + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout(1); + mb(); + } + while(time_before(jiffies, timeout)); - /* - * No free messages, try again next time - no big deal - */ - - if(m == 0xFFFFFFFF) - return SCSI_RESET_PUNT; msg = c->mem_offset + m; i2o_raw_writel(FOUR_WORD_MSG_SIZE|SGL_OFFSET_0, msg); @@ -1012,7 +1024,12 @@ /* Now store unit,tid so we can tie the completion back to a specific device */ __raw_writel(c->unit << 16 | tid, msg+12); wmb(); + + /* We want the command to complete after we return */ + spin_lock_irq(host->host_lock); i2o_post_message(c,m); + + /* Should we wait for the reset to complete ? */ return SUCCESS; } @@ -1044,8 +1061,9 @@ /** * i2o_scsi_bios_param - Invent disk geometry - * @disk: device + * @sdev: scsi device * @dev: block layer device + * @capacity: size in sectors * @ip: geometry array * * This is anyones guess quite frankly. We use the same rules everyone diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/drivers/net/hamradio/baycom_epp.c linux.2.5.47-ac6/drivers/net/hamradio/baycom_epp.c --- linux.2.5.47/drivers/net/hamradio/baycom_epp.c 2002-10-31 15:05:01.000000000 +0000 +++ linux.2.5.47-ac6/drivers/net/hamradio/baycom_epp.c 2002-11-11 19:55:15.000000000 +0000 @@ -54,7 +54,6 @@ #include #include #include -#include #if defined(CONFIG_AX25) || defined(CONFIG_AX25_MODULE) /* prototypes for ax25_encapsulate and ax25_rebuild_header */ #include @@ -1200,7 +1199,6 @@ struct baycom_state *bc; struct baycom_ioctl bi; struct hdlcdrv_ioctl hi; - struct sm_ioctl si; baycom_paranoia_check(dev, "baycom_ioctl", -EINVAL); bc = (struct baycom_state *)dev->priv; @@ -1208,28 +1206,6 @@ return -ENOIOCTLCMD; if (get_user(cmd, (int *)ifr->ifr_data)) return -EFAULT; -#ifdef BAYCOM_DEBUG - if (cmd == BAYCOMCTL_GETDEBUG) { - bi.data.dbg.debug1 = bc->ptt_keyed; - bi.data.dbg.debug2 = bc->debug_vals.last_intcnt; - bi.data.dbg.debug3 = bc->debug_vals.last_pllcorr; - bc->debug_vals.last_intcnt = 0; - if (copy_to_user(ifr->ifr_data, &bi, sizeof(bi))) - return -EFAULT; - return 0; - } - if (cmd == SMCTL_GETDEBUG) { - si.data.dbg.int_rate = bc->debug_vals.last_intcnt; - si.data.dbg.mod_cycles = bc->debug_vals.mod_cycles; - si.data.dbg.demod_cycles = bc->debug_vals.demod_cycles; - si.data.dbg.dma_residue = 0; - bc->debug_vals.mod_cycles = bc->debug_vals.demod_cycles = 0; - bc->debug_vals.last_intcnt = 0; - if (copy_to_user(ifr->ifr_data, &si, sizeof(si))) - return -EFAULT; - return 0; - } -#endif /* BAYCOM_DEBUG */ if (copy_from_user(&hi, ifr->ifr_data, sizeof(hi))) return -EFAULT; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/drivers/net/hamradio/dmascc.c linux.2.5.47-ac6/drivers/net/hamradio/dmascc.c --- linux.2.5.47/drivers/net/hamradio/dmascc.c 2002-10-31 14:57:01.000000000 +0000 +++ linux.2.5.47-ac6/drivers/net/hamradio/dmascc.c 2002-11-19 00:21:19.000000000 +0000 @@ -235,6 +235,8 @@ int state; unsigned long tx_start; int rr0; + spinlock_t *register_lock; /* Per scc_info */ + spinlock_t ring_lock; }; struct scc_info { @@ -243,6 +245,7 @@ struct net_device dev[2]; struct scc_priv priv[2]; struct scc_info *next; + spinlock_t register_lock; /* Per device register lock */ }; @@ -371,7 +374,7 @@ /* Cards found = 0 */ n = 0; /* Warning message */ - if (!io[0]) printk("dmascc: autoprobing (dangerous)\n"); + if (!io[0]) printk(KERN_INFO "dmascc: autoprobing (dangerous)\n"); /* Run autodetection for each card type */ for (h = 0; h < NUM_TYPES; h++) { @@ -456,7 +459,7 @@ if (n) return 0; /* If no adapter found, return error */ - printk("dmascc: no adapters found\n"); + printk(KERN_INFO "dmascc: no adapters found\n"); return -EIO; } @@ -475,18 +478,21 @@ /* Allocate memory */ info = kmalloc(sizeof(struct scc_info), GFP_KERNEL | GFP_DMA); if (!info) { - printk("dmascc: could not allocate memory for %s at %#3x\n", + printk(KERN_ERR "dmascc: could not allocate memory for %s at %#3x\n", hw[type].name, card_base); return -1; } /* Initialize what is necessary for write_scc and write_scc_data */ memset(info, 0, sizeof(struct scc_info)); + spin_lock_init(&info->register_lock); + priv = &info->priv[0]; priv->type = type; priv->card_base = card_base; priv->scc_cmd = scc_base + SCCA_CMD; priv->scc_data = scc_base + SCCA_DATA; + priv->register_lock = &info->register_lock; /* Reset SCC */ write_scc(priv, R9, FHWRES | MIE | NV); @@ -510,7 +516,6 @@ write_scc(priv, R15, 0); /* Start IRQ auto-detection */ - sti(); irqs = probe_irq_on(); /* Enable interrupts */ @@ -543,7 +548,7 @@ } if (irq <= 0) { - printk("dmascc: could not find irq of %s at %#3x (irq=%d)\n", + printk(KERN_ERR "dmascc: could not find irq of %s at %#3x (irq=%d)\n", hw[type].name, card_base, irq); kfree(info); return -1; @@ -558,6 +563,8 @@ priv->dev = dev; priv->info = info; priv->channel = i; + spin_lock_init(&priv->ring_lock); + priv->register_lock = &info->register_lock; priv->card_base = card_base; priv->scc_cmd = scc_base + (i ? SCCB_CMD : SCCA_CMD); priv->scc_data = scc_base + (i ? SCCB_DATA : SCCA_DATA); @@ -594,7 +601,7 @@ memcpy(dev->dev_addr, ax25_test, 7); rtnl_lock(); if (register_netdevice(dev)) { - printk("dmascc: could not register %s\n", dev->name); + printk(KERN_ERR "dmascc: could not register %s\n", dev->name); } rtnl_unlock(); } @@ -603,7 +610,7 @@ info->next = first; first = info; - printk("dmascc: found %s (%s) at %#3x, irq %d\n", hw[type].name, + printk(KERN_INFO "dmascc: found %s (%s) at %#3x, irq %d\n", hw[type].name, chipnames[chip], card_base, irq); return 0; } @@ -623,13 +630,12 @@ outb_p(val, priv->scc_cmd); return; default: - save_flags(flags); - cli(); + spin_lock_irqsave(priv->register_lock, flags); outb_p(0, priv->card_base + PI_DREQ_MASK); if (reg) outb_p(reg, priv->scc_cmd); outb_p(val, priv->scc_cmd); outb(1, priv->card_base + PI_DREQ_MASK); - restore_flags(flags); + spin_unlock_irqrestore(priv->register_lock, flags); return; } } @@ -647,12 +653,11 @@ default: if (fast) outb_p(val, priv->scc_data); else { - save_flags(flags); - cli(); + spin_lock_irqsave(priv->register_lock, flags); outb_p(0, priv->card_base + PI_DREQ_MASK); outb_p(val, priv->scc_data); outb(1, priv->card_base + PI_DREQ_MASK); - restore_flags(flags); + spin_unlock_irqrestore(priv->register_lock, flags); } return; } @@ -670,13 +675,12 @@ if (reg) outb_p(reg, priv->scc_cmd); return inb_p(priv->scc_cmd); default: - save_flags(flags); - cli(); + spin_lock_irqsave(&priv->register_lock, flags); outb_p(0, priv->card_base + PI_DREQ_MASK); if (reg) outb_p(reg, priv->scc_cmd); rc = inb_p(priv->scc_cmd); outb(1, priv->card_base + PI_DREQ_MASK); - restore_flags(flags); + spin_unlock_irqrestore(priv->register_lock, flags); return rc; } } @@ -691,12 +695,11 @@ case TYPE_TWIN: return inb_p(priv->scc_data); default: - save_flags(flags); - cli(); + spin_lock_irqsave(priv->register_lock, flags); outb_p(0, priv->card_base + PI_DREQ_MASK); rc = inb_p(priv->scc_data); outb(1, priv->card_base + PI_DREQ_MASK); - restore_flags(flags); + spin_unlock_irqrestore(priv->register_lock, flags); return rc; } } @@ -905,9 +908,8 @@ priv->tx_len[i] = skb->len-1; /* Clear interrupts while we touch our circular buffers */ - save_flags(flags); - cli(); + spin_lock_irqsave(&priv->ring_lock, flags); /* Move the ring buffer's head */ priv->tx_head = (i + 1) % NUM_TX_BUF; priv->tx_count++; @@ -928,7 +930,7 @@ } /* Turn interrupts back on and free buffer */ - restore_flags(flags); + spin_unlock_irqrestore(&priv->ring_lock, flags); dev_kfree_skb(skb); return 0; @@ -951,6 +953,7 @@ static void scc_isr(int irq, void *dev_id, struct pt_regs * regs) { struct scc_info *info = dev_id; + spin_lock(info->priv[0].register_lock); /* At this point interrupts are enabled, and the interrupt under service is already acknowledged, but masked off. @@ -978,6 +981,7 @@ } } } else z8530_isr(info); + spin_unlock(info->priv[0].register_lock); } @@ -1002,7 +1006,7 @@ i++; } if (i < 0) { - printk("dmascc: stuck in ISR with RR3=0x%02x.\n", is); + printk(KERN_ERR "dmascc: stuck in ISR with RR3=0x%02x.\n", is); } /* Ok, no interrupts pending from this 8530. The INT line should be inactive now. */ @@ -1099,11 +1103,9 @@ struct sk_buff *skb; unsigned char *data; - save_flags(flags); - cli(); - + spin_lock_irqsave(&priv->ring_lock, flags); while (priv->rx_count) { - restore_flags(flags); + spin_unlock_irqrestore(&priv->ring_lock, flags); cb = priv->rx_len[i]; /* Allocate buffer */ skb = dev_alloc_skb(cb+1); @@ -1123,14 +1125,12 @@ priv->stats.rx_packets++; priv->stats.rx_bytes += cb; } - save_flags(flags); - cli(); + spin_lock_irqsave(&priv->ring_lock, flags); /* Move tail */ priv->rx_tail = i = (i + 1) % NUM_RX_BUF; priv->rx_count--; } - - restore_flags(flags); + spin_unlock_irqrestore(&priv->ring_lock, flags); } @@ -1319,12 +1319,11 @@ else write_scc(priv, R1, EXT_INT_ENAB | WT_FN_RDYFN | WT_RDY_ENAB); /* Write first byte(s) */ - save_flags(flags); - cli(); + spin_lock_irqsave(priv->register_lock, flags); for (i = 0; i < n; i++) write_scc_data(priv, priv->tx_buf[priv->tx_tail][i], 1); enable_dma(priv->param.dma); - restore_flags(flags); + spin_unlock_irqrestore(priv->register_lock, flags); } else { write_scc(priv, R15, TxUIE); write_scc(priv, R1, EXT_INT_ENAB | WT_FN_RDYFN | TxINT_ENAB); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/drivers/net/hamradio/Kconfig linux.2.5.47-ac6/drivers/net/hamradio/Kconfig --- linux.2.5.47/drivers/net/hamradio/Kconfig 2002-10-31 15:05:01.000000000 +0000 +++ linux.2.5.47-ac6/drivers/net/hamradio/Kconfig 2002-11-05 16:08:04.000000000 +0000 @@ -185,120 +185,6 @@ say M here and read . This is recommended. The module will be called baycom_par.o. -config SOUNDMODEM - tristate "Soundcard modem driver" - depends on PARPORT && AX25 - ---help--- - This experimental driver allows a standard Sound Blaster or - WindowsSoundSystem compatible sound card to be used as a packet - radio modem (NOT as a telephone modem!), to send digital traffic - over amateur radio. - - To configure the driver, use the sethdlc, smdiag and smmixer - utilities available in the standard ax25 utilities package. For - information on how to key the transmitter, see - and - . - - If you want to compile this driver as a module ( = code which can be - inserted in and removed from the running kernel whenever you want), - say M here and read . This is - recommended. The module will be called soundmodem.o. - -config SOUNDMODEM_SBC - bool "soundmodem support for Soundblaster and compatible cards" - depends on SOUNDMODEM - help - This option enables the soundmodem driver to use Sound Blaster and - compatible cards. If you have a dual mode card (i.e. a WSS cards - with a Sound Blaster emulation) you should say N here and Y to - "Sound card modem support for WSS and Crystal cards", below, because - this usually results in better performance. This option also - supports SB16/32/64 in full-duplex mode. - -config SOUNDMODEM_WSS - bool "soundmodem support for WSS and Crystal cards" - depends on SOUNDMODEM - help - This option enables the soundmodem driver to use WindowsSoundSystem - compatible cards. These cards feature a codec chip from either - Analog Devices (such as AD1848, AD1845, AD1812) or Crystal - Semiconductors (such as CS4248, CS423x). This option also supports - the WSS full-duplex operation which currently works with Crystal - CS423x chips. If you don't need full-duplex operation, do not enable - it to save performance. - -config SOUNDMODEM_AFSK1200 - bool "soundmodem support for 1200 baud AFSK modulation" - depends on SOUNDMODEM - help - This option enables the soundmodem driver 1200 baud AFSK modem, - compatible to popular modems using TCM3105 or AM7911. The - demodulator requires about 12% of the CPU power of a Pentium 75 CPU - per channel. - -config SOUNDMODEM_AFSK2400_7 - bool "soundmodem support for 2400 baud AFSK modulation (7.3728MHz crystal)" - depends on SOUNDMODEM - help - This option enables the soundmodem driver 2400 baud AFSK modem, - compatible to TCM3105 modems (over-)clocked with a 7.3728MHz - crystal. Note that the availability of this driver does _not_ imply - that I recommend building such links. It is only here since users - especially in eastern Europe have asked me to do so. In fact this - modulation scheme has many disadvantages, mainly its incompatibility - with many transceiver designs and the fact that the TCM3105 (if - used) is operated widely outside its specifications. - -config SOUNDMODEM_AFSK2400_8 - bool "soundmodem support for 2400 baud AFSK modulation (8MHz crystal)" - depends on SOUNDMODEM - help - This option enables the soundmodem driver 2400 baud AFSK modem, - compatible to TCM3105 modems (over-)clocked with an 8MHz crystal. - Note that the availability of this driver does _not_ imply that I - recommend building such links. It is only here since users - especially in eastern Europe have asked me to do so. In fact this - modulation scheme has many disadvantages, mainly its incompatibility - with many transceiver designs and the fact that the TCM3105 (if - used) is operated widely outside its specifications. - -config SOUNDMODEM_AFSK2666 - bool "soundmodem support for 2666 baud AFSK modulation" - depends on SOUNDMODEM - help - This option enables the soundmodem driver 2666 baud AFSK modem. - This modem is experimental, and not compatible to anything - else I know of. - -config SOUNDMODEM_HAPN4800 - bool "soundmodem support for 4800 baud HAPN-1 modulation" - depends on SOUNDMODEM - help - This option enables the soundmodem driver 4800 baud HAPN-1 - compatible modem. This modulation seems to be widely used 'down - under' and in the Netherlands. Here, nobody uses it, so I could not - test if it works. It is compatible to itself, however :-) - -config SOUNDMODEM_PSK4800 - bool "soundmodem support for 4800 baud PSK modulation" - depends on SOUNDMODEM - help - This option enables the soundmodem driver 4800 baud 8PSK modem. - This modem is experimental, and not compatible to anything - else I know of. - -config SOUNDMODEM_FSK9600 - bool "soundmodem support for 9600 baud FSK G3RUH modulation" - depends on SOUNDMODEM - help - This option enables the soundmodem driver 9600 baud FSK modem, - compatible to the G3RUH standard. The demodulator requires about 4% - of the CPU power of a Pentium 75 CPU per channel. You can say Y to - both 1200 baud AFSK and 9600 baud FSK if you want (but obviously you - can only use one protocol at a time, depending on what the other end - can understand). - config YAM tristate "YAM driver for AX.25" depends on AX25 diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/drivers/net/hamradio/Makefile linux.2.5.47-ac6/drivers/net/hamradio/Makefile --- linux.2.5.47/drivers/net/hamradio/Makefile 2002-10-31 14:57:01.000000000 +0000 +++ linux.2.5.47-ac6/drivers/net/hamradio/Makefile 2002-11-05 16:08:04.000000000 +0000 @@ -22,6 +22,5 @@ obj-$(CONFIG_BAYCOM_SER_HDX) += baycom_ser_hdx.o hdlcdrv.o obj-$(CONFIG_BAYCOM_PAR) += baycom_par.o hdlcdrv.o obj-$(CONFIG_BAYCOM_EPP) += baycom_epp.o hdlcdrv.o -obj-$(CONFIG_SOUNDMODEM) += soundmodem/ hdlcdrv.o include $(TOPDIR)/Rules.make diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/drivers/net/hamradio/soundmodem/gentbl.c linux.2.5.47-ac6/drivers/net/hamradio/soundmodem/gentbl.c --- linux.2.5.47/drivers/net/hamradio/soundmodem/gentbl.c 2002-10-31 14:57:01.000000000 +0000 +++ linux.2.5.47-ac6/drivers/net/hamradio/soundmodem/gentbl.c 1970-01-01 01:00:00.000000000 +0100 @@ -1,689 +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 -#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" : ""); - } - } -#ifdef VERBOSE - fprintf(stderr, "fsk9600: txfilt4: min = %f; max = %f\n", min, max); -#endif - 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" : ""); - } - } -#ifdef VERBOSE - fprintf(stderr, "fsk9600: txfilt5: min = %f; max = %f\n", min, max); -#endif - 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[44]; - 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" : ""); - } - } -#ifdef VERBOSE - fprintf(stderr, "hapn4800: txfilt8: min = %f; max = %f\n", min, max); -#endif - 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" : ""); - } - } -#ifdef VERBOSE - fprintf(stderr, "hapn4800: txfilt10: min = %f; max = %f\n", min, max); -#endif - 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" : ""); - } - } -#ifdef VERBOSE - fprintf(stderr, "hapn4800: txfiltpm8: min = %f; max = %f\n", min, max); -#endif - 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" : ""); - } - } -#ifdef VERBOSE - fprintf(stderr, "hapn4800: txfiltpm10: min = %f; max = %f\n", min, max); -#endif - 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); -} - -/* -------------------------------------------------------------------- */ - -int 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 --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/drivers/net/hamradio/soundmodem/Makefile linux.2.5.47-ac6/drivers/net/hamradio/soundmodem/Makefile --- linux.2.5.47/drivers/net/hamradio/soundmodem/Makefile 2002-10-31 15:05:01.000000000 +0000 +++ linux.2.5.47-ac6/drivers/net/hamradio/soundmodem/Makefile 1970-01-01 01:00:00.000000000 +0100 @@ -1,42 +0,0 @@ -# -# Makefile for the soundmodem device driver. -# - -obj-$(CONFIG_SOUNDMODEM) += soundmodem.o - -soundmodem-y := sm.o -soundmodem-$(CONFIG_SOUNDMODEM_SBC) += sm_sbc.o -soundmodem-$(CONFIG_SOUNDMODEM_WSS) += sm_wss.o -soundmodem-$(CONFIG_SOUNDMODEM_AFSK1200) += sm_afsk1200.o -soundmodem-$(CONFIG_SOUNDMODEM_AFSK2400_7) += sm_afsk2400_7.o -soundmodem-$(CONFIG_SOUNDMODEM_AFSK2400_8) += sm_afsk2400_8.o -soundmodem-$(CONFIG_SOUNDMODEM_AFSK2666) += sm_afsk2666.o -soundmodem-$(CONFIG_SOUNDMODEM_HAPN4800) += sm_hapn4800.o -soundmodem-$(CONFIG_SOUNDMODEM_PSK4800) += sm_psk4800.o -soundmodem-$(CONFIG_SOUNDMODEM_FSK9600) += sm_fsk9600.o -soundmodem-objs := $(soundmodem-y) - -host-progs := gentbl -HOST_LOADLIBES := -lm - -# Files generated that shall be removed upon make clean -clean-files := sm_tbl_afsk1200.h sm_tbl_afsk2400_7.h \ - sm_tbl_afsk2400_8.h sm_tbl_afsk2666.h \ - sm_tbl_psk4800.h sm_tbl_hapn4800.h \ - sm_tbl_fsk9600.h - -include $(TOPDIR)/Rules.make - -# Dependencies on generates files need to be listed explicitly - -$(obj)/sm_afsk1200.o: $(obj)/sm_tbl_afsk1200.h -$(obj)/sm_afsk2400_7.o: $(obj)/sm_tbl_afsk2400_7.h -$(obj)/sm_afsk2400_8.o: $(obj)/sm_tbl_afsk2400_8.h -$(obj)/sm_afsk2666.o: $(obj)/sm_tbl_afsk2666.h -$(obj)/sm_psk4800.o: $(obj)/sm_tbl_psk4800.h -$(obj)/sm_hapn4800.o: $(obj)/sm_tbl_hapn4800.h -$(obj)/sm_fsk9600.o: $(obj)/sm_tbl_fsk9600.h - -$(obj)/sm_tbl_%: $(obj)/gentbl - cd $(obj) && ./gentbl - diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/drivers/net/hamradio/soundmodem/sm_afsk1200.c linux.2.5.47-ac6/drivers/net/hamradio/soundmodem/sm_afsk1200.c --- linux.2.5.47/drivers/net/hamradio/soundmodem/sm_afsk1200.c 2002-10-31 14:57:01.000000000 +0000 +++ linux.2.5.47-ac6/drivers/net/hamradio/soundmodem/sm_afsk1200.c 1970-01-01 01:00:00.000000000 +0100 @@ -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; - } -} - -/* --------------------------------------------------------------------- */ - -static __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; -} - -static __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; -} - -static __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; -} - -static __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 --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/drivers/net/hamradio/soundmodem/sm_afsk2400_7.c linux.2.5.47-ac6/drivers/net/hamradio/soundmodem/sm_afsk2400_7.c --- linux.2.5.47/drivers/net/hamradio/soundmodem/sm_afsk2400_7.c 2002-10-31 14:57:01.000000000 +0000 +++ linux.2.5.47-ac6/drivers/net/hamradio/soundmodem/sm_afsk2400_7.c 1970-01-01 01:00:00.000000000 +0100 @@ -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; - } -} - -/* --------------------------------------------------------------------- */ - -static __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; -} - -static __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; -} - -static __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; -} - -static __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 --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/drivers/net/hamradio/soundmodem/sm_afsk2400_8.c linux.2.5.47-ac6/drivers/net/hamradio/soundmodem/sm_afsk2400_8.c --- linux.2.5.47/drivers/net/hamradio/soundmodem/sm_afsk2400_8.c 2002-10-31 14:57:01.000000000 +0000 +++ linux.2.5.47-ac6/drivers/net/hamradio/soundmodem/sm_afsk2400_8.c 1970-01-01 01:00:00.000000000 +0100 @@ -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; - } -} - -/* --------------------------------------------------------------------- */ - -static __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; -} - -static __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; -} - -static __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; -} - -static __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 --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/drivers/net/hamradio/soundmodem/sm_afsk2666.c linux.2.5.47-ac6/drivers/net/hamradio/soundmodem/sm_afsk2666.c --- linux.2.5.47/drivers/net/hamradio/soundmodem/sm_afsk2666.c 2002-10-31 14:57:01.000000000 +0000 +++ linux.2.5.47-ac6/drivers/net/hamradio/soundmodem/sm_afsk2666.c 1970-01-01 01:00:00.000000000 +0100 @@ -1,356 +0,0 @@ -/*****************************************************************************/ - -/* - * sm_afsk2666.c -- soundcard radio modem driver, 2666 baud AFSK modem - * - * 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. - * - */ - -#include "sm.h" -#include "sm_tbl_afsk2666.h" - -/* --------------------------------------------------------------------- */ - -struct demod_state_afsk26 { - unsigned int shreg; - unsigned long descram; - int dem_sum[8]; - int dem_sum_mean; - int dem_cnt; - 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_afsk26 { - unsigned int shreg; - unsigned long scram; - unsigned int bit_pll; - unsigned int phinc; - unsigned int tx_seq; -}; - -/* --------------------------------------------------------------------- */ - -#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_2666_u8(struct sm_state *sm, unsigned char *buf, unsigned int buflen) -{ - struct mod_state_afsk26 *st = (struct mod_state_afsk26 *)(&sm->m); - - for (; buflen > 0; buflen--, buf++) { - if (!st->tx_seq++) { - 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->phinc = afsk26_carfreq[!(st->scram & (SCRAM_TAP1 << 2))]; - } - if (st->tx_seq >= 6) - st->tx_seq = 0; - *buf = OFFSCOS(st->bit_pll); - st->bit_pll += st->phinc; - } -} - -/* --------------------------------------------------------------------- */ - -static void modulator_2666_s16(struct sm_state *sm, short *buf, unsigned int buflen) -{ - struct mod_state_afsk26 *st = (struct mod_state_afsk26 *)(&sm->m); - - for (; buflen > 0; buflen--, buf++) { - if (!st->tx_seq++) { - 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->phinc = afsk26_carfreq[!(st->scram & (SCRAM_TAP1 << 2))]; - } - if (st->tx_seq >= 6) - st->tx_seq = 0; - *buf = COS(st->bit_pll); - st->bit_pll += st->phinc; - } -} - -/* --------------------------------------------------------------------- */ - -static __inline__ int convolution12_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]); - - return sum; -} - -static __inline__ int convolution12_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 >>= 8; - return sum; -} - -/* ---------------------------------------------------------------------- */ - -#if 0 -static int binexp(unsigned int i) -{ - int ret = 31; - - if (!i) - return 0; - if (i < 0x10000LU) { - i <<= 16; - ret -= 16; - } - if (i < 0x1000000LU) { - i <<= 8; - ret -= 8; - } - if (i < 0x10000000LU) { - i <<= 4; - ret -= 4; - } - if (i < 0x40000000LU) { - i <<= 2; - ret -= 2; - } - if (i < 0x80000000LU) - ret -= 1; - return ret; -} - -static const sqrt_tab[16] = { - 00000, 16384, 23170, 28378, 32768, 36636, 40132, 43348, - 46341, 49152, 51811, 54340, 56756, 59073, 61303, 63455 -}; - - -static unsigned int int_sqrt_approx(unsigned int i) -{ - unsigned int j; - - if (i < 16) - return sqrt_tab[i] >> 14; - j = binexp(i) >> 1; - i >>= (j * 2 - 2); - return (sqrt_tab[i & 0xf] << j) >> 15; -} -#endif - -/* --------------------------------------------------------------------- */ - -extern unsigned int est_pwr(int i, int q) -{ - unsigned int ui = abs(i); - unsigned int uq = abs(q); - - if (uq > ui) { - unsigned int tmp; - tmp = ui; - ui = uq; - uq = tmp; - } - if (uq > (ui >> 1)) - return 7*(ui>>3) + 9*(uq>>4); - else - return ui + (uq>>2); -} - -/* --------------------------------------------------------------------- */ - -static void demod_one_sample(struct sm_state *sm, struct demod_state_afsk26 *st, int curval, - int loi, int loq, int hii, int hiq) -{ - static const int pll_corr[2] = { -0xa00, 0xa00 }; - unsigned char curbit; - unsigned int descx; - int val; - - /* - * estimate power - */ - val = est_pwr(hii, hiq) - est_pwr(loi, loq); - /* - * estimate center value - */ - st->dem_sum[0] += val >> 8; - if ((++st->dem_cnt) >= 256) { - st->dem_cnt = 0; - st->dem_sum_mean = (st->dem_sum[0]+st->dem_sum[1]+ - st->dem_sum[2]+st->dem_sum[3]+ - st->dem_sum[4]+st->dem_sum[5]+ - st->dem_sum[6]+st->dem_sum[7]) >> 3; - memmove(st->dem_sum+1, st->dem_sum, - sizeof(st->dem_sum)-sizeof(st->dem_sum[0])); - st->dem_sum[0] = 0; - } - /* - * decision and bit clock regen - */ - val -= st->dem_sum_mean; - diag_add(sm, curval, val); - - st->dcd_shreg <<= 1; - st->bit_pll += 0x1555; - curbit = (val > 0); - if (st->last_sample ^ curbit) { - st->dcd_shreg |= 1; - st->bit_pll += pll_corr[st->bit_pll < (0x8000+0x1555)]; - st->dcd_sum0 += 4*hweight8(st->dcd_shreg & 0x1e) - - hweight16(st->dcd_shreg & 0xfe00); - } - st->last_sample = curbit; - hdlcdrv_channelbit(&sm->hdrv, curbit); - 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 = 400; - } - if (st->bit_pll >= 0x10000) { - st->bit_pll &= 0xffffu; - 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); - } -} - -/* --------------------------------------------------------------------- */ - -static void demodulator_2666_u8(struct sm_state *sm, const unsigned char *buf, unsigned int buflen) -{ - struct demod_state_afsk26 *st = (struct demod_state_afsk26 *)(&sm->d); - - for (; buflen > 0; buflen--, buf++) { - demod_one_sample(sm, st, (*buf-0x80)<<8, - convolution12_u8(buf, afsk26_dem_tables[0][0].i, AFSK26_DEM_SUM_I_0_0), - convolution12_u8(buf, afsk26_dem_tables[0][0].q, AFSK26_DEM_SUM_Q_0_0), - convolution12_u8(buf, afsk26_dem_tables[0][1].i, AFSK26_DEM_SUM_I_0_1), - convolution12_u8(buf, afsk26_dem_tables[0][1].q, AFSK26_DEM_SUM_Q_0_1)); - demod_one_sample(sm, st, (*buf-0x80)<<8, - convolution12_u8(buf, afsk26_dem_tables[1][0].i, AFSK26_DEM_SUM_I_1_0), - convolution12_u8(buf, afsk26_dem_tables[1][0].q, AFSK26_DEM_SUM_Q_1_0), - convolution12_u8(buf, afsk26_dem_tables[1][1].i, AFSK26_DEM_SUM_I_1_1), - convolution12_u8(buf, afsk26_dem_tables[1][1].q, AFSK26_DEM_SUM_Q_1_1)); - } -} - -/* --------------------------------------------------------------------- */ - -static void demodulator_2666_s16(struct sm_state *sm, const short *buf, unsigned int buflen) -{ - struct demod_state_afsk26 *st = (struct demod_state_afsk26 *)(&sm->d); - - for (; buflen > 0; buflen--, buf++) { - demod_one_sample(sm, st, *buf, - convolution12_s16(buf, afsk26_dem_tables[0][0].i, AFSK26_DEM_SUM_I_0_0), - convolution12_s16(buf, afsk26_dem_tables[0][0].q, AFSK26_DEM_SUM_Q_0_0), - convolution12_s16(buf, afsk26_dem_tables[0][1].i, AFSK26_DEM_SUM_I_0_1), - convolution12_s16(buf, afsk26_dem_tables[0][1].q, AFSK26_DEM_SUM_Q_0_1)); - demod_one_sample(sm, st, *buf, - convolution12_s16(buf, afsk26_dem_tables[1][0].i, AFSK26_DEM_SUM_I_1_0), - convolution12_s16(buf, afsk26_dem_tables[1][0].q, AFSK26_DEM_SUM_Q_1_0), - convolution12_s16(buf, afsk26_dem_tables[1][1].i, AFSK26_DEM_SUM_I_1_1), - convolution12_s16(buf, afsk26_dem_tables[1][1].q, AFSK26_DEM_SUM_Q_1_1)); - } -} - -/* --------------------------------------------------------------------- */ - -static void demod_init_2666(struct sm_state *sm) -{ - struct demod_state_afsk26 *st = (struct demod_state_afsk26 *)(&sm->d); - - st->dcd_time = 400; - st->dcd_sum0 = 2; -} - -/* --------------------------------------------------------------------- */ - -const struct modem_tx_info sm_afsk2666_tx = { - "afsk2666", sizeof(struct mod_state_afsk26), AFSK26_SAMPLERATE, 2666, - modulator_2666_u8, modulator_2666_s16, NULL -}; - -const struct modem_rx_info sm_afsk2666_rx = { - "afsk2666", sizeof(struct demod_state_afsk26), AFSK26_SAMPLERATE, 2666, 12, 6, - demodulator_2666_u8, demodulator_2666_s16, demod_init_2666 -}; - -/* --------------------------------------------------------------------- */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/drivers/net/hamradio/soundmodem/sm.c linux.2.5.47-ac6/drivers/net/hamradio/soundmodem/sm.c --- linux.2.5.47/drivers/net/hamradio/soundmodem/sm.c 2002-10-31 14:57:01.000000000 +0000 +++ linux.2.5.47-ac6/drivers/net/hamradio/soundmodem/sm.c 1970-01-01 01:00:00.000000000 +0100 @@ -1,759 +0,0 @@ -/*****************************************************************************/ - -/* - * sm.c -- soundcard radio modem driver. - * - * Copyright (C) 1996-2000 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.1996 Started - * 18.10.1996 Changed to new user space access routines (copy_{to,from}_user) - * 0.4 21.01.1997 Separately compileable soundcard/modem modules - * 0.5 03.03.1997 fixed LPT probing (check_lpt result was interpreted the wrong way round) - * 0.6 16.04.1997 init code/data tagged - * 0.7 30.07.1997 fixed halfduplex interrupt handlers/hotfix for CS423X - * 0.8 14.04.1998 cleanups - * 0.9 03.08.1999 adapt to Linus' new __setup/__initcall - * use parport lowlevel drivers instead of directly writing to a parallel port - * removed some pre-2.2 kernel compatibility cruft - * 0.10 10.08.1999 Check if parport can do SPP and is safe to access during interrupt contexts - * 0.11 12.02.2000 adapted to softnet driver interface - * 0.12 03.07.2000 fix interface name handling - */ - -/*****************************************************************************/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "sm.h" - -/* --------------------------------------------------------------------- */ - -/*static*/ const char sm_drvname[] = "soundmodem"; -static const char sm_drvinfo[] = KERN_INFO "soundmodem: (C) 1996-2000 Thomas Sailer, HB9JNX/AE4WA\n" -KERN_INFO "soundmodem: version 0.12 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 net_device sm_device[NR_PORTS]; - -/* --------------------------------------------------------------------- */ - -#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 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 ======================== - */ - -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 && sm->pardev && sm->pardev->port) - parport_write_data(sm->pardev->port, ptt | (dcd << 1)); - 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, const char *ifname) -{ - enum uart u = c_uart_unknown; - struct parport *pp = NULL; - - 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 */ - } - sm->pardev = NULL; - if (sm->hdrv.ptt_out.pariobase > 0) { - pp = parport_enumerate(); - while (pp && pp->base != sm->hdrv.ptt_out.pariobase) - pp = pp->next; - if (!pp) - printk(KERN_WARNING "%s: parport at address 0x%x not found\n", sm_drvname, sm->hdrv.ptt_out.pariobase); - else if ((~pp->modes) & (PARPORT_MODE_PCSPP | PARPORT_MODE_SAFEININT)) - printk(KERN_WARNING "%s: parport at address 0x%x cannot be used\n", sm_drvname, sm->hdrv.ptt_out.pariobase); - else { - sm->pardev = parport_register_device(pp, ifname, NULL, NULL, NULL, PARPORT_DEV_EXCL, NULL); - if (!sm->pardev) { - pp = NULL; - printk(KERN_WARNING "%s: cannot register parport device (address 0x%x)\n", sm_drvname, sm->hdrv.ptt_out.pariobase); - } else { - if (parport_claim(sm->pardev)) { - parport_unregister_device(sm->pardev); - sm->pardev = NULL; - printk(KERN_WARNING "%s: cannot claim parport at address 0x%x\n", sm_drvname, sm->hdrv.ptt_out.pariobase); - } else - sm->hdrv.ptt_out.flags |= SP_PAR; - } - } - } - 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 && sm->pardev) { - parport_release(sm->pardev); - parport_unregister_device(sm->pardev); - } - 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 net_device *dev); -static int sm_close(struct net_device *dev); -static int sm_ioctl(struct net_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 net_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, dev->name); - 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 net_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 net_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 net_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 (netif_running(dev) || !capable(CAP_NET_ADMIN)) - 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(cp, "%s:,", (*hwp)->hw_name); - hwp++; - } - while (*mtp) { - if ((*mtp)->name) - cp += sprintf(cp, ">%s,", (*mtp)->name); - mtp++; - } - while (*mrp) { - if ((*mrp)->name) - cp += sprintf(cp, "<%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; - } -} - -/* --------------------------------------------------------------------- */ - -/* - * command line settable parameters - */ -static char *mode[NR_PORTS] = { [0 ... NR_PORTS-1] = NULL }; -static int iobase[NR_PORTS] = { [0 ... NR_PORTS-1] = -1 }; -static int irq[NR_PORTS] = { [0 ... NR_PORTS-1] = -1 }; -static int dma[NR_PORTS] = { [0 ... NR_PORTS-1] = -1 }; -static int dma2[NR_PORTS] = { [0 ... NR_PORTS-1] = -1 }; -static int serio[NR_PORTS] = { [0 ... NR_PORTS-1] = 0 }; -static int pario[NR_PORTS] = { [0 ... NR_PORTS-1] = 0 }; -static int midiio[NR_PORTS] = { [0 ... NR_PORTS-1] = 0 }; - -MODULE_PARM(mode, "1-" __MODULE_STRING(NR_PORTS) "s"); -MODULE_PARM_DESC(mode, "soundmodem operating mode; eg. sbc:afsk1200 or wss:fsk9600"); -MODULE_PARM(iobase, "1-" __MODULE_STRING(NR_PORTS) "i"); -MODULE_PARM_DESC(iobase, "soundmodem base address"); -MODULE_PARM(irq, "1-" __MODULE_STRING(NR_PORTS) "i"); -MODULE_PARM_DESC(irq, "soundmodem interrupt"); -MODULE_PARM(dma, "1-" __MODULE_STRING(NR_PORTS) "i"); -MODULE_PARM_DESC(dma, "soundmodem dma channel"); -MODULE_PARM(dma2, "1-" __MODULE_STRING(NR_PORTS) "i"); -MODULE_PARM_DESC(dma2, "soundmodem 2nd dma channel; full duplex only"); -MODULE_PARM(serio, "1-" __MODULE_STRING(NR_PORTS) "i"); -MODULE_PARM_DESC(serio, "soundmodem PTT output on serial port"); -MODULE_PARM(pario, "1-" __MODULE_STRING(NR_PORTS) "i"); -MODULE_PARM_DESC(pario, "soundmodem PTT output on parallel port"); -MODULE_PARM(midiio, "1-" __MODULE_STRING(NR_PORTS) "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"); - -/* --------------------------------------------------------------------- */ - -static int __init init_soundmodem(void) -{ - int i, j, found = 0; - char set_hw = 1; - struct sm_state *sm; - - printk(sm_drvinfo); - /* - * register net devices - */ - for (i = 0; i < NR_PORTS; i++) { - struct net_device *dev = sm_device+i; - char ifname[IFNAMSIZ]; - - sprintf(ifname, "sm%d", i); - if (!mode[i]) - set_hw = 0; - else { - if (!strncmp(mode[i], "sbc", 3)) { - if (iobase[i] == -1) - iobase[i] = 0x220; - if (irq[i] == -1) - irq[i] = 5; - if (dma[i] == -1) - dma[i] = 1; - } else { - if (iobase[i] == -1) - iobase[i] = 0x530; - if (irq[i] == -1) - irq[i] = 11; - if (dma[i] == -1) - dma[i] = 1; - } - } - if (!set_hw) - iobase[i] = irq[i] = 0; - j = hdlcdrv_register_hdlcdrv(dev, &sm_ops, sizeof(struct sm_state), ifname, iobase[i], irq[i], dma[i]); - if (!j) { - sm = (struct sm_state *)dev->priv; - sm->hdrv.ptt_out.dma2 = dma2[i]; - sm->hdrv.ptt_out.seriobase = serio[i]; - sm->hdrv.ptt_out.pariobase = pario[i]; - sm->hdrv.ptt_out.midiiobase = midiio[i]; - if (set_hw && sethw(dev, sm, mode[i])) - set_hw = 0; - found++; - } else { - printk(KERN_WARNING "%s: cannot register net device\n", sm_drvname); - } - } - if (!found) - return -ENXIO; - return 0; -} - -static void __exit cleanup_soundmodem(void) -{ - int i; - - printk(KERN_INFO "sm: cleanup_module called\n"); - - for(i = 0; i < NR_PORTS; i++) { - struct net_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); - } - } -} - -module_init(init_soundmodem); -module_exit(cleanup_soundmodem); - -/* --------------------------------------------------------------------- */ - -#ifndef MODULE - -/* - * format: soundmodem=io,irq,dma[,dma2[,serio[,pario]]],mode - * mode: hw:modem - * hw: sbc, wss, wssfdx - * modem: afsk1200, fsk9600 - */ - -static int __init sm_setup(char *str) -{ - static unsigned nr_dev; - int ints[8]; - - if (nr_dev >= NR_PORTS) - return 0; - str = get_options(str, 8, ints); - mode[nr_dev] = str; - if (ints[0] >= 1) - iobase[nr_dev] = ints[1]; - if (ints[0] >= 2) - irq[nr_dev] = ints[2]; - if (ints[0] >= 3) - dma[nr_dev] = ints[3]; - if (ints[0] >= 4) - dma2[nr_dev] = ints[4]; - if (ints[0] >= 5) - serio[nr_dev] = ints[5]; - if (ints[0] >= 6) - pario[nr_dev] = ints[6]; - if (ints[0] >= 7) - midiio[nr_dev] = ints[7]; - nr_dev++; - return 1; -} - -__setup("soundmodem=", sm_setup); - -#endif /* MODULE */ -/* --------------------------------------------------------------------- */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/drivers/net/hamradio/soundmodem/smdma.h linux.2.5.47-ac6/drivers/net/hamradio/soundmodem/smdma.h --- linux.2.5.47/drivers/net/hamradio/soundmodem/smdma.h 2002-10-31 14:57:01.000000000 +0000 +++ linux.2.5.47-ac6/drivers/net/hamradio/soundmodem/smdma.h 1970-01-01 01:00:00.000000000 +0100 @@ -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 - */ -static __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; - } -} - -/* --------------------------------------------------------------------- */ - -static __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; - } -} - -/* --------------------------------------------------------------------- */ - -static __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; -} - -static __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++; - } -} - -static __inline__ void dma_init_transmit(struct sm_state *sm) -{ - sm->dma.ofragptr = 0; - sm->dma.ptt_cnt = 0; -} - -static __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; -} - -static __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); -} - -/* --------------------------------------------------------------------- */ - -static __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; - } -} - -static __inline__ void dma_init_receive(struct sm_state *sm) -{ - sm->dma.ifragptr = 0; -} - -/* --------------------------------------------------------------------- */ -#endif /* _SMDMA_H */ - - - diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/drivers/net/hamradio/soundmodem/sm_fsk9600.c linux.2.5.47-ac6/drivers/net/hamradio/soundmodem/sm_fsk9600.c --- linux.2.5.47/drivers/net/hamradio/soundmodem/sm_fsk9600.c 2002-10-31 14:57:01.000000000 +0000 +++ linux.2.5.47-ac6/drivers/net/hamradio/soundmodem/sm_fsk9600.c 1970-01-01 01:00:00.000000000 +0100 @@ -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 --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/drivers/net/hamradio/soundmodem/sm.h linux.2.5.47-ac6/drivers/net/hamradio/soundmodem/sm.h --- linux.2.5.47/drivers/net/hamradio/soundmodem/sm.h 2002-10-31 14:57:01.000000000 +0000 +++ linux.2.5.47-ac6/drivers/net/hamradio/soundmodem/sm.h 1970-01-01 01:00:00.000000000 +0100 @@ -1,383 +0,0 @@ -/*****************************************************************************/ - -/* - * sm.h -- soundcard radio modem driver internal header. - * - * Copyright (C) 1996-1999 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 -#include -#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; - - struct pardevice *pardev; - - /* - * 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[48/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 net_device *, struct sm_state *); - int (*close)(struct net_device *, struct sm_state *); - int (*ioctl)(struct net_device *, struct sm_state *, struct ifreq *, - struct hdlcdrv_ioctl *, int); - int (*sethw)(struct net_device *, struct sm_state *, char *); -}; - -/* --------------------------------------------------------------------- */ - -extern const char sm_drvname[]; -extern const char sm_drvinfo[]; - -/* --------------------------------------------------------------------- */ -/* - * ===================== diagnostics stuff =============================== - */ - -static 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) - -static 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; -} - -/* --------------------------------------------------------------------- */ - -static 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 =============================== - */ - -#if 0 -static inline unsigned int hweight32(unsigned int w) - __attribute__ ((unused)); -static inline unsigned int hweight16(unsigned short w) - __attribute__ ((unused)); -static inline unsigned int hweight8(unsigned char w) - __attribute__ ((unused)); - -static 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); -} - -static 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); -} - -static 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); -} - -#endif - -static inline unsigned int gcd(unsigned int x, unsigned int y) - __attribute__ ((unused)); -static inline unsigned int lcm(unsigned int x, unsigned int y) - __attribute__ ((unused)); - -static 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; - } -} - -static inline unsigned int lcm(unsigned int x, unsigned int y) -{ - return x * y / gcd(x, y); -} - -/* --------------------------------------------------------------------- */ -/* - * ===================== profiling ======================================= - */ - - -#ifdef __i386__ - -#include - -/* - * only do 32bit cycle counter arithmetic; we hope we won't overflow. - * in fact, overflowing modems would require over 2THz CPU clock speeds :-) - */ - -#define time_exec(var,cmd) \ -({ \ - if (cpu_has_tsc) { \ - unsigned int cnt1, cnt2; \ - rdtscl(cnt1); \ - cmd; \ - rdtscl(cnt2); \ - 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 --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/drivers/net/hamradio/soundmodem/sm_hapn4800.c linux.2.5.47-ac6/drivers/net/hamradio/soundmodem/sm_hapn4800.c --- linux.2.5.47/drivers/net/hamradio/soundmodem/sm_hapn4800.c 2002-10-31 14:57:01.000000000 +0000 +++ linux.2.5.47-ac6/drivers/net/hamradio/soundmodem/sm_hapn4800.c 1970-01-01 01:00:00.000000000 +0100 @@ -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 --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/drivers/net/hamradio/soundmodem/sm_psk4800.c linux.2.5.47-ac6/drivers/net/hamradio/soundmodem/sm_psk4800.c --- linux.2.5.47/drivers/net/hamradio/soundmodem/sm_psk4800.c 2002-10-31 14:57:01.000000000 +0000 +++ linux.2.5.47-ac6/drivers/net/hamradio/soundmodem/sm_psk4800.c 1970-01-01 01:00:00.000000000 +0100 @@ -1,418 +0,0 @@ -/*****************************************************************************/ - -/* - * sm_psk4800.c -- soundcard radio modem driver, 4800 baud 8PSK modem - * - * 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. - * - */ - -#include "sm.h" -#include "sm_tbl_psk4800.h" - -/* --------------------------------------------------------------------- */ - -#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 */ - -#define SCRAM_SHIFT 17 - -/* --------------------------------------------------------------------- */ - -struct demod_state_psk48 { - /* - * input mixer and lowpass - */ - short infi[PSK48_RXF_LEN/2], infq[PSK48_RXF_LEN/2]; - unsigned int downmixer; - int ovrphase; - short magi, magq; - /* - * sampling instant recovery - */ - int pwrhist[5]; - unsigned int s_phase; - int cur_sync; - /* - * phase recovery - */ - short cur_phase_dev; - short last_ph_err; - unsigned short pskph; - unsigned int phase; - unsigned short last_pskph; - unsigned char cur_raw, last_raw, rawbits; - /* - * decoding - */ - 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_psk48 { - unsigned char txbits[PSK48_TXF_NUMSAMPLES]; - unsigned short txphase; - unsigned int shreg; - unsigned long scram; - const short *tbl; - unsigned int txseq; -}; - -/* --------------------------------------------------------------------- */ - -static void modulator_4800_u8(struct sm_state *sm, unsigned char *buf, unsigned int buflen) -{ - struct mod_state_psk48 *st = (struct mod_state_psk48 *)(&sm->m); - int i, j; - int si, sq; - - for (; buflen > 0; buflen--, buf++) { - if (!st->txseq++) { - memmove(st->txbits+1, st->txbits, - sizeof(st->txbits)-sizeof(st->txbits[0])); - for (i = 0; i < 3; i++) { - if (st->shreg <= 1) - st->shreg = hdlcdrv_getbits(&sm->hdrv) | 0x10000; - st->scram = (st->scram << 1) | - (st->shreg & 1); - st->shreg >>= 1; - if (st->scram & SCRAM_TAP1) - st->scram ^= SCRAM_TAPN; - } - j = (st->scram >> (SCRAM_SHIFT+3)) & 7; - st->txbits[0] -= (j ^ (j >> 1)); - st->txbits[0] &= 7; - st->tbl = psk48_tx_table; - } - if (st->txseq >= PSK48_TXF_OVERSAMPLING) - st->txseq = 0; - for (j = si = sq = 0; j < PSK48_TXF_NUMSAMPLES; j++, st->tbl += 16) { - si += st->tbl[st->txbits[j]]; - sq += st->tbl[st->txbits[j]+8]; - } - *buf = ((si*COS(st->txphase)+ sq*SIN(st->txphase)) >> 23) + 0x80; - st->txphase = (st->txphase + PSK48_PHASEINC) & 0xffffu; - } -} - -/* --------------------------------------------------------------------- */ - -static void modulator_4800_s16(struct sm_state *sm, short *buf, unsigned int buflen) -{ - struct mod_state_psk48 *st = (struct mod_state_psk48 *)(&sm->m); - int i, j; - int si, sq; - - for (; buflen > 0; buflen--, buf++) { - if (!st->txseq++) { - memmove(st->txbits+1, st->txbits, - sizeof(st->txbits)-sizeof(st->txbits[0])); - for (i = 0; i < 3; i++) { - if (st->shreg <= 1) - st->shreg = hdlcdrv_getbits(&sm->hdrv) | 0x10000; - st->scram = (st->scram << 1) | - (st->shreg & 1); - st->shreg >>= 1; - if (st->scram & SCRAM_TAP1) - st->scram ^= SCRAM_TAPN; - } - j = (st->scram >> (SCRAM_SHIFT+3)) & 7; - st->txbits[0] -= (j ^ (j >> 1)); - st->txbits[0] &= 7; - st->tbl = psk48_tx_table; - } - if (st->txseq >= PSK48_TXF_OVERSAMPLING) - st->txseq = 0; - for (j = si = sq = 0; j < PSK48_TXF_NUMSAMPLES; j++, st->tbl += 16) { - si += st->tbl[st->txbits[j]]; - sq += st->tbl[st->txbits[j]+8]; - } - *buf = (si*COS(st->txphase)+ sq*SIN(st->txphase)) >> 15; - st->txphase = (st->txphase + PSK48_PHASEINC) & 0xffffu; - } -} - -/* --------------------------------------------------------------------- */ - -static __inline__ unsigned short tbl_atan(short q, short i) -{ - short tmp; - unsigned short argoffs = 0; - - if (i == 0 && q == 0) - return 0; - switch (((q < 0) << 1) | (i < 0)) { - case 0: - break; - case 1: - tmp = q; - q = -i; - i = tmp; - argoffs = 0x4000; - break; - case 3: - q = -q; - i = -i; - argoffs = 0x8000; - break; - case 2: - tmp = -q; - q = i; - i = tmp; - argoffs = 0xc000; - break; - } - if (q > i) { - tmp = i / q * ATAN_TABLEN; - return (argoffs+0x4000-atan_tab[((i<<15)/q*ATAN_TABLEN>>15)]) - &0xffffu; - } - return (argoffs+atan_tab[((q<<15)/i*ATAN_TABLEN)>>15])&0xffffu; -} - -#define ATAN(q,i) tbl_atan(q, i) - -/* --------------------------------------------------------------------- */ - -static void demod_psk48_baseband(struct sm_state *sm, struct demod_state_psk48 *st, - short vali, short valq) -{ - int i, j; - - st->magi = vali; - st->magq = valq; - memmove(st->pwrhist+1, st->pwrhist, - sizeof(st->pwrhist)-sizeof(st->pwrhist[0])); - st->pwrhist[0] = st->magi * st->magi + - st->magq * st->magq; - st->cur_sync = ((st->pwrhist[4] >> 2) > st->pwrhist[2] && - (st->pwrhist[0] >> 2) > st->pwrhist[2] && - st-> pwrhist[3] > st->pwrhist[2] && - st->pwrhist[1] > st->pwrhist[2]); - st->s_phase &= 0xffff; - st->s_phase += PSK48_SPHASEINC; - st->dcd_shreg <<= 1; - if (st->cur_sync) { - if (st->s_phase >= (0x8000 + 5*PSK48_SPHASEINC/2)) - st->s_phase -= PSK48_SPHASEINC/6; - else - st->s_phase += PSK48_SPHASEINC/6; - st->dcd_sum0 = 4*hweight8(st->dcd_shreg & 0xf8)- - hweight16(st->dcd_shreg & 0x1f00); - } - 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->s_phase < 0x10000) - return; - /* - * sample one constellation - */ - st->last_pskph = st->pskph; - st->pskph = (ATAN(st->magq, st->magi)- - st->phase) & 0xffffu; - st->last_ph_err = (st->pskph & 0x1fffu) - 0x1000; - st->phase += st->last_ph_err/16; - st->last_raw = st->cur_raw; - st->cur_raw = ((st->pskph >> 13) & 7); - i = (st->cur_raw - st->last_raw) & 7; - st->rawbits = i ^ (i >> 1) ^ (i >> 2); - st->descram = (st->descram << 3) | (st->rawbits); - hdlcdrv_channelbit(&sm->hdrv, st->descram & 4); - hdlcdrv_channelbit(&sm->hdrv, st->descram & 2); - hdlcdrv_channelbit(&sm->hdrv, st->descram & 1); - i = (((st->descram >> DESCRAM_TAPSH1) & 7) ^ - ((st->descram >> DESCRAM_TAPSH2) & 7) ^ - ((st->descram >> DESCRAM_TAPSH3) & 7)); - for (j = 4; j; j >>= 1) { - st->shreg >>= 1; - st->shreg |= (!!(i & j)) << 16; - if (st->shreg & 1) { - hdlcdrv_putbits(&sm->hdrv, st->shreg >> 1); - st->shreg = 0x10000; - } - } - -#if 0 - 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 &= 0xffffu; - 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); -#endif - - diag_trigger(sm); - diag_add_constellation(sm, (vali*COS(st->phase)+ valq*SIN(st->phase)) >> 13, - (valq*COS(st->phase) - vali*SIN(st->phase)) >> 13); -} - -/* --------------------------------------------------------------------- */ - -static void demodulator_4800_u8(struct sm_state *sm, const unsigned char *buf, unsigned int buflen) -{ - struct demod_state_psk48 *st = (struct demod_state_psk48 *)(&sm->d); - int i, si, sq; - const short *coeff; - - for (; buflen > 0; buflen--, buf++) { - memmove(st->infi+1, st->infi, - sizeof(st->infi)-sizeof(st->infi[0])); - memmove(st->infq+1, st->infq, - sizeof(st->infq)-sizeof(st->infq[0])); - si = *buf; - si &= 0xff; - si -= 128; - diag_add_one(sm, si << 8); - st->infi[0] = (si * COS(st->downmixer))>>7; - st->infq[0] = (si * SIN(st->downmixer))>>7; - st->downmixer = (st->downmixer-PSK48_PHASEINC)&0xffffu; - for (i = si = sq = 0, coeff = psk48_rx_coeff; i < (PSK48_RXF_LEN/2); - i++, coeff += 2) { - si += st->infi[i] * (*coeff); - sq += st->infq[i] * (*coeff); - } - demod_psk48_baseband(sm, st, si >> 15, sq >> 15); - for (i = si = sq = 0, coeff = psk48_rx_coeff + 1; i < (PSK48_RXF_LEN/2); - i++, coeff += 2) { - si += st->infi[i] * (*coeff); - sq += st->infq[i] * (*coeff); - } - demod_psk48_baseband(sm, st, si >> 15, sq >> 15); - } -} - -/* --------------------------------------------------------------------- */ - -static void demodulator_4800_s16(struct sm_state *sm, const short *buf, unsigned int buflen) -{ - struct demod_state_psk48 *st = (struct demod_state_psk48 *)(&sm->d); - int i, si, sq; - const short *coeff; - - for (; buflen > 0; buflen--, buf++) { - memmove(st->infi+1, st->infi, - sizeof(st->infi)-sizeof(st->infi[0])); - memmove(st->infq+1, st->infq, - sizeof(st->infq)-sizeof(st->infq[0])); - si = *buf; - diag_add_one(sm, si); - st->infi[0] = (si * COS(st->downmixer))>>15; - st->infq[0] = (si * SIN(st->downmixer))>>15; - st->downmixer = (st->downmixer-PSK48_PHASEINC)&0xffffu; - for (i = si = sq = 0, coeff = psk48_rx_coeff; i < (PSK48_RXF_LEN/2); - i++, coeff += 2) { - si += st->infi[i] * (*coeff); - sq += st->infq[i] * (*coeff); - } - demod_psk48_baseband(sm, st, si >> 15, sq >> 15); - for (i = si = sq = 0, coeff = psk48_rx_coeff + 1; i < (PSK48_RXF_LEN/2); - i++, coeff += 2) { - si += st->infi[i] * (*coeff); - sq += st->infq[i] * (*coeff); - } - demod_psk48_baseband(sm, st, si >> 15, sq >> 15); - } -} - -/* --------------------------------------------------------------------- */ - -static void mod_init_4800(struct sm_state *sm) -{ - struct mod_state_psk48 *st = (struct mod_state_psk48 *)(&sm->m); - - st->scram = 1; -} - -/* --------------------------------------------------------------------- */ - -static void demod_init_4800(struct sm_state *sm) -{ - struct demod_state_psk48 *st = (struct demod_state_psk48 *)(&sm->d); - - st->dcd_time = 120; - st->dcd_sum0 = 2; -} - -/* --------------------------------------------------------------------- */ - -const struct modem_tx_info sm_psk4800_tx = { - "psk4800", sizeof(struct mod_state_psk48), - PSK48_SAMPLERATE, 4800, - modulator_4800_u8, modulator_4800_s16, mod_init_4800 -}; - -const struct modem_rx_info sm_psk4800_rx = { - "psk4800", sizeof(struct demod_state_psk48), - PSK48_SAMPLERATE, 4800, 1, PSK48_TXF_OVERSAMPLING, - demodulator_4800_u8, demodulator_4800_s16, demod_init_4800 -}; - -/* --------------------------------------------------------------------- */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/drivers/net/hamradio/soundmodem/sm_sbc.c linux.2.5.47-ac6/drivers/net/hamradio/soundmodem/sm_sbc.c --- linux.2.5.47/drivers/net/hamradio/soundmodem/sm_sbc.c 2002-10-31 14:57:01.000000000 +0000 +++ linux.2.5.47-ac6/drivers/net/hamradio/soundmodem/sm_sbc.c 1970-01-01 01:00:00.000000000 +0100 @@ -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 -#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; }) - -static 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; -} - -static 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 net_device *dev) -{ - int i; - - outb(1, DSP_RESET(dev->base_addr)); - udelay(300); - 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 net_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 net_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 net_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 net_device *dev) -{ - inb(DSP_DATA_AVAIL(dev->base_addr)); -} - -/* --------------------------------------------------------------------- */ - -static void inline sbc_int_ack_16bit(struct net_device *dev) -{ - inb(DSP_INTACK_16BIT(dev->base_addr)); -} - -/* --------------------------------------------------------------------- */ - -static void setup_dma_dsp(struct net_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 net_device *dev = (struct net_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 net_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(sm->dma.obuf); - return -EBUSY; - } - if (request_irq(dev->irq, sbc_interrupt, SA_INTERRUPT, - sm->hwdrv->hw_name, dev)) { - free_dma(dev->dma); - kfree(sm->dma.obuf); - 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 net_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 net_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 net_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 (!capable(CAP_SYS_RAWIO)) - 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 net_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 net_device *dev = (struct net_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 net_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 net_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 net_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 net_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 --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/drivers/net/hamradio/soundmodem/sm_wss.c linux.2.5.47-ac6/drivers/net/hamradio/soundmodem/sm_wss.c --- linux.2.5.47/drivers/net/hamradio/soundmodem/sm_wss.c 2002-10-31 14:57:01.000000000 +0000 +++ linux.2.5.47-ac6/drivers/net/hamradio/soundmodem/sm_wss.c 1970-01-01 01:00:00.000000000 +0100 @@ -1,967 +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; }) - -static 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; -} - -static 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 net_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 net_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 net_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 net_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) { - restore_flags(flags); - 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 net_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 net_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 net_device *dev = (struct net_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 net_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(sm->dma.obuf); - return -EBUSY; - } - if (request_irq(dev->irq, wss_interrupt, SA_INTERRUPT, - sm->hwdrv->hw_name, dev)) { - free_dma(dev->dma); - kfree(sm->dma.obuf); - 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 net_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 net_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 net_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 (!capable(CAP_SYS_RAWIO)) - 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 net_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 net_device *dev = (struct net_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 net_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 net_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 net_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 net_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 --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/drivers/net/pcmcia/smc91c92_cs.c linux.2.5.47-ac6/drivers/net/pcmcia/smc91c92_cs.c --- linux.2.5.47/drivers/net/pcmcia/smc91c92_cs.c 2002-11-11 16:39:10.000000000 +0000 +++ linux.2.5.47-ac6/drivers/net/pcmcia/smc91c92_cs.c 2002-11-13 15:22:31.000000000 +0000 @@ -358,6 +358,7 @@ memset(smc, 0, sizeof(struct smc_private)); link = &smc->link; dev = &smc->dev; spin_lock_init(&smc->lock); + init_timer(&link->release); link->release.function = &smc91c92_release; link->release.data = (u_long)link; link->io.NumPorts1 = 16; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/drivers/net/rrunner.c linux.2.5.47-ac6/drivers/net/rrunner.c --- linux.2.5.47/drivers/net/rrunner.c 2002-10-31 14:57:04.000000000 +0000 +++ linux.2.5.47-ac6/drivers/net/rrunner.c 2002-11-13 15:13:33.000000000 +0000 @@ -1,7 +1,7 @@ /* * rrunner.c: Linux driver for the Essential RoadRunner HIPPI board. * - * Copyright (C) 1998-2000 by Jes Sorensen, . + * Copyright (C) 1998-2002 by Jes Sorensen, . * * Thanks to Essential Communication for providing us with hardware * and very comprehensive documentation without which I would not have @@ -19,9 +19,10 @@ * * Softnet support and various other patches from Val Henson of * ODS/Essential. + * + * PCI DMA mapping code partly based on work by Francois Romieu. */ -#error Please convert me to Documentation/DMA-mapping.txt #define DEBUG 1 #define RX_DMA_SKBUFF 1 @@ -50,45 +51,20 @@ #include #include -#if (LINUX_VERSION_CODE < 0x02030e) -#define net_device device -#endif - -#if (LINUX_VERSION_CODE >= 0x02031b) -#define NEW_NETINIT -#endif - -#if (LINUX_VERSION_CODE < 0x02032b) -/* - * SoftNet changes - */ -#define dev_kfree_skb_irq(a) dev_kfree_skb(a) -#define netif_wake_queue(dev) clear_bit(0, &dev->tbusy) -#define netif_stop_queue(dev) set_bit(0, &dev->tbusy) - -static inline void netif_start_queue(struct net_device *dev) -{ - dev->tbusy = 0; - dev->start = 1; -} - -#define rr_mark_net_bh(foo) mark_bh(foo) -#define rr_if_busy(dev) dev->tbusy -#define rr_if_running(dev) dev->start /* Currently unused. */ -#define rr_if_down(dev) do { dev->start = 0; } while (0) -#else -#define NET_BH 0 -#define rr_mark_net_bh(foo) do { } while(0) #define rr_if_busy(dev) netif_queue_stopped(dev) #define rr_if_running(dev) netif_running(dev) -#define rr_if_down(dev) do { } while(0) -#endif #include "rrunner.h" #define RUN_AT(x) (jiffies + (x)) +MODULE_AUTHOR("Jes Sorensen "); +MODULE_DESCRIPTION("Essential RoadRunner HIPPI driver"); +MODULE_LICENSE("GPL"); + +static char version[] __initdata = "rrunner.c: v0.50 11/11/2002 Jes Sorensen (jes@wildopensource.com)\n"; + /* * Implementation notes: * @@ -104,11 +80,6 @@ * stack will need to know about I/O vectors or something similar. */ -static char version[] __initdata = "rrunner.c: v0.22 03/01/2000 Jes Sorensen (Jes.Sorensen@cern.ch)\n"; - -static struct net_device *root_dev; - - /* * These are checked at init time to see if they are at least 256KB * and increased to 256KB if they are not. This is done to avoid ending @@ -117,200 +88,185 @@ extern __u32 sysctl_wmem_max; extern __u32 sysctl_rmem_max; -static int probed __initdata = 0; - -#if LINUX_VERSION_CODE >= 0x20400 -static struct pci_device_id rrunner_pci_tbl[] __initdata = { - { PCI_VENDOR_ID_ESSENTIAL, PCI_DEVICE_ID_ESSENTIAL_ROADRUNNER, PCI_ANY_ID, PCI_ANY_ID, }, - { } /* Terminating entry */ -}; -MODULE_DEVICE_TABLE(pci, rrunner_pci_tbl); -#endif /* LINUX_VERSION_CODE >= 0x20400 */ - -#ifdef NEW_NETINIT -int __init rr_hippi_probe (void) -#else -int __init rr_hippi_probe (struct net_device *dev) -#endif +static int __devinit rr_init_one(struct pci_dev *pdev, + const struct pci_device_id *ent) { -#ifdef NEW_NETINIT struct net_device *dev; -#endif - int boards_found = 0; - int version_disp; /* was version info already displayed? */ - struct pci_dev *pdev = NULL; - struct pci_dev *opdev = NULL; + static int version_disp; u8 pci_latency; struct rr_private *rrpriv; + void *tmpptr; + dma_addr_t ring_dma; + int ret; - if (probed) - return -ENODEV; - probed++; - - version_disp = 0; - - while((pdev = pci_find_device(PCI_VENDOR_ID_ESSENTIAL, - PCI_DEVICE_ID_ESSENTIAL_ROADRUNNER, - pdev))) - { - if (pci_enable_device(pdev)) - continue; + dev = init_hippi_dev(NULL, sizeof(struct rr_private)); + if (!dev) { + ret = -ENOMEM; + goto out2; + } - if (pdev == opdev) - return 0; + ret = pci_enable_device(pdev); + if (ret) { + ret = -ENODEV; + goto out2; + } - /* - * So we found our HIPPI ... time to tell the system. - */ + if (!dev->priv) + dev->priv = kmalloc(sizeof(*rrpriv), GFP_KERNEL); - dev = init_hippi_dev(NULL, sizeof(struct rr_private)); + if (!dev->priv) { + ret = -ENOMEM; + goto out2; + } - if (!dev) - break; + rrpriv = (struct rr_private *)dev->priv; + memset(rrpriv, 0, sizeof(*rrpriv)); - if (!dev->priv) - dev->priv = kmalloc(sizeof(*rrpriv), GFP_KERNEL); + SET_MODULE_OWNER(dev); - if (!dev->priv) - return -ENOMEM; + if (pci_request_regions(pdev, "rrunner")) { + ret = -EIO; + goto out; + } - rrpriv = (struct rr_private *)dev->priv; - memset(rrpriv, 0, sizeof(*rrpriv)); + pci_set_drvdata(pdev, dev); -#ifdef CONFIG_SMP - spin_lock_init(&rrpriv->lock); -#endif - sprintf(rrpriv->name, "RoadRunner serial HIPPI"); + rrpriv->pci_dev = pdev; - dev->irq = pdev->irq; - SET_MODULE_OWNER(dev); - dev->open = &rr_open; - dev->hard_start_xmit = &rr_start_xmit; - dev->stop = &rr_close; - dev->get_stats = &rr_get_stats; - dev->do_ioctl = &rr_ioctl; + spin_lock_init(&rrpriv->lock); + sprintf(rrpriv->name, "RoadRunner serial HIPPI"); -#if (LINUX_VERSION_CODE < 0x02030d) - dev->base_addr = pdev->base_address[0]; -#else - dev->base_addr = pdev->resource[0].start; -#endif + dev->irq = pdev->irq; + dev->open = &rr_open; + dev->hard_start_xmit = &rr_start_xmit; + dev->stop = &rr_close; + dev->get_stats = &rr_get_stats; + dev->do_ioctl = &rr_ioctl; - /* display version info if adapter is found */ - if (!version_disp) - { - /* set display flag to TRUE so that */ - /* we only display this string ONCE */ - version_disp = 1; - printk(version); - } - - pci_read_config_byte(pdev, PCI_LATENCY_TIMER, &pci_latency); - if (pci_latency <= 0x58){ - pci_latency = 0x58; - pci_write_config_byte(pdev, PCI_LATENCY_TIMER, - pci_latency); - } - - pci_set_master(pdev); - - printk(KERN_INFO "%s: Essential RoadRunner serial HIPPI " - "at 0x%08lx, irq %i, PCI latency %i\n", dev->name, - dev->base_addr, dev->irq, pci_latency); + dev->base_addr = pci_resource_start(pdev, 0); - /* - * Remap the regs into kernel space. - */ + /* display version info if adapter is found */ + if (!version_disp) { + /* set display flag to TRUE so that */ + /* we only display this string ONCE */ + version_disp = 1; + printk(version); + } - rrpriv->regs = (struct rr_regs *) - ioremap(dev->base_addr, 0x1000); + pci_read_config_byte(pdev, PCI_LATENCY_TIMER, &pci_latency); + if (pci_latency <= 0x58){ + pci_latency = 0x58; + pci_write_config_byte(pdev, PCI_LATENCY_TIMER, pci_latency); + } - if (!rrpriv->regs){ - printk(KERN_ERR "%s: Unable to map I/O register, " - "RoadRunner %i will be disabled.\n", - dev->name, boards_found); - break; - } + pci_set_master(pdev); - /* - * Don't access any registes before this point! - */ -#ifdef __BIG_ENDIAN - writel(readl(®s->HostCtrl) | NO_SWAP, ®s->HostCtrl); -#endif - /* - * Need to add a case for little-endian 64-bit hosts here. - */ + printk(KERN_INFO "%s: Essential RoadRunner serial HIPPI " + "at 0x%08lx, irq %i, PCI latency %i\n", dev->name, + dev->base_addr, dev->irq, pci_latency); + + /* + * Remap the regs into kernel space. + */ - rr_init(dev); + rrpriv->regs = (struct rr_regs *)ioremap(dev->base_addr, 0x1000); - boards_found++; - dev->base_addr = 0; - dev = NULL; - opdev = pdev; + if (!rrpriv->regs){ + printk(KERN_ERR "%s: Unable to map I/O register, " + "RoadRunner will be disabled.\n", dev->name); + ret = -EIO; + goto out; } - /* - * If we're at this point we're going through rr_hippi_probe() - * for the first time. Return success (0) if we've initialized - * 1 or more boards. Otherwise, return failure (-ENODEV). - */ + tmpptr = pci_alloc_consistent(pdev, TX_TOTAL_SIZE, &ring_dma); + rrpriv->tx_ring = tmpptr; + rrpriv->tx_ring_dma = ring_dma; -#ifdef MODULE - return boards_found; -#else - if (boards_found > 0) - return 0; - else - return -ENODEV; -#endif -} + if (!tmpptr) { + ret = -ENOMEM; + goto out; + } + tmpptr = pci_alloc_consistent(pdev, RX_TOTAL_SIZE, &ring_dma); + rrpriv->rx_ring = tmpptr; + rrpriv->rx_ring_dma = ring_dma; -#ifdef MODULE -#if LINUX_VERSION_CODE > 0x20118 -MODULE_AUTHOR("Jes Sorensen "); -MODULE_DESCRIPTION("Essential RoadRunner HIPPI driver"); -MODULE_LICENSE("GPL"); -#endif + if (!tmpptr) { + ret = -ENOMEM; + goto out; + } -int init_module(void) -{ - int cards; + tmpptr = pci_alloc_consistent(pdev, EVT_RING_SIZE, &ring_dma); + rrpriv->evt_ring = tmpptr; + rrpriv->evt_ring_dma = ring_dma; - root_dev = NULL; + if (!tmpptr) { + ret = -ENOMEM; + goto out; + } -#ifdef NEW_NETINIT - cards = rr_hippi_probe(); -#else - cards = rr_hippi_probe(NULL); + /* + * Don't access any register before this point! + */ +#ifdef __BIG_ENDIAN + writel(readl(®s->HostCtrl) | NO_SWAP, ®s->HostCtrl); #endif - return cards ? 0 : -ENODEV; + /* + * Need to add a case for little-endian 64-bit hosts here. + */ + + rr_init(dev); + + dev->base_addr = 0; + return 0; + + out: + if (rrpriv->rx_ring) + pci_free_consistent(pdev, RX_TOTAL_SIZE, rrpriv->rx_ring, + rrpriv->rx_ring_dma); + if (rrpriv->tx_ring) + pci_free_consistent(pdev, TX_TOTAL_SIZE, rrpriv->tx_ring, + rrpriv->tx_ring_dma); + if (rrpriv->regs) + iounmap(rrpriv->regs); + if (pdev) { + pci_release_regions(pdev); + pci_set_drvdata(pdev, NULL); + } + + out2: + if (dev) { + unregister_hipdev(dev); + kfree(dev); + } + return ret; } -void cleanup_module(void) +static void __devexit rr_remove_one (struct pci_dev *pdev) { - struct rr_private *rr; - struct net_device *next; - - while (root_dev) { - next = ((struct rr_private *)root_dev->priv)->next; - rr = (struct rr_private *)root_dev->priv; + struct net_device *dev = pci_get_drvdata(pdev); + struct rr_private *rr = (struct rr_private *)dev->priv; + if (dev) { if (!(readl(&rr->regs->HostCtrl) & NIC_HALTED)){ printk(KERN_ERR "%s: trying to unload running NIC\n", - root_dev->name); + dev->name); writel(HALT_NIC, &rr->regs->HostCtrl); } + pci_free_consistent(pdev, EVT_RING_SIZE, rr->evt_ring, + rr->evt_ring_dma); + pci_free_consistent(pdev, RX_TOTAL_SIZE, rr->rx_ring, + rr->rx_ring_dma); + pci_free_consistent(pdev, TX_TOTAL_SIZE, rr->tx_ring, + rr->tx_ring_dma); + unregister_hipdev(dev); iounmap(rr->regs); - unregister_hipdev(root_dev); - kfree(root_dev); - - root_dev = next; + kfree(dev); + pci_release_regions(pdev); + pci_set_drvdata(pdev, NULL); } } -#endif /* @@ -634,9 +590,6 @@ sysctl_wmem_max = 262144; } - rrpriv->next = root_dev; - root_dev = dev; - return 0; } @@ -668,14 +621,14 @@ goto error; } - set_rxaddr(regs, rrpriv->rx_ctrl); - set_infoaddr(regs, rrpriv->info); + set_rxaddr(regs, rrpriv->rx_ctrl_dma); + set_infoaddr(regs, rrpriv->info_dma); rrpriv->info->evt_ctrl.entry_size = sizeof(struct event); rrpriv->info->evt_ctrl.entries = EVT_RING_ENTRIES; rrpriv->info->evt_ctrl.mode = 0; rrpriv->info->evt_ctrl.pi = 0; - set_rraddr(&rrpriv->info->evt_ctrl.rngptr, rrpriv->evt_ring); + set_rraddr(&rrpriv->info->evt_ctrl.rngptr, rrpriv->evt_ring_dma); rrpriv->info->cmd_ctrl.entry_size = sizeof(struct cmd); rrpriv->info->cmd_ctrl.entries = CMD_RING_ENTRIES; @@ -695,7 +648,7 @@ rrpriv->info->tx_ctrl.entries = TX_RING_ENTRIES; rrpriv->info->tx_ctrl.mode = 0; rrpriv->info->tx_ctrl.pi = 0; - set_rraddr(&rrpriv->info->tx_ctrl.rngptr, rrpriv->tx_ring); + set_rraddr(&rrpriv->info->tx_ctrl.rngptr, rrpriv->tx_ring_dma); /* * Set dirty_tx before we start receiving interrupts, otherwise @@ -730,6 +683,7 @@ for (i = 0; i < RX_RING_ENTRIES; i++) { struct sk_buff *skb; + dma_addr_t addr; rrpriv->rx_ring[i].mode = 0; skb = alloc_skb(dev->mtu + HIPPI_HLEN, GFP_ATOMIC); @@ -740,6 +694,8 @@ goto error; } rrpriv->rx_skbuff[i] = skb; + addr = pci_map_single(rrpriv->pci_dev, skb->data, + dev->mtu + HIPPI_HLEN, PCI_DMA_FROMDEVICE); /* * Sanity test to see if we conflict with the DMA * limitations of the Roadrunner. @@ -747,7 +703,7 @@ if ((((unsigned long)skb->data) & 0xfff) > ~65320) printk("skb alloc error\n"); - set_rraddr(&rrpriv->rx_ring[i].addr, skb->data); + set_rraddr(&rrpriv->rx_ring[i].addr, addr); rrpriv->rx_ring[i].size = dev->mtu + HIPPI_HLEN; } @@ -756,7 +712,7 @@ rrpriv->rx_ctrl[4].mode = 8; rrpriv->rx_ctrl[4].pi = 0; wmb(); - set_rraddr(&rrpriv->rx_ctrl[4].rngptr, rrpriv->rx_ring); + set_rraddr(&rrpriv->rx_ctrl[4].rngptr, rrpriv->rx_ring_dma); udelay(1000); @@ -785,10 +741,17 @@ * make sure we release everything we allocated before failing */ for (i = 0; i < RX_RING_ENTRIES; i++) { - if (rrpriv->rx_skbuff[i]) { + struct sk_buff *skb = rrpriv->rx_skbuff[i]; + + if (skb) { + pci_unmap_single(rrpriv->pci_dev, + rrpriv->rx_ring[i].addr.addrlo, + dev->mtu + HIPPI_HLEN, + PCI_DMA_FROMDEVICE); rrpriv->rx_ring[i].size = 0; set_rraddr(&rrpriv->rx_ring[i].addr, 0); - dev_kfree_skb(rrpriv->rx_skbuff[i]); + dev_kfree_skb(skb); + rrpriv->rx_skbuff[i] = 0; } } return ecode; @@ -1009,12 +972,14 @@ struct rr_regs *regs = rrpriv->regs; do { + struct rx_desc *desc; u32 pkt_len; - pkt_len = rrpriv->rx_ring[index].size; + + desc = &(rrpriv->rx_ring[index]); + pkt_len = desc->size; #if (DEBUG > 2) printk("index %i, rxlimit %i\n", index, rxlimit); - printk("len %x, mode %x\n", pkt_len, - rrpriv->rx_ring[index].mode); + printk("len %x, mode %x\n", pkt_len, desc->mode); #endif if ( (rrpriv->rx_ring[index].mode & PACKET_BAD) == PACKET_BAD){ rrpriv->stats.rx_dropped++; @@ -1022,7 +987,12 @@ } if (pkt_len > 0){ - struct sk_buff *skb; + struct sk_buff *skb, *rx_skb; + + rx_skb = rrpriv->rx_skbuff[index]; + + pci_dma_sync_single(rrpriv->pci_dev, desc->addr.addrlo, + pkt_len, PCI_DMA_FROMDEVICE); if (pkt_len < PKT_COPY_THRESHOLD) { skb = alloc_skb(pkt_len, GFP_ATOMIC); @@ -1032,19 +1002,27 @@ goto defer; }else memcpy(skb_put(skb, pkt_len), - rrpriv->rx_skbuff[index]->data, - pkt_len); + rx_skb->data, pkt_len); }else{ struct sk_buff *newskb; newskb = alloc_skb(dev->mtu + HIPPI_HLEN, - GFP_ATOMIC); + GFP_ATOMIC); if (newskb){ - skb = rrpriv->rx_skbuff[index]; + dma_addr_t addr; + + pci_unmap_single(rrpriv->pci_dev, + desc->addr.addrlo, dev->mtu + + HIPPI_HLEN, PCI_DMA_FROMDEVICE); + skb = rx_skb; skb_put(skb, pkt_len); rrpriv->rx_skbuff[index] = newskb; - set_rraddr(&rrpriv->rx_ring[index].addr, newskb->data); - }else{ + addr = pci_map_single(rrpriv->pci_dev, + newskb->data, + dev->mtu + HIPPI_HLEN, + PCI_DMA_FROMDEVICE); + set_rraddr(&desc->addr, addr); + } else { printk("%s: Out of memory, deferring " "packet\n", dev->name); rrpriv->stats.rx_dropped++; @@ -1061,8 +1039,8 @@ rrpriv->stats.rx_bytes += pkt_len; } defer: - rrpriv->rx_ring[index].mode = 0; - rrpriv->rx_ring[index].size = dev->mtu + HIPPI_HLEN; + desc->mode = 0; + desc->size = dev->mtu + HIPPI_HLEN; if ((index & 7) == 7) writel(index, ®s->IpRxPi); @@ -1120,14 +1098,24 @@ * of sync. error need to check entry in ring -kbf */ if(rrpriv->tx_skbuff[txcon]){ + struct tx_desc *desc; + struct sk_buff *skb; + + desc = &(rrpriv->tx_ring[txcon]); + skb = rrpriv->tx_skbuff[txcon]; + rrpriv->stats.tx_packets++; - rrpriv->stats.tx_bytes +=rrpriv->tx_skbuff[txcon]->len; - dev_kfree_skb_irq(rrpriv->tx_skbuff[txcon]); + rrpriv->stats.tx_bytes += skb->len; + + pci_unmap_single(rrpriv->pci_dev, + desc->addr.addrlo, skb->len, + PCI_DMA_TODEVICE); + dev_kfree_skb_irq(skb); rrpriv->tx_skbuff[txcon] = NULL; - rrpriv->tx_ring[txcon].size = 0; + desc->size = 0; set_rraddr(&rrpriv->tx_ring[txcon].addr, 0); - rrpriv->tx_ring[txcon].mode = 0; + desc->mode = 0; } txcon = (txcon + 1) % TX_RING_ENTRIES; } while (txcsmr != txcon); @@ -1139,7 +1127,6 @@ != rrpriv->dirty_tx)){ rrpriv->tx_full = 0; netif_wake_queue(dev); - rr_mark_net_bh(NET_BH); } } @@ -1164,6 +1151,7 @@ memset(rrpriv->rx_ctrl, 0, 256 * sizeof(struct ring_ctrl)); memset(rrpriv->info, 0, sizeof(struct rr_info)); wmb(); + for (i = 0; i < TX_RING_ENTRIES; i++) { if (rrpriv->tx_skbuff[i]) { rrpriv->tx_ring[i].size = 0; @@ -1181,6 +1169,7 @@ rrpriv->rx_skbuff[i] = NULL; } } + if (rr_init1(dev)) { spin_lock_irqsave(&rrpriv->lock, flags); writel(readl(®s->HostCtrl)|HALT_NIC|RR_CLEAR_INT, @@ -1195,12 +1184,13 @@ static int rr_open(struct net_device *dev) { - struct rr_private *rrpriv; + struct rr_private *rrpriv = (struct rr_private *)dev->priv; + struct pci_dev *pdev = rrpriv->pci_dev; struct rr_regs *regs; int ecode = 0; unsigned long flags; + dma_addr_t dma_addr; - rrpriv = (struct rr_private *)dev->priv; regs = rrpriv->regs; if (rrpriv->fw_rev < 0x00020000) { @@ -1210,24 +1200,29 @@ goto error; } - rrpriv->rx_ctrl = kmalloc(256*sizeof(struct ring_ctrl), GFP_KERNEL); + rrpriv->rx_ctrl = pci_alloc_consistent(pdev, + 256 * sizeof(struct ring_ctrl), + &dma_addr); if (!rrpriv->rx_ctrl) { ecode = -ENOMEM; goto error; } + rrpriv->rx_ctrl_dma = dma_addr; + memset(rrpriv->rx_ctrl, 0, 256*sizeof(struct ring_ctrl)); - rrpriv->info = kmalloc(sizeof(struct rr_info), GFP_KERNEL); - if (!rrpriv->info){ - rrpriv->rx_ctrl = NULL; + rrpriv->info = pci_alloc_consistent(pdev, sizeof(struct rr_info), + &dma_addr); + if (!rrpriv->info) { ecode = -ENOMEM; goto error; } - memset(rrpriv->rx_ctrl, 0, 256 * sizeof(struct ring_ctrl)); + rrpriv->info_dma = dma_addr; memset(rrpriv->info, 0, sizeof(struct rr_info)); wmb(); spin_lock_irqsave(&rrpriv->lock, flags); writel(readl(®s->HostCtrl)|HALT_NIC|RR_CLEAR_INT, ®s->HostCtrl); + readl(®s->HostCtrl); spin_unlock_irqrestore(&rrpriv->lock, flags); if (request_irq(dev->irq, rr_interrupt, SA_SHIRQ, rrpriv->name, dev)) @@ -1251,6 +1246,7 @@ netif_start_queue(dev); + MOD_INC_USE_COUNT; return ecode; error: @@ -1268,12 +1264,54 @@ } netif_stop_queue(dev); - rr_if_down(dev); return ecode; } +static inline void rr_raz_tx(struct rr_private *rrpriv, + struct net_device *dev) +{ + int i; + + for (i = 0; i < TX_RING_ENTRIES; i++) { + struct sk_buff *skb = rrpriv->tx_skbuff[i]; + + if (skb) { + struct tx_desc *desc = &(rrpriv->tx_ring[i]); + + pci_unmap_single(rrpriv->pci_dev, desc->addr.addrlo, + skb->len, PCI_DMA_TODEVICE); + desc->size = 0; + set_rraddr(&desc->addr, 0); + dev_kfree_skb(skb); + rrpriv->tx_skbuff[i] = NULL; + } + } +} + + +static inline void rr_raz_rx(struct rr_private *rrpriv, + struct net_device *dev) +{ + int i; + + for (i = 0; i < RX_RING_ENTRIES; i++) { + struct sk_buff *skb = rrpriv->rx_skbuff[i]; + + if (skb) { + struct rx_desc *desc = &(rrpriv->rx_ring[i]); + + pci_unmap_single(rrpriv->pci_dev, desc->addr.addrlo, + dev->mtu + HIPPI_HLEN, PCI_DMA_FROMDEVICE); + desc->size = 0; + set_rraddr(&desc->addr, 0); + dev_kfree_skb(skb); + rrpriv->rx_skbuff[i] = NULL; + } + } +} + static void rr_dump(struct net_device *dev) { struct rr_private *rrpriv; @@ -1313,11 +1351,10 @@ if (rrpriv->tx_skbuff[cons]){ len = min_t(int, 0x80, rrpriv->tx_skbuff[cons]->len); printk("skbuff for cons %i is valid - dumping data (0x%x bytes - skbuff len 0x%x)\n", cons, len, rrpriv->tx_skbuff[cons]->len); - printk("mode 0x%x, size 0x%x,\n phys %08x (virt %08lx), skbuff-addr %08lx, truesize 0x%x\n", + printk("mode 0x%x, size 0x%x,\n phys %08x, skbuff-addr %08lx, truesize 0x%x\n", rrpriv->tx_ring[cons].mode, rrpriv->tx_ring[cons].size, rrpriv->tx_ring[cons].addr.addrlo, - (unsigned long)bus_to_virt(rrpriv->tx_ring[cons].addr.addrlo), (unsigned long)rrpriv->tx_skbuff[cons]->data, (unsigned int)rrpriv->tx_skbuff[cons]->truesize); for (i = 0; i < len; i++){ @@ -1342,20 +1379,20 @@ { struct rr_private *rrpriv; struct rr_regs *regs; + unsigned long flags; u32 tmp; short i; netif_stop_queue(dev); - rr_if_down(dev); - + rrpriv = (struct rr_private *)dev->priv; regs = rrpriv->regs; /* * Lock to make sure we are not cleaning up while another CPU - * handling interrupts. + * is handling interrupts. */ - spin_lock(&rrpriv->lock); + spin_lock_irqsave(&rrpriv->lock, flags); tmp = readl(®s->HostCtrl); if (tmp & NIC_HALTED){ @@ -1364,12 +1401,12 @@ }else{ tmp |= HALT_NIC | RR_CLEAR_INT; writel(tmp, ®s->HostCtrl); - wmb(); + readl(®s->HostCtrl); } rrpriv->fw_running = 0; - del_timer(&rrpriv->timer); + del_timer_sync(&rrpriv->timer); writel(0, ®s->TxPi); writel(0, ®s->IpRxPi); @@ -1403,18 +1440,18 @@ } } - if (rrpriv->rx_ctrl) { - kfree(rrpriv->rx_ctrl); - rrpriv->rx_ctrl = NULL; - } - if (rrpriv->info) { - kfree(rrpriv->info); - rrpriv->info = NULL; - } + pci_free_consistent(rrpriv->pci_dev, 256 * sizeof(struct ring_ctrl), + rrpriv->rx_ctrl, rrpriv->rx_ctrl_dma); + rrpriv->rx_ctrl = NULL; + + pci_free_consistent(rrpriv->pci_dev, sizeof(struct rr_info), + rrpriv->info, rrpriv->info_dma); + rrpriv->info = NULL; free_irq(dev->irq, dev); - spin_unlock(&rrpriv->lock); + spin_unlock_irqrestore(&rrpriv->lock, flags); + MOD_DEC_USE_COUNT; return 0; } @@ -1467,7 +1504,8 @@ index = txctrl->pi; rrpriv->tx_skbuff[index] = skb; - set_rraddr(&rrpriv->tx_ring[index].addr, skb->data); + set_rraddr(&rrpriv->tx_ring[index].addr, pci_map_single( + rrpriv->pci_dev, skb->data, len + 8, PCI_DMA_TODEVICE)); rrpriv->tx_ring[index].size = len + 8; /* include IFIELD */ rrpriv->tx_ring[index].mode = PACKET_START | PACKET_END; txctrl->pi = (index + 1) % TX_RING_ENTRIES; @@ -1612,6 +1650,7 @@ { struct rr_private *rrpriv; unsigned char *image, *oldimage; + unsigned long flags; unsigned int i; int error = -EOPNOTSUPP; @@ -1629,25 +1668,27 @@ "for EEPROM image\n", dev->name); return -ENOMEM; } - - spin_lock(&rrpriv->lock); - + + if (rrpriv->fw_running){ printk("%s: Firmware already running\n", dev->name); error = -EPERM; - goto out_spin; + goto gf_out; } + spin_lock_irqsave(&rrpriv->lock, flags); i = rr_read_eeprom(rrpriv, 0, image, EEPROM_BYTES); if (i != EEPROM_BYTES){ - printk(KERN_ERR "%s: Error reading EEPROM\n", dev->name); + printk(KERN_ERR "%s: Error reading EEPROM\n", + dev->name); error = -EFAULT; - goto out_spin; + goto gf_out; } - spin_unlock(&rrpriv->lock); + spin_unlock_irqrestore(&rrpriv->lock, flags); error = copy_to_user(rq->ifr_data, image, EEPROM_BYTES); if (error) error = -EFAULT; + gf_out: kfree(image); return error; @@ -1657,56 +1698,52 @@ } image = kmalloc(EEPROM_WORDS * sizeof(u32), GFP_KERNEL); - if (!image){ - printk(KERN_ERR "%s: Unable to allocate memory " - "for EEPROM image\n", dev->name); - return -ENOMEM; - } - oldimage = kmalloc(EEPROM_WORDS * sizeof(u32), GFP_KERNEL); - if (!oldimage){ - kfree(image); + if (!image || !oldimage) { printk(KERN_ERR "%s: Unable to allocate memory " - "for old EEPROM image\n", dev->name); - return -ENOMEM; + "for EEPROM image\n", dev->name); + error = -ENOMEM; + goto wf_out; } error = copy_from_user(image, rq->ifr_data, EEPROM_BYTES); if (error) { - kfree(image); - kfree(oldimage); - return -EFAULT; + error = -EFAULT; + goto wf_out; } - spin_lock(&rrpriv->lock); if (rrpriv->fw_running){ - kfree(oldimage); printk("%s: Firmware already running\n", dev->name); error = -EPERM; - goto out_spin; + goto wf_out; } printk("%s: Updating EEPROM firmware\n", dev->name); + spin_lock_irqsave(&rrpriv->lock, flags); error = write_eeprom(rrpriv, 0, image, EEPROM_BYTES); if (error) printk(KERN_ERR "%s: Error writing EEPROM\n", dev->name); i = rr_read_eeprom(rrpriv, 0, oldimage, EEPROM_BYTES); + spin_unlock_irqrestore(&rrpriv->lock, flags); + if (i != EEPROM_BYTES) printk(KERN_ERR "%s: Error reading back EEPROM " "image\n", dev->name); - spin_unlock(&rrpriv->lock); error = memcmp(image, oldimage, EEPROM_BYTES); if (error){ printk(KERN_ERR "%s: Error verifying EEPROM image\n", dev->name); error = -EFAULT; } - kfree(image); - kfree(oldimage); + wf_out: + if (oldimage) + kfree(oldimage); + if (image) + kfree(image); return error; case SIOCRRID: @@ -1714,13 +1751,34 @@ default: return error; } +} - out_spin: - kfree(image); - spin_unlock(&rrpriv->lock); - return error; +static struct pci_device_id rr_pci_tbl[] __devinitdata = { + { PCI_VENDOR_ID_ESSENTIAL, PCI_DEVICE_ID_ESSENTIAL_ROADRUNNER, + PCI_ANY_ID, PCI_ANY_ID, }, + { 0,} +}; +MODULE_DEVICE_TABLE(pci, rr_pci_tbl); + +static struct pci_driver rr_driver = { + name: "rrunner", + id_table: rr_pci_tbl, + probe: rr_init_one, + remove: rr_remove_one, +}; + +static int __init rr_init_module(void) +{ + return pci_module_init(&rr_driver); +} + +static void __exit rr_cleanup_module(void) +{ + pci_unregister_driver(&rr_driver); } +module_init(rr_init_module); +module_exit(rr_cleanup_module); /* * Local variables: diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/drivers/net/rrunner.h linux.2.5.47-ac6/drivers/net/rrunner.h --- linux.2.5.47/drivers/net/rrunner.h 2002-10-31 14:57:04.000000000 +0000 +++ linux.2.5.47-ac6/drivers/net/rrunner.h 2002-11-13 15:13:33.000000000 +0000 @@ -351,7 +351,7 @@ */ #define EVT_RING_ENTRIES 64 -#define EVT_RING_SIZE (EVT_RING_ENTRIES * sizeof(struct event)) +#define EVT_RING_SIZE (EVT_RING_ENTRIES * sizeof(struct event)) struct event { #ifdef __LITTLE_ENDIAN @@ -496,9 +496,9 @@ } rraddr; -static inline void set_rraddr(rraddr *ra, volatile void *addr) +static inline void set_rraddr(rraddr *ra, dma_addr_t addr) { - unsigned long baddr = virt_to_bus((void *)addr); + unsigned long baddr = addr; #if (BITS_PER_LONG == 64) ra->addrlo = baddr; #else @@ -509,9 +509,9 @@ } -static inline void set_rxaddr(struct rr_regs *regs, volatile void *addr) +static inline void set_rxaddr(struct rr_regs *regs, volatile dma_addr_t addr) { - unsigned long baddr = virt_to_bus((void *)addr); + unsigned long baddr = addr; #if (BITS_PER_LONG == 64) && defined(__LITTLE_ENDIAN) writel(baddr & 0xffffffff, ®s->RxRingHi); writel(baddr >> 32, ®s->RxRingLo); @@ -526,9 +526,9 @@ } -static inline void set_infoaddr(struct rr_regs *regs, volatile void *addr) +static inline void set_infoaddr(struct rr_regs *regs, volatile dma_addr_t addr) { - unsigned long baddr = virt_to_bus((void *)addr); + unsigned long baddr = addr; #if (BITS_PER_LONG == 64) && defined(__LITTLE_ENDIAN) writel(baddr & 0xffffffff, ®s->InfoPtrHi); writel(baddr >> 32, ®s->InfoPtrLo); @@ -552,7 +552,7 @@ #else #define TX_RING_ENTRIES 16 #endif -#define TX_RING_SIZE (TX_RING_ENTRIES * sizeof(struct tx_desc)) +#define TX_TOTAL_SIZE (TX_RING_ENTRIES * sizeof(struct tx_desc)) struct tx_desc{ rraddr addr; @@ -574,7 +574,7 @@ #else #define RX_RING_ENTRIES 16 #endif -#define RX_RING_SIZE (RX_RING_ENTRIES * sizeof(struct rx_desc)) +#define RX_TOTAL_SIZE (RX_RING_ENTRIES * sizeof(struct rx_desc)) struct rx_desc{ rraddr addr; @@ -798,24 +798,30 @@ struct rr_private { - struct rx_desc rx_ring[RX_RING_ENTRIES]; - struct tx_desc tx_ring[TX_RING_ENTRIES]; - struct event evt_ring[EVT_RING_ENTRIES]; + struct rx_desc *rx_ring; + struct tx_desc *tx_ring; + struct event *evt_ring; + dma_addr_t tx_ring_dma; + dma_addr_t rx_ring_dma; + dma_addr_t evt_ring_dma; + /* Alignment ok ? */ struct sk_buff *rx_skbuff[RX_RING_ENTRIES]; struct sk_buff *tx_skbuff[TX_RING_ENTRIES]; struct rr_regs *regs; /* Register base */ struct ring_ctrl *rx_ctrl; /* Receive ring control */ struct rr_info *info; /* Shared info page */ - struct net_device *next; + dma_addr_t rx_ctrl_dma; + dma_addr_t info_dma; spinlock_t lock; struct timer_list timer; u32 cur_rx, cur_cmd, cur_evt; u32 dirty_rx, dirty_tx; u32 tx_full; u32 fw_rev; - short fw_running; + volatile short fw_running; char name[24]; /* The assigned name */ struct net_device_stats stats; + struct pci_dev *pci_dev; }; @@ -837,5 +843,6 @@ unsigned long length); static u32 rr_read_eeprom_word(struct rr_private *rrpriv, void * offset); static int rr_load_firmware(struct net_device *dev); - +static inline void rr_raz_tx(struct rr_private *, struct net_device *); +static inline void rr_raz_rx(struct rr_private *, struct net_device *); #endif /* _RRUNNER_H_ */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/drivers/net/slip.c linux.2.5.47-ac6/drivers/net/slip.c --- linux.2.5.47/drivers/net/slip.c 2002-10-31 14:57:04.000000000 +0000 +++ linux.2.5.47-ac6/drivers/net/slip.c 2002-11-05 13:52:33.000000000 +0000 @@ -261,7 +261,7 @@ if (xbuff == NULL || rbuff == NULL) { #endif if (mtu >= sl->mtu) { - printk("%s: unable to grow slip buffers, MTU change cancelled.\n", + printk(KERN_WARNING "%s: unable to grow slip buffers, MTU change cancelled.\n", dev->name); err = -ENOBUFS; } @@ -348,7 +348,7 @@ if ((c = sl->rbuff[0]) & SL_TYPE_COMPRESSED_TCP) { /* ignore compressed packets when CSLIP is off */ if (!(sl->mode & SL_MODE_CSLIP)) { - printk("%s: compressed packet ignored\n", sl->dev->name); + printk(KERN_WARNING "%s: compressed packet ignored\n", sl->dev->name); return; } /* make sure we've reserved enough space for uncompress to use */ @@ -365,7 +365,7 @@ /* turn on header compression */ sl->mode |= SL_MODE_CSLIP; sl->mode &= ~SL_MODE_ADAPTIVE; - printk("%s: header compression turned on\n", sl->dev->name); + printk(KERN_INFO "%s: header compression turned on\n", sl->dev->name); } sl->rbuff[0] &= 0x4f; if (slhc_remember(sl->slcomp, sl->rbuff, count) <= 0) { @@ -379,7 +379,7 @@ skb = dev_alloc_skb(count); if (skb == NULL) { - printk("%s: memory squeeze, dropping packet.\n", sl->dev->name); + printk(KERN_WARNING "%s: memory squeeze, dropping packet.\n", sl->dev->name); sl->rx_dropped++; return; } @@ -400,7 +400,7 @@ int actual, count; if (len > sl->mtu) { /* Sigh, shouldn't occur BUT ... */ - printk ("%s: truncating oversized transmit packet!\n", sl->dev->name); + printk(KERN_WARNING "%s: truncating oversized transmit packet!\n", sl->dev->name); sl->tx_dropped++; sl_unlock(sl); return; @@ -487,7 +487,7 @@ /* 20 sec timeout not reached */ goto out; } - printk("%s: transmit timed out, %s?\n", dev->name, + printk(KERN_WARNING "%s: transmit timed out, %s?\n", dev->name, (sl->tty->driver.chars_in_buffer(sl->tty) || sl->xleft) ? "bad line quality" : "driver error"); sl->xleft = 0; @@ -510,7 +510,7 @@ spin_lock(&sl->lock); if (!netif_running(dev)) { spin_unlock(&sl->lock); - printk("%s: xmit call when iface is down\n", dev->name); + printk(KERN_WARNING "%s: xmit call when iface is down\n", dev->name); dev_kfree_skb(skb); return 0; } @@ -1332,7 +1332,7 @@ ".\n", SLIP_VERSION, slip_maxdev ); #if defined(SL_INCLUDE_CSLIP) && !defined(MODULE) - printk("CSLIP: code copyright 1989 Regents of the University of California.\n"); + printk(KERN_INFO "CSLIP: code copyright 1989 Regents of the University of California.\n"); #endif #ifdef CONFIG_SLIP_SMART printk(KERN_INFO "SLIP linefill/keepalive option.\n"); @@ -1341,7 +1341,7 @@ slip_ctrls = (slip_ctrl_t **) kmalloc(sizeof(void*)*slip_maxdev, GFP_KERNEL); if (slip_ctrls == NULL) { - printk("SLIP: Can't allocate slip_ctrls[] array! Uaargh! (-> No SLIP available)\n"); + printk(KERN_ERR "SLIP: Can't allocate slip_ctrls[] array! Uaargh! (-> No SLIP available)\n"); return -ENOMEM; } @@ -1364,7 +1364,7 @@ sl_ldisc.receive_room = slip_receive_room; sl_ldisc.write_wakeup = slip_write_wakeup; if ((status = tty_register_ldisc(N_SLIP, &sl_ldisc)) != 0) { - printk("SLIP: can't register line discipline (err = %d)\n", status); + printk(KERN_ERR "SLIP: can't register line discipline (err = %d)\n", status); } @@ -1418,7 +1418,7 @@ if (slc) { unregister_netdev(&slc->dev); if (slc->ctrl.tty) { - printk("%s: tty discipline is still running\n", slc->dev.name); + printk(KERN_ERR "%s: tty discipline is still running\n", slc->dev.name); /* Pin module forever */ MOD_INC_USE_COUNT; busy++; @@ -1436,7 +1436,7 @@ } if ((i = tty_register_ldisc(N_SLIP, NULL))) { - printk("SLIP: can't unregister line discipline (err = %d)\n", i); + printk(KERN_ERR "SLIP: can't unregister line discipline (err = %d)\n", i); } } #endif /* MODULE */ @@ -1498,7 +1498,7 @@ /* keepalive still high :(, we must hangup */ if( sl->outfill ) /* outfill timer must be deleted too */ (void)del_timer(&sl->outfill_timer); - printk("%s: no packets received during keepalive timeout, hangup.\n", sl->dev->name); + printk(KERN_DEBUG "%s: no packets received during keepalive timeout, hangup.\n", sl->dev->name); tty_hangup(sl->tty); /* this must hangup tty & close slip */ /* I think we need not something else */ goto out; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/drivers/net/tokenring/olympic.c linux.2.5.47-ac6/drivers/net/tokenring/olympic.c --- linux.2.5.47/drivers/net/tokenring/olympic.c 2002-10-31 14:57:03.000000000 +0000 +++ linux.2.5.47-ac6/drivers/net/tokenring/olympic.c 2002-10-31 15:05:20.000000000 +0000 @@ -655,8 +655,8 @@ printk(" stat_ring[7]: %p\n", &(olympic_priv->olympic_rx_status_ring[7]) ); printk("RXCDA: %x, rx_ring[0]: %p\n",readl(olympic_mmio+RXCDA),&olympic_priv->olympic_rx_ring[0]); - printk("Rx_ring_dma_addr = %08x, rx_status_dma_addr = -%08x\n",olympic_priv->rx_ring_dma_addr,olympic_priv->rx_status_ring_dma_addr) ; + printk("Rx_ring_dma_addr = %08x, rx_status_dma_addr = %08x\n", + olympic_priv->rx_ring_dma_addr,olympic_priv->rx_status_ring_dma_addr) ; #endif writew((((readw(olympic_mmio+RXENQ)) & 0x8000) ^ 0x8000) | i,olympic_mmio+RXENQ); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/drivers/net/wan/hostess_sv11.c linux.2.5.47-ac6/drivers/net/wan/hostess_sv11.c --- linux.2.5.47/drivers/net/wan/hostess_sv11.c 2002-10-31 14:57:03.000000000 +0000 +++ linux.2.5.47-ac6/drivers/net/wan/hostess_sv11.c 2002-11-19 00:24:33.000000000 +0000 @@ -284,9 +284,11 @@ goto dmafail; } } - save_flags(flags); - cli(); - + + /* Kill our private IRQ line the hostess can end up chattering + until the configuration is set */ + disable_irq(irq); + /* * Begin normal initialise */ @@ -294,7 +296,7 @@ if(z8530_init(dev)!=0) { printk(KERN_ERR "Z8530 series device not found.\n"); - restore_flags(flags); + enable_irq(irq); goto dmafail2; } z8530_channel_load(&dev->chanB, z8530_dead_port); @@ -303,8 +305,8 @@ else z8530_channel_load(&dev->chanA, z8530_hdlc_kilostream_85230); - restore_flags(flags); - + enable_irq(irq); + /* * Now we can take the IRQ @@ -399,7 +401,7 @@ int init_module(void) { - printk(KERN_INFO "SV-11 Z85230 Synchronous Driver v 0.02.\n"); + printk(KERN_INFO "SV-11 Z85230 Synchronous Driver v 0.03.\n"); printk(KERN_INFO "(c) Copyright 2001, Red Hat Inc.\n"); if((sv11_unit=sv11_init(io,irq))==NULL) return -ENODEV; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/drivers/net/wan/pc300_drv.c linux.2.5.47-ac6/drivers/net/wan/pc300_drv.c --- linux.2.5.47/drivers/net/wan/pc300_drv.c 2002-10-31 15:05:01.000000000 +0000 +++ linux.2.5.47-ac6/drivers/net/wan/pc300_drv.c 2002-11-12 15:36:56.000000000 +0000 @@ -3687,3 +3687,9 @@ module_init(cpc_init); module_exit(cpc_cleanup_module); + +MODULE_DESCRIPTION("Cyclades-PC300 cards driver"); +MODULE_AUTHOR( "Author: Ivan Passos \r\n" + "Maintainer: Henrique Gobbi chanA.rxdma, "SeaLevel (RX)")!=0) goto dmafail; - save_flags(flags); - cli(); - + disable_irq(irq); + /* * Begin normal initialise */ @@ -312,7 +311,7 @@ if(z8530_init(dev)!=0) { printk(KERN_ERR "Z8530 series device not found.\n"); - restore_flags(flags); + enable_irq(irq); goto dmafail2; } if(dev->type==Z85C30) @@ -330,7 +329,7 @@ * Now we can take the IRQ */ - restore_flags(flags); + enable_irq(irq); for(u=0; u<2; u++) { @@ -446,7 +445,7 @@ int init_module(void) { - printk(KERN_INFO "SeaLevel Z85230 Synchronous Driver v 0.01.\n"); + printk(KERN_INFO "SeaLevel Z85230 Synchronous Driver v 0.02.\n"); printk(KERN_INFO "(c) Copyright 1998, Building Number Three Ltd.\n"); if((slvl_unit=slvl_init(io,irq, txdma, rxdma, slow))==NULL) return -ENODEV; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/drivers/pci/compat.c linux.2.5.47-ac6/drivers/pci/compat.c --- linux.2.5.47/drivers/pci/compat.c 2002-10-31 14:57:18.000000000 +0000 +++ linux.2.5.47-ac6/drivers/pci/compat.c 1970-01-01 01:00:00.000000000 +0100 @@ -1,37 +0,0 @@ -/* - * $Id: compat.c,v 1.1 1998/02/16 10:35:50 mj Exp $ - * - * PCI Bus Services -- Function For Backward Compatibility - * - * Copyright 1998--2000 Martin Mares - */ - -#include -#include -#include -#include - -/* Obsolete functions, these will be going away... */ - -#define PCI_OP(rw,size,type) \ -int pcibios_##rw##_config_##size (unsigned char bus, unsigned char dev_fn, \ - unsigned char where, unsigned type val) \ -{ \ - struct pci_dev *dev = pci_find_slot(bus, dev_fn); \ - if (!dev) return PCIBIOS_DEVICE_NOT_FOUND; \ - return pci_##rw##_config_##size(dev, where, val); \ -} - -PCI_OP(read, byte, char *) -PCI_OP(read, word, short *) -PCI_OP(read, dword, int *) -PCI_OP(write, byte, char) -PCI_OP(write, word, short) -PCI_OP(write, dword, int) - -EXPORT_SYMBOL(pcibios_read_config_byte); -EXPORT_SYMBOL(pcibios_read_config_word); -EXPORT_SYMBOL(pcibios_read_config_dword); -EXPORT_SYMBOL(pcibios_write_config_byte); -EXPORT_SYMBOL(pcibios_write_config_word); -EXPORT_SYMBOL(pcibios_write_config_dword); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/drivers/pci/Makefile linux.2.5.47-ac6/drivers/pci/Makefile --- linux.2.5.47/drivers/pci/Makefile 2002-11-11 16:39:10.000000000 +0000 +++ linux.2.5.47-ac6/drivers/pci/Makefile 2002-11-11 16:56:01.000000000 +0000 @@ -6,7 +6,7 @@ probe.o proc.o search.o compat.o setup-bus.o obj-y += access.o probe.o pci.o pool.o quirks.o \ - compat.o names.o pci-driver.o search.o hotplug.o + names.o pci-driver.o search.o hotplug.o obj-$(CONFIG_PM) += power.o obj-$(CONFIG_PROC_FS) += proc.o diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/drivers/pci/pci.c linux.2.5.47-ac6/drivers/pci/pci.c --- linux.2.5.47/drivers/pci/pci.c 2002-11-11 16:39:10.000000000 +0000 +++ linux.2.5.47-ac6/drivers/pci/pci.c 2002-11-11 16:55:33.000000000 +0000 @@ -729,6 +729,7 @@ __setup("pci=", pci_setup); #if defined(CONFIG_ISA) || defined(CONFIG_EISA) +/* FIXME: Some boxes have multiple ISA bridges! */ struct pci_dev *isa_bridge; EXPORT_SYMBOL(isa_bridge); #endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/drivers/pci/pci.ids linux.2.5.47-ac6/drivers/pci/pci.ids --- linux.2.5.47/drivers/pci/pci.ids 2002-11-11 16:39:10.000000000 +0000 +++ linux.2.5.47-ac6/drivers/pci/pci.ids 2002-11-11 16:55:33.000000000 +0000 @@ -497,8 +497,8 @@ 1011 500b DE500B Fast Ethernet 1014 0001 10/100 EtherJet Cardbus 1025 0315 ALN315 Fast Ethernet - 1033 800c PC-9821-CS01 - 1033 800d PC-9821NR-B06 + 1033 800c PC-9821-CS01 100BASE-TX Interface Card + 1033 800d PC-9821NR-B06 100BASE-TX Interface Card 108d 0016 Rapidfire 2327 10/100 Ethernet 108d 0017 GoCard 2250 Ethernet 10/100 Cardbus 10b8 2005 SMC8032DT Extreme Ethernet 10/100 @@ -1049,17 +1049,21 @@ 0003 ATM Controller 0004 R4000 PCI Bridge 0005 PCI to 486-like bus Bridge - 0006 GUI Accelerator + 0006 PC-9800 Graphic Accelerator 0007 PCI to UX-Bus Bridge - 0008 GUI Accelerator - 0009 GUI Accelerator for W98 + 0008 PC-9800 Graphic Accelerator + 0009 PCI to PC9800 Core-Graph Bridge + 0016 PCI to VL Bridge 001a [Nile II] 0021 Vrc4373 [Nile I] 0029 PowerVR PCX1 002a PowerVR 3D + 002c Star Alpha 2 + 002d PCI to C-bus Bridge 0035 USB 1179 0001 USB 12ee 7000 Root Hub + 003b PCI to C-bus Bridge 003e NAPCCARD Cardbus Controller 0046 PowerVR PCX2 [midas] 005a Vrc5074 [Nile 4] @@ -3489,7 +3493,7 @@ 5811 FW323 dead 0800 FireWire Host Bus Adapter 11c2 Sand Microelectronics -11c3 NEC Corp +11c3 NEC Corporation 11c4 Document Technologies, Inc 11c5 Shiva Corporation 11c6 Dainippon Screen Mfg. Co. Ltd diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/drivers/pci/probe.c linux.2.5.47-ac6/drivers/pci/probe.c --- linux.2.5.47/drivers/pci/probe.c 2002-11-11 16:39:10.000000000 +0000 +++ linux.2.5.47-ac6/drivers/pci/probe.c 2002-11-11 16:56:21.000000000 +0000 @@ -34,13 +34,20 @@ } /* - * Find the extent of a PCI decode.. + * Find the extent of a PCI decode, do sanity checks. */ -static u32 pci_size(u32 base, unsigned long mask) +static u32 pci_size(u32 base, u32 maxbase, unsigned long mask) { - u32 size = mask & base; /* Find the significant bits */ + u32 size = mask & maxbase; /* Find the significant bits */ + if (!size) + return 0; size = size & ~(size-1); /* Get the lowest of them to find the decode size */ - return size-1; /* extent = size - 1 */ + size -= 1; /* extent = size - 1 */ + if (base == maxbase && ((base | size) & mask) != mask) + return 0; /* base == maxbase can be valid only + if the BAR has been already + programmed with all 1s */ + return size; } static void pci_read_bases(struct pci_dev *dev, unsigned int howmany, int rom) @@ -63,13 +70,17 @@ if (l == 0xffffffff) l = 0; if ((l & PCI_BASE_ADDRESS_SPACE) == PCI_BASE_ADDRESS_SPACE_MEMORY) { + sz = pci_size(l, sz, PCI_BASE_ADDRESS_MEM_MASK); + if (!sz) + continue; res->start = l & PCI_BASE_ADDRESS_MEM_MASK; res->flags |= l & ~PCI_BASE_ADDRESS_MEM_MASK; - sz = pci_size(sz, PCI_BASE_ADDRESS_MEM_MASK); } else { + sz = pci_size(l, sz, PCI_BASE_ADDRESS_IO_MASK & 0xffff); + if (!sz) + continue; res->start = l & PCI_BASE_ADDRESS_IO_MASK; res->flags |= l & ~PCI_BASE_ADDRESS_IO_MASK; - sz = pci_size(sz, PCI_BASE_ADDRESS_IO_MASK & 0xffff); } res->end = res->start + (unsigned long) sz; res->flags |= pci_calc_resource_flags(l); @@ -99,6 +110,7 @@ if (rom) { dev->rom_base_reg = rom; res = &dev->resource[PCI_ROM_RESOURCE]; + res->name = dev->name; pci_read_config_dword(dev, rom, &l); pci_write_config_dword(dev, rom, ~PCI_ROM_ADDRESS_ENABLE); pci_read_config_dword(dev, rom, &sz); @@ -106,13 +118,14 @@ if (l == 0xffffffff) l = 0; if (sz && sz != 0xffffffff) { + sz = pci_size(l, sz, PCI_ROM_ADDRESS_MASK); + if (!sz) + return; res->flags = (l & PCI_ROM_ADDRESS_ENABLE) | IORESOURCE_MEM | IORESOURCE_PREFETCH | IORESOURCE_READONLY | IORESOURCE_CACHEABLE; res->start = l & PCI_ROM_ADDRESS_MASK; - sz = pci_size(sz, PCI_ROM_ADDRESS_MASK); res->end = res->start + (unsigned long) sz; } - res->name = dev->name; } } @@ -384,7 +397,7 @@ /* The PCI-to-PCI bridge spec requires that subtractive decoding (i.e. transparent) bridge must have programming interface code of 0x01. */ - dev->transparent = ((class & 0xff) == 1); + dev->transparent = ((dev->class & 0xff) == 1); pci_read_bases(dev, 2, PCI_ROM_ADDRESS1); break; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/drivers/pci/quirks.c linux.2.5.47-ac6/drivers/pci/quirks.c --- linux.2.5.47/drivers/pci/quirks.c 2002-11-11 16:39:10.000000000 +0000 +++ linux.2.5.47-ac6/drivers/pci/quirks.c 2002-11-16 23:16:41.000000000 +0000 @@ -212,6 +212,19 @@ } /* + * ATI Northbridge setups MCE the processor if you even + * read somewhere between 0x3b0->0x3bb or read 0x3d3 + */ + +static void __devinit quirk_ati_exploding_mce(struct pci_dev *dev) +{ + printk(KERN_INFO "ATI Northbridge, reserving I/O ports 0x3b0 to 0x3bb.\n"); + /* Mae rhaid in i beidio a edrych ar y lleoliad I/O hyn */ + request_region(0x3b0, 0x0C, "RadeonIGP"); + request_region(0x3d3, 0x01, "RadeonIGP"); +} + +/* * Let's make the southbridge information explicit instead * of having to worry about people probing the ACPI areas, * for example.. (Yes, it happens, and if you read the wrong @@ -477,6 +490,24 @@ } /* + * Common misconfiguration of the MediaGX/Geode PCI master that will + * reduce PCI bandwidth from 70MB/s to 25MB/s. See the GXM/GXLV/GX1 + * datasheets found at http://www.national.com/ds/GX for info on what + * these bits do. + */ + +static void __init quirk_mediagx_master(struct pci_dev *dev) +{ + u8 reg; + pci_read_config_byte(dev, 0x41, ®); + if (reg & 2) { + reg &= ~2; + printk(KERN_INFO "PCI: Fixup for MediaGX/Geode Slave Disconnect Boundary (0x41=0x%02x)\n", reg); + pci_write_config_byte(dev, 0x41, reg); + } +} + +/* * The main table of quirks. */ @@ -491,6 +522,7 @@ { PCI_FIXUP_FINAL, PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C586_0, quirk_isa_dma_hangs }, { PCI_FIXUP_FINAL, PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C596, quirk_isa_dma_hangs }, { PCI_FIXUP_FINAL, PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371SB_0, quirk_isa_dma_hangs }, + { PCI_FIXUP_FINAL, PCI_VENDOR_ID_NEC, PCI_DEVICE_ID_NEC_CBUS_1, quirk_isa_dma_hangs }, { PCI_FIXUP_HEADER, PCI_VENDOR_ID_S3, PCI_DEVICE_ID_S3_868, quirk_s3_64M }, { PCI_FIXUP_HEADER, PCI_VENDOR_ID_S3, PCI_DEVICE_ID_S3_968, quirk_s3_64M }, { PCI_FIXUP_FINAL, PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82437, quirk_triton }, @@ -530,6 +562,7 @@ { PCI_FIXUP_FINAL, PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_VIPER_7410, quirk_amd_ioapic }, { PCI_FIXUP_FINAL, PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_FE_GATE_700C, quirk_amd_ordering }, + { PCI_FIXUP_FINAL, PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_RADEON_IGP, quirk_ati_exploding_mce }, /* * i82380FB mobile docking controller: its PCI-to-PCI bridge * is subtractive decoding (transparent), and does indicate this @@ -538,6 +571,8 @@ */ { PCI_FIXUP_HEADER, PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82380FB, quirk_transparent_bridge }, + { PCI_FIXUP_FINAL, PCI_VENDOR_ID_CYRIX, PCI_DEVICE_ID_CYRIX_PCI_MASTER, quirk_mediagx_master }, + { 0 } }; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/drivers/pci/setup-res.c linux.2.5.47-ac6/drivers/pci/setup-res.c --- linux.2.5.47/drivers/pci/setup-res.c 2002-10-31 14:57:18.000000000 +0000 +++ linux.2.5.47-ac6/drivers/pci/setup-res.c 2002-10-31 15:05:41.000000000 +0000 @@ -137,7 +137,7 @@ } /* Sort resources by alignment */ -void __init +void __devinit pdev_sort_resources(struct pci_dev *dev, struct resource_list *head) { int i; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/drivers/pcmcia/cistpl.c linux.2.5.47-ac6/drivers/pcmcia/cistpl.c --- linux.2.5.47/drivers/pcmcia/cistpl.c 2002-11-11 16:39:10.000000000 +0000 +++ linux.2.5.47-ac6/drivers/pcmcia/cistpl.c 2002-11-17 00:26:18.000000000 +0000 @@ -429,8 +429,12 @@ tuple->TupleLink = tuple->Flags = 0; #ifdef CONFIG_CARDBUS if (s->state & SOCKET_CARDBUS) { - u_int ptr; - pcibios_read_config_dword(s->cap.cb_dev->subordinate->number, 0, 0x28, &ptr); + u32 ptr; + /* We need the cardbus device - not the bridge */ + struct pci_dev *dev = pci_find_slot(s->cap.cb_dev->subordinate->number, 0); + if(dev == NULL) + return CS_BAD_HANDLE; + pci_read_config_dword(dev, 0x28, &ptr); tuple->CISOffset = ptr & ~7; SPACE(tuple->Flags) = (ptr & 7); } else diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/drivers/pnp/core.c linux.2.5.47-ac6/drivers/pnp/core.c --- linux.2.5.47/drivers/pnp/core.c 2002-10-31 15:05:01.000000000 +0000 +++ linux.2.5.47-ac6/drivers/pnp/core.c 2002-11-18 17:06:18.000000000 +0000 @@ -164,7 +164,7 @@ return bus_register(&pnp_bus_type); } -core_initcall(pnp_init); +device_initcall(pnp_init); EXPORT_SYMBOL(pnp_protocol_register); EXPORT_SYMBOL(pnp_protocol_unregister); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/drivers/pnp/isapnp/core.c linux.2.5.47-ac6/drivers/pnp/isapnp/core.c --- linux.2.5.47/drivers/pnp/isapnp/core.c 2002-11-05 13:54:44.000000000 +0000 +++ linux.2.5.47-ac6/drivers/pnp/isapnp/core.c 2002-11-16 01:56:41.000000000 +0000 @@ -1167,7 +1167,7 @@ return 0; } -subsys_initcall(isapnp_init); +device_initcall(isapnp_init); /* format is: noisapnp */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/drivers/pnp/pnpbios/core.c linux.2.5.47-ac6/drivers/pnp/pnpbios/core.c --- linux.2.5.47/drivers/pnp/pnpbios/core.c 2002-10-31 15:05:01.000000000 +0000 +++ linux.2.5.47-ac6/drivers/pnp/pnpbios/core.c 2002-11-18 16:56:19.000000000 +0000 @@ -1494,7 +1494,7 @@ spin_lock_init(&pnp_bios_lock); - if(pnpbios_disabled) { + if(pnpbios_disabled || (dmi_broken & BROKEN_PNP_BIOS) ) { printk(KERN_INFO "PnPBIOS: Disabled\n"); return -ENODEV; } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/drivers/s390/block/dasd_3990_erp.c linux.2.5.47-ac6/drivers/s390/block/dasd_3990_erp.c --- linux.2.5.47/drivers/s390/block/dasd_3990_erp.c 2002-10-31 14:57:13.000000000 +0000 +++ linux.2.5.47-ac6/drivers/s390/block/dasd_3990_erp.c 2002-10-31 15:05:34.000000000 +0000 @@ -1122,6 +1122,9 @@ break; default: /* unknown message format - should not happen */ + DEV_MESSAGE (KERN_WARNING, device, + "unknown message format %02x", + msg_format); break; } /* end switch message format */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/drivers/s390/block/dasd.c linux.2.5.47-ac6/drivers/s390/block/dasd.c --- linux.2.5.47/drivers/s390/block/dasd.c 2002-10-31 15:05:01.000000000 +0000 +++ linux.2.5.47-ac6/drivers/s390/block/dasd.c 2002-10-31 17:37:12.000000000 +0000 @@ -80,6 +80,7 @@ MODULE_SUPPORTED_DEVICE("dasd"); MODULE_PARM(dasd, "1-" __MODULE_STRING(256) "s"); MODULE_PARM(dasd_disciplines, "1-" __MODULE_STRING(8) "s"); +MODULE_LICENSE("GPL"); /* * SECTION: prototypes for static functions of dasd.c @@ -1172,6 +1173,7 @@ BUG(); break; } + retries++; } dasd_schedule_bh(device); return rc; @@ -1536,7 +1538,7 @@ goto restart; } - /* Rechain request on device device request queue */ + /* Rechain finished requests to final queue */ cqr->endclk = get_clock(); list_move_tail(&cqr->list, final_queue); } @@ -1623,7 +1625,7 @@ /* * Take a look at the first request on the ccw queue and check - * if it reached its expire time. + * if it reached its expire time. If so, terminate the IO. */ static inline void __dasd_check_expire(dasd_device_t * device) @@ -1748,7 +1750,7 @@ } /* - * Schedules a call to dasd_process_queues over the device tasklet. + * Schedules a call to dasd_tasklet over the device tasklet. */ void dasd_schedule_bh(dasd_device_t * device) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/drivers/s390/block/dasd_devmap.c linux.2.5.47-ac6/drivers/s390/block/dasd_devmap.c --- linux.2.5.47/drivers/s390/block/dasd_devmap.c 2002-10-31 14:57:13.000000000 +0000 +++ linux.2.5.47-ac6/drivers/s390/block/dasd_devmap.c 2002-10-31 15:05:34.000000000 +0000 @@ -87,6 +87,8 @@ int dasd_devno(char *str, char **endp) { + int val; + /* remove leading '0x' */ if (*str == '0') { str++; @@ -96,7 +98,10 @@ /* We require at least one hex digit */ if (!isxdigit(*str)) return -EINVAL; - return simple_strtoul(str, endp, 16); + val = simple_strtoul(str, endp, 16); + if ((val > 0xFFFF) || (val < 0)) + return -EINVAL; + return val; } /* diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/drivers/s390/block/dasd_diag.c linux.2.5.47-ac6/drivers/s390/block/dasd_diag.c --- linux.2.5.47/drivers/s390/block/dasd_diag.c 2002-10-31 14:57:13.000000000 +0000 +++ linux.2.5.47-ac6/drivers/s390/block/dasd_diag.c 2002-10-31 15:05:34.000000000 +0000 @@ -40,6 +40,8 @@ #endif /* PRINTK_HEADER */ #define PRINTK_HEADER "dasd(diag):" +MODULE_LICENSE("GPL"); + static dasd_discipline_t dasd_diag_discipline; typedef struct dasd_diag_private_t { diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/drivers/s390/block/dasd_eckd.c linux.2.5.47-ac6/drivers/s390/block/dasd_eckd.c --- linux.2.5.47/drivers/s390/block/dasd_eckd.c 2002-10-31 14:57:13.000000000 +0000 +++ linux.2.5.47-ac6/drivers/s390/block/dasd_eckd.c 2002-10-31 15:05:34.000000000 +0000 @@ -59,6 +59,8 @@ #define ECKD_F7(i) (i->factor7) #define ECKD_F8(i) (i->factor8) +MODULE_LICENSE("GPL"); + static dasd_discipline_t dasd_eckd_discipline; typedef struct dasd_eckd_private_t { @@ -183,6 +185,31 @@ } static inline void +check_XRC (ccw1_t *de_ccw, + DE_eckd_data_t *data, + dasd_device_t *device) +{ + dasd_eckd_private_t *private; + + private = (dasd_eckd_private_t *) device->private; + + /* switch on System Time Stamp - needed for XRC Support */ + if (private->rdc_data.facilities.XRC_supported) { + + data->ga_extended |= 0x08; /* switch on 'Time Stamp Valid' */ + data->ga_extended |= 0x02; /* switch on 'Extended Parameter' */ + + data->ep_sys_time = get_clock (); + + de_ccw->count = sizeof (DE_eckd_data_t); + de_ccw->flags = CCW_FLAG_SLI; + } + + return; + +} /* end check_XRC */ + +static inline void define_extent(ccw1_t * ccw, DE_eckd_data_t * data, int trk, int totrk, int cmd, dasd_device_t * device) { @@ -216,10 +243,12 @@ case DASD_ECKD_CCW_WRITE_KD_MT: data->mask.perm = 0x02; data->attributes.operation = private->attrib.operation; + check_XRC (ccw, data, device); break; case DASD_ECKD_CCW_WRITE_CKD: case DASD_ECKD_CCW_WRITE_CKD_MT: data->attributes.operation = DASD_BYPASS_CACHE; + check_XRC (ccw, data, device); break; case DASD_ECKD_CCW_ERASE: case DASD_ECKD_CCW_WRITE_HOME_ADDRESS: @@ -227,6 +256,7 @@ data->mask.perm = 0x3; data->mask.auth = 0x1; data->attributes.operation = DASD_BYPASS_CACHE; + check_XRC (ccw, data, device); break; default: MESSAGE(KERN_ERR, "unknown opcode 0x%x", cmd); @@ -497,6 +527,11 @@ private->rdc_data.cu_type, private->rdc_data.cu_model.model); return 0; + + /* get characteristis via diag to determine the kind of minidisk under VM */ + /* needed beacause XRC is not support by VM (jet) */ + /* Can be removed as soon as VM supports XRC */ + // TBD ??? HUM } static int @@ -563,6 +598,7 @@ cqr->device = device; cqr->retries = 0; + cqr->buildclk = get_clock(); cqr->status = DASD_CQR_FILLED; return cqr; } @@ -881,6 +917,7 @@ } fcp->device = device; fcp->retries = 2; /* set retry counter to enable ERP */ + fcp->buildclk = get_clock(); fcp->status = DASD_CQR_FILLED; return fcp; } @@ -1119,6 +1156,7 @@ cqr->device = device; cqr->retries = 0; cqr->expires = 10 * HZ; + cqr->buildclk = get_clock(); cqr->status = DASD_CQR_FILLED; rc = dasd_sleep_on_immediatly(cqr); @@ -1163,6 +1201,7 @@ cqr->device = device; cqr->retries = 0; cqr->expires = 10 * HZ; + cqr->buildclk = get_clock(); cqr->status = DASD_CQR_FILLED; rc = dasd_sleep_on_immediatly(cqr); @@ -1209,6 +1248,7 @@ cqr->device = device; cqr->retries = 0; cqr->expires = 10 * HZ; + cqr->buildclk = get_clock(); cqr->status = DASD_CQR_FILLED; rc = dasd_sleep_on_immediatly(cqr); @@ -1277,6 +1317,7 @@ ccw->count = sizeof (dasd_rssd_perf_stats_t); ccw->cda = (__u32)(addr_t) stats; + cqr->buildclk = get_clock(); cqr->status = DASD_CQR_FILLED; rc = dasd_sleep_on(cqr); if (rc == 0) { diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/drivers/s390/block/dasd_eckd.h linux.2.5.47-ac6/drivers/s390/block/dasd_eckd.h --- linux.2.5.47/drivers/s390/block/dasd_eckd.h 2002-10-31 14:57:13.000000000 +0000 +++ linux.2.5.47-ac6/drivers/s390/block/dasd_eckd.h 2002-10-31 15:05:34.000000000 +0000 @@ -1,3 +1,16 @@ +/* + * File...........: linux/drivers/s390/block/dasd_eckd.h + * Author(s)......: Holger Smolinski + * Horst Hummel + * Bugreports.to..: + * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999,2000 + * + * $Revision: 1.4 $ + * + * History of changes + * + */ + #ifndef DASD_ECKD_H #define DASD_ECKD_H @@ -102,6 +115,10 @@ __u8 ga_extended; /* Global Attributes Extended */ ch_t beg_ext; ch_t end_ext; + unsigned long long ep_sys_time; /* Extended Parameter - System Time Stamp */ + __u8 ep_format; /* Extended Parameter format byte */ + __u8 ep_prio; /* Extended Parameter priority I/O byte */ + __u8 ep_reserved[6]; /* Extended Parameter Reserved */ } __attribute__ ((packed)) DE_eckd_data_t; typedef struct LO_eckd_data_t { @@ -141,7 +158,8 @@ unsigned char reserved2:4; unsigned char reserved3:8; unsigned char defect_wr:1; - unsigned char reserved4:2; + unsigned char XRC_supported:1; + unsigned char reserved4:1; unsigned char striping:1; unsigned char reserved5:4; unsigned char cfw:1; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/drivers/s390/block/dasd_fba.c linux.2.5.47-ac6/drivers/s390/block/dasd_fba.c --- linux.2.5.47/drivers/s390/block/dasd_fba.c 2002-10-31 14:57:13.000000000 +0000 +++ linux.2.5.47-ac6/drivers/s390/block/dasd_fba.c 2002-10-31 15:05:34.000000000 +0000 @@ -38,6 +38,8 @@ #define DASD_FBA_CCW_LOCATE 0x43 #define DASD_FBA_CCW_DEFINE_EXTENT 0x63 +MODULE_LICENSE("GPL"); + static dasd_discipline_t dasd_fba_discipline; typedef struct dasd_fba_private_t { diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/drivers/s390/block/dasd_proc.c linux.2.5.47-ac6/drivers/s390/block/dasd_proc.c --- linux.2.5.47/drivers/s390/block/dasd_proc.c 2002-10-31 14:57:13.000000000 +0000 +++ linux.2.5.47-ac6/drivers/s390/block/dasd_proc.c 2002-10-31 15:05:34.000000000 +0000 @@ -195,10 +195,7 @@ break; case DASD_STATE_READY: case DASD_STATE_ONLINE: - if (device->state < DASD_STATE_ONLINE) - len += sprintf(str + len, "fenced "); - else - len += sprintf(str + len, "active "); + len += sprintf(str + len, "active "); if (dasd_check_blocksize(device->bp_block)) len += sprintf(str + len, "n/f "); else diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/drivers/scsi/aacraid/aachba.c linux.2.5.47-ac6/drivers/scsi/aacraid/aachba.c --- linux.2.5.47/drivers/scsi/aacraid/aachba.c 2002-11-05 13:54:44.000000000 +0000 +++ linux.2.5.47-ac6/drivers/scsi/aacraid/aachba.c 2002-11-11 20:32:15.000000000 +0000 @@ -1113,12 +1113,12 @@ qd.locked = fsa_dev_ptr->locked[qd.cnum]; qd.deleted = fsa_dev_ptr->deleted[qd.cnum]; - if (fsa_dev_ptr->devno[qd.cnum][0] == '\0') + if (fsa_dev_ptr->devname[qd.cnum][0] == '\0') qd.unmapped = 1; else qd.unmapped = 0; - strncpy(dq.name, fsa_dev_ptr->devname[qd.cnum], 8); + strncpy(qd.name, fsa_dev_ptr->devname[qd.cnum], 8); if (copy_to_user(arg, &qd, sizeof (struct aac_query_disk))) return -EFAULT; @@ -1170,7 +1170,7 @@ * Mark the container as no longer being valid. */ fsa_dev_ptr->valid[dd.cnum] = 0; - fsa_dev_ptr->devno[dd.cnum][0] = '\0'; + fsa_dev_ptr->devname[dd.cnum][0] = '\0'; return 0; } } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/drivers/scsi/aacraid/commctrl.c linux.2.5.47-ac6/drivers/scsi/aacraid/commctrl.c --- linux.2.5.47/drivers/scsi/aacraid/commctrl.c 2002-10-31 14:57:13.000000000 +0000 +++ linux.2.5.47-ac6/drivers/scsi/aacraid/commctrl.c 2002-10-31 15:05:34.000000000 +0000 @@ -424,7 +424,12 @@ status = aac_get_pci_info(dev,arg); break; default: - status = -ENOTTY; + /* + * Return EINVAL instead of ENOTTY because blkdev_ioctl + * understands the EINVAL return code to mean that the + * ioctl wasn't handled and blk_ioctl should be called. + */ + status = -EINVAL; break; } return status; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/drivers/scsi/aic7xxx/aic7xxx_reg.h linux.2.5.47-ac6/drivers/scsi/aic7xxx/aic7xxx_reg.h --- linux.2.5.47/drivers/scsi/aic7xxx/aic7xxx_reg.h 1970-01-01 01:00:00.000000000 +0100 +++ linux.2.5.47-ac6/drivers/scsi/aic7xxx/aic7xxx_reg.h 2002-11-12 17:24:34.000000000 +0000 @@ -0,0 +1,716 @@ +/* + * DO NOT EDIT - This file is automatically generated + * from the following source files: + * + * $Id: //depot/aic7xxx/aic7xxx/aic7xxx.seq#37 $ + * $Id: //depot/aic7xxx/aic7xxx/aic7xxx.reg#24 $ + */ + +#define SCSISEQ 0x00 +#define TEMODE 0x80 +#define SCSIRSTO 0x01 + +#define SXFRCTL0 0x01 +#define DFON 0x80 +#define DFPEXP 0x40 +#define FAST20 0x20 +#define CLRSTCNT 0x10 +#define SPIOEN 0x08 +#define SCAMEN 0x04 +#define CLRCHN 0x02 + +#define SXFRCTL1 0x02 +#define BITBUCKET 0x80 +#define SWRAPEN 0x40 +#define STIMESEL 0x18 +#define ENSTIMER 0x04 +#define ACTNEGEN 0x02 +#define STPWEN 0x01 + +#define SCSISIGO 0x03 +#define CDO 0x80 +#define IOO 0x40 +#define MSGO 0x20 +#define ATNO 0x10 +#define SELO 0x08 +#define BSYO 0x04 +#define REQO 0x02 +#define ACKO 0x01 + +#define SCSISIGI 0x03 +#define P_DATAIN_DT 0x60 +#define P_DATAOUT_DT 0x20 +#define ATNI 0x10 +#define SELI 0x08 +#define BSYI 0x04 +#define REQI 0x02 +#define ACKI 0x01 + +#define SCSIRATE 0x04 +#define WIDEXFER 0x80 +#define SXFR 0x70 +#define ENABLE_CRC 0x40 +#define SINGLE_EDGE 0x10 +#define SOFS 0x0f +#define SXFR_ULTRA2 0x0f + +#define SCSIID 0x05 +#define SCSIOFFSET 0x05 +#define SOFS_ULTRA2 0x7f + +#define SCSIDATL 0x06 + +#define SCSIDATH 0x07 + +#define STCNT 0x08 + +#define OPTIONMODE 0x08 +#define AUTORATEEN 0x80 +#define AUTOACKEN 0x40 +#define ATNMGMNTEN 0x20 +#define BUSFREEREV 0x10 +#define EXPPHASEDIS 0x08 +#define SCSIDATL_IMGEN 0x04 +#define OPTIONMODE_DEFAULTS 0x03 +#define AUTO_MSGOUT_DE 0x02 +#define DIS_MSGIN_DUALEDGE 0x01 + +#define TARGCRCCNT 0x0a + +#define CLRSINT0 0x0b +#define CLRSELDO 0x40 +#define CLRSELDI 0x20 +#define CLRSELINGO 0x10 +#define CLRIOERR 0x08 +#define CLRSWRAP 0x08 +#define CLRSPIORDY 0x02 + +#define SSTAT0 0x0b +#define TARGET 0x80 +#define SELDO 0x40 +#define SELDI 0x20 +#define SELINGO 0x10 +#define SWRAP 0x08 +#define IOERR 0x08 +#define SDONE 0x04 +#define SPIORDY 0x02 +#define DMADONE 0x01 + +#define CLRSINT1 0x0c +#define CLRSELTIMEO 0x80 +#define CLRATNO 0x40 +#define CLRSCSIRSTI 0x20 +#define CLRBUSFREE 0x08 +#define CLRSCSIPERR 0x04 +#define CLRPHASECHG 0x02 +#define CLRREQINIT 0x01 + +#define SSTAT1 0x0c +#define SELTO 0x80 +#define ATNTARG 0x40 +#define SCSIRSTI 0x20 +#define PHASEMIS 0x10 +#define BUSFREE 0x08 +#define SCSIPERR 0x04 +#define PHASECHG 0x02 +#define REQINIT 0x01 + +#define SSTAT2 0x0d +#define OVERRUN 0x80 +#define SHVALID 0x40 +#define SFCNT 0x1f +#define EXP_ACTIVE 0x10 +#define CRCVALERR 0x08 +#define CRCENDERR 0x04 +#define CRCREQERR 0x02 +#define DUAL_EDGE_ERR 0x01 + +#define SSTAT3 0x0e +#define SCSICNT 0xf0 +#define U2OFFCNT 0x7f +#define OFFCNT 0x0f + +#define SCSIID_ULTRA2 0x0f + +#define SIMODE0 0x10 +#define ENSELDO 0x40 +#define ENSELDI 0x20 +#define ENSELINGO 0x10 +#define ENIOERR 0x08 +#define ENSWRAP 0x08 +#define ENSDONE 0x04 +#define ENSPIORDY 0x02 +#define ENDMADONE 0x01 + +#define SIMODE1 0x11 +#define ENSELTIMO 0x80 +#define ENATNTARG 0x40 +#define ENSCSIRST 0x20 +#define ENPHASEMIS 0x10 +#define ENBUSFREE 0x08 +#define ENSCSIPERR 0x04 +#define ENPHASECHG 0x02 +#define ENREQINIT 0x01 + +#define SCSIBUSL 0x12 + +#define SCSIBUSH 0x13 + +#define SHADDR 0x14 + +#define SELTIMER 0x18 +#define TARGIDIN 0x18 +#define STAGE6 0x20 +#define STAGE5 0x10 +#define STAGE4 0x08 +#define STAGE3 0x04 +#define STAGE2 0x02 +#define STAGE1 0x01 + +#define SELID 0x19 +#define SELID_MASK 0xf0 +#define ONEBIT 0x08 + +#define SCAMCTL 0x1a +#define ENSCAMSELO 0x80 +#define CLRSCAMSELID 0x40 +#define ALTSTIM 0x20 +#define DFLTTID 0x10 +#define SCAMLVL 0x03 + +#define TARGID 0x1b + +#define SPIOCAP 0x1b +#define SOFT1 0x80 +#define SOFT0 0x40 +#define SOFTCMDEN 0x20 +#define HAS_BRDCTL 0x10 +#define SEEPROM 0x08 +#define EEPROM 0x04 +#define ROM 0x02 +#define SSPIOCPS 0x01 + +#define BRDCTL 0x1d +#define BRDDAT7 0x80 +#define BRDDAT6 0x40 +#define BRDDAT5 0x20 +#define BRDDAT4 0x10 +#define BRDSTB 0x10 +#define BRDDAT3 0x08 +#define BRDCS 0x08 +#define BRDDAT2 0x04 +#define BRDRW 0x04 +#define BRDRW_ULTRA2 0x02 +#define BRDCTL1 0x02 +#define BRDCTL0 0x01 +#define BRDSTB_ULTRA2 0x01 + +#define SEECTL 0x1e +#define EXTARBACK 0x80 +#define EXTARBREQ 0x40 +#define SEEMS 0x20 +#define SEERDY 0x10 +#define SEECS 0x08 +#define SEECK 0x04 +#define SEEDO 0x02 +#define SEEDI 0x01 + +#define SBLKCTL 0x1f +#define DIAGLEDEN 0x80 +#define DIAGLEDON 0x40 +#define AUTOFLUSHDIS 0x20 +#define ENAB40 0x08 +#define SELBUSB 0x08 +#define ENAB20 0x04 +#define SELWIDE 0x02 +#define XCVR 0x01 + +#define BUSY_TARGETS 0x20 +#define TARG_SCSIRATE 0x20 + +#define SRAM_BASE 0x20 + +#define ULTRA_ENB 0x30 +#define CMDSIZE_TABLE 0x30 + +#define DISC_DSB 0x32 + +#define CMDSIZE_TABLE_TAIL 0x34 + +#define MWI_RESIDUAL 0x38 + +#define NEXT_QUEUED_SCB 0x39 + +#define MSG_OUT 0x3a + +#define DMAPARAMS 0x3b +#define PRELOADEN 0x80 +#define WIDEODD 0x40 +#define SCSIEN 0x20 +#define SDMAEN 0x10 +#define SDMAENACK 0x10 +#define HDMAEN 0x08 +#define HDMAENACK 0x08 +#define DIRECTION 0x04 +#define FIFOFLUSH 0x02 +#define FIFORESET 0x01 + +#define SEQ_FLAGS 0x3c +#define IDENTIFY_SEEN 0x80 +#define TARGET_CMD_IS_TAGGED 0x40 +#define DPHASE 0x20 +#define TARG_CMD_PENDING 0x10 +#define CMDPHASE_PENDING 0x08 +#define DPHASE_PENDING 0x04 +#define SPHASE_PENDING 0x02 +#define NO_DISCONNECT 0x01 + +#define SAVED_SCSIID 0x3d + +#define SAVED_LUN 0x3e + +#define LASTPHASE 0x3f +#define P_MESGIN 0xe0 +#define PHASE_MASK 0xe0 +#define P_STATUS 0xc0 +#define P_MESGOUT 0xa0 +#define P_COMMAND 0x80 +#define CDI 0x80 +#define P_DATAIN 0x40 +#define IOI 0x40 +#define MSGI 0x20 +#define P_BUSFREE 0x01 +#define P_DATAOUT 0x00 + +#define WAITING_SCBH 0x40 + +#define DISCONNECTED_SCBH 0x41 + +#define FREE_SCBH 0x42 + +#define COMPLETE_SCBH 0x43 + +#define HSCB_ADDR 0x44 + +#define SHARED_DATA_ADDR 0x48 + +#define KERNEL_QINPOS 0x4c + +#define QINPOS 0x4d + +#define QOUTPOS 0x4e + +#define KERNEL_TQINPOS 0x4f + +#define TQINPOS 0x50 + +#define ARG_1 0x51 +#define RETURN_1 0x51 +#define SEND_MSG 0x80 +#define SEND_SENSE 0x40 +#define SEND_REJ 0x20 +#define MSGOUT_PHASEMIS 0x10 +#define EXIT_MSG_LOOP 0x08 +#define CONT_MSG_LOOP 0x04 +#define CONT_TARG_SESSION 0x02 + +#define ARG_2 0x52 +#define RETURN_2 0x52 + +#define LAST_MSG 0x53 + +#define SCSISEQ_TEMPLATE 0x54 +#define ENSELO 0x40 +#define ENSELI 0x20 +#define ENRSELI 0x10 +#define ENAUTOATNO 0x08 +#define ENAUTOATNI 0x04 +#define ENAUTOATNP 0x02 + +#define DATA_COUNT_ODD 0x55 + +#define INITIATOR_TAG 0x56 + +#define SEQ_FLAGS2 0x57 +#define TARGET_MSG_PENDING 0x02 +#define SCB_DMA 0x01 + +#define SCSICONF 0x5a +#define TERM_ENB 0x80 +#define RESET_SCSI 0x40 +#define ENSPCHK 0x20 +#define HWSCSIID 0x0f +#define HSCSIID 0x07 + +#define INTDEF 0x5c +#define EDGE_TRIG 0x80 +#define VECTOR 0x0f + +#define HOSTCONF 0x5d + +#define HA_274_BIOSCTRL 0x5f +#define BIOSDISABLED 0x30 +#define BIOSMODE 0x30 +#define CHANNEL_B_PRIMARY 0x08 + +#define SEQCTL 0x60 +#define PERRORDIS 0x80 +#define PAUSEDIS 0x40 +#define FAILDIS 0x20 +#define FASTMODE 0x10 +#define BRKADRINTEN 0x08 +#define STEP 0x04 +#define SEQRESET 0x02 +#define LOADRAM 0x01 + +#define SEQRAM 0x61 + +#define SEQADDR0 0x62 + +#define SEQADDR1 0x63 +#define SEQADDR1_MASK 0x01 + +#define ACCUM 0x64 + +#define SINDEX 0x65 + +#define DINDEX 0x66 + +#define ALLONES 0x69 + +#define ALLZEROS 0x6a + +#define NONE 0x6a + +#define FLAGS 0x6b +#define ZERO 0x02 +#define CARRY 0x01 + +#define SINDIR 0x6c + +#define DINDIR 0x6d + +#define FUNCTION1 0x6e + +#define STACK 0x6f + +#define TARG_OFFSET 0x70 + +#define BCTL 0x84 +#define ACE 0x08 +#define ENABLE 0x01 + +#define DSCOMMAND0 0x84 +#define CACHETHEN 0x80 +#define DPARCKEN 0x40 +#define MPARCKEN 0x20 +#define EXTREQLCK 0x10 +#define INTSCBRAMSEL 0x08 +#define RAMPS 0x04 +#define USCBSIZE32 0x02 +#define CIOPARCKEN 0x01 + +#define BUSTIME 0x85 +#define BOFF 0xf0 +#define BON 0x0f + +#define DSCOMMAND1 0x85 +#define DSLATT 0xfc +#define HADDLDSEL1 0x02 +#define HADDLDSEL0 0x01 + +#define BUSSPD 0x86 +#define DFTHRSH 0xc0 +#define DFTHRSH_75 0x80 +#define STBOFF 0x38 +#define STBON 0x07 + +#define HS_MAILBOX 0x86 +#define HOST_MAILBOX 0xf0 +#define HOST_TQINPOS 0x80 +#define SEQ_MAILBOX 0x0f + +#define DSPCISTATUS 0x86 +#define DFTHRSH_100 0xc0 + +#define HCNTRL 0x87 +#define POWRDN 0x40 +#define SWINT 0x10 +#define IRQMS 0x08 +#define PAUSE 0x04 +#define INTEN 0x02 +#define CHIPRST 0x01 +#define CHIPRSTACK 0x01 + +#define HADDR 0x88 + +#define HCNT 0x8c + +#define SCBPTR 0x90 + +#define INTSTAT 0x91 +#define SEQINT_MASK 0xf1 +#define OUT_OF_RANGE 0xe1 +#define NO_FREE_SCB 0xd1 +#define SCB_MISMATCH 0xc1 +#define MISSED_BUSFREE 0xb1 +#define MKMSG_FAILED 0xa1 +#define DATA_OVERRUN 0x91 +#define PERR_DETECTED 0x81 +#define BAD_STATUS 0x71 +#define HOST_MSG_LOOP 0x61 +#define PDATA_REINIT 0x51 +#define IGN_WIDE_RES 0x41 +#define NO_MATCH 0x31 +#define NO_IDENT 0x21 +#define SEND_REJECT 0x11 +#define INT_PEND 0x0f +#define BRKADRINT 0x08 +#define SCSIINT 0x04 +#define CMDCMPLT 0x02 +#define BAD_PHASE 0x01 +#define SEQINT 0x01 + +#define CLRINT 0x92 +#define CLRPARERR 0x10 +#define CLRBRKADRINT 0x08 +#define CLRSCSIINT 0x04 +#define CLRCMDINT 0x02 +#define CLRSEQINT 0x01 + +#define ERROR 0x92 +#define CIOPARERR 0x80 +#define PCIERRSTAT 0x40 +#define MPARERR 0x20 +#define DPARERR 0x10 +#define SQPARERR 0x08 +#define ILLOPCODE 0x04 +#define ILLSADDR 0x02 +#define ILLHADDR 0x01 + +#define DFCNTRL 0x93 + +#define DFSTATUS 0x94 +#define PRELOAD_AVAIL 0x80 +#define DFCACHETH 0x40 +#define FIFOQWDEMP 0x20 +#define MREQPEND 0x10 +#define HDONE 0x08 +#define DFTHRESH 0x04 +#define FIFOFULL 0x02 +#define FIFOEMP 0x01 + +#define DFWADDR 0x95 + +#define DFRADDR 0x97 + +#define DFDAT 0x99 + +#define SCBCNT 0x9a +#define SCBAUTO 0x80 +#define SCBCNT_MASK 0x1f + +#define QINFIFO 0x9b + +#define QINCNT 0x9c + +#define QOUTFIFO 0x9d + +#define CRCCONTROL1 0x9d +#define CRCONSEEN 0x80 +#define CRCVALCHKEN 0x40 +#define CRCENDCHKEN 0x20 +#define CRCREQCHKEN 0x10 +#define TARGCRCENDEN 0x08 +#define TARGCRCCNTEN 0x04 + +#define QOUTCNT 0x9e + +#define SCSIPHASE 0x9e +#define STATUS_PHASE 0x20 +#define COMMAND_PHASE 0x10 +#define MSG_IN_PHASE 0x08 +#define MSG_OUT_PHASE 0x04 +#define DATA_PHASE_MASK 0x03 +#define DATA_IN_PHASE 0x02 +#define DATA_OUT_PHASE 0x01 + +#define SFUNCT 0x9f +#define ALT_MODE 0x80 + +#define SCB_BASE 0xa0 + +#define SCB_CDB_PTR 0xa0 +#define SCB_RESIDUAL_DATACNT 0xa0 +#define SCB_CDB_STORE 0xa0 + +#define SCB_RESIDUAL_SGPTR 0xa4 + +#define SCB_SCSI_STATUS 0xa8 + +#define SCB_TARGET_PHASES 0xa9 + +#define SCB_TARGET_DATA_DIR 0xaa + +#define SCB_TARGET_ITAG 0xab + +#define SCB_DATAPTR 0xac + +#define SCB_DATACNT 0xb0 +#define SG_LAST_SEG 0x80 +#define SG_HIGH_ADDR_BITS 0x7f + +#define SCB_SGPTR 0xb4 +#define SG_RESID_VALID 0x04 +#define SG_FULL_RESID 0x02 +#define SG_LIST_NULL 0x01 + +#define SCB_CONTROL 0xb8 +#define TARGET_SCB 0x80 +#define DISCENB 0x40 +#define TAG_ENB 0x20 +#define MK_MESSAGE 0x10 +#define ULTRAENB 0x08 +#define DISCONNECTED 0x04 +#define SCB_TAG_TYPE 0x03 + +#define SCB_SCSIID 0xb9 +#define TID 0xf0 +#define TWIN_CHNLB 0x80 +#define TWIN_TID 0x70 +#define OID 0x0f + +#define SCB_LUN 0xba +#define LID 0xff + +#define SCB_TAG 0xbb + +#define SCB_CDB_LEN 0xbc + +#define SCB_SCSIRATE 0xbd + +#define SCB_SCSIOFFSET 0xbe + +#define SCB_NEXT 0xbf + +#define SCB_64_SPARE 0xc0 + +#define SEECTL_2840 0xc0 +#define CS_2840 0x04 +#define CK_2840 0x02 +#define DO_2840 0x01 + +#define STATUS_2840 0xc1 +#define EEPROM_TF 0x80 +#define BIOS_SEL 0x60 +#define ADSEL 0x1e +#define DI_2840 0x01 + +#define SCB_64_BTT 0xd0 + +#define CCHADDR 0xe0 + +#define CCHCNT 0xe8 + +#define CCSGRAM 0xe9 + +#define CCSGADDR 0xea + +#define CCSGCTL 0xeb +#define CCSGDONE 0x80 +#define CCSGEN 0x08 +#define SG_FETCH_NEEDED 0x02 +#define CCSGRESET 0x01 + +#define CCSCBRAM 0xec + +#define CCSCBADDR 0xed + +#define CCSCBCTL 0xee +#define CCSCBDONE 0x80 +#define ARRDONE 0x40 +#define CCARREN 0x10 +#define CCSCBEN 0x08 +#define CCSCBDIR 0x04 +#define CCSCBRESET 0x01 + +#define CCSCBCNT 0xef + +#define SCBBADDR 0xf0 + +#define CCSCBPTR 0xf1 + +#define HNSCB_QOFF 0xf4 + +#define SNSCB_QOFF 0xf6 + +#define SDSCB_QOFF 0xf8 + +#define QOFF_CTLSTA 0xfa +#define SCB_AVAIL 0x40 +#define SNSCB_ROLLOVER 0x20 +#define SDSCB_ROLLOVER 0x10 +#define SCB_QSIZE 0x07 +#define SCB_QSIZE_256 0x06 + +#define DFF_THRSH 0xfb +#define WR_DFTHRSH 0x70 +#define WR_DFTHRSH_MAX 0x70 +#define WR_DFTHRSH_90 0x60 +#define WR_DFTHRSH_85 0x50 +#define WR_DFTHRSH_75 0x40 +#define WR_DFTHRSH_63 0x30 +#define WR_DFTHRSH_50 0x20 +#define WR_DFTHRSH_25 0x10 +#define RD_DFTHRSH 0x07 +#define RD_DFTHRSH_MAX 0x07 +#define RD_DFTHRSH_90 0x06 +#define RD_DFTHRSH_85 0x05 +#define RD_DFTHRSH_75 0x04 +#define RD_DFTHRSH_63 0x03 +#define RD_DFTHRSH_50 0x02 +#define RD_DFTHRSH_25 0x01 +#define RD_DFTHRSH_MIN 0x00 +#define WR_DFTHRSH_MIN 0x00 + +#define SG_CACHE_SHADOW 0xfc +#define SG_ADDR_MASK 0xf8 +#define ODD_SEG 0x04 +#define LAST_SEG 0x02 +#define LAST_SEG_DONE 0x01 + +#define SG_CACHE_PRE 0xfc + + +#define MAX_OFFSET_ULTRA2 0x7f +#define MAX_OFFSET_16BIT 0x08 +#define BUS_8_BIT 0x00 +#define TARGET_CMD_CMPLT 0xfe +#define STATUS_QUEUE_FULL 0x28 +#define STATUS_BUSY 0x08 +#define MAX_OFFSET_8BIT 0x0f +#define BUS_32_BIT 0x02 +#define CCSGADDR_MAX 0x80 +#define TID_SHIFT 0x04 +#define SCB_DOWNLOAD_SIZE_64 0x30 +#define HOST_MAILBOX_SHIFT 0x04 +#define CMD_GROUP_CODE_SHIFT 0x05 +#define CCSGRAM_MAXSEGS 0x10 +#define SCB_LIST_NULL 0xff +#define SG_SIZEOF 0x08 +#define SCB_DOWNLOAD_SIZE 0x20 +#define SEQ_MAILBOX_SHIFT 0x00 +#define TARGET_DATA_IN 0x01 +#define HOST_MSG 0xff +#define BUS_16_BIT 0x01 +#define SCB_UPLOAD_SIZE 0x20 + + +/* Downloaded Constant Definitions */ +#define INVERTED_CACHESIZE_MASK 0x03 +#define SG_PREFETCH_ADDR_MASK 0x06 +#define SG_PREFETCH_ALIGN_MASK 0x05 +#define QOUTFIFO_OFFSET 0x00 +#define SG_PREFETCH_CNT 0x04 +#define CACHESIZE_MASK 0x02 +#define QINFIFO_OFFSET 0x01 diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/drivers/scsi/aic7xxx/aic7xxx_seq.h linux.2.5.47-ac6/drivers/scsi/aic7xxx/aic7xxx_seq.h --- linux.2.5.47/drivers/scsi/aic7xxx/aic7xxx_seq.h 1970-01-01 01:00:00.000000000 +0100 +++ linux.2.5.47-ac6/drivers/scsi/aic7xxx/aic7xxx_seq.h 2002-11-12 17:24:34.000000000 +0000 @@ -0,0 +1,1299 @@ +/* + * DO NOT EDIT - This file is automatically generated + * from the following source files: + * + * $Id: //depot/aic7xxx/aic7xxx/aic7xxx.seq#37 $ + * $Id: //depot/aic7xxx/aic7xxx/aic7xxx.reg#24 $ + */ +static uint8_t seqprog[] = { + 0xb2, 0x00, 0x00, 0x08, + 0xf7, 0x11, 0x22, 0x08, + 0x00, 0x65, 0xe0, 0x59, + 0xf7, 0x01, 0x02, 0x08, + 0xff, 0x6a, 0x24, 0x08, + 0x40, 0x00, 0x40, 0x68, + 0x08, 0x1f, 0x3e, 0x10, + 0x40, 0x00, 0x40, 0x68, + 0xff, 0x40, 0x3c, 0x60, + 0x08, 0x1f, 0x3e, 0x10, + 0x60, 0x0b, 0x42, 0x68, + 0x40, 0xfa, 0x12, 0x78, + 0x01, 0x4d, 0xc8, 0x30, + 0x00, 0x4c, 0x12, 0x70, + 0x01, 0x39, 0xa2, 0x30, + 0x00, 0x6a, 0xb2, 0x5e, + 0x01, 0x51, 0x20, 0x31, + 0x01, 0x57, 0xae, 0x00, + 0x0d, 0x6a, 0x76, 0x00, + 0x00, 0x51, 0x04, 0x5e, + 0x01, 0x51, 0xc8, 0x30, + 0x00, 0x39, 0xc8, 0x60, + 0x00, 0xbb, 0x30, 0x70, + 0xc1, 0x6a, 0xca, 0x5e, + 0x01, 0xbf, 0x72, 0x30, + 0x01, 0x40, 0x7e, 0x31, + 0x01, 0x90, 0x80, 0x30, + 0x01, 0xf6, 0xd4, 0x30, + 0x01, 0x4d, 0x9a, 0x18, + 0xfe, 0x57, 0xae, 0x08, + 0x01, 0x40, 0x20, 0x31, + 0x00, 0x65, 0xcc, 0x58, + 0x60, 0x0b, 0x40, 0x78, + 0x08, 0x6a, 0x18, 0x00, + 0x08, 0x11, 0x22, 0x00, + 0x60, 0x0b, 0x00, 0x78, + 0x40, 0x0b, 0xfc, 0x68, + 0x80, 0x0b, 0xb6, 0x78, + 0x20, 0x6a, 0x16, 0x00, + 0xa4, 0x6a, 0x06, 0x00, + 0x08, 0x3c, 0x78, 0x00, + 0x01, 0x50, 0xc8, 0x30, + 0xe0, 0x6a, 0xcc, 0x00, + 0x48, 0x6a, 0xee, 0x5d, + 0x01, 0x6a, 0xdc, 0x01, + 0x88, 0x6a, 0xcc, 0x00, + 0x48, 0x6a, 0xee, 0x5d, + 0x01, 0x6a, 0x26, 0x01, + 0xf0, 0x19, 0x7a, 0x08, + 0x0f, 0x18, 0xc8, 0x08, + 0x0f, 0x0f, 0xc8, 0x08, + 0x0f, 0x05, 0xc8, 0x08, + 0x00, 0x3d, 0x7a, 0x00, + 0x08, 0x1f, 0x6e, 0x78, + 0x80, 0x3d, 0x7a, 0x00, + 0x01, 0x3d, 0xd8, 0x31, + 0x01, 0x3d, 0x32, 0x31, + 0x10, 0x03, 0x46, 0x79, + 0x00, 0x65, 0xf4, 0x58, + 0x80, 0x66, 0xae, 0x78, + 0x01, 0x66, 0xd8, 0x31, + 0x01, 0x66, 0x32, 0x31, + 0x3f, 0x66, 0x7c, 0x08, + 0x40, 0x66, 0x82, 0x68, + 0x01, 0x3c, 0x78, 0x00, + 0x10, 0x03, 0x9e, 0x78, + 0x00, 0x65, 0xf4, 0x58, + 0xe0, 0x66, 0xc8, 0x18, + 0x00, 0x65, 0xaa, 0x50, + 0xdd, 0x66, 0xc8, 0x18, + 0x00, 0x65, 0xaa, 0x48, + 0x01, 0x66, 0xd8, 0x31, + 0x01, 0x66, 0x32, 0x31, + 0x10, 0x03, 0x46, 0x79, + 0x00, 0x65, 0xf4, 0x58, + 0x01, 0x66, 0xd8, 0x31, + 0x01, 0x66, 0x32, 0x31, + 0x01, 0x66, 0xac, 0x30, + 0x40, 0x3c, 0x78, 0x00, + 0xff, 0x6a, 0xd8, 0x01, + 0xff, 0x6a, 0x32, 0x01, + 0x90, 0x3c, 0x78, 0x00, + 0x02, 0x57, 0x3a, 0x69, + 0x10, 0x03, 0x38, 0x69, + 0x00, 0x65, 0x1e, 0x41, + 0x02, 0x57, 0xae, 0x00, + 0x00, 0x65, 0x9e, 0x40, + 0x61, 0x6a, 0xca, 0x5e, + 0x08, 0x51, 0x1e, 0x71, + 0x02, 0x0b, 0xb2, 0x78, + 0x00, 0x65, 0xae, 0x40, + 0x1a, 0x01, 0x02, 0x00, + 0xf0, 0x19, 0x7a, 0x08, + 0x0f, 0x0f, 0xc8, 0x08, + 0x0f, 0x05, 0xc8, 0x08, + 0x00, 0x3d, 0x7a, 0x00, + 0x08, 0x1f, 0xc4, 0x78, + 0x80, 0x3d, 0x7a, 0x00, + 0x20, 0x6a, 0x16, 0x00, + 0x00, 0x65, 0xc0, 0x41, + 0x00, 0x65, 0xa4, 0x5e, + 0x00, 0x65, 0x12, 0x40, + 0x20, 0x11, 0xd2, 0x68, + 0x20, 0x6a, 0x18, 0x00, + 0x20, 0x11, 0x22, 0x00, + 0xf7, 0x1f, 0xca, 0x08, + 0x80, 0xb9, 0xd8, 0x78, + 0x08, 0x65, 0xca, 0x00, + 0x01, 0x65, 0x3e, 0x30, + 0x01, 0xb9, 0x1e, 0x30, + 0x7f, 0xb9, 0x0a, 0x08, + 0x01, 0xb9, 0x0a, 0x30, + 0x01, 0x54, 0xca, 0x30, + 0x80, 0xb8, 0xe6, 0x78, + 0x80, 0x65, 0xca, 0x00, + 0x01, 0x65, 0x00, 0x34, + 0x01, 0x54, 0x00, 0x34, + 0x1a, 0x01, 0x02, 0x00, + 0x08, 0xb8, 0xf0, 0x78, + 0x20, 0x01, 0x02, 0x00, + 0x02, 0xbd, 0x08, 0x34, + 0x01, 0xbd, 0x08, 0x34, + 0x08, 0x01, 0x02, 0x00, + 0x02, 0x0b, 0xf6, 0x78, + 0xf7, 0x01, 0x02, 0x08, + 0x01, 0x06, 0xcc, 0x34, + 0xb2, 0x00, 0x00, 0x08, + 0x40, 0x6a, 0x16, 0x00, + 0x01, 0x40, 0x20, 0x31, + 0x01, 0xbf, 0x80, 0x30, + 0x01, 0xb9, 0x7a, 0x30, + 0x01, 0xba, 0x7c, 0x30, + 0x00, 0x65, 0xea, 0x58, + 0x80, 0x0b, 0xbc, 0x79, + 0xe4, 0x6a, 0x60, 0x5d, + 0x80, 0xba, 0x76, 0x5d, + 0x20, 0xb8, 0x16, 0x79, + 0x20, 0x6a, 0x76, 0x5d, + 0x00, 0xab, 0x76, 0x5d, + 0x01, 0xa9, 0x78, 0x30, + 0x10, 0xb8, 0x1e, 0x79, + 0xe4, 0x6a, 0x60, 0x5d, + 0x00, 0x65, 0xae, 0x40, + 0x10, 0x03, 0x36, 0x69, + 0x08, 0x3c, 0x52, 0x69, + 0x04, 0x3c, 0x8a, 0x69, + 0x02, 0x3c, 0x90, 0x69, + 0x01, 0x3c, 0x3c, 0x79, + 0x01, 0x6a, 0xa2, 0x30, + 0x00, 0x65, 0x9c, 0x59, + 0x04, 0x51, 0x2c, 0x61, + 0x00, 0x6a, 0xb2, 0x5e, + 0x0d, 0x6a, 0x76, 0x00, + 0x00, 0xbb, 0x04, 0x5e, + 0x00, 0x65, 0x16, 0x41, + 0xa4, 0x6a, 0x06, 0x00, + 0x00, 0x65, 0xf4, 0x58, + 0x00, 0x65, 0xae, 0x40, + 0xe4, 0x6a, 0x60, 0x5d, + 0x20, 0x3c, 0x42, 0x79, + 0x02, 0x6a, 0x76, 0x5d, + 0x04, 0x6a, 0x76, 0x5d, + 0x01, 0x03, 0x44, 0x69, + 0xf7, 0x11, 0x22, 0x08, + 0xff, 0x6a, 0x24, 0x08, + 0xff, 0x6a, 0x06, 0x08, + 0x01, 0x6a, 0x7e, 0x00, + 0x00, 0x65, 0x9c, 0x59, + 0x00, 0x65, 0x04, 0x40, + 0x80, 0x86, 0xc8, 0x08, + 0x01, 0x4f, 0xc8, 0x30, + 0x00, 0x50, 0x64, 0x61, + 0xc4, 0x6a, 0x60, 0x5d, + 0x40, 0x3c, 0x60, 0x79, + 0x28, 0x6a, 0x76, 0x5d, + 0x00, 0x65, 0x44, 0x41, + 0x08, 0x6a, 0x76, 0x5d, + 0x00, 0x65, 0x44, 0x41, + 0x84, 0x6a, 0x60, 0x5d, + 0x00, 0x65, 0xf4, 0x58, + 0x01, 0x66, 0xc8, 0x30, + 0x01, 0x64, 0xd8, 0x31, + 0x01, 0x64, 0x32, 0x31, + 0x5b, 0x64, 0xc8, 0x28, + 0x30, 0x64, 0xca, 0x18, + 0x01, 0x6c, 0xc8, 0x30, + 0xff, 0x64, 0x86, 0x79, + 0x08, 0x01, 0x02, 0x00, + 0x02, 0x0b, 0x78, 0x79, + 0x01, 0x64, 0x7e, 0x61, + 0xf7, 0x01, 0x02, 0x08, + 0x01, 0x06, 0xd8, 0x31, + 0x01, 0x06, 0x32, 0x31, + 0xff, 0x64, 0xc8, 0x18, + 0xff, 0x64, 0x78, 0x69, + 0xf7, 0x3c, 0x78, 0x08, + 0x00, 0x65, 0x1e, 0x41, + 0x40, 0xaa, 0x7e, 0x10, + 0x04, 0xaa, 0x60, 0x5d, + 0x00, 0x65, 0x52, 0x42, + 0xc4, 0x6a, 0x60, 0x5d, + 0xc0, 0x6a, 0x7e, 0x00, + 0x00, 0xa8, 0x76, 0x5d, + 0xe4, 0x6a, 0x06, 0x00, + 0x00, 0x6a, 0x76, 0x5d, + 0x00, 0x65, 0x44, 0x41, + 0x10, 0x3c, 0xa0, 0x69, + 0x00, 0xbb, 0x80, 0x44, + 0x18, 0x6a, 0xda, 0x01, + 0x01, 0x69, 0xd8, 0x31, + 0x1c, 0x6a, 0xd0, 0x01, + 0x09, 0xee, 0xdc, 0x01, + 0x80, 0xee, 0xa8, 0x79, + 0xff, 0x6a, 0xdc, 0x09, + 0x01, 0x93, 0x26, 0x01, + 0x03, 0x6a, 0x2a, 0x01, + 0x01, 0x69, 0x32, 0x31, + 0x1c, 0x6a, 0xd2, 0x5d, + 0x0a, 0x93, 0x26, 0x01, + 0x00, 0x65, 0x9a, 0x5e, + 0x01, 0x50, 0xa0, 0x18, + 0x02, 0x6a, 0x22, 0x05, + 0x80, 0x6a, 0x74, 0x00, + 0x80, 0x3c, 0x78, 0x00, + 0x00, 0x65, 0xca, 0x5d, + 0x01, 0x3f, 0xc8, 0x30, + 0xbf, 0x64, 0x52, 0x7a, + 0x80, 0x64, 0xa6, 0x73, + 0xa0, 0x64, 0x04, 0x74, + 0xc0, 0x64, 0xf8, 0x73, + 0xe0, 0x64, 0x34, 0x74, + 0x01, 0x6a, 0xca, 0x5e, + 0x00, 0x65, 0xc0, 0x41, + 0xf7, 0x11, 0x22, 0x08, + 0x01, 0x06, 0xd4, 0x30, + 0xff, 0x6a, 0x24, 0x08, + 0xf7, 0x01, 0x02, 0x08, + 0x09, 0x0c, 0xda, 0x79, + 0x08, 0x0c, 0x04, 0x68, + 0xb1, 0x6a, 0xca, 0x5e, + 0xff, 0x6a, 0x26, 0x09, + 0x12, 0x01, 0x02, 0x00, + 0x02, 0x6a, 0x08, 0x30, + 0xff, 0x6a, 0x08, 0x08, + 0xdf, 0x01, 0x02, 0x08, + 0x01, 0x6a, 0x7e, 0x00, + 0xff, 0x6a, 0x78, 0x0c, + 0xff, 0x6a, 0xc8, 0x08, + 0x08, 0xa4, 0x48, 0x19, + 0x00, 0xa5, 0x4a, 0x21, + 0x00, 0xa6, 0x4c, 0x21, + 0x00, 0xa7, 0x4e, 0x25, + 0x08, 0xeb, 0xce, 0x7e, + 0x80, 0xeb, 0xfa, 0x79, + 0xff, 0x6a, 0xd6, 0x09, + 0x08, 0xeb, 0xfe, 0x69, + 0xff, 0x6a, 0xd4, 0x0c, + 0x80, 0xa3, 0xce, 0x6e, + 0x88, 0xeb, 0x14, 0x72, + 0x08, 0xeb, 0xce, 0x6e, + 0x04, 0xea, 0x18, 0xe2, + 0x08, 0xee, 0xce, 0x6e, + 0x04, 0x6a, 0xd0, 0x81, + 0x05, 0xa4, 0xc0, 0x89, + 0x03, 0xa5, 0xc2, 0x31, + 0x09, 0x6a, 0xd6, 0x05, + 0x00, 0x65, 0xfc, 0x59, + 0x06, 0xa4, 0xd4, 0x89, + 0x80, 0x94, 0xce, 0x7e, + 0x07, 0xe9, 0x10, 0x31, + 0x01, 0x8c, 0x20, 0x7a, + 0x01, 0x55, 0xaa, 0x10, + 0x01, 0xe9, 0x46, 0x31, + 0x00, 0xa3, 0xac, 0x5e, + 0x00, 0x65, 0xee, 0x59, + 0x01, 0xa4, 0xca, 0x30, + 0x01, 0x55, 0x2c, 0x7a, + 0x04, 0x65, 0xca, 0x00, + 0x80, 0xa3, 0x30, 0x7a, + 0x02, 0x65, 0xca, 0x00, + 0x01, 0x65, 0xf8, 0x31, + 0x80, 0x93, 0x26, 0x01, + 0xff, 0x6a, 0xd4, 0x0c, + 0x01, 0x8c, 0xc8, 0x30, + 0x00, 0x88, 0xc8, 0x18, + 0x02, 0x64, 0xc8, 0x88, + 0xff, 0x64, 0xce, 0x7e, + 0xff, 0x8d, 0x46, 0x6a, + 0xff, 0x8e, 0x46, 0x6a, + 0x03, 0x8c, 0xd4, 0x98, + 0x00, 0x65, 0xce, 0x56, + 0x01, 0x64, 0x70, 0x30, + 0xff, 0x64, 0xc8, 0x10, + 0x01, 0x64, 0xc8, 0x18, + 0x00, 0x8c, 0x18, 0x19, + 0xff, 0x8d, 0x1a, 0x21, + 0xff, 0x8e, 0x1c, 0x25, + 0x80, 0x3c, 0x56, 0x6a, + 0x21, 0x6a, 0xca, 0x46, + 0xa8, 0x6a, 0x76, 0x00, + 0x79, 0x6a, 0x76, 0x00, + 0x40, 0x3f, 0x5e, 0x6a, + 0x04, 0x3b, 0x76, 0x00, + 0x04, 0x6a, 0xd4, 0x81, + 0x20, 0x3c, 0x66, 0x7a, + 0x51, 0x6a, 0xca, 0x5e, + 0x00, 0x65, 0x80, 0x42, + 0x20, 0x3c, 0x78, 0x00, + 0x00, 0xb3, 0xac, 0x5e, + 0x07, 0xac, 0x10, 0x31, + 0x05, 0xb3, 0x46, 0x31, + 0x88, 0x6a, 0xcc, 0x00, + 0xac, 0x6a, 0xe0, 0x5d, + 0xa3, 0x6a, 0xcc, 0x00, + 0xb3, 0x6a, 0xe4, 0x5d, + 0x00, 0x65, 0x36, 0x5a, + 0xfd, 0xa4, 0x48, 0x09, + 0x01, 0x8c, 0xaa, 0x08, + 0x03, 0x8c, 0x10, 0x30, + 0x00, 0x65, 0xd8, 0x5d, + 0x01, 0xa4, 0x92, 0x7a, + 0x04, 0x3b, 0x76, 0x08, + 0x01, 0x3b, 0x26, 0x31, + 0x80, 0x02, 0x04, 0x00, + 0x10, 0x0c, 0x88, 0x7a, + 0x03, 0x9e, 0x8a, 0x6a, + 0x7f, 0x02, 0x04, 0x08, + 0x91, 0x6a, 0xca, 0x5e, + 0x00, 0x65, 0xc0, 0x41, + 0x01, 0xa4, 0xca, 0x30, + 0x80, 0xa3, 0x98, 0x7a, + 0x02, 0x65, 0xca, 0x00, + 0x01, 0x55, 0x9c, 0x7a, + 0x04, 0x65, 0xca, 0x00, + 0x01, 0x65, 0xf8, 0x31, + 0x01, 0x3b, 0x26, 0x31, + 0x00, 0x65, 0x02, 0x5a, + 0x01, 0xfc, 0xaa, 0x6a, + 0x80, 0x0b, 0xa0, 0x6a, + 0x10, 0x0c, 0xa0, 0x7a, + 0x20, 0x93, 0xa0, 0x6a, + 0x02, 0x93, 0x26, 0x01, + 0x02, 0xfc, 0xb4, 0x7a, + 0x40, 0x0d, 0xce, 0x6a, + 0x01, 0xa4, 0x48, 0x01, + 0x00, 0x65, 0xce, 0x42, + 0x40, 0x0d, 0xba, 0x6a, + 0x00, 0x65, 0x02, 0x5a, + 0x00, 0x65, 0xac, 0x42, + 0x80, 0xfc, 0xc4, 0x7a, + 0x80, 0xa4, 0xc4, 0x6a, + 0xff, 0xa5, 0x4a, 0x19, + 0xff, 0xa6, 0x4c, 0x21, + 0xff, 0xa7, 0x4e, 0x21, + 0xf8, 0xfc, 0x48, 0x09, + 0xff, 0x6a, 0xaa, 0x08, + 0x04, 0xfc, 0xcc, 0x7a, + 0x01, 0x55, 0xaa, 0x00, + 0xff, 0x6a, 0x46, 0x09, + 0x04, 0x3b, 0xe6, 0x6a, + 0x02, 0x93, 0x26, 0x01, + 0x01, 0x94, 0xd0, 0x7a, + 0x01, 0x94, 0xd0, 0x7a, + 0x01, 0x94, 0xd0, 0x7a, + 0x01, 0x94, 0xd0, 0x7a, + 0x01, 0x94, 0xd0, 0x7a, + 0x01, 0xa4, 0xe4, 0x7a, + 0x01, 0xfc, 0xde, 0x7a, + 0x01, 0x94, 0xe6, 0x6a, + 0x00, 0x65, 0x80, 0x42, + 0x01, 0x94, 0xe4, 0x7a, + 0x10, 0x94, 0xe6, 0x6a, + 0xd7, 0x93, 0x26, 0x09, + 0x28, 0x93, 0xea, 0x6a, + 0x01, 0x85, 0x0a, 0x01, + 0x02, 0xfc, 0xf2, 0x6a, + 0x01, 0x14, 0x46, 0x31, + 0xff, 0x6a, 0x10, 0x09, + 0xfe, 0x85, 0x0a, 0x09, + 0xff, 0x38, 0x00, 0x6b, + 0x80, 0xa3, 0x00, 0x7b, + 0x80, 0x0b, 0xfe, 0x7a, + 0x04, 0x3b, 0x00, 0x7b, + 0xbf, 0x3b, 0x76, 0x08, + 0x01, 0x3b, 0x26, 0x31, + 0x00, 0x65, 0x02, 0x5a, + 0x01, 0x0b, 0x0e, 0x6b, + 0x10, 0x0c, 0x02, 0x7b, + 0x04, 0x93, 0x0c, 0x6b, + 0x01, 0x94, 0x0a, 0x7b, + 0x10, 0x94, 0x0c, 0x6b, + 0xc7, 0x93, 0x26, 0x09, + 0x01, 0x99, 0xd4, 0x30, + 0x38, 0x93, 0x10, 0x6b, + 0xff, 0x08, 0x62, 0x6b, + 0xff, 0x09, 0x62, 0x6b, + 0xff, 0x0a, 0x62, 0x6b, + 0xff, 0x38, 0x2c, 0x7b, + 0x04, 0x14, 0x10, 0x31, + 0x01, 0x38, 0x18, 0x31, + 0x02, 0x6a, 0x1a, 0x31, + 0x88, 0x6a, 0xcc, 0x00, + 0x14, 0x6a, 0xe6, 0x5d, + 0x00, 0x38, 0xd2, 0x5d, + 0xff, 0x6a, 0x70, 0x08, + 0x00, 0x65, 0x58, 0x43, + 0x80, 0xa3, 0x32, 0x7b, + 0x01, 0xa4, 0x48, 0x01, + 0x00, 0x65, 0x62, 0x43, + 0x08, 0xeb, 0x38, 0x7b, + 0x00, 0x65, 0x02, 0x5a, + 0x08, 0xeb, 0x34, 0x6b, + 0x07, 0xe9, 0x10, 0x31, + 0x01, 0xe9, 0xca, 0x30, + 0x01, 0x65, 0x46, 0x31, + 0x00, 0x6a, 0xac, 0x5e, + 0x88, 0x6a, 0xcc, 0x00, + 0xa4, 0x6a, 0xe6, 0x5d, + 0x08, 0x6a, 0xd2, 0x5d, + 0x0d, 0x93, 0x26, 0x01, + 0x00, 0x65, 0x9a, 0x5e, + 0x88, 0x6a, 0xcc, 0x00, + 0x00, 0x65, 0x7c, 0x5e, + 0x01, 0x99, 0x46, 0x31, + 0x00, 0xa3, 0xac, 0x5e, + 0x01, 0x88, 0x10, 0x31, + 0x00, 0x65, 0x36, 0x5a, + 0x00, 0x65, 0xee, 0x59, + 0x03, 0x8c, 0x10, 0x30, + 0x00, 0x65, 0xd8, 0x5d, + 0x01, 0x8c, 0x60, 0x7b, + 0x01, 0x55, 0xaa, 0x10, + 0x80, 0x0b, 0x80, 0x6a, + 0x80, 0x0b, 0x6a, 0x6b, + 0x01, 0x0c, 0x64, 0x7b, + 0x10, 0x0c, 0x80, 0x7a, + 0x03, 0x9e, 0x80, 0x6a, + 0x00, 0x65, 0xf8, 0x59, + 0x00, 0x6a, 0xac, 0x5e, + 0x01, 0xa4, 0x8a, 0x6b, + 0xff, 0x38, 0x80, 0x7b, + 0x01, 0x38, 0xc8, 0x30, + 0x00, 0x08, 0x40, 0x19, + 0xff, 0x6a, 0xc8, 0x08, + 0x00, 0x09, 0x42, 0x21, + 0x00, 0x0a, 0x44, 0x21, + 0xff, 0x6a, 0x70, 0x08, + 0x00, 0x65, 0x82, 0x43, + 0x03, 0x08, 0x40, 0x31, + 0x03, 0x08, 0x40, 0x31, + 0x01, 0x08, 0x40, 0x31, + 0x01, 0x09, 0x42, 0x31, + 0x01, 0x0a, 0x44, 0x31, + 0xfd, 0xb4, 0x68, 0x09, + 0x12, 0x01, 0x02, 0x00, + 0x12, 0x01, 0x02, 0x00, + 0x04, 0x3c, 0xc0, 0x79, + 0xfb, 0x3c, 0x78, 0x08, + 0x04, 0x93, 0x1e, 0x79, + 0x01, 0x0c, 0x96, 0x6b, + 0x01, 0x55, 0x1e, 0x79, + 0x80, 0x04, 0x1e, 0x79, + 0xe4, 0x6a, 0x60, 0x5d, + 0x23, 0x6a, 0x76, 0x5d, + 0x01, 0x6a, 0x76, 0x5d, + 0x00, 0x65, 0x1e, 0x41, + 0x00, 0x65, 0xc0, 0x41, + 0x80, 0x3c, 0xaa, 0x6b, + 0x21, 0x6a, 0xca, 0x46, + 0x01, 0xbc, 0x18, 0x31, + 0x02, 0x6a, 0x1a, 0x31, + 0x02, 0x6a, 0xf8, 0x01, + 0x01, 0xbc, 0x10, 0x30, + 0x02, 0x6a, 0x12, 0x30, + 0x01, 0xbc, 0x10, 0x30, + 0xff, 0x6a, 0x12, 0x08, + 0xff, 0x6a, 0x14, 0x08, + 0xf3, 0xbc, 0xd4, 0x18, + 0xa0, 0x6a, 0xd0, 0x53, + 0x04, 0xa0, 0x10, 0x31, + 0xac, 0x6a, 0x26, 0x01, + 0x04, 0xa0, 0x10, 0x31, + 0x03, 0x08, 0x18, 0x31, + 0x88, 0x6a, 0xcc, 0x00, + 0xa0, 0x6a, 0xe6, 0x5d, + 0x00, 0xbc, 0xd2, 0x5d, + 0x3d, 0x6a, 0x26, 0x01, + 0x00, 0x65, 0xe8, 0x43, + 0xff, 0x6a, 0x10, 0x09, + 0xa4, 0x6a, 0x26, 0x01, + 0x0c, 0xa0, 0x32, 0x31, + 0x05, 0x6a, 0x26, 0x01, + 0x35, 0x6a, 0x26, 0x01, + 0x0c, 0xa0, 0x32, 0x31, + 0x36, 0x6a, 0x26, 0x01, + 0x02, 0x93, 0x26, 0x01, + 0x35, 0x6a, 0x26, 0x01, + 0x00, 0x65, 0x8e, 0x5e, + 0x00, 0x65, 0x8e, 0x5e, + 0x02, 0x93, 0x26, 0x01, + 0x04, 0x0b, 0xec, 0x6b, + 0x10, 0x0c, 0xe8, 0x7b, + 0x01, 0x03, 0xec, 0x6b, + 0x20, 0x93, 0xe8, 0x6b, + 0xc7, 0x93, 0x26, 0x09, + 0x38, 0x93, 0xf2, 0x6b, + 0x10, 0x01, 0x02, 0x00, + 0x00, 0x65, 0xc0, 0x41, + 0x80, 0x3c, 0xfc, 0x6b, + 0x21, 0x6a, 0xca, 0x46, + 0x01, 0x06, 0x50, 0x31, + 0x00, 0x65, 0xc0, 0x41, + 0x10, 0x3f, 0x06, 0x00, + 0x10, 0x6a, 0x06, 0x00, + 0x01, 0x3a, 0xca, 0x30, + 0x80, 0x65, 0x20, 0x64, + 0x10, 0xb8, 0x44, 0x6c, + 0xc0, 0xba, 0xca, 0x00, + 0x40, 0xb8, 0x10, 0x6c, + 0xbf, 0x65, 0xca, 0x08, + 0x20, 0xb8, 0x24, 0x7c, + 0x01, 0x65, 0x0c, 0x30, + 0x00, 0x65, 0xca, 0x5d, + 0xa0, 0x3f, 0x2c, 0x64, + 0x23, 0xb8, 0x0c, 0x08, + 0x00, 0x65, 0xca, 0x5d, + 0xa0, 0x3f, 0x2c, 0x64, + 0x00, 0xbb, 0x24, 0x44, + 0xff, 0x65, 0x24, 0x64, + 0x00, 0x65, 0x44, 0x44, + 0x40, 0x6a, 0x18, 0x00, + 0x01, 0x65, 0x0c, 0x30, + 0x00, 0x65, 0xca, 0x5d, + 0xa0, 0x3f, 0x00, 0x74, + 0x40, 0x6a, 0x18, 0x00, + 0x01, 0x3a, 0xa6, 0x30, + 0x08, 0x6a, 0x74, 0x00, + 0x00, 0x65, 0xc0, 0x41, + 0x64, 0x6a, 0x5a, 0x5d, + 0x80, 0x64, 0xca, 0x6c, + 0x04, 0x64, 0x90, 0x74, + 0x02, 0x64, 0x9e, 0x74, + 0x00, 0x6a, 0x60, 0x74, + 0x03, 0x64, 0xbc, 0x74, + 0x23, 0x64, 0x4c, 0x74, + 0x08, 0x64, 0x5c, 0x74, + 0x61, 0x6a, 0xca, 0x5e, + 0x00, 0x65, 0xca, 0x5d, + 0x08, 0x51, 0xc2, 0x71, + 0x00, 0x65, 0x44, 0x44, + 0x80, 0x04, 0x5a, 0x7c, + 0x51, 0x6a, 0x50, 0x5d, + 0x01, 0x51, 0x5a, 0x64, + 0x01, 0xa4, 0x56, 0x7c, + 0x01, 0x55, 0x5c, 0x7c, + 0x41, 0x6a, 0xca, 0x5e, + 0x00, 0x65, 0x5c, 0x44, + 0x07, 0x6a, 0x46, 0x5d, + 0x01, 0x06, 0xd4, 0x30, + 0x00, 0x65, 0xc0, 0x41, + 0x10, 0xb8, 0x64, 0x7c, + 0xa1, 0x6a, 0xca, 0x5e, + 0x01, 0xb4, 0x6a, 0x6c, + 0x02, 0xb4, 0x6c, 0x6c, + 0x01, 0xa4, 0x6c, 0x7c, + 0xff, 0xa8, 0x7c, 0x7c, + 0x04, 0xb4, 0x68, 0x01, + 0x01, 0x6a, 0x76, 0x00, + 0x00, 0xbb, 0x04, 0x5e, + 0xff, 0xa8, 0x7c, 0x7c, + 0x71, 0x6a, 0xca, 0x5e, + 0x40, 0x51, 0x7c, 0x64, + 0x00, 0x65, 0xa4, 0x5e, + 0x00, 0x65, 0xd2, 0x41, + 0x00, 0xbb, 0x80, 0x5c, + 0x00, 0x65, 0xd2, 0x41, + 0x00, 0x65, 0xa4, 0x5e, + 0x01, 0x65, 0xa2, 0x30, + 0x01, 0xf8, 0xc8, 0x30, + 0x01, 0x4e, 0xc8, 0x30, + 0x00, 0x6a, 0xa8, 0xdd, + 0x00, 0x51, 0xba, 0x5d, + 0x01, 0x4e, 0x9c, 0x18, + 0x02, 0x6a, 0x22, 0x05, + 0x04, 0xb8, 0x70, 0x01, + 0x00, 0x65, 0xc6, 0x5e, + 0x20, 0xb8, 0xd2, 0x69, + 0x01, 0xbb, 0xa2, 0x30, + 0x01, 0xba, 0x7c, 0x30, + 0x00, 0xb9, 0xc0, 0x5c, + 0x00, 0x65, 0xd2, 0x41, + 0x01, 0x06, 0xd4, 0x30, + 0x20, 0x3c, 0xc0, 0x79, + 0x20, 0x3c, 0x5c, 0x7c, + 0x01, 0xa4, 0xac, 0x7c, + 0x01, 0xb4, 0x68, 0x01, + 0x00, 0x65, 0xc0, 0x41, + 0x00, 0x65, 0x5c, 0x44, + 0x04, 0x14, 0x58, 0x31, + 0x01, 0x06, 0xd4, 0x30, + 0x08, 0xa0, 0x60, 0x31, + 0xac, 0x6a, 0xcc, 0x00, + 0x14, 0x6a, 0xe6, 0x5d, + 0x01, 0x06, 0xd4, 0x30, + 0xa0, 0x6a, 0xde, 0x5d, + 0x00, 0x65, 0xc0, 0x41, + 0xdf, 0x3c, 0x78, 0x08, + 0x00, 0x65, 0x5c, 0x44, + 0x4c, 0x65, 0xcc, 0x28, + 0x01, 0x3e, 0x20, 0x31, + 0xd0, 0x66, 0xcc, 0x18, + 0x20, 0x66, 0xcc, 0x18, + 0x01, 0x51, 0xda, 0x34, + 0x4c, 0x3d, 0xca, 0x28, + 0x3f, 0x64, 0x7c, 0x08, + 0xd0, 0x65, 0xca, 0x18, + 0x01, 0x3e, 0x20, 0x31, + 0x30, 0x65, 0xd4, 0x18, + 0x00, 0x65, 0xd8, 0x4c, + 0xe1, 0x6a, 0x22, 0x01, + 0xff, 0x6a, 0xd4, 0x08, + 0x20, 0x65, 0xd4, 0x18, + 0x00, 0x65, 0xe0, 0x54, + 0xe1, 0x6a, 0x22, 0x01, + 0xff, 0x6a, 0xd4, 0x08, + 0x20, 0x65, 0xca, 0x18, + 0xe0, 0x65, 0xd4, 0x18, + 0x00, 0x65, 0xea, 0x4c, + 0xe1, 0x6a, 0x22, 0x01, + 0xff, 0x6a, 0xd4, 0x08, + 0xd0, 0x65, 0xd4, 0x18, + 0x00, 0x65, 0xf2, 0x54, + 0xe1, 0x6a, 0x22, 0x01, + 0xff, 0x6a, 0xd4, 0x08, + 0x01, 0x6c, 0xa2, 0x30, + 0xff, 0x51, 0x04, 0x75, + 0x00, 0x51, 0x80, 0x5d, + 0x01, 0x51, 0x20, 0x31, + 0x00, 0x65, 0x26, 0x45, + 0x01, 0xba, 0xc8, 0x30, + 0x00, 0x3e, 0x26, 0x75, + 0x00, 0x65, 0xa2, 0x5e, + 0x80, 0x3c, 0x78, 0x00, + 0x01, 0x06, 0xd4, 0x30, + 0x00, 0x65, 0xca, 0x5d, + 0x01, 0x3c, 0x78, 0x00, + 0xe0, 0x3f, 0x42, 0x65, + 0x02, 0x3c, 0x78, 0x00, + 0x20, 0x12, 0x42, 0x65, + 0x51, 0x6a, 0x50, 0x5d, + 0x00, 0x51, 0x80, 0x5d, + 0x51, 0x6a, 0x50, 0x5d, + 0x01, 0x51, 0x20, 0x31, + 0x04, 0x3c, 0x78, 0x00, + 0x01, 0xb9, 0xc8, 0x30, + 0x00, 0x3d, 0x40, 0x65, + 0x08, 0x3c, 0x78, 0x00, + 0x01, 0xba, 0xc8, 0x30, + 0x00, 0x3e, 0x40, 0x65, + 0x10, 0x3c, 0x78, 0x00, + 0x04, 0xb8, 0x40, 0x7d, + 0xfb, 0xb8, 0x70, 0x09, + 0x20, 0xb8, 0x36, 0x6d, + 0x01, 0x90, 0xc8, 0x30, + 0xff, 0x6a, 0xa2, 0x00, + 0x00, 0x3d, 0xc0, 0x5c, + 0x01, 0x64, 0x20, 0x31, + 0x80, 0x6a, 0x78, 0x00, + 0x00, 0x65, 0xec, 0x58, + 0x10, 0xb8, 0x5c, 0x7c, + 0xff, 0x6a, 0x46, 0x5d, + 0x00, 0x65, 0x5c, 0x44, + 0x00, 0x65, 0xa2, 0x5e, + 0x31, 0x6a, 0xca, 0x5e, + 0x00, 0x65, 0x5c, 0x44, + 0x10, 0x3f, 0x06, 0x00, + 0x10, 0x6a, 0x06, 0x00, + 0x01, 0x65, 0x74, 0x34, + 0x81, 0x6a, 0xca, 0x5e, + 0x00, 0x65, 0x52, 0x45, + 0x01, 0x06, 0xd4, 0x30, + 0x01, 0x0c, 0x52, 0x7d, + 0x04, 0x0c, 0x4c, 0x6d, + 0xe0, 0x03, 0x7e, 0x08, + 0xe0, 0x3f, 0xc0, 0x61, + 0x01, 0x65, 0xcc, 0x30, + 0x01, 0x12, 0xda, 0x34, + 0x01, 0x06, 0xd4, 0x34, + 0x01, 0x03, 0x60, 0x6d, + 0x40, 0x03, 0xcc, 0x08, + 0x01, 0x65, 0x06, 0x30, + 0x40, 0x65, 0xc8, 0x08, + 0x00, 0x66, 0x6e, 0x75, + 0x40, 0x65, 0x6e, 0x7d, + 0x00, 0x65, 0x6e, 0x5d, + 0xff, 0x6a, 0xd4, 0x08, + 0xff, 0x6a, 0xd4, 0x08, + 0xff, 0x6a, 0xd4, 0x08, + 0xff, 0x6a, 0xd4, 0x0c, + 0x08, 0x01, 0x02, 0x00, + 0x02, 0x0b, 0x78, 0x7d, + 0x01, 0x65, 0x0c, 0x30, + 0x02, 0x0b, 0x7c, 0x7d, + 0xf7, 0x01, 0x02, 0x0c, + 0x01, 0x65, 0xc8, 0x30, + 0xff, 0x41, 0xa0, 0x75, + 0x01, 0x41, 0x20, 0x31, + 0xff, 0x6a, 0xa4, 0x00, + 0x00, 0x65, 0x90, 0x45, + 0xff, 0xbf, 0xa0, 0x75, + 0x01, 0x90, 0xa4, 0x30, + 0x01, 0xbf, 0x20, 0x31, + 0x00, 0xbb, 0x8a, 0x65, + 0xff, 0x52, 0x9e, 0x75, + 0x01, 0xbf, 0xcc, 0x30, + 0x01, 0x90, 0xca, 0x30, + 0x01, 0x52, 0x20, 0x31, + 0x01, 0x66, 0x7e, 0x31, + 0x01, 0x65, 0x20, 0x35, + 0x01, 0xbf, 0x82, 0x34, + 0x01, 0x64, 0xa2, 0x30, + 0x00, 0x6a, 0xb2, 0x5e, + 0x0d, 0x6a, 0x76, 0x00, + 0x00, 0x51, 0x04, 0x46, + 0x01, 0x65, 0xa4, 0x30, + 0xe0, 0x6a, 0xcc, 0x00, + 0x48, 0x6a, 0xf8, 0x5d, + 0x01, 0x6a, 0xd0, 0x01, + 0x01, 0x6a, 0xdc, 0x05, + 0x88, 0x6a, 0xcc, 0x00, + 0x48, 0x6a, 0xf8, 0x5d, + 0x01, 0x6a, 0xd2, 0x5d, + 0x01, 0x6a, 0x26, 0x05, + 0x01, 0x65, 0xd8, 0x31, + 0x09, 0xee, 0xdc, 0x01, + 0x80, 0xee, 0xbe, 0x7d, + 0xff, 0x6a, 0xdc, 0x0d, + 0x01, 0x65, 0x32, 0x31, + 0x0a, 0x93, 0x26, 0x01, + 0x00, 0x65, 0x9a, 0x46, + 0x81, 0x6a, 0xca, 0x5e, + 0x01, 0x0c, 0xca, 0x7d, + 0x04, 0x0c, 0xc8, 0x6d, + 0xe0, 0x03, 0x06, 0x08, + 0xe0, 0x03, 0x7e, 0x0c, + 0x01, 0x65, 0x18, 0x31, + 0xff, 0x6a, 0x1a, 0x09, + 0xff, 0x6a, 0x1c, 0x0d, + 0x01, 0x8c, 0x10, 0x30, + 0x01, 0x8d, 0x12, 0x30, + 0x01, 0x8e, 0x14, 0x34, + 0x01, 0x6c, 0xda, 0x30, + 0x01, 0x6c, 0xda, 0x30, + 0x01, 0x6c, 0xda, 0x30, + 0x01, 0x6c, 0xda, 0x30, + 0x01, 0x6c, 0xda, 0x30, + 0x01, 0x6c, 0xda, 0x30, + 0x01, 0x6c, 0xda, 0x30, + 0x01, 0x6c, 0xda, 0x34, + 0x3d, 0x64, 0xa4, 0x28, + 0x55, 0x64, 0xc8, 0x28, + 0x00, 0x65, 0xf8, 0x45, + 0x2e, 0x64, 0xa4, 0x28, + 0x66, 0x64, 0xc8, 0x28, + 0x00, 0x6c, 0xda, 0x18, + 0x01, 0x52, 0xc8, 0x30, + 0x00, 0x6c, 0xda, 0x20, + 0xff, 0x6a, 0xc8, 0x08, + 0x00, 0x6c, 0xda, 0x20, + 0x00, 0x6c, 0xda, 0x24, + 0x01, 0x65, 0xc8, 0x30, + 0xe0, 0x6a, 0xcc, 0x00, + 0x44, 0x6a, 0xf4, 0x5d, + 0x01, 0x90, 0xe2, 0x31, + 0x04, 0x3b, 0x18, 0x7e, + 0x30, 0x6a, 0xd0, 0x01, + 0x20, 0x6a, 0xd0, 0x01, + 0x1d, 0x6a, 0xdc, 0x01, + 0xdc, 0xee, 0x14, 0x66, + 0x00, 0x65, 0x30, 0x46, + 0x20, 0x6a, 0xd0, 0x01, + 0x01, 0x6a, 0xdc, 0x01, + 0x20, 0xa0, 0xd8, 0x31, + 0x09, 0xee, 0xdc, 0x01, + 0x80, 0xee, 0x20, 0x7e, + 0x11, 0x6a, 0xdc, 0x01, + 0x50, 0xee, 0x24, 0x66, + 0x20, 0x6a, 0xd0, 0x01, + 0x09, 0x6a, 0xdc, 0x01, + 0x88, 0xee, 0x2a, 0x66, + 0x19, 0x6a, 0xdc, 0x01, + 0xd8, 0xee, 0x2e, 0x66, + 0xff, 0x6a, 0xdc, 0x09, + 0x18, 0xee, 0x32, 0x6e, + 0xff, 0x6a, 0xd4, 0x0c, + 0x88, 0x6a, 0xcc, 0x00, + 0x44, 0x6a, 0xf4, 0x5d, + 0x20, 0x6a, 0xd2, 0x5d, + 0x01, 0x3b, 0x26, 0x31, + 0x04, 0x3b, 0x4c, 0x6e, + 0xa0, 0x6a, 0xca, 0x00, + 0x20, 0x65, 0xc8, 0x18, + 0x00, 0x65, 0x8a, 0x5e, + 0x00, 0x65, 0x44, 0x66, + 0x0a, 0x93, 0x26, 0x01, + 0x00, 0x65, 0x9a, 0x46, + 0xa0, 0x6a, 0xcc, 0x00, + 0xff, 0x6a, 0xc8, 0x08, + 0x20, 0x94, 0x50, 0x6e, + 0x10, 0x94, 0x52, 0x6e, + 0x08, 0x94, 0x6c, 0x6e, + 0x08, 0x94, 0x6c, 0x6e, + 0x08, 0x94, 0x6c, 0x6e, + 0xff, 0x8c, 0xc8, 0x10, + 0xc1, 0x64, 0xc8, 0x18, + 0xf8, 0x64, 0xc8, 0x08, + 0x01, 0x99, 0xda, 0x30, + 0x00, 0x66, 0x60, 0x66, + 0xc0, 0x66, 0x9c, 0x76, + 0x60, 0x66, 0xc8, 0x18, + 0x3d, 0x64, 0xc8, 0x28, + 0x00, 0x65, 0x50, 0x46, + 0xf7, 0x93, 0x26, 0x09, + 0x08, 0x93, 0x6e, 0x6e, + 0x00, 0x62, 0xc4, 0x18, + 0x00, 0x65, 0x9a, 0x5e, + 0x00, 0x65, 0x7a, 0x5e, + 0x00, 0x65, 0x7a, 0x5e, + 0x00, 0x65, 0x7a, 0x5e, + 0x01, 0x99, 0xda, 0x30, + 0x01, 0x99, 0xda, 0x30, + 0x01, 0x99, 0xda, 0x30, + 0x01, 0x99, 0xda, 0x30, + 0x01, 0x99, 0xda, 0x30, + 0x01, 0x99, 0xda, 0x30, + 0x01, 0x99, 0xda, 0x30, + 0x01, 0x99, 0xda, 0x34, + 0x01, 0x6c, 0x32, 0x31, + 0x01, 0x6c, 0x32, 0x31, + 0x01, 0x6c, 0x32, 0x31, + 0x01, 0x6c, 0x32, 0x31, + 0x01, 0x6c, 0x32, 0x31, + 0x01, 0x6c, 0x32, 0x31, + 0x01, 0x6c, 0x32, 0x31, + 0x01, 0x6c, 0x32, 0x35, + 0x08, 0x94, 0x9a, 0x7e, + 0xf7, 0x93, 0x26, 0x09, + 0x08, 0x93, 0x9e, 0x6e, + 0xff, 0x6a, 0xd4, 0x0c, + 0x04, 0xb8, 0xc6, 0x6e, + 0x01, 0x42, 0x7e, 0x31, + 0xff, 0x6a, 0x76, 0x01, + 0x01, 0x90, 0x84, 0x34, + 0xff, 0x6a, 0x76, 0x05, + 0x01, 0x85, 0x0a, 0x01, + 0x7f, 0x65, 0x10, 0x09, + 0xfe, 0x85, 0x0a, 0x0d, + 0xff, 0x42, 0xc2, 0x66, + 0xff, 0x41, 0xba, 0x66, + 0xd1, 0x6a, 0xca, 0x5e, + 0xff, 0x6a, 0xca, 0x04, + 0x01, 0x41, 0x20, 0x31, + 0x01, 0xbf, 0x82, 0x30, + 0x01, 0x6a, 0x76, 0x00, + 0x00, 0xbb, 0x04, 0x46, + 0x01, 0x42, 0x20, 0x31, + 0x01, 0xbf, 0x84, 0x34, + 0x01, 0x41, 0x7e, 0x31, + 0x01, 0x90, 0x82, 0x34, + 0x01, 0x65, 0x22, 0x31, + 0xff, 0x6a, 0xd4, 0x08, + 0xff, 0x6a, 0xd4, 0x0c +}; + +static int ahc_patch23_func(struct ahc_softc *ahc); + +static int +ahc_patch23_func(struct ahc_softc *ahc) +{ + return ((ahc->bugs & AHC_SCBCHAN_UPLOAD_BUG) != 0); +} + +static int ahc_patch22_func(struct ahc_softc *ahc); + +static int +ahc_patch22_func(struct ahc_softc *ahc) +{ + return ((ahc->features & AHC_CMD_CHAN) == 0); +} + +static int ahc_patch21_func(struct ahc_softc *ahc); + +static int +ahc_patch21_func(struct ahc_softc *ahc) +{ + return ((ahc->features & AHC_QUEUE_REGS) == 0); +} + +static int ahc_patch20_func(struct ahc_softc *ahc); + +static int +ahc_patch20_func(struct ahc_softc *ahc) +{ + return ((ahc->features & AHC_WIDE) != 0); +} + +static int ahc_patch19_func(struct ahc_softc *ahc); + +static int +ahc_patch19_func(struct ahc_softc *ahc) +{ + return ((ahc->flags & AHC_SCB_BTT) != 0); +} + +static int ahc_patch18_func(struct ahc_softc *ahc); + +static int +ahc_patch18_func(struct ahc_softc *ahc) +{ + return ((ahc->bugs & AHC_PCI_2_1_RETRY_BUG) != 0); +} + +static int ahc_patch17_func(struct ahc_softc *ahc); + +static int +ahc_patch17_func(struct ahc_softc *ahc) +{ + return ((ahc->flags & AHC_TMODE_WIDEODD_BUG) != 0); +} + +static int ahc_patch16_func(struct ahc_softc *ahc); + +static int +ahc_patch16_func(struct ahc_softc *ahc) +{ + return ((ahc->bugs & AHC_AUTOFLUSH_BUG) != 0); +} + +static int ahc_patch15_func(struct ahc_softc *ahc); + +static int +ahc_patch15_func(struct ahc_softc *ahc) +{ + return ((ahc->features & AHC_ULTRA2) == 0); +} + +static int ahc_patch14_func(struct ahc_softc *ahc); + +static int +ahc_patch14_func(struct ahc_softc *ahc) +{ + return ((ahc->bugs & AHC_PCI_MWI_BUG) != 0 && ahc->pci_cachesize != 0); +} + +static int ahc_patch13_func(struct ahc_softc *ahc); + +static int +ahc_patch13_func(struct ahc_softc *ahc) +{ + return ((ahc->flags & AHC_39BIT_ADDRESSING) != 0); +} + +static int ahc_patch12_func(struct ahc_softc *ahc); + +static int +ahc_patch12_func(struct ahc_softc *ahc) +{ + return ((ahc->features & AHC_HS_MAILBOX) != 0); +} + +static int ahc_patch11_func(struct ahc_softc *ahc); + +static int +ahc_patch11_func(struct ahc_softc *ahc) +{ + return ((ahc->features & AHC_ULTRA) != 0); +} + +static int ahc_patch10_func(struct ahc_softc *ahc); + +static int +ahc_patch10_func(struct ahc_softc *ahc) +{ + return ((ahc->features & AHC_MULTI_TID) != 0); +} + +static int ahc_patch9_func(struct ahc_softc *ahc); + +static int +ahc_patch9_func(struct ahc_softc *ahc) +{ + return ((ahc->features & AHC_CMD_CHAN) != 0); +} + +static int ahc_patch8_func(struct ahc_softc *ahc); + +static int +ahc_patch8_func(struct ahc_softc *ahc) +{ + return ((ahc->flags & AHC_INITIATORROLE) != 0); +} + +static int ahc_patch7_func(struct ahc_softc *ahc); + +static int +ahc_patch7_func(struct ahc_softc *ahc) +{ + return ((ahc->flags & AHC_TARGETROLE) != 0); +} + +static int ahc_patch6_func(struct ahc_softc *ahc); + +static int +ahc_patch6_func(struct ahc_softc *ahc) +{ + return ((ahc->features & AHC_DT) == 0); +} + +static int ahc_patch5_func(struct ahc_softc *ahc); + +static int +ahc_patch5_func(struct ahc_softc *ahc) +{ + return ((ahc->flags & AHC_SEQUENCER_DEBUG) != 0); +} + +static int ahc_patch4_func(struct ahc_softc *ahc); + +static int +ahc_patch4_func(struct ahc_softc *ahc) +{ + return ((ahc->flags & AHC_PAGESCBS) != 0); +} + +static int ahc_patch3_func(struct ahc_softc *ahc); + +static int +ahc_patch3_func(struct ahc_softc *ahc) +{ + return ((ahc->features & AHC_QUEUE_REGS) != 0); +} + +static int ahc_patch2_func(struct ahc_softc *ahc); + +static int +ahc_patch2_func(struct ahc_softc *ahc) +{ + return ((ahc->features & AHC_TWIN) != 0); +} + +static int ahc_patch1_func(struct ahc_softc *ahc); + +static int +ahc_patch1_func(struct ahc_softc *ahc) +{ + return ((ahc->features & AHC_ULTRA2) != 0); +} + +static int ahc_patch0_func(struct ahc_softc *ahc); + +static int +ahc_patch0_func(struct ahc_softc *ahc) +{ + return (0); +} + +typedef int patch_func_t (struct ahc_softc *); +struct patch { + patch_func_t *patch_func; + uint32_t begin :10, + skip_instr :10, + skip_patch :12; +} patches[] = { + { ahc_patch1_func, 4, 1, 1 }, + { ahc_patch2_func, 6, 2, 1 }, + { ahc_patch2_func, 9, 1, 1 }, + { ahc_patch3_func, 11, 1, 2 }, + { ahc_patch0_func, 12, 2, 1 }, + { ahc_patch4_func, 15, 1, 2 }, + { ahc_patch0_func, 16, 1, 1 }, + { ahc_patch5_func, 22, 2, 1 }, + { ahc_patch3_func, 27, 1, 2 }, + { ahc_patch0_func, 28, 1, 1 }, + { ahc_patch6_func, 34, 1, 1 }, + { ahc_patch7_func, 37, 54, 19 }, + { ahc_patch8_func, 37, 1, 1 }, + { ahc_patch9_func, 42, 3, 2 }, + { ahc_patch0_func, 45, 3, 1 }, + { ahc_patch10_func, 49, 1, 2 }, + { ahc_patch0_func, 50, 2, 3 }, + { ahc_patch1_func, 50, 1, 2 }, + { ahc_patch0_func, 51, 1, 1 }, + { ahc_patch2_func, 53, 2, 1 }, + { ahc_patch9_func, 55, 1, 2 }, + { ahc_patch0_func, 56, 1, 1 }, + { ahc_patch9_func, 60, 1, 2 }, + { ahc_patch0_func, 61, 1, 1 }, + { ahc_patch9_func, 71, 1, 2 }, + { ahc_patch0_func, 72, 1, 1 }, + { ahc_patch9_func, 75, 1, 2 }, + { ahc_patch0_func, 76, 1, 1 }, + { ahc_patch9_func, 79, 1, 2 }, + { ahc_patch0_func, 80, 1, 1 }, + { ahc_patch8_func, 91, 9, 4 }, + { ahc_patch1_func, 93, 1, 2 }, + { ahc_patch0_func, 94, 1, 1 }, + { ahc_patch2_func, 96, 2, 1 }, + { ahc_patch2_func, 105, 4, 1 }, + { ahc_patch1_func, 109, 1, 2 }, + { ahc_patch0_func, 110, 2, 3 }, + { ahc_patch2_func, 110, 1, 2 }, + { ahc_patch0_func, 111, 1, 1 }, + { ahc_patch7_func, 112, 4, 2 }, + { ahc_patch0_func, 116, 1, 1 }, + { ahc_patch11_func, 118, 2, 1 }, + { ahc_patch1_func, 120, 1, 2 }, + { ahc_patch0_func, 121, 1, 1 }, + { ahc_patch7_func, 122, 4, 1 }, + { ahc_patch7_func, 133, 89, 11 }, + { ahc_patch4_func, 151, 1, 1 }, + { ahc_patch1_func, 164, 1, 1 }, + { ahc_patch12_func, 169, 1, 2 }, + { ahc_patch0_func, 170, 1, 1 }, + { ahc_patch9_func, 181, 1, 2 }, + { ahc_patch0_func, 182, 1, 1 }, + { ahc_patch9_func, 191, 1, 2 }, + { ahc_patch0_func, 192, 1, 1 }, + { ahc_patch9_func, 208, 6, 2 }, + { ahc_patch0_func, 214, 6, 1 }, + { ahc_patch8_func, 222, 18, 2 }, + { ahc_patch1_func, 235, 1, 1 }, + { ahc_patch1_func, 242, 1, 2 }, + { ahc_patch0_func, 243, 2, 2 }, + { ahc_patch11_func, 244, 1, 1 }, + { ahc_patch9_func, 252, 31, 3 }, + { ahc_patch1_func, 268, 14, 2 }, + { ahc_patch13_func, 273, 1, 1 }, + { ahc_patch14_func, 283, 14, 1 }, + { ahc_patch1_func, 299, 1, 2 }, + { ahc_patch0_func, 300, 1, 1 }, + { ahc_patch9_func, 303, 1, 1 }, + { ahc_patch13_func, 308, 1, 1 }, + { ahc_patch9_func, 309, 2, 2 }, + { ahc_patch0_func, 311, 4, 1 }, + { ahc_patch14_func, 315, 1, 1 }, + { ahc_patch15_func, 318, 2, 3 }, + { ahc_patch9_func, 318, 1, 2 }, + { ahc_patch0_func, 319, 1, 1 }, + { ahc_patch6_func, 324, 1, 2 }, + { ahc_patch0_func, 325, 1, 1 }, + { ahc_patch1_func, 329, 50, 11 }, + { ahc_patch6_func, 338, 2, 4 }, + { ahc_patch7_func, 338, 1, 1 }, + { ahc_patch8_func, 339, 1, 1 }, + { ahc_patch0_func, 340, 1, 1 }, + { ahc_patch16_func, 341, 1, 1 }, + { ahc_patch6_func, 360, 6, 3 }, + { ahc_patch16_func, 360, 5, 1 }, + { ahc_patch0_func, 366, 5, 1 }, + { ahc_patch13_func, 374, 5, 1 }, + { ahc_patch0_func, 379, 54, 17 }, + { ahc_patch14_func, 379, 1, 1 }, + { ahc_patch7_func, 381, 2, 2 }, + { ahc_patch17_func, 382, 1, 1 }, + { ahc_patch9_func, 385, 1, 1 }, + { ahc_patch18_func, 392, 1, 1 }, + { ahc_patch14_func, 397, 9, 3 }, + { ahc_patch9_func, 398, 3, 2 }, + { ahc_patch0_func, 401, 3, 1 }, + { ahc_patch9_func, 409, 6, 2 }, + { ahc_patch0_func, 415, 9, 2 }, + { ahc_patch13_func, 415, 1, 1 }, + { ahc_patch13_func, 424, 2, 1 }, + { ahc_patch14_func, 426, 1, 1 }, + { ahc_patch9_func, 428, 1, 2 }, + { ahc_patch0_func, 429, 1, 1 }, + { ahc_patch7_func, 432, 1, 1 }, + { ahc_patch7_func, 433, 1, 1 }, + { ahc_patch8_func, 434, 3, 3 }, + { ahc_patch6_func, 435, 1, 2 }, + { ahc_patch0_func, 436, 1, 1 }, + { ahc_patch9_func, 437, 1, 1 }, + { ahc_patch15_func, 438, 1, 2 }, + { ahc_patch13_func, 438, 1, 1 }, + { ahc_patch14_func, 440, 9, 4 }, + { ahc_patch9_func, 440, 1, 1 }, + { ahc_patch9_func, 447, 2, 1 }, + { ahc_patch0_func, 449, 4, 3 }, + { ahc_patch9_func, 449, 1, 2 }, + { ahc_patch0_func, 450, 3, 1 }, + { ahc_patch1_func, 454, 2, 1 }, + { ahc_patch7_func, 456, 10, 2 }, + { ahc_patch0_func, 466, 1, 1 }, + { ahc_patch8_func, 467, 109, 23 }, + { ahc_patch1_func, 469, 3, 2 }, + { ahc_patch0_func, 472, 5, 3 }, + { ahc_patch9_func, 472, 2, 2 }, + { ahc_patch0_func, 474, 3, 1 }, + { ahc_patch1_func, 479, 2, 2 }, + { ahc_patch0_func, 481, 6, 3 }, + { ahc_patch9_func, 481, 2, 2 }, + { ahc_patch0_func, 483, 3, 1 }, + { ahc_patch1_func, 489, 2, 2 }, + { ahc_patch0_func, 491, 9, 7 }, + { ahc_patch9_func, 491, 5, 6 }, + { ahc_patch19_func, 491, 1, 2 }, + { ahc_patch0_func, 492, 1, 1 }, + { ahc_patch19_func, 494, 1, 2 }, + { ahc_patch0_func, 495, 1, 1 }, + { ahc_patch0_func, 496, 4, 1 }, + { ahc_patch6_func, 500, 3, 2 }, + { ahc_patch0_func, 503, 1, 1 }, + { ahc_patch1_func, 506, 1, 1 }, + { ahc_patch6_func, 512, 1, 2 }, + { ahc_patch0_func, 513, 1, 1 }, + { ahc_patch20_func, 550, 7, 1 }, + { ahc_patch3_func, 578, 1, 2 }, + { ahc_patch0_func, 579, 1, 1 }, + { ahc_patch21_func, 582, 1, 1 }, + { ahc_patch8_func, 584, 104, 33 }, + { ahc_patch4_func, 585, 1, 1 }, + { ahc_patch1_func, 591, 2, 2 }, + { ahc_patch0_func, 593, 1, 1 }, + { ahc_patch1_func, 596, 1, 2 }, + { ahc_patch0_func, 597, 1, 1 }, + { ahc_patch9_func, 598, 3, 3 }, + { ahc_patch15_func, 599, 1, 1 }, + { ahc_patch0_func, 601, 4, 1 }, + { ahc_patch19_func, 609, 2, 2 }, + { ahc_patch0_func, 611, 1, 1 }, + { ahc_patch19_func, 615, 10, 3 }, + { ahc_patch5_func, 617, 8, 1 }, + { ahc_patch0_func, 625, 9, 2 }, + { ahc_patch5_func, 626, 8, 1 }, + { ahc_patch4_func, 636, 1, 2 }, + { ahc_patch0_func, 637, 1, 1 }, + { ahc_patch19_func, 638, 1, 2 }, + { ahc_patch0_func, 639, 3, 2 }, + { ahc_patch4_func, 641, 1, 1 }, + { ahc_patch5_func, 642, 1, 1 }, + { ahc_patch5_func, 645, 1, 1 }, + { ahc_patch5_func, 647, 1, 1 }, + { ahc_patch4_func, 649, 2, 2 }, + { ahc_patch0_func, 651, 2, 1 }, + { ahc_patch5_func, 653, 1, 1 }, + { ahc_patch5_func, 656, 1, 1 }, + { ahc_patch5_func, 659, 1, 1 }, + { ahc_patch19_func, 663, 1, 1 }, + { ahc_patch19_func, 666, 1, 1 }, + { ahc_patch4_func, 672, 1, 1 }, + { ahc_patch6_func, 675, 1, 2 }, + { ahc_patch0_func, 676, 1, 1 }, + { ahc_patch7_func, 688, 16, 1 }, + { ahc_patch4_func, 704, 20, 1 }, + { ahc_patch9_func, 725, 4, 2 }, + { ahc_patch0_func, 729, 4, 1 }, + { ahc_patch9_func, 733, 4, 2 }, + { ahc_patch0_func, 737, 3, 1 }, + { ahc_patch6_func, 743, 1, 1 }, + { ahc_patch22_func, 745, 14, 1 }, + { ahc_patch7_func, 759, 3, 1 }, + { ahc_patch9_func, 771, 24, 8 }, + { ahc_patch19_func, 775, 1, 2 }, + { ahc_patch0_func, 776, 1, 1 }, + { ahc_patch15_func, 781, 4, 2 }, + { ahc_patch0_func, 785, 7, 3 }, + { ahc_patch23_func, 785, 5, 2 }, + { ahc_patch0_func, 790, 2, 1 }, + { ahc_patch0_func, 795, 42, 3 }, + { ahc_patch18_func, 807, 18, 2 }, + { ahc_patch0_func, 825, 1, 1 }, + { ahc_patch4_func, 849, 1, 1 }, + { ahc_patch4_func, 850, 3, 2 }, + { ahc_patch0_func, 853, 1, 1 }, + { ahc_patch13_func, 854, 3, 1 }, + { ahc_patch4_func, 857, 12, 1 } +}; +struct cs { + u_int16_t begin; + u_int16_t end; +} critical_sections[] = { + { 11, 18 }, + { 21, 30 }, + { 704, 720 }, + { 850, 853 }, + { 857, 863 }, + { 865, 867 }, + { 867, 869 } +}; +const int num_critical_sections = sizeof(critical_sections) + / sizeof(*critical_sections); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/drivers/scsi/dpt_i2o.c linux.2.5.47-ac6/drivers/scsi/dpt_i2o.c --- linux.2.5.47/drivers/scsi/dpt_i2o.c 2002-10-31 15:05:01.000000000 +0000 +++ linux.2.5.47-ac6/drivers/scsi/dpt_i2o.c 2002-10-31 17:49:27.000000000 +0000 @@ -1033,10 +1033,10 @@ kfree(pHba->lct); } if(pHba->status_block) { - kfree(pHba->status_block); + pci_free_consistent(pHba->pDev, sizeof(struct i2o_status_block), pHba->status_block, pHba->status_block_dma); } if(pHba->reply_pool){ - kfree(pHba->reply_pool); + pci_free_consistent(pHba->pDev, pHba->reply_pool_size, pHba->reply_pool, pHba->reply_pool_dma); } for(d = pHba->devices; d ; d = next){ @@ -2106,18 +2106,19 @@ } // msg[0] is set later // I2O_CMD_SCSI_EXEC - msg[1] = ((0xff<<24)|(HOST_TID<<12)|d->tid); + msg[1] = cpu_to_le32((0xff<<24)|(HOST_TID<<12)|d->tid); msg[2] = 0; - msg[3] = (u32)cmd; /* We want the SCSI control block back */ + // FIXME: Broken for 64bit !! + msg[3] = cpu_to_le32((u32)cmd); /* We want the SCSI control block back */ // Our cards use the transaction context as the tag for queueing // Adaptec/DPT Private stuff - msg[4] = I2O_CMD_SCSI_EXEC|(DPT_ORGANIZATION_ID<<16); - msg[5] = d->tid; + msg[4] = cpu_to_le32(I2O_CMD_SCSI_EXEC|(DPT_ORGANIZATION_ID<<16)); + msg[5] = cpu_to_le32(d->tid); /* Direction, disconnect ok | sense data | simple queue , CDBLen */ // I2O_SCB_FLAG_ENABLE_DISCONNECT | // I2O_SCB_FLAG_SIMPLE_QUEUE_TAG | // I2O_SCB_FLAG_SENSE_DATA_IN_MESSAGE; - msg[6] = scsidir|0x20a00000|cmd->cmd_len; + msg[6] = cpu_to_le32(scsidir|0x20a00000|cmd->cmd_len); mptr=msg+7; @@ -2130,15 +2131,21 @@ /* Now fill in the SGList and command */ if(cmd->use_sg) { struct scatterlist *sg = (struct scatterlist *)cmd->request_buffer; + int sg_count = pci_map_sg(pHba->pDev, sg, Cmnd->use_sg, + scsi_to_pci_dma_dir(Cmnd->sc_data_direction)); + + if(sg_count == 0) + return -ENOMEM; + len = 0; - for(i = 0 ; i < cmd->use_sg; i++) { - *mptr++ = direction|0x10000000|sg->length; - len+=sg->length; - *mptr++ = virt_to_bus(sg->address); + for(i = 0 ; i < sg_count; i++) { + *mptr++ = cpu_to_le32(direction|0x10000000|sg_dma_length(sg)); + len+= cpu_to_le32(sg_dma_length(sg)); + *mptr++ = sg_dmap_address(sg); sg++; } /* Make this an end of list */ - mptr[-2] = direction|0xD0000000|(sg-1)->length; + mptr[-2] = cpu_to_le32(direction|0xD0000000|sg_dma_length(sg-1)); reqlen = mptr - msg; *lenptr = len; @@ -2147,24 +2154,29 @@ len, cmd->underflow); } } else { + dma_addr_t dma_addr = pci_map_single(pHba->pDev, + Cmnd->request_buffer, + Cmnd->request_bufflen, + scsi_to_pci_dma_dir(Cmnd->sc_data_direction)); + + if(dma_addr == 0) + return -ENOMEM; + + Cmnd->SCp.ptr = (char *)(unsigned long) dma_addr; *lenptr = len = cmd->request_bufflen; if(len == 0) { reqlen = 12; } else { - *mptr++ = 0xD0000000|direction|cmd->request_bufflen; - *mptr++ = virt_to_bus(cmd->request_buffer); + *mptr++ = cpu_to_le32(0xD0000000|direction|cmd->request_bufflen); + *mptr++ = cpu_to_le32(dma_addr); } } /* Stick the headers on */ - msg[0] = reqlen<<16 | ((reqlen > 12) ? SGL_OFFSET_12 : SGL_OFFSET_0); + msg[0] = cpu_to_le32(reqlen<<16 | ((reqlen > 12) ? SGL_OFFSET_12 : SGL_OFFSET_0)); // Send it on it's way - rcode = adpt_i2o_post_this(pHba, msg, reqlen<<2); - if (rcode == 0) { - return 0; - } - return rcode; + return adpt_i2o_post_this(pHba, msg, reqlen<<2); } @@ -2204,19 +2216,31 @@ adpt_hba* pHba; u32 hba_status; u32 dev_status; - u32 reply_flags = readl(reply) & 0xff00; // Leave it shifted up 8 bits + u32 reply_flags = le32_to_cpu(readl(reply)) & 0xff00; // Leave it shifted up 8 bits // I know this would look cleaner if I just read bytes // but the model I have been using for all the rest of the // io is in 4 byte words - so I keep that model - u16 detailed_status = readl(reply+16) &0xffff; + u16 detailed_status = le32_to_cpu(readl(reply+16)) &0xffff; dev_status = (detailed_status & 0xff); hba_status = detailed_status >> 8; // calculate resid for sg - cmd->resid = cmd->request_bufflen - readl(reply+5); + cmd->resid = cmd->request_bufflen - le32_to_cpu(readl(reply+5)); pHba = (adpt_hba*) cmd->host->hostdata[0]; + if (cmd->use_sg) + pci_unmap_sg(pHba->pDev, + (struct scatterlist *)cmd->buffer, + cmd->use_sg, + scsi_to_pci_dma_dir(cmd->sc_data_direction)); + else if (Cmnd->request_bufflen) + pci_unmap_single(pHba->pDev, + (dma_addr_t)((long)cmd->SCp.ptr), + cmd->request_bufflen, + scsi_to_pci_dma_dir(cmd->sc_data_direction)); + + cmd->sense_buffer[0] = '\0'; // initialize sense valid flag to false if(!(reply_flags & MSG_FAIL)) { @@ -2224,7 +2248,7 @@ case I2O_SCSI_DSC_SUCCESS: cmd->result = (DID_OK << 16); // handle underflow - if(readl(reply+5) < cmd->underflow ) { + if(le32_to_cpu(readl(reply+5)) < cmd->underflow ) { cmd->result = (DID_ERROR <<16); printk(KERN_WARNING"%s: SCSI CMD underflow\n",pHba->name); } @@ -2646,6 +2670,7 @@ u32* ptr; u32 outbound_frame; // This had to be a 32 bit address u32 m; + dma_addr_t statdma; do { rmb(); @@ -2662,25 +2687,24 @@ msg=(u32 *)(pHba->msg_addr_virt+m); - status = kmalloc(4,GFP_KERNEL|ADDR32); + status = pci_alloc_consistent(pHba->pDev, 4, &statdma); if (status==NULL) { adpt_send_nop(pHba, m); - printk(KERN_WARNING"%s: IOP reset failed - no free memory.\n", - pHba->name); + printk(KERN_WARNING"%s: IOP reset failed - no free memory.\n", pHba->name); return -ENOMEM; } memset(status, 0, 4); - writel(EIGHT_WORD_MSG_SIZE| SGL_OFFSET_6, &msg[0]); - writel(I2O_CMD_OUTBOUND_INIT<<24 | HOST_TID<<12 | ADAPTER_TID, &msg[1]); + writel(cpu_to_le32(EIGHT_WORD_MSG_SIZE| SGL_OFFSET_6), &msg[0]); + writel(cpu_to_le32(I2O_CMD_OUTBOUND_INIT<<24 | HOST_TID<<12 | ADAPTER_TID), &msg[1]); writel(0, &msg[2]); - writel(0x0106, &msg[3]); /* Transaction context */ - writel(4096, &msg[4]); /* Host page frame size */ - writel((REPLY_FRAME_SIZE)<<16|0x80, &msg[5]); /* Outbound msg frame size and Initcode */ - writel(0xD0000004, &msg[6]); /* Simple SG LE, EOB */ - writel(virt_to_bus(status), &msg[7]); + writel(cpu_to_le32(0x0106), &msg[3]); /* Transaction context */ + writel(cpu_to_le32(4096), &msg[4]); /* Host page frame size */ + writel(cpu_to_le32((REPLY_FRAME_SIZE)<<16|0x80), &msg[5]); /* Outbound msg frame size and Initcode */ + writel(cpu_to_le32(0xD0000004), &msg[6]); /* Simple SG LE, EOB */ + writel(cpu_to_le32(statdma), &msg[7]); - writel(m, pHba->post_port); + writel(cpu_to_le32(m), pHba->post_port); wmb(); // Wait for the reply status to come back @@ -2701,16 +2725,17 @@ // If the command was successful, fill the fifo with our reply // message packets if(*status != 0x04 /*I2O_EXEC_OUTBOUND_INIT_COMPLETE*/) { - kfree((void*)status); + pci_free_consistent(pHba->pDev, 4, status, statdma); return -2; } - kfree((void*)status); + pci_free_consistent(pHba->pDev, 4, status, statdma); if(pHba->reply_pool != NULL){ - kfree(pHba->reply_pool); + pci_free_consistent(pHba->pDev, pHba->reply_pool_size, pHba->reply_pool, pHba->reply_pool_dma); } - pHba->reply_pool = (u32*)kmalloc(pHba->reply_fifo_size * REPLY_FRAME_SIZE * 4, GFP_KERNEL|ADDR32); + pHba->reply_pool_size = pHba->reply_fifo_size * REPLY_FRAME_SIZE * 4 + pHba->reply_pool = (u32*)pci_alloc_consistent(pHba->pDev, pHba->reply_pool_size , &pHba->reply_pool_dma); if(!pHba->reply_pool){ printk(KERN_ERR"%s: Could not allocate reply pool\n",pHba->name); return -1; @@ -2718,11 +2743,12 @@ memset(pHba->reply_pool, 0 , pHba->reply_fifo_size * REPLY_FRAME_SIZE * 4); ptr = pHba->reply_pool; + dma = pHba->reply_pool_dma; for(i = 0; i < pHba->reply_fifo_size; i++) { - outbound_frame = (u32)virt_to_bus(ptr); - writel(outbound_frame, pHba->reply_port); + writel(cpu_to_le32(dma), pHba->reply_port); wmb(); ptr += REPLY_FRAME_SIZE; + dma += REPLY_FRAME_SIZE; } adpt_i2o_status_get(pHba); return 0; @@ -2738,39 +2764,32 @@ * used by IOPs to track changes. */ - - static s32 adpt_i2o_status_get(adpt_hba* pHba) { ulong timeout; u32 m; u32 *msg; u8 *status_block=NULL; - ulong status_block_bus; if(pHba->status_block == NULL) { - pHba->status_block = (i2o_status_block*) - kmalloc(sizeof(i2o_status_block),GFP_KERNEL|ADDR32); + pHba->status_block = (i2o_status_block*) pci_alloc_consistent(pHba->pDev, (sizeof(i2o_status_block), &pHba->status_block_dma); if(pHba->status_block == NULL) { - printk(KERN_ERR - "dpti%d: Get Status Block failed; Out of memory. \n", - pHba->unit); + printk(KERN_ERR "dpti%d: Get Status Block failed; Out of memory. \n", pHba->unit); return -ENOMEM; } } memset(pHba->status_block, 0, sizeof(i2o_status_block)); status_block = (u8*)(pHba->status_block); - status_block_bus = virt_to_bus(pHba->status_block); + timeout = jiffies+TMOUT_GETSTATUS*HZ; do { rmb(); - m = readl(pHba->post_port); + m = cpu_to_le32(readl(pHba->post_port)); if (m != EMPTY_QUEUE) { break; } if(time_after(jiffies,timeout)){ - printk(KERN_ERR "%s: Timeout waiting for message !\n", - pHba->name); + printk(KERN_ERR "%s: Timeout waiting for message !\n", pHba->name); return -ETIMEDOUT; } } while(m==EMPTY_QUEUE); @@ -2778,24 +2797,23 @@ msg=(u32*)(pHba->msg_addr_virt+m); - writel(NINE_WORD_MSG_SIZE|SGL_OFFSET_0, &msg[0]); - writel(I2O_CMD_STATUS_GET<<24|HOST_TID<<12|ADAPTER_TID, &msg[1]); + writel(cpu_to_le32(NINE_WORD_MSG_SIZE|SGL_OFFSET_0), &msg[0]); + writel(cpu_to_le32(I2O_CMD_STATUS_GET<<24|HOST_TID<<12|ADAPTER_TID), &msg[1]); writel(1, &msg[2]); writel(0, &msg[3]); writel(0, &msg[4]); writel(0, &msg[5]); - writel(((u32)status_block_bus)&0xffffffff, &msg[6]); + writel(cpu_to_le32(pHba->status_block_dma), &msg[6]); writel(0, &msg[7]); - writel(sizeof(i2o_status_block), &msg[8]); // 88 bytes + writel(cpu_to_le32(sizeof(i2o_status_block)), &msg[8]); // 88 bytes //post message - writel(m, pHba->post_port); + writel(cpu_to_le32(m), pHba->post_port); wmb(); while(status_block[87]!=0xff){ if(time_after(jiffies,timeout)){ - printk(KERN_ERR"dpti%d: Get status timeout.\n", - pHba->unit); + printk(KERN_ERR"dpti%d: Get status timeout.\n", pHba->unit); return -ETIMEDOUT; } rmb(); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/drivers/scsi/dpti.h linux.2.5.47-ac6/drivers/scsi/dpti.h --- linux.2.5.47/drivers/scsi/dpti.h 2002-10-31 15:05:01.000000000 +0000 +++ linux.2.5.47-ac6/drivers/scsi/dpti.h 2002-10-31 17:49:39.000000000 +0000 @@ -282,12 +282,15 @@ u32 post_fifo_size; u32 reply_fifo_size; u32* reply_pool; + dma_addr_t reply_pool_dma; + u32 reply_pool_size; u32 sg_tablesize; // Scatter/Gather List Size. u8 top_scsi_channel; u8 top_scsi_id; u8 top_scsi_lun; i2o_status_block* status_block; + dma_addr_t status_block_dma; i2o_hrt* hrt; i2o_lct* lct; uint lct_size; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/drivers/scsi/i60uscsi.c linux.2.5.47-ac6/drivers/scsi/i60uscsi.c --- linux.2.5.47/drivers/scsi/i60uscsi.c 2002-10-31 14:57:11.000000000 +0000 +++ linux.2.5.47-ac6/drivers/scsi/i60uscsi.c 2002-11-03 01:14:17.000000000 +0000 @@ -566,10 +566,10 @@ ORC_WR(pHCB->HCS_Base + ORC_HCTRL, SCSIRST); if (waitSCSIRSTdone(pHCB) == FALSE) { spin_unlock_irqrestore(&(pHCB->BitAllocFlagLock), flags); - return (SCSI_RESET_ERROR); + return FAILED; } else { spin_unlock_irqrestore(&(pHCB->BitAllocFlagLock), flags); - return (SCSI_RESET_SUCCESS); + return SUCCESS; } } @@ -581,7 +581,7 @@ Output : None. Return : pSRB - Pointer to SCSI request block. *****************************************************************************/ -int orc_device_reset(ORC_HCS * pHCB, Scsi_Cmnd *SCpnt, unsigned int target, unsigned int ResetFlags) +int orc_device_reset(ORC_HCS * pHCB, Scsi_Cmnd *SCpnt, unsigned int target) { /* I need Host Control Block Information */ ORC_SCB *pScb; ESCB *pVirEscb; @@ -608,11 +608,11 @@ if (i == ORC_MAXQUEUE) { printk("Unable to Reset - No SCB Found\n"); spin_unlock_irqrestore(&(pHCB->BitAllocFlagLock), flags); - return (SCSI_RESET_NOT_RUNNING); + return FAILED; } if ((pScb = orc_alloc_scb(pHCB)) == NULL) { spin_unlock_irqrestore(&(pHCB->BitAllocFlagLock), flags); - return (SCSI_RESET_NOT_RUNNING); + return FAILED; } pScb->SCB_Opcode = ORC_BUSDEVRST; pScb->SCB_Target = target; @@ -626,12 +626,10 @@ pScb->SCB_SGLen = 0; pVirEscb->SCB_Srb = 0; - if (ResetFlags & SCSI_RESET_SYNCHRONOUS) { - pVirEscb->SCB_Srb = SCpnt; - } + pVirEscb->SCB_Srb = SCpnt; orc_exec_scb(pHCB, pScb); /* Start execute SCB */ spin_unlock_irqrestore(&(pHCB->BitAllocFlagLock), flags); - return SCSI_RESET_PENDING; + return SUCCESS; } @@ -838,21 +836,21 @@ if ((pVirScb->SCB_Status) && (pVirEscb->SCB_Srb == SCpnt)) { if (pVirScb->SCB_TagMsg == 0) { spin_unlock_irqrestore(&(hcsp->BitAllocFlagLock), flags); - return (SCSI_ABORT_BUSY); + return FAILED; } else { if (abort_SCB(hcsp, pVirScb)) { pVirEscb->SCB_Srb = NULL; spin_unlock_irqrestore(&(hcsp->BitAllocFlagLock), flags); - return (SCSI_ABORT_SUCCESS); + return SUCCESS; } else { spin_unlock_irqrestore(&(hcsp->BitAllocFlagLock), flags); - return (SCSI_ABORT_NOT_RUNNING); + return FAILED; } } } } spin_unlock_irqrestore(&(hcsp->BitAllocFlagLock), flags); - return (SCSI_ABORT_NOT_RUNNING); + return FAILED; } /*********************************************************************** diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/drivers/scsi/inia100.c linux.2.5.47-ac6/drivers/scsi/inia100.c --- linux.2.5.47/drivers/scsi/inia100.c 2002-11-03 01:15:47.000000000 +0000 +++ linux.2.5.47-ac6/drivers/scsi/inia100.c 2002-11-03 01:17:58.000000000 +0000 @@ -123,7 +123,7 @@ extern void orc_release_scb(ORC_HCS * hcsp, ORC_SCB * scbp); extern void orc_release_dma(ORC_HCS * hcsp, Scsi_Cmnd * cmnd); extern void orc_interrupt(ORC_HCS * hcsp); -extern int orc_device_reset(ORC_HCS * pHCB, Scsi_Cmnd *SCpnt, unsigned int target, unsigned int ResetFlags); +extern int orc_device_reset(ORC_HCS * pHCB, Scsi_Cmnd *SCpnt, unsigned int target); extern int orc_reset_scsi_bus(ORC_HCS * pHCB); extern int abort_SCB(ORC_HCS * hcsp, ORC_SCB * pScb); extern int orc_abort_srb(ORC_HCS * hcsp, Scsi_Cmnd *SCpnt); @@ -511,7 +511,7 @@ Output : None. Return : pSRB - Pointer to SCSI request block. *****************************************************************************/ -int inia100_queue(Scsi_Cmnd * SCpnt, void (*done) (Scsi_Cmnd *)) +static int inia100_queue(Scsi_Cmnd * SCpnt, void (*done) (Scsi_Cmnd *)) { register ORC_SCB *pSCB; ORC_HCS *pHCB; /* Point to Host adapter control block */ @@ -538,7 +538,7 @@ Output : None. Return : pSRB - Pointer to SCSI request block. *****************************************************************************/ -int inia100_abort(Scsi_Cmnd * SCpnt) +static int inia100_abort(Scsi_Cmnd * SCpnt) { ORC_HCS *hcsp; @@ -554,15 +554,25 @@ Output : None. Return : pSRB - Pointer to SCSI request block. *****************************************************************************/ -int inia100_reset(Scsi_Cmnd * SCpnt, unsigned int reset_flags) +static int inia100_bus_reset(Scsi_Cmnd * SCpnt) { /* I need Host Control Block Information */ ORC_HCS *pHCB; pHCB = (ORC_HCS *) SCpnt->host->hostdata; + return orc_reset_scsi_bus(pHCB); +} - if (reset_flags & (SCSI_RESET_SUGGEST_BUS_RESET | SCSI_RESET_SUGGEST_HOST_RESET)) - return orc_reset_scsi_bus(pHCB); - else - return orc_device_reset(pHCB, SCpnt, SCpnt->target, reset_flags); +/***************************************************************************** + Function name : inia100_device_reset + Description : Reset the device + Input : pHCB - Pointer to host adapter structure + Output : None. + Return : pSRB - Pointer to SCSI request block. +*****************************************************************************/ +static int inia100_device_reset(Scsi_Cmnd * SCpnt) +{ /* I need Host Control Block Information */ + ORC_HCS *pHCB; + pHCB = (ORC_HCS *) SCpnt->host->hostdata; + return orc_device_reset(pHCB, SCpnt, SCpnt->target); } @@ -645,41 +655,6 @@ return; } -/***************************************************************************** - Function name : inia100_biosparam - Description : Return the "logical geometry" - Input : pHCB - Pointer to host adapter structure - Output : None. - Return : pSRB - Pointer to SCSI request block. -*****************************************************************************/ -int inia100_biosparam(struct scsi_device *sdev, struct block_device *bdev, - sector_t capacity, int *info_array) -{ - ORC_HCS *pHcb; /* Point to Host adapter control block */ - ORC_TCS *pTcb; - - pHcb = (ORC_HCS *) sdev->host->hostdata; - pTcb = &pHcb->HCS_Tcs[sdev->id]; - - if (pTcb->TCS_DrvHead) { - info_array[0] = pTcb->TCS_DrvHead; - info_array[1] = pTcb->TCS_DrvSector; - info_array[2] = (unsigned long)capacity / pTcb->TCS_DrvHead / pTcb->TCS_DrvSector; - } else { - if (pTcb->TCS_DrvFlags & TCF_DRV_255_63) { - info_array[0] = 255; - info_array[1] = 63; - info_array[2] = (unsigned long)capacity / 255 / 63; - } else { - info_array[0] = 64; - info_array[1] = 32; - info_array[2] = capacity >> 11; - } - } - return 0; -} - - /* * Interrupt handler (main routine of the driver) */ @@ -707,7 +682,7 @@ /* * Release ressources */ -int inia100_release(struct Scsi_Host *hreg) +static int inia100_release(struct Scsi_Host *hreg) { ORC_HCS *pHCB = (ORC_HCS *)hreg->hostdata; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/drivers/scsi/inia100.h linux.2.5.47-ac6/drivers/scsi/inia100.h --- linux.2.5.47/drivers/scsi/inia100.h 2002-11-05 13:54:44.000000000 +0000 +++ linux.2.5.47-ac6/drivers/scsi/inia100.h 2002-11-05 14:24:54.000000000 +0000 @@ -75,14 +75,12 @@ #include #include -extern int inia100_detect(Scsi_Host_Template *); -extern int inia100_release(struct Scsi_Host *); -extern int inia100_queue(Scsi_Cmnd *, void (*done) (Scsi_Cmnd *)); -extern int inia100_abort(Scsi_Cmnd *); -extern int inia100_reset(Scsi_Cmnd *, unsigned int); - -extern int inia100_biosparam(struct scsi_device *, struct block_device *, - sector_t, int *); +static int inia100_detect(Scsi_Host_Template *); +static int inia100_release(struct Scsi_Host *); +static int inia100_queue(Scsi_Cmnd *, void (*done) (Scsi_Cmnd *)); +static int inia100_abort(Scsi_Cmnd *); +static int inia100_device_reset(Scsi_Cmnd *); +static int inia100_bus_reset(Scsi_Cmnd *); #define inia100_REVID "Initio INI-A100U2W SCSI device driver; Revision: 1.02d" @@ -92,8 +90,9 @@ detect: inia100_detect, \ release: inia100_release, \ queuecommand: inia100_queue, \ - abort: inia100_abort, \ - reset: inia100_reset, \ + eh_abort_handler:inia100_abort, \ + eh_bus_reset_handler: inia100_bus_reset, \ + eh_device_reset_handler:inia100_device_reset, \ can_queue: 1, \ this_id: 1, \ sg_tablesize: SG_ALL, \ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/drivers/scsi/ips.c linux.2.5.47-ac6/drivers/scsi/ips.c --- linux.2.5.47/drivers/scsi/ips.c 2002-10-31 15:05:01.000000000 +0000 +++ linux.2.5.47-ac6/drivers/scsi/ips.c 2002-11-11 20:20:52.000000000 +0000 @@ -856,7 +856,7 @@ ips_name, ips_next_controller, mem_addr, mem_len); #if LINUX_VERSION_CODE >= LinuxVersionCode(2,4,0) - if (check_mem_region(mem_addr, mem_len)) { + if (!request_mem_region(mem_addr, mem_len, "ips")) { /* Couldn't allocate io space */ printk(KERN_WARNING "(%s%d) couldn't allocate IO space %x len %d.\n", ips_name, ips_next_controller, io_addr, io_len); @@ -866,7 +866,6 @@ continue; } - request_mem_region(mem_addr, mem_len, "ips"); #endif base = mem_addr & PAGE_MASK; @@ -884,7 +883,7 @@ DEBUG_VAR(1, "(%s%d) detect, IO region %x, size: %d", ips_name, ips_next_controller, io_addr, io_len); - if (check_region(io_addr, io_len)) { + if (!request_region(io_addr, io_len, "ips")) { /* Couldn't allocate io space */ printk(KERN_WARNING "(%s%d) couldn't allocate IO space %x len %d.\n", ips_name, ips_next_controller, io_addr, io_len); @@ -894,7 +893,6 @@ continue; } - request_region(io_addr, io_len, "ips"); } /* get planer status */ @@ -7329,12 +7327,11 @@ uint32_t base; uint32_t offs; - if (check_mem_region(mem_addr, mem_len)) { + if (!request_mem_region(mem_addr, mem_len, "ips")) { printk(KERN_WARNING "Couldn't allocate IO Memory space %x len %d.\n", mem_addr, mem_len); return -1; } - request_mem_region(mem_addr, mem_len, "ips"); base = mem_addr & PAGE_MASK; offs = mem_addr - base; ioremap_ptr = ioremap(base, PAGE_SIZE); @@ -7346,11 +7343,10 @@ /* setup I/O mapped area (if applicable) */ if (io_addr) { - if (check_region(io_addr, io_len)) { + if (!request_region(io_addr, io_len, "ips")) { printk(KERN_WARNING "Couldn't allocate IO space %x len %d.\n", io_addr, io_len); return -1; } - request_region(io_addr, io_len, "ips"); } /* get the revision ID */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/drivers/scsi/megaraid.c linux.2.5.47-ac6/drivers/scsi/megaraid.c --- linux.2.5.47/drivers/scsi/megaraid.c 2002-11-11 16:39:10.000000000 +0000 +++ linux.2.5.47-ac6/drivers/scsi/megaraid.c 2002-11-12 15:34:26.000000000 +0000 @@ -494,27 +494,18 @@ #include #include #include +#include #include #include #include #include /* for kmalloc() */ -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,0) /* 0x20100 */ -#include -#else -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0) /* 0x20300 */ -#include -#else #include -#endif -#endif #include #include -#if LINUX_VERSION_CODE > KERNEL_VERSION(2,0,24) /* 0x020024 */ #include -#endif /* * These header files are required for Shutdown Notification routines @@ -557,17 +548,6 @@ writel (value, megaCfg->base + 0x2C); } -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0) /* 0x020200 */ -#include -#define cpuid smp_processor_id() -#endif - -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,4) -#define scsi_set_pci_device(x,y) -#endif - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) /* 0x020400 */ - /* * Linux 2.4 and higher * @@ -580,122 +560,6 @@ MODULE_DESCRIPTION ("LSI Logic MegaRAID driver"); MODULE_LICENSE ("GPL"); -#define DRIVER_LOCK_T -#define DRIVER_LOCK_INIT(p) -#define DRIVER_LOCK(p) -#define DRIVER_UNLOCK(p) -#define IO_LOCK_T unsigned long io_flags = 0 -#define IO_LOCK(host) spin_lock_irqsave(host->host_lock,io_flags) -#define IO_UNLOCK(host) spin_unlock_irqrestore(host->host_lock,io_flags) -#define IO_LOCK_IRQ(host) spin_lock_irq(host->host_lock) -#define IO_UNLOCK_IRQ(host) spin_unlock_irq(host->host_lock) - -#define queue_task_irq(a,b) queue_task(a,b) -#define queue_task_irq_off(a,b) queue_task(a,b) - -#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0) /* 0x020200 */ - -/* - * Linux 2.2 and higher - * - * No driver private lock - * Use the io_request_lock not cli/sti - * No pci region api - * queue_task is now a single simple API - */ - -static char kernel_version[] = UTS_RELEASE; -MODULE_AUTHOR ("LSI Logic Corporation"); -MODULE_DESCRIPTION ("LSI Logic MegaRAID driver"); - -#define DRIVER_LOCK_T -#define DRIVER_LOCK_INIT(p) -#define DRIVER_LOCK(p) -#define DRIVER_UNLOCK(p) -#define IO_LOCK_T unsigned long io_flags = 0 -#define IO_LOCK(host) spin_lock_irqsave(host->host_lock,io_flags); -#define IO_UNLOCK(host) spin_unlock_irqrestore(host->host_lock,io_flags); - -#define pci_free_consistent(a,b,c,d) -#define pci_unmap_single(a,b,c,d) -#define pci_enable_device(x) (0) -#define queue_task_irq(a,b) queue_task(a,b) -#define queue_task_irq_off(a,b) queue_task(a,b) - -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,2,19) /* 0x020219 */ -#define init_MUTEX_LOCKED(x) (*(x)=MUTEX_LOCKED) -#define init_MUTEX(x) (*(x)=MUTEX) -#define DECLARE_WAIT_QUEUE_HEAD(x) struct wait_queue *x = NULL -#endif - - -#else - -/* - * Linux 2.0 macros. Here we have to provide some of our own - * functionality. We also only work little endian 32bit. - * Again no pci_alloc/free api - * IO_LOCK/IO_LOCK_T were never used in 2.0 so now are empty - */ - -#define cpuid 0 -#define DRIVER_LOCK_T long cpu_flags; -#define DRIVER_LOCK_INIT(p) -#define DRIVER_LOCK(p) \ - save_flags(cpu_flags); \ - cli(); -#define DRIVER_UNLOCK(p) \ - restore_flags(cpu_flags); -#define IO_LOCK_T -#define IO_LOCK(p) -#define IO_UNLOCK(p) -#define le32_to_cpu(x) (x) -#define cpu_to_le32(x) (x) - -#define pci_free_consistent(a,b,c,d) -#define pci_unmap_single(a,b,c,d) - -#define init_MUTEX_LOCKED(x) (*(x)=MUTEX_LOCKED) -#define init_MUTEX(x) (*(x)=MUTEX) - -#define pci_enable_device(x) (0) - -/* - * 2.0 lacks spinlocks, iounmap/ioremap - */ - -#define ioremap vremap -#define iounmap vfree - - /* simulate spin locks */ -typedef struct { - volatile char lock; -} spinlock_t; - -#define spin_lock_init(x) { (x)->lock = 0;} -#define spin_lock_irqsave(x,flags) { while ((x)->lock) barrier();\ - (x)->lock=1; save_flags(flags);\ - cli();} -#define spin_unlock_irqrestore(x,flags) { (x)->lock=0; restore_flags(flags);} - -#define DECLARE_WAIT_QUEUE_HEAD(x) struct wait_queue *x = NULL - -#endif - - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) /* 0x020400 */ -#define dma_alloc_consistent pci_alloc_consistent -#define dma_free_consistent pci_free_consistent -#else -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,2,19) /* 0x020219 */ -typedef unsigned long dma_addr_t; -#endif -void *dma_alloc_consistent(void *, size_t, dma_addr_t *); -void dma_free_consistent(void *, size_t, void *, dma_addr_t); -int mega_get_order(int); -int pow_2(int); -#endif - /* set SERDEBUG to 1 to enable serial debugging */ #define SERDEBUG 0 #if SERDEBUG @@ -705,7 +569,6 @@ static int ser_printk (const char *fmt, ...); #endif -#ifdef CONFIG_PROC_FS #define COPY_BACK if (offset > megaCfg->procidx) { \ *eof = TRUE; \ megaCfg->procidx = 0; \ @@ -717,7 +580,6 @@ memcpy(page, &megaCfg->procbuf[offset], count); \ megaCfg->procidx = 0; \ megaCfg->procbuf[0] = 0; -#endif /* * ================================================================ @@ -730,11 +592,7 @@ processor id cannot be scanned */ static char *megaraid; -#if LINUX_VERSION_CODE > KERNEL_VERSION(2,1,0) /* 0x20100 */ -#ifdef MODULE MODULE_PARM (megaraid, "s"); -#endif -#endif static int skip_id = -1; static int numCtlrs = 0; static mega_host_config *megaCtlrs[FC_MAX_CHANNELS] = { 0 }; @@ -760,6 +618,7 @@ /* For controller re-ordering */ static struct file_operations megadev_fops = { + owner: THIS_MODULE, ioctl:megadev_ioctl_entry, open:megadev_open, release:megadev_close, @@ -785,13 +644,6 @@ volatile static spinlock_t serial_lock; #endif -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0) /* 0x20300 */ -static struct proc_dir_entry proc_scsi_megaraid = { - PROC_SCSI_MEGARAID, 8, "megaraid", - S_IFDIR | S_IRUGO | S_IXUGO, 2 -}; -#endif - #ifdef CONFIG_PROC_FS extern struct proc_dir_entry proc_root; #endif @@ -887,7 +739,6 @@ if ((pScb == NULL) || (pScb->idx >= 0xFE)) { return; } -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) switch (pScb->dma_type) { case M_RD_DMA_TYPE_NONE: break; @@ -927,7 +778,6 @@ default: break; } -#endif /* Unlink from pending queue */ if (pScb == megaCfg->qPendingH) { @@ -991,9 +841,7 @@ pScb->state = SCB_ACTIVE; pScb->SCpnt = SCpnt; -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) pScb->dma_type = M_RD_DMA_TYPE_NONE; -#endif return pScb; } @@ -1059,13 +907,8 @@ SCpnt = pScb->SCpnt; -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) pthru = pScb->pthru; epthru = pScb->epthru; -#else - pthru = &pScb->pthru; - epthru = &pScb->epthru; -#endif mbox = (mega_mailbox *) & pScb->mboxData; @@ -1079,11 +922,7 @@ islogical = ( (SCpnt->channel >= megaCfg->productInfo.SCSIChanPresent) && (SCpnt->channel <= megaCfg->host->max_channel) ); -#if 0 - islogical = (SCpnt->channel == megaCfg->host->max_channel); -#endif -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) /* Special Case to handle PassThrough->XferAddrress > 4GB */ switch (SCpnt->cmnd[0]) { case INQUIRY: @@ -1092,7 +931,6 @@ pScb->bounce_buffer, SCpnt->request_bufflen); break; } -#endif mega_freeSCB (megaCfg, pScb); @@ -1101,24 +939,14 @@ * sent, and returned data==hard disk or removable hard disk and not * logical, request should return failure! - PJ */ -#if 0 - if (SCpnt->cmnd[0] == INQUIRY && ((((u_char *) SCpnt->request_buffer)[0] & 0x1F) == TYPE_DISK) && !islogical) { - status = 0xF0; - } -#endif if (SCpnt->cmnd[0] == INQUIRY && !islogical) { if ( SCpnt->use_sg ) { sgList = (struct scatterlist *)SCpnt->request_buffer; - memcpy(&c, cpu_to_le32(sg_dma_address(&sgList[0])), 0x1); + c = *(u8 *) cpu_to_le32(sg_dma_address(&sgList[0])); } else { - memcpy(&c, SCpnt->request_buffer, 0x1); - } -#if 0 - if( (c & 0x1F ) == TYPE_DISK ) { - status = 0xF0; + c = *(u8 *)SCpnt->request_buffer; } -#endif if( IS_RAID_CH(SCpnt->channel) && ((c & 0x1F ) == TYPE_DISK) ) { status = 0xF0; } @@ -1214,22 +1042,12 @@ if ((SCpnt->cmnd[0] == M_RD_IOCTL_CMD) || (SCpnt->cmnd[0] == M_RD_IOCTL_CMD_NEW)) -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0) - return mega_ioctl (megaCfg, SCpnt); /* Handle IOCTL command */ -#else { - printk(KERN_WARNING "megaraid ioctl: older interface - " - "not supported.\n"); return NULL; } -#endif islogical = ( (SCpnt->channel >= megaCfg->productInfo.SCSIChanPresent) && (SCpnt->channel <= megaCfg->host->max_channel) ); -#if 0 - islogical = (IS_RAID_CH(SCpnt->channel) && /* virtual ch is raid - AM */ - (SCpnt->channel == megaCfg->host->max_channel)); -#endif if ( ! megaCfg->support_ext_cdb ) { if (!islogical && lun != 0) { @@ -1320,11 +1138,7 @@ callDone (SCpnt); return NULL; } -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) pthru = pScb->pthru; -#else - pthru = &pScb->pthru; -#endif mbox = (mega_mailbox *) & pScb->mboxData; memset (mbox, 0, sizeof (pScb->mboxData)); @@ -1336,30 +1150,12 @@ pthru->logdrv = lun; pthru->cdblen = SCpnt->cmd_len; -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) /*Not sure about the direction */ pScb->dma_direction = PCI_DMA_BIDIRECTIONAL; pScb->dma_type = M_RD_PTHRU_WITH_BULK_DATA; -#if 0 -/* Normal Code w/o the need for bounce buffer */ - pScb->dma_h_bulkdata - = pci_map_single (megaCfg->dev, - SCpnt->request_buffer, - SCpnt->request_bufflen, - pScb->dma_direction); - - pthru->dataxferaddr = pScb->dma_h_bulkdata; -#else -/* Special Code to use bounce buffer for READ_CAPA/INQ */ pthru->dataxferaddr = pScb->dma_bounce_buffer; pScb->dma_type = M_RD_DMA_TYPE_NONE; -#endif - -#else - pthru->dataxferaddr = - virt_to_bus (SCpnt->request_buffer); -#endif pthru->dataxferlen = SCpnt->request_bufflen; memcpy (pthru->cdb, SCpnt->cmnd, SCpnt->cmd_len); @@ -1367,12 +1163,8 @@ /* Initialize mailbox area */ mbox->cmd = MEGA_MBOXCMD_PASSTHRU; -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) mbox->xferaddr = pScb->dma_passthruhandle64; TRACE1 (("M_RD_PTHRU_WITH_BULK_DATA Enabled \n")); -#else - mbox->xferaddr = virt_to_bus (pthru); -#endif return pScb; case READ_6: @@ -1396,9 +1188,7 @@ READ_10) ? MEGA_MBOXCMD_LREAD64 : MEGA_MBOXCMD_LWRITE64; } else { - mbox->cmd = (*SCpnt->cmnd == READ_6 - || *SCpnt->cmnd == - READ_10) ? MEGA_MBOXCMD_LREAD : + mbox->cmd = (*SCpnt->cmnd == READ_6 || *SCpnt->cmnd == READ_10) ? MEGA_MBOXCMD_LREAD : MEGA_MBOXCMD_LWRITE; } @@ -1469,20 +1259,16 @@ } } -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) - if (*SCpnt->cmnd == READ_6 || *SCpnt->cmnd == READ_10 - || *SCpnt->cmnd == READ_12) { + if (*SCpnt->cmnd == READ_6 || *SCpnt->cmnd == READ_10 || *SCpnt->cmnd == READ_12) { pScb->dma_direction = PCI_DMA_FROMDEVICE; } else { /*WRITE_6 or WRITE_10 */ pScb->dma_direction = PCI_DMA_TODEVICE; } -#endif /* Calculate Scatter-Gather info */ mbox->numsgelements = mega_build_sglist (megaCfg, pScb, (u32 *)&mbox->xferaddr, (u32 *)&seg); -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) pScb->iDataSize = seg; if (mbox->numsgelements) { @@ -1492,8 +1278,6 @@ pScb->dma_type = M_RD_BULK_DATA_ONLY; TRACE1 (("M_RD_BULK_DATA_ONLY Enabled \n")); } -#endif - return pScb; default: SCpnt->result = (DID_BAD_TARGET << 16); @@ -1520,7 +1304,6 @@ if ( megaCfg->support_ext_cdb && SCpnt->cmd_len > 10 ) { epthru = mega_prepare_extpassthru(megaCfg, pScb, SCpnt); mbox->cmd = MEGA_MBOXCMD_EXTPASSTHRU; -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) mbox->xferaddr = pScb->dma_ext_passthruhandle64; if(epthru->numsgelements) { @@ -1528,16 +1311,12 @@ } else { pScb->dma_type = M_RD_EPTHRU_WITH_BULK_DATA; } -#else - mbox->xferaddr = virt_to_bus(epthru); -#endif } else { pthru = mega_prepare_passthru(megaCfg, pScb, SCpnt); /* Initialize mailbox */ mbox->cmd = MEGA_MBOXCMD_PASSTHRU; -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) mbox->xferaddr = pScb->dma_passthruhandle64; if (pthru->numsgelements) { @@ -1545,9 +1324,6 @@ } else { pScb->dma_type = M_RD_PTHRU_WITH_BULK_DATA; } -#else - mbox->xferaddr = virt_to_bus(pthru); -#endif } return pScb; } @@ -1597,11 +1373,7 @@ { mega_passthru *pthru; -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) pthru = scb->pthru; -#else - pthru = &scb->pthru; -#endif memset (pthru, 0, sizeof (mega_passthru)); /* set adapter timeout value to 10 min. for tape drive */ @@ -1618,7 +1390,6 @@ memcpy (pthru->cdb, sc->cmnd, sc->cmd_len); -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) /* Not sure about the direction */ scb->dma_direction = PCI_DMA_BIDIRECTIONAL; @@ -1631,20 +1402,12 @@ pthru->dataxferlen = sc->request_bufflen; break; default: - pthru->numsgelements = - mega_build_sglist( + pthru->numsgelements = mega_build_sglist( megacfg, scb, (u32 *)&pthru->dataxferaddr, (u32 *)&pthru->dataxferlen ); break; } -#else - pthru->numsgelements = - mega_build_sglist( - megacfg, scb, (u32 *)&pthru->dataxferaddr, - (u32 *)&pthru->dataxferlen - ); -#endif return pthru; } @@ -1653,11 +1416,7 @@ { mega_ext_passthru *epthru; -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) epthru = scb->epthru; -#else - epthru = &scb->epthru; -#endif memset(epthru, 0, sizeof(mega_ext_passthru)); /* set adapter timeout value to 10 min. for tape drive */ @@ -1674,7 +1433,6 @@ memcpy(epthru->cdb, sc->cmnd, sc->cmd_len); -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) /* Not sure about the direction */ scb->dma_direction = PCI_DMA_BIDIRECTIONAL; @@ -1694,13 +1452,6 @@ ); break; } -#else - epthru->numsgelements = - mega_build_sglist( - megacfg, scb, (u32 *)&epthru->dataxferaddr, - (u32 *)&epthru->dataxferlen - ); -#endif return epthru; } @@ -1741,8 +1492,6 @@ static void inline set_mbox_xfer_addr (mega_host_config * megaCfg, mega_scb * pScb, mega_ioctl_mbox * mbox, u32 direction) { - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) switch (direction) { case TO_DEVICE: pScb->dma_direction = PCI_DMA_TODEVICE; @@ -1755,290 +1504,15 @@ break; } - pScb->dma_h_bulkdata - = pci_map_single (megaCfg->dev, - pScb->buff_ptr, - pScb->iDataSize, pScb->dma_direction); + pScb->dma_h_bulkdata = pci_map_single (megaCfg->dev, pScb->buff_ptr, pScb->iDataSize, pScb->dma_direction); mbox->xferaddr = pScb->dma_h_bulkdata; pScb->dma_type = M_RD_BULK_DATA_ONLY; TRACE1 (("M_RD_BULK_DATA_ONLY Enabled \n")); -#else - mbox->xferaddr = virt_to_bus (pScb->buff_ptr); -#endif -} - -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0) - -/*-------------------------------------------------------------------- - * build RAID commands for controller, passed down through ioctl() - *--------------------------------------------------------------------*/ -static mega_scb *mega_ioctl (mega_host_config * megaCfg, Scsi_Cmnd * SCpnt) -{ - mega_scb *pScb; - mega_ioctl_mbox *mbox; - mega_mailbox *mailbox; - mega_passthru *pthru; - u8 *mboxdata; - long seg, i = 0; - unsigned char *data = (unsigned char *) SCpnt->request_buffer; - - if ((pScb = mega_allocateSCB (megaCfg, SCpnt)) == NULL) { - SCpnt->result = (DID_ERROR << 16); - callDone (SCpnt); - return NULL; - } - pthru = &pScb->pthru; - - mboxdata = (u8 *) & pScb->mboxData; - mbox = (mega_ioctl_mbox *) & pScb->mboxData; - mailbox = (mega_mailbox *) & pScb->mboxData; - memset (mailbox, 0, sizeof (pScb->mboxData)); - - if (data[0] == 0x03) { /* passthrough command */ - unsigned char cdblen = data[2]; - memset (pthru, 0, sizeof (mega_passthru)); - pthru->islogical = (data[cdblen + 3] & 0x80) ? 1 : 0; - pthru->timeout = data[cdblen + 3] & 0x07; - pthru->reqsenselen = 14; - pthru->ars = (data[cdblen + 3] & 0x08) ? 1 : 0; - pthru->logdrv = data[cdblen + 4]; - pthru->channel = data[cdblen + 5]; - pthru->target = data[cdblen + 6]; - pthru->cdblen = cdblen; - memcpy (pthru->cdb, &data[3], cdblen); - - mailbox->cmd = MEGA_MBOXCMD_PASSTHRU; - - - pthru->numsgelements = mega_build_sglist (megaCfg, pScb, - (u32 *) & pthru-> - dataxferaddr, - (u32 *) & pthru-> - dataxferlen); - - mailbox->xferaddr = virt_to_bus (pthru); - - for (i = 0; i < (SCpnt->request_bufflen - cdblen - 7); i++) { - data[i] = data[i + cdblen + 7]; - } - return pScb; - } - /* else normal (nonpassthru) command */ - -#if LINUX_VERSION_CODE > KERNEL_VERSION(2,0,24) /*0x020024 */ - /* - *usage of the function copy from user is used in case of data more than - *4KB.This is used only with adapters which supports more than 8 logical - * drives.This feature is disabled on kernels earlier or same as 2.0.36 - * as the uaccess.h file is not available with those kernels. - */ - - if (SCpnt->cmnd[0] == M_RD_IOCTL_CMD_NEW) { - /* use external data area for large xfers */ - /* If cmnd[0] is set to M_RD_IOCTL_CMD_NEW then * - * cmnd[4..7] = external user buffer * - * cmnd[8..11] = length of buffer * - * */ - char *user_area = (char *)*((u32*)&SCpnt->cmnd[4]); - u32 xfer_size = *((u32 *) & SCpnt->cmnd[8]); - switch (data[0]) { - case FW_FIRE_WRITE: - case FW_FIRE_FLASH: - if ((ulong) user_area & (PAGE_SIZE - 1)) { - printk - ("megaraid:user address not aligned on 4K boundary.Error.\n"); - SCpnt->result = (DID_ERROR << 16); - callDone (SCpnt); - return NULL; - } - break; - default: - break; - } - - if (!(pScb->buff_ptr = kmalloc (xfer_size, GFP_KERNEL))) { - printk - ("megaraid: Insufficient mem for M_RD_IOCTL_CMD_NEW.\n"); - SCpnt->result = (DID_ERROR << 16); - callDone (SCpnt); - return NULL; - } - - copy_from_user (pScb->buff_ptr, user_area, xfer_size); - pScb->iDataSize = xfer_size; - - switch (data[0]) { - case DCMD_FC_CMD: - switch (data[1]) { - case DCMD_FC_READ_NVRAM_CONFIG: - case DCMD_GET_DISK_CONFIG: - { - if ((ulong) pScb-> - buff_ptr & (PAGE_SIZE - 1)) { - printk - ("megaraid:user address not sufficient Error.\n"); - SCpnt->result = - (DID_ERROR << 16); - callDone (SCpnt); - return NULL; - } - - /*building SG list */ - mega_build_kernel_sg (pScb->buff_ptr, - xfer_size, - pScb, mbox); - break; - } - default: - break; - } /*switch (data[1]) */ - break; - } - - } -#endif - - mbox->cmd = data[0]; - mbox->channel = data[1]; - mbox->param = data[2]; - mbox->pad[0] = data[3]; - mbox->logdrv = data[4]; - - if (SCpnt->cmnd[0] == M_RD_IOCTL_CMD_NEW) { - switch (data[0]) { - case FW_FIRE_WRITE: - mbox->cmd = FW_FIRE_WRITE; - mbox->channel = data[1]; /* Current Block Number */ - set_mbox_xfer_addr (megaCfg, pScb, mbox, TO_DEVICE); - mbox->numsgelements = 0; - break; - case FW_FIRE_FLASH: - mbox->cmd = FW_FIRE_FLASH; - mbox->channel = data[1] | 0x80; /* Origin */ - set_mbox_xfer_addr (megaCfg, pScb, mbox, TO_DEVICE); - mbox->numsgelements = 0; - break; - case DCMD_FC_CMD: - *(mboxdata + 0) = data[0]; /*mailbox byte 0: DCMD_FC_CMD */ - *(mboxdata + 2) = data[1]; /*sub command */ - switch (data[1]) { - case DCMD_FC_READ_NVRAM_CONFIG: - case DCMD_FC_READ_NVRAM_CONFIG_64: - /* number of elements in SG list */ - *(mboxdata + 3) = mbox->numsgelements; - if (megaCfg->flag & BOARD_64BIT) - *(mboxdata + 2) = - DCMD_FC_READ_NVRAM_CONFIG_64; - break; - case DCMD_WRITE_CONFIG: - case DCMD_WRITE_CONFIG_64: - if (megaCfg->flag & BOARD_64BIT) - *(mboxdata + 2) = DCMD_WRITE_CONFIG_64; - set_mbox_xfer_addr (megaCfg, pScb, mbox, - TO_DEVICE); - mbox->numsgelements = 0; - break; - case DCMD_GET_DISK_CONFIG: - case DCMD_GET_DISK_CONFIG_64: - if (megaCfg->flag & BOARD_64BIT) - *(mboxdata + 2) = - DCMD_GET_DISK_CONFIG_64; - *(mboxdata + 3) = data[2]; /*number of elements in SG list */ - /*nr of elements in SG list */ - *(mboxdata + 4) = mbox->numsgelements; - break; - case DCMD_DELETE_LOGDRV: - case DCMD_DELETE_DRIVEGROUP: - case NC_SUBOP_ENQUIRY3: - *(mboxdata + 3) = data[2]; - set_mbox_xfer_addr (megaCfg, pScb, mbox, - FROMTO_DEVICE); - mbox->numsgelements = 0; - break; - case DCMD_CHANGE_LDNO: - case DCMD_CHANGE_LOOPID: - *(mboxdata + 3) = data[2]; - *(mboxdata + 4) = data[3]; - set_mbox_xfer_addr (megaCfg, pScb, mbox, - TO_DEVICE); - mbox->numsgelements = 0; - break; - default: - set_mbox_xfer_addr (megaCfg, pScb, mbox, - FROMTO_DEVICE); - mbox->numsgelements = 0; - break; - } /*switch */ - break; - default: - set_mbox_xfer_addr (megaCfg, pScb, mbox, FROMTO_DEVICE); - mbox->numsgelements = 0; - break; - } - } else { - - mbox->numsgelements = mega_build_sglist (megaCfg, pScb, - (u32 *) & mbox-> - xferaddr, - (u32 *) & seg); - - /* Handling some of the fw special commands */ - switch (data[0]) { - case 6: /* START_DEV */ - mbox->xferaddr = *((u32 *) & data[i + 6]); - break; - default: - break; - } - - for (i = 0; i < (SCpnt->request_bufflen - 6); i++) { - data[i] = data[i + 6]; - } - } - - return (pScb); } - -static void mega_build_kernel_sg (char *barea, ulong xfersize, mega_scb * pScb, mega_ioctl_mbox * mbox) -{ - ulong i, buffer_area, len, end, end_page, x, idx = 0; - - buffer_area = (ulong) barea; - i = buffer_area; - end = buffer_area + xfersize; - end_page = (end) & ~(PAGE_SIZE - 1); - - do { - len = PAGE_SIZE - (i % PAGE_SIZE); - x = pScb->sgList[idx].address = - virt_to_bus ((volatile void *) i); - pScb->sgList[idx].length = len; - i += len; - idx++; - } while (i < end_page); - - if ((end - i) < 0) { - printk ("megaraid:Error in user address\n"); - } - - if (end - i) { - pScb->sgList[idx].address = virt_to_bus ((volatile void *) i); - pScb->sgList[idx].length = end - i; - idx++; - } - mbox->xferaddr = virt_to_bus (pScb->sgList); - mbox->numsgelements = idx; -} -#endif - - -#if DEBUG -static unsigned int cum_time = 0; -static unsigned int cum_time_cnt = 0; - static void showMbox (mega_scb * pScb) { +#ifdef DEBUG mega_mailbox *mbox; if (pScb == NULL) @@ -2049,16 +1523,15 @@ pScb->SCpnt->pid, mbox->cmd, mbox->cmdid, mbox->numsectors, mbox->lba, mbox->xferaddr, mbox->logdrv, mbox->numsgelements); +#endif } -#endif - /*-------------------------------------------------------------------- * Interrupt service routine *--------------------------------------------------------------------*/ static void megaraid_isr (int irq, void *devp, struct pt_regs *regs) { - IO_LOCK_T; + unsigned long io_flags; mega_host_config * megaCfg; u_char byte, idx, sIdx, tmpBox[MAILBOX_SIZE]; u32 dword = 0; @@ -2103,7 +1576,7 @@ for (idx = 0; idx < MAX_FIRMWARE_STATUS; idx++) completed[idx] = 0; - IO_LOCK(megaCfg->host); + spin_lock_irqsave(megaCfg->host->host_lock, io_flags); megaCfg->nInterrupts++; qCnt = 0xff; @@ -2124,27 +1597,8 @@ if (megaCfg->flag & BOARD_QUARTZ) { WROUTDOOR (megaCfg, dword); /* Acknowledge interrupt */ -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) /* In this case mbox contains physical address */ -#if 0 - WRINDOOR (megaCfg, megaCfg->adjdmahandle64 | 0x2); -#else WRINDOOR (megaCfg, 0x2); -#endif - -#else - -#if 0 - WRINDOOR (megaCfg, virt_to_bus (megaCfg->mbox) | 0x2); -#else - WRINDOOR (megaCfg, 0x2); -#endif - -#endif - -#if 0 - while (RDINDOOR (megaCfg) & 0x02) ; -#endif } else { CLEAR_INTR (megaCfg->host->io_port); } @@ -2222,7 +1676,7 @@ megaCfg->flag &= ~IN_ISR; /* Loop through any pending requests */ mega_runpendq (megaCfg); - IO_UNLOCK(megaCfg->host); + spin_unlock_irqrestore(megaCfg->host->host_lock, io_flags); } @@ -2267,9 +1721,7 @@ { volatile mega_mailbox *mbox = (mega_mailbox *) megaCfg->mbox; -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) volatile mega_mailbox64 *mbox64 = (mega_mailbox64 *) megaCfg->mbox64; -#endif u_char byte; @@ -2283,12 +1735,8 @@ mboxData[0x1] = (pScb ? pScb->idx + 1 : 0xFE); /* Set cmdid */ mboxData[0xF] = 1; /* Set busy */ -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) /* In this case mbox contains physical address */ phys_mbox = megaCfg->adjdmahandle64; -#else - phys_mbox = virt_to_bus (megaCfg->mbox); -#endif #if DEBUG ShowMbox (pScb); @@ -2296,12 +1744,10 @@ /* Wait until mailbox is free */ if (mega_busyWaitMbox (megaCfg)) { - printk ("Blocked mailbox......!!\n"); + printk (KERN_WARNING "megaraid: Blocked mailbox......!!\n"); udelay (1000); -#if DEBUG showMbox (pLastScb); -#endif /* Abort command */ if (pScb == NULL) { @@ -2320,7 +1766,6 @@ memcpy ((char *) mbox, mboxData, 16); -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) switch (mboxData[0]) { case MEGA_MBOXCMD_LREAD64: case MEGA_MBOXCMD_LWRITE64: @@ -2329,7 +1774,6 @@ mbox->xferaddr = 0xFFFFFFFF; break; } -#endif /* Kick IO */ if (intr) { @@ -2416,10 +1860,7 @@ { struct scatterlist *sgList; int idx; - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) int sgcnt; -#endif mega_mailbox *mbox = NULL; @@ -2427,7 +1868,6 @@ /* Scatter-gather not used */ if (scb->SCpnt->use_sg == 0) { -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) scb->dma_h_bulkdata = pci_map_single (megaCfg->dev, scb->SCpnt->request_buffer, scb->SCpnt->request_bufflen, @@ -2448,45 +1888,11 @@ *buffer = scb->dma_h_bulkdata; *length = (u32) scb->SCpnt->request_bufflen; } -#else - *buffer = virt_to_bus (scb->SCpnt->request_buffer); - *length = (u32) scb->SCpnt->request_bufflen; -#endif return 0; } sgList = (struct scatterlist *) scb->SCpnt->request_buffer; -#if 0 - if (scb->SCpnt->use_sg == 1) { - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) - scb->dma_h_bulkdata = pci_map_single (megaCfg->dev, - sgList[0].address, - sgList[0].length, scb->dma_direction); - - if ((megaCfg->flag & BOARD_64BIT) && - ((mbox->cmd == MEGA_MBOXCMD_LREAD64) || - (mbox->cmd == MEGA_MBOXCMD_LWRITE64))) { - scb->sg64List[0].address = scb->dma_h_bulkdata; - scb->sg64List[0].length = scb->SCpnt->request_bufflen; - *buffer = scb->dma_sghandle64; - *length = 0; - scb->sglist_count = 1; - return 1; - } else { - *buffer = scb->dma_h_bulkdata; - *length = (u32) sgList[0].length; - } -#else - *buffer = virt_to_bus (sgList[0].address); - *length = (u32) sgList[0].length; -#endif - - return 0; - } -#endif /* Copy Scatter-Gather list info into controller structure */ -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) sgcnt = pci_map_sg (megaCfg->dev, sgList, scb->SCpnt->use_sg, scb->dma_direction); @@ -2508,29 +1914,14 @@ } -#else - for (idx = 0; idx < scb->SCpnt->use_sg; idx++) { - scb->sgList[idx].address = virt_to_bus (sgList[idx].address); - scb->sgList[idx].length = (u32) sgList[idx].length; - } -#endif /* Reset pointer and length fields */ -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) *buffer = scb->dma_sghandle64; scb->sglist_count = scb->SCpnt->use_sg; -#else - *buffer = virt_to_bus (scb->sgList); -#endif *length = 0; -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) /* Return count of SG requests */ return sgcnt; -#else - /* Return count of SG requests */ - return scb->SCpnt->use_sg; -#endif } /*-------------------------------------------------------------------- @@ -2553,11 +1944,7 @@ mega_register_mailbox (mega_host_config * megaCfg, u32 paddr) { /* align on 16-byte boundary */ -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) megaCfg->mbox = &megaCfg->mailbox64ptr->mailbox; -#else - megaCfg->mbox = &megaCfg->mailbox64.mailbox; -#endif #ifdef __LP64__ megaCfg->mbox = (mega_mailbox *) ((((u64) megaCfg->mbox) + 16) & ((u64) (-1) ^ 0x0F)); @@ -2568,9 +1955,7 @@ megaCfg->mbox = (mega_mailbox *) ((((u32) megaCfg->mbox) + 16) & 0xFFFFFFF0); -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) megaCfg->adjdmahandle64 = ((megaCfg->dma_handle64 + 16) & 0xFFFFFFF0); -#endif megaCfg->mbox64 = (mega_mailbox64 *) ((u_char *) megaCfg->mbox - 8); paddr = (paddr + 4 + 16) & 0xFFFFFFF0; @@ -2639,9 +2024,7 @@ mega_mailbox *mbox; u_char mboxData[16]; -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) dma_addr_t raid_inq_dma_handle = 0, prod_info_dma_handle = 0, enquiry3_dma_handle = 0; -#endif u8 retval; /* Initialize adapter inquiry mailbox */ @@ -2657,16 +2040,11 @@ * if not succeeded, then issue MEGA_MBOXCMD_ADAPTERINQ command and * update enquiry3 structure */ -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) enquiry3_dma_handle = pci_map_single (megaCfg->dev, (void *) megaCfg->mega_buffer, (2 * 1024L), PCI_DMA_FROMDEVICE); mbox->xferaddr = enquiry3_dma_handle; -#else - /*Taken care */ - mbox->xferaddr = virt_to_bus ((void *) megaCfg->mega_buffer); -#endif /* Initialize mailbox databuffer addr */ enquiry3Pnt = (mega_Enquiry3 *) megaCfg->mega_buffer; @@ -2681,16 +2059,11 @@ mega_RAIDINQ adapterInquiryData; mega_RAIDINQ *adapterInquiryPnt = &adapterInquiryData; -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) raid_inq_dma_handle = pci_map_single (megaCfg->dev, (void *) adapterInquiryPnt, sizeof (mega_RAIDINQ), PCI_DMA_FROMDEVICE); mbox->xferaddr = raid_inq_dma_handle; -#else - /*taken care */ - mbox->xferaddr = virt_to_bus ((void *) adapterInquiryPnt); -#endif mbox->cmd = MEGA_MBOXCMD_ADAPTERINQ; /*issue old 0x05 command to adapter */ /* Issue a blocking command to the card */ ; @@ -2712,7 +2085,6 @@ pci_unmap_single (megaCfg->dev, enquiry3_dma_handle, (2 * 1024L), PCI_DMA_FROMDEVICE); -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) /*get productInfo, which is static information and will be unchanged*/ prod_info_dma_handle = pci_map_single (megaCfg->dev, @@ -2720,10 +2092,6 @@ sizeof (megaRaidProductInfo), PCI_DMA_FROMDEVICE); mbox->xferaddr = prod_info_dma_handle; -#else - /*taken care */ - mbox->xferaddr = virt_to_bus ((void *) &megaCfg->productInfo); -#endif mboxData[0] = FC_NEW_CONFIG; /* i.e. mbox->cmd=0xA1 */ mboxData[2] = NC_SUBOP_PRODUCT_INFO; /* i.e. 0x0E */ @@ -2741,16 +2109,10 @@ /* * kernel scans the channels from 0 to <= max_channel */ - megaCfg->host->max_channel = - megaCfg->productInfo.SCSIChanPresent + NVIRT_CHAN -1; + megaCfg->host->max_channel = megaCfg->productInfo.SCSIChanPresent + NVIRT_CHAN -1; megaCfg->host->max_id = 16; /* max targets per channel */ /*(megaCfg->flag & BOARD_40LD)?FC_MAX_TARGETS_PER_CHANNEL:MAX_TARGET+1; */ -#if 0 - megaCfg->host->max_lun = /* max lun */ - (megaCfg->flag & BOARD_40LD) ? - FC_MAX_LOGICAL_DRIVES : MAX_LOGICAL_DRIVES; -#endif megaCfg->host->max_lun = 7; /* Upto 7 luns for non disk devices */ megaCfg->host->cmd_per_lun = MAX_CMD_PER_LUN; @@ -2762,12 +2124,6 @@ megaCfg->host->can_queue = megaCfg->max_cmds - 1; -#if 0 - if (megaCfg->host->can_queue >= MAX_COMMANDS) { - megaCfg->host->can_queue = MAX_COMMANDS - 16; - } -#endif - /* use HP firmware and bios version encoding */ if (megaCfg->productInfo.subSystemVendorID == HP_SUBSYS_ID) { sprintf (megaCfg->fwVer, "%c%d%d.%d%d", @@ -2816,7 +2172,7 @@ * Returns data to be displayed in /proc/scsi/megaraid/X *----------------------------------------------------------*/ -int megaraid_proc_info (char *buffer, char **start, off_t offset, +static int megaraid_proc_info (char *buffer, char **start, off_t offset, int length, int host_no, int inout) { *start = buffer; @@ -2829,114 +2185,45 @@ mega_host_config *megaCfg = NULL; struct Scsi_Host *host = NULL; u_char pciBus, pciDevFun, megaIrq; - u16 magic; -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) u32 magic64; -#endif - - int i; - -#ifdef __LP64__ - u64 megaBase; -#else - u32 megaBase; -#endif - + int i; + unsigned long megaBase; u16 pciIdx = 0; u16 numFound = 0; - u16 subsysid, subsysvid; - -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,0) /* 0x20100 */ - while (!pcibios_find_device - (pciVendor, pciDev, pciIdx, &pciBus, &pciDevFun)) { -#else - -#if LINUX_VERSION_CODE > KERNEL_VERSION(2,3,0) /*0x20300 */ struct pci_dev *pdev = NULL; -#else - struct pci_dev *pdev = pci_devices; -#endif - while ((pdev = pci_find_device (pciVendor, pciDev, pdev))) { + while ((pdev = pci_find_device (pciVendor, pciDev, pdev))) + { if(pci_enable_device (pdev)) continue; pciBus = pdev->bus->number; pciDevFun = pdev->devfn; -#endif - if ((flag & BOARD_QUARTZ) && (skip_id == -1)) { - pci_read_config_word (pdev, PCI_CONF_AMISIG, &magic); - if ((magic != AMI_SIGNATURE) - && (magic != AMI_SIGNATURE_471)) { + + if ((flag & BOARD_QUARTZ) && (skip_id == -1)) + { + pci_read_config_word (pdev, PCI_CONF_AMISIG, &magic); + if ((magic != AMI_SIGNATURE) && (magic != AMI_SIGNATURE_471)) + { pciIdx++; continue; /* not an AMI board */ } -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) pci_read_config_dword (pdev, PCI_CONF_AMISIG64, &magic64); if (magic64 == AMI_64BIT_SIGNATURE) flag |= BOARD_64BIT; -#endif } /* Hmmm...Should we not make this more modularized so that in future we dont add for each firmware */ - if (flag & BOARD_QUARTZ) { - /* Check to see if this is a Dell PERC RAID controller model 466 */ -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,0) /* 0x20100 */ - pcibios_read_config_word (pciBus, pciDevFun, - PCI_SUBSYSTEM_VENDOR_ID, - &subsysvid); - pcibios_read_config_word (pciBus, pciDevFun, - PCI_SUBSYSTEM_ID, &subsysid); -#else - pci_read_config_word (pdev, - PCI_SUBSYSTEM_VENDOR_ID, - &subsysvid); - pci_read_config_word (pdev, - PCI_SUBSYSTEM_ID, &subsysid); -#endif - -#if 0 - /* - * This routine is called with well know values and we - * should not be getting what we have not asked. - * Also, the check is not right. It should have been for - * pci_vendor_id not subsysvid - AM - */ - - /* If we dont detect this valid subsystem vendor id's - we refuse to load the driver - PART of PC200X compliance - */ - - if ((subsysvid != AMI_SUBSYS_ID) - && (subsysvid != DELL_SUBSYS_ID) - && (subsysvid != HP_SUBSYS_ID)) - continue; -#endif - } - printk (KERN_NOTICE "megaraid: found 0x%4.04x:0x%4.04x:idx %d:bus %d:slot %d:func %d\n", pciVendor, pciDev, pciIdx, pciBus, PCI_SLOT (pciDevFun), PCI_FUNC (pciDevFun)); /* Read the base port and IRQ from PCI */ -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,0) /* 0x20100 */ - pcibios_read_config_dword (pciBus, pciDevFun, - PCI_BASE_ADDRESS_0, - (u_int *) & megaBase); - pcibios_read_config_byte (pciBus, pciDevFun, - PCI_INTERRUPT_LINE, &megaIrq); -#elif LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0) /*0x20300 */ - megaBase = pdev->base_address[0]; - megaIrq = pdev->irq; -#else - megaBase = pci_resource_start (pdev, 0); megaIrq = pdev->irq; -#endif pciIdx++; @@ -2971,8 +2258,7 @@ M_RD_CRLFSTR, host->host_no, (u_int) megaBase, megaIrq); if (flag & BOARD_64BIT) - printk (KERN_NOTICE "scsi%d : Enabling 64 bit support\n", - host->host_no); + printk (KERN_NOTICE "scsi%d : Enabling 64 bit support\n", host->host_no); /* Copy resource info into structure */ megaCfg->qCompletedH = NULL; @@ -2991,10 +2277,7 @@ megaCfg->int_qh = NULL; megaCfg->int_qt = NULL; megaCfg->int_qlen = 0; - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) megaCfg->dev = pdev; -#endif megaCfg->host = host; megaCfg->base = megaBase; megaCfg->host->irq = megaIrq; @@ -3012,41 +2295,30 @@ } /* Request our IRQ */ - if (request_irq (megaIrq, megaraid_isr, SA_SHIRQ, - "megaraid", megaCfg)) { - printk (KERN_WARNING - "megaraid: Couldn't register IRQ %d!\n", - megaIrq); + if (request_irq (megaIrq, megaraid_isr, SA_SHIRQ, "megaraid", megaCfg)) { + printk (KERN_WARNING "megaraid: Couldn't register IRQ %d!\n", megaIrq); goto err_release; } -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) /* * unmap while releasing the driver, Is it required to be * PCI_DMA_BIDIRECTIONAL */ - megaCfg->mailbox64ptr - = pci_alloc_consistent (megaCfg->dev, - sizeof (mega_mailbox64), - &(megaCfg->dma_handle64)); + megaCfg->mailbox64ptr = pci_alloc_consistent (megaCfg->dev, sizeof (mega_mailbox64), &(megaCfg->dma_handle64)); mega_register_mailbox (megaCfg, megaCfg->dma_handle64); -#else - mega_register_mailbox (megaCfg, - virt_to_bus ((void *) &megaCfg-> - mailbox64)); -#endif mega_i_query_adapter (megaCfg); - if ((subsysid == 0x1111) && (subsysvid == 0x1111)) { - + if (pdev->subsystem_vendor == 0x1111 && pdev->subsystem_device == 0x1111) + { /* * Which firmware */ if( strcmp(megaCfg->fwVer, "3.00") == 0 || - strcmp(megaCfg->fwVer, "3.01") == 0 ) { + strcmp(megaCfg->fwVer, "3.01") == 0 ) + { printk( KERN_WARNING "megaraid: Your card is a Dell PERC 2/SC RAID controller " @@ -3064,20 +2336,22 @@ /* * If we have a HP 1M(0x60E7)/2M(0x60E8) controller with - * firmware H.01.07 or H.01.08, disable 64 bit support, + * firmware H.01.07 H.01.08 or H.01.09, disable 64 bit support, * since this firmware cannot handle 64 bit addressing */ - if( (subsysvid == HP_SUBSYS_ID) && - ((subsysid == 0x60E7)||(subsysid == 0x60E8)) ) { - + if(pdev->subsystem_vendor == HP_SUBSYS_ID && + (pdev->subsystem_device == 0x60E7 || pdev->subsystem_device == 0x60E8 || pdev->subsystem_device == 0x60E9)) + { /* * which firmware */ if( strcmp(megaCfg->fwVer, "H01.07") == 0 || - strcmp(megaCfg->fwVer, "H01.08") == 0 ) { + strcmp(megaCfg->fwVer, "H01.08") == 0 || + strcmp(megaCfg->fwVer, "H01.09") == 0 ) + { printk(KERN_WARNING - "megaraid: Firmware H.01.07 or H.01.08 on 1M/2M " + "megaraid: Firmware H.01.07 to H.01.09 on 1M/2M " "controllers\nmegaraid: do not support 64 bit " "addressing.\n" "megaraid: DISABLING 64 bit support.\n"); @@ -3147,21 +2421,19 @@ numFound++; /* Set the Mode of addressing to 64 bit */ -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) if ((megaCfg->flag & BOARD_64BIT) && BITS_PER_LONG == 64) #ifdef __LP64__ pdev->dma_mask = 0xffffffffffffffff; #else pdev->dma_mask = 0xffffffff; #endif -#endif continue; - err_release: +err_release: if (flag & BOARD_QUARTZ) release_region (megaBase, 16); - err_unregister: +err_unregister: scsi_unregister (host); - err_unmap: +err_unmap: if (flag & BOARD_QUARTZ) iounmap ((void *) megaBase); } @@ -3172,23 +2444,12 @@ * Detects if a megaraid controller exists in this system *---------------------------------------------------------*/ -int megaraid_detect (Scsi_Host_Template * pHostTmpl) +static int megaraid_detect (Scsi_Host_Template * pHostTmpl) { int ctlridx = 0, count = 0; -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0) /*0x20300 */ - pHostTmpl->proc_dir = &proc_scsi_megaraid; -#else pHostTmpl->proc_name = "megaraid"; -#endif -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,0) /* 0x20100 */ - if (!pcibios_present ()) { - printk (KERN_WARNING "megaraid: PCI bios not present." - M_RD_CRLFSTR); - return 0; - } -#endif skip_id = -1; if (megaraid && !strncmp (megaraid, "skip", strlen ("skip"))) { if (megaraid[4] != '\0') { @@ -3216,13 +2477,7 @@ #ifdef CONFIG_PROC_FS if (count) { -#if LINUX_VERSION_CODE > KERNEL_VERSION(2,3,0) /*0x20300 */ mega_proc_dir_entry = proc_mkdir ("megaraid", &proc_root); -#else - mega_proc_dir_entry = create_proc_entry ("megaraid", - S_IFDIR | S_IRUGO | - S_IXUGO, &proc_root); -#endif if (!mega_proc_dir_entry) printk ("megaraid: failed to create megaraid root\n"); else @@ -3260,7 +2515,7 @@ /*--------------------------------------------------------------------- * Release the controller's resources *---------------------------------------------------------------------*/ -int megaraid_release (struct Scsi_Host *pSHost) +static int megaraid_release (struct Scsi_Host *pSHost) { mega_host_config *megaCfg; mega_mailbox *mbox; @@ -3367,10 +2622,7 @@ mega_mailbox *mboxp; unsigned char mbox[16]; int i; - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) dma_addr_t dma_handle; -#endif mboxp = (mega_mailbox *)mbox; @@ -3383,14 +2635,10 @@ memset((void *)megacfg->mega_buffer, 0, sizeof(megacfg->mega_buffer)); -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) dma_handle = pci_map_single(megacfg->dev, (void *)megacfg->mega_buffer, (2 * 1024L), PCI_DMA_FROMDEVICE); mboxp->xferaddr = dma_handle; -#else - mboxp->xferaddr = virt_to_bus((void *)megacfg->mega_buffer); -#endif /* * Non-ROMB firware fail this command, so all channels @@ -3407,13 +2655,8 @@ else { mega_ch_class = 0xFF; } - - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) pci_unmap_single(megacfg->dev, dma_handle, (2 * 1024L), PCI_DMA_FROMDEVICE); -#endif - } @@ -3429,10 +2672,7 @@ u16 cksum = 0; char *cksum_p; int i; - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) dma_addr_t dma_handle; -#endif mboxp = (mega_mailbox *)mbox; @@ -3443,14 +2683,10 @@ memset((void *)megacfg->mega_buffer, 0, sizeof(megacfg->mega_buffer)); -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) dma_handle = pci_map_single(megacfg->dev, (void *)megacfg->mega_buffer, (2 * 1024L), PCI_DMA_FROMDEVICE); mboxp->xferaddr = dma_handle; -#else - mboxp->xferaddr = virt_to_bus((void *)megacfg->mega_buffer); -#endif megacfg->boot_ldrv_enabled = 0; megacfg->boot_ldrv = 0; @@ -3470,11 +2706,8 @@ } } -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) pci_unmap_single(megacfg->dev, dma_handle, (2 * 1024L), PCI_DMA_FROMDEVICE); -#endif - } @@ -3490,16 +2723,13 @@ megaCfg->scbList[i].sgList, megaCfg->scbList[i]. dma_sghandle64); -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0) /* 0x020400 */ - kfree (megaCfg->scbList[i].sgList); /* free sgList */ -#endif } } /*---------------------------------------------- * Get information about the card/driver *----------------------------------------------*/ -const char *megaraid_info (struct Scsi_Host *pSHost) +static const char *megaraid_info (struct Scsi_Host *pSHost) { static char buffer[512]; mega_host_config *megaCfg; @@ -3531,12 +2761,11 @@ *-----------------------------------------------------------------*/ int megaraid_queue (Scsi_Cmnd * SCpnt, void (*pktComp) (Scsi_Cmnd *)) { - DRIVER_LOCK_T mega_host_config * megaCfg; + mega_host_config * megaCfg; mega_scb *pScb; char *user_area = NULL; megaCfg = (mega_host_config *) SCpnt->host->hostdata; - DRIVER_LOCK (megaCfg); if (!(megaCfg->flag & (1L << SCpnt->channel))) { if (SCpnt->channel < megaCfg->productInfo.SCSIChanPresent) @@ -3571,7 +2800,6 @@ megaCfg->qCompletedT->host_scribble = (unsigned char *) NULL; megaCfg->qCcnt++; - DRIVER_UNLOCK (megaCfg); return 0; } else if (megaCfg->flag & IN_RESET) { SCpnt->result = (DID_RESET << 16); @@ -3586,7 +2814,6 @@ megaCfg->qCompletedT->host_scribble = (unsigned char *) NULL; megaCfg->qCcnt++; - DRIVER_UNLOCK (megaCfg); return 0; } @@ -3611,7 +2838,6 @@ megaCfg->qPcnt++; if (mega_runpendq (megaCfg) == -1) { - DRIVER_UNLOCK (megaCfg); return 0; } } @@ -3629,38 +2855,31 @@ if (pScb->SCpnt->cmnd[0] == M_RD_IOCTL_CMD_NEW) { init_MUTEX_LOCKED (&pScb->ioctl_sem); - IO_UNLOCK_IRQ(megaCfg->host); + spin_unlock_irq(megaCfg->host->host_lock); down (&pScb->ioctl_sem); - user_area = (char *)*((u32*)&pScb->SCpnt->cmnd[4]); - if (copy_to_user - (user_area, pScb->buff_ptr, pScb->iDataSize)) { - printk - ("megaraid: Error copying ioctl return value to user buffer.\n"); + user_area = (char *)*((u32*)&pScb->SCpnt->cmnd[4]); + if (copy_to_user(user_area, pScb->buff_ptr, pScb->iDataSize)) { pScb->SCpnt->result = (DID_ERROR << 16); } - IO_LOCK_IRQ(megaCfg->host); - DRIVER_LOCK (megaCfg); + spin_lock_irq(megaCfg->host->host_lock); kfree (pScb->buff_ptr); pScb->buff_ptr = NULL; mega_cmd_done (megaCfg, pScb, pScb->SCpnt->result); mega_rundoneq (megaCfg); mega_runpendq (megaCfg); - DRIVER_UNLOCK (megaCfg); } megaCfg->flag &= ~IN_QUEUE; } - - DRIVER_UNLOCK (megaCfg); return 0; } /*---------------------------------------------------------------------- * Issue a blocking command to the controller *----------------------------------------------------------------------*/ -volatile static int internal_done_flag = 0; -volatile static int internal_done_errcode = 0; +static int internal_done_flag = 0; +static int internal_done_errcode = 0; static DECLARE_WAIT_QUEUE_HEAD (internal_wait); @@ -3673,30 +2892,31 @@ /* shouldn't be used, but included for completeness */ -int megaraid_command (Scsi_Cmnd * SCpnt) +static int megaraid_command (Scsi_Cmnd * SCpnt) { internal_done_flag = 0; - /* Queue command, and wait until it has completed */ megaraid_queue (SCpnt, internal_done); - - while (!internal_done_flag) { - interruptible_sleep_on (&internal_wait); - } - + wait_event(internal_wait, internal_done_flag); return internal_done_errcode; } /*--------------------------------------------------------------------- * Abort a previous SCSI request *---------------------------------------------------------------------*/ -int megaraid_abort (Scsi_Cmnd * SCpnt) +static int megaraid_abort(Scsi_Cmnd * SCpnt) { mega_host_config *megaCfg; + struct Scsi_Host *host; int rc; /*, idx; */ mega_scb *pScb; + unsigned long flags; - rc = SCSI_ABORT_NOT_RUNNING; + host = SCpnt->host; + + spin_lock_irqsave(host->host_lock, flags); + + rc = SUCCESS; megaCfg = (mega_host_config *) SCpnt->host->hostdata; @@ -3705,9 +2925,7 @@ for (pScb = megaCfg->qPendingH; pScb; pScb = pScb->next) { if (pScb->SCpnt == SCpnt) { /* Found an aborting command */ -#if DEBUG showMbox (pScb); -#endif /* * If the command is queued to be issued to the firmware, abort the scsi cmd, @@ -3724,10 +2942,10 @@ switch (pScb->state) { case SCB_ABORTED: /* Already aborted */ - rc = SCSI_ABORT_SNOOZE; + rc = SUCCESS; break; case SCB_ISSUED: /* Waiting on ISR result */ - rc = SCSI_ABORT_NOT_RUNNING; + rc = SUCCESS; pScb->state = SCB_ABORTED; break; case SCB_ACTIVE: /* still on the pending queue */ @@ -3744,12 +2962,11 @@ megaCfg->qCompletedT->host_scribble = (unsigned char *) NULL; megaCfg->qCcnt++; - rc = SCSI_ABORT_SUCCESS; + rc = SUCCESS; break; default: - printk - ("megaraid_abort: unknown command state!!\n"); - rc = SCSI_ABORT_NOT_RUNNING; + printk(KERN_ERR "megaraid_abort: unknown command state!!\n"); + rc = FAILED; break; } break; @@ -3781,6 +2998,7 @@ } mega_rundoneq (megaCfg); + spin_unlock_irqrestore(host->host_lock, flags); return rc; } @@ -3788,22 +3006,22 @@ * Reset a previous SCSI request *---------------------------------------------------------------------*/ -int megaraid_reset (Scsi_Cmnd * SCpnt, unsigned int rstflags) +static int megaraid_host_reset(Scsi_Cmnd * SCpnt) { mega_host_config *megaCfg; int idx; - int rc; mega_scb *pScb; + unsigned long flags; + struct Scsi_Host *host = SCpnt->host; - rc = SCSI_RESET_NOT_RUNNING; - megaCfg = (mega_host_config *) SCpnt->host->hostdata; + megaCfg = (mega_host_config *) host->hostdata; + spin_lock_irqsave(host->host_lock, flags); megaCfg->flag |= IN_RESET; - printk - ("megaraid_RESET: %.08lx cmd=%.02x , flag = %x\n", + printk("megaraid_RESET: %.08lx cmd=%.02x \n", SCpnt->serial_number, SCpnt->cmnd[0], SCpnt->channel, - SCpnt->target, SCpnt->lun, rstflags); + SCpnt->target, SCpnt->lun); TRACE (("RESET: %.08lx %.02x <%d.%d.%d>\n", SCpnt->serial_number, SCpnt->cmnd[0], SCpnt->channel, @@ -3826,7 +3044,8 @@ megaCfg->flag &= ~IN_RESET; mega_rundoneq (megaCfg); - return rc; + spin_unlock_irqrestore(host->host_lock, flags); + return SUCCESS; } #ifdef CONFIG_PROC_FS @@ -3974,42 +3193,10 @@ return count; } -#if LINUX_VERSION_CODE > KERNEL_VERSION(2,3,0) /*0x20300 */ #define CREATE_READ_PROC(string, fxn) create_proc_read_entry(string, \ S_IRUSR | S_IFREG,\ controller_proc_dir_entry,\ fxn, megaCfg) -#else -#define CREATE_READ_PROC(string, fxn) create_proc_read_entry(string,S_IRUSR | S_IFREG, controller_proc_dir_entry, fxn, megaCfg) - -static struct proc_dir_entry * -create_proc_read_entry (const char *string, - int mode, - struct proc_dir_entry *parent, - read_proc_t * fxn, mega_host_config * megaCfg) -{ - struct proc_dir_entry *temp = NULL; - - temp = kmalloc (sizeof (struct proc_dir_entry), GFP_KERNEL); - if (!temp) - return NULL; - memset (temp, 0, sizeof (struct proc_dir_entry)); - - if ((temp->name = kmalloc (strlen (string) + 1, GFP_KERNEL)) == NULL) { - kfree (temp); - return NULL; - } - - strcpy ((char *) temp->name, string); - temp->namelen = strlen (string); - temp->mode = mode; /*S_IFREG | S_IRUSR */ ; - temp->data = (void *) megaCfg; - temp->read_proc = fxn; - proc_register (parent, temp); - return temp; -} -#endif - static void mega_create_proc_entry (int index, struct proc_dir_entry *parent) { u_char string[64] = { 0 }; @@ -4018,30 +3205,36 @@ sprintf (string, "%d", index); -#if LINUX_VERSION_CODE > KERNEL_VERSION(2,3,0) /*0x20300 */ - controller_proc_dir_entry = - megaCfg->controller_proc_dir_entry = proc_mkdir (string, parent); -#else - controller_proc_dir_entry = - megaCfg->controller_proc_dir_entry = - create_proc_entry (string, S_IFDIR | S_IRUGO | S_IXUGO, parent); -#endif + controller_proc_dir_entry = megaCfg->controller_proc_dir_entry = proc_mkdir (string, parent); if (!controller_proc_dir_entry) printk ("\nmegaraid: proc_mkdir failed\n"); else { - megaCfg->proc_read = - CREATE_READ_PROC ("config", proc_read_config); - megaCfg->proc_status = - CREATE_READ_PROC ("status", proc_read_status); + megaCfg->proc_read = CREATE_READ_PROC ("config", proc_read_config); + megaCfg->proc_status = CREATE_READ_PROC ("status", proc_read_status); megaCfg->proc_stat = CREATE_READ_PROC ("stat", proc_read_stat); - megaCfg->proc_mbox = - CREATE_READ_PROC ("mailbox", proc_read_mbox); + megaCfg->proc_mbox = CREATE_READ_PROC ("mailbox", proc_read_mbox); } } #endif /* CONFIG_PROC_FS */ + +/*--------------------------------------------------------- + * Convert capacity to cylinders + * accounting for the fact capacity could be a 64 bit value + *---------------------------------------------------------- + */ +static inline u32 cap_to_cyls(sector_t capacity, u32 divisor) +{ +#ifdef CONFIG_LBD + do_div(capacity, divisor); +#else + capacity /= divisor; +#endif + return (u32) capacity; +} + /*------------------------------------------------------------- * Return the disk geometry for a particular disk * Input: @@ -4052,59 +3245,34 @@ * geom[1] = sectors * geom[2] = cylinders *-------------------------------------------------------------*/ -int megaraid_biosparam (struct scsi_device *sdev, struct block_device *bdev, +static int megaraid_biosparam (struct scsi_device *sdev, struct block_device *bdev, sector_t capacity, int *geom) { - int heads, sectors, cylinders; - mega_host_config *megaCfg; - - /* Get pointer to host config structure */ - megaCfg = (mega_host_config *) sdev->host->hostdata; + int rv = 0; + int heads = 64; + int sectors = 32; if( IS_RAID_CH(sdev->channel)) { - /* Default heads (64) & sectors (32) */ - heads = 64; - sectors = 32; - cylinders = (unsigned long)capacity >> 11; - - /* Handle extended translation size for logical drives > 1Gb */ - if (capacity >= 0x200000) { - heads = 255; - sectors = 63; - cylinders = (unsigned long)capacity / (heads * sectors); - } - - /* return result */ - geom[0] = heads; - geom[1] = sectors; - geom[2] = cylinders; - } - else { - if( mega_partsize(bdev, capacity, geom) == 0 ) return 0; - - printk(KERN_WARNING - "megaraid: invalid partition on this disk on channel %d\n", - sdev->channel); - - /* Default heads (64) & sectors (32) */ - heads = 64; - sectors = 32; - cylinders = capacity >> 11; - /* Handle extended translation size for logical drives > 1Gb */ if (capacity >= 0x200000) { heads = 255; sectors = 63; - cylinders = (unsigned long)capacity / (heads * sectors); } - /* return result */ + /* partition size based on defaults */ geom[0] = heads; geom[1] = sectors; - geom[2] = cylinders; + geom[2] = cap_to_cyls(capacity, heads * sectors); /* cylinders */ + } else { + rv = mega_partsize(bdev, capacity, geom); } - return 0; + if (rv != 0) { + printk(KERN_WARNING + "megaraid: invalid partition on this disk on channel %d\n", + sdev->channel); + } + return rv; } /* @@ -4121,50 +3289,42 @@ mega_partsize(struct block_device *bdev, sector_t capacity, int *geom) { struct partition *p, *largest = NULL; - int i, largest_cyl; - int heads, cyls, sectors; - unsigned char *buf; - - if (!(buf = scsi_bios_ptable(bdev))) - return -1; - - if( *(unsigned short *)(buf + 64) == 0xAA55 ) { - - for( largest_cyl = -1, p = (struct partition *)buf, - i = 0; i < 4; ++i, ++p) { - - if (!p->sys_ind) continue; - - cyls = p->end_cyl + ((p->end_sector & 0xc0) << 2); - - if(cyls >= largest_cyl) { - largest_cyl = cyls; - largest = p; + int i, cyls, largest_cyl; + int rv = -1; + unsigned char *buf = scsi_bios_ptable(bdev); + + if (buf) { + if( *(unsigned short *)(buf + 64) == 0xAA55 ) { + for( largest_cyl = -1, p = (struct partition *)buf, + i = 0; i < 4; ++i, ++p) { + + if (!p->sys_ind) continue; + + cyls = p->end_cyl + ((p->end_sector & 0xc0) << 2); + + if(cyls >= largest_cyl) { + largest_cyl = cyls; + largest = p; + } } } - } - - if (largest) { - heads = largest->end_head + 1; - sectors = largest->end_sector & 0x3f; - - if (heads == 0 || sectors == 0) { - kfree(buf); - return -1; + if (largest) { + int heads = largest->end_head + 1; + int sectors = largest->end_sector & 0x3f; + + if (heads != 0 && sectors != 0) { + geom[0] = heads; + geom[1] = sectors; + geom[2] = cap_to_cyls(capacity, heads * sectors); + rv = 0; + } + } - - cyls = (unsigned long)capacity/(heads * sectors); - - geom[0] = heads; - geom[1] = sectors; - geom[2] = cyls; - + kfree(buf); - return 0; } - - kfree(buf); - return -1; + + return rv; } @@ -4228,7 +3388,6 @@ * and the mid-layer operations are not connected with this flag. */ -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) megacfg->scbList[idx].sgList = pci_alloc_consistent (megacfg->dev, sizeof (mega_64sglist) * MAX_SGLIST, @@ -4237,9 +3396,6 @@ megacfg->scbList[idx].sg64List = (mega_64sglist *) megacfg->scbList[idx].sgList; -#else - megacfg->scbList[idx].sgList = kmalloc (sizeof (mega_sglist) * MAX_SGLIST, GFP_ATOMIC | GFP_DMA); -#endif if (megacfg->scbList[idx].sgList == NULL) { printk (KERN_WARNING @@ -4247,20 +3403,13 @@ mega_freeSgList (megacfg); return -1; } -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) - megacfg->scbList[idx].pthru = pci_alloc_consistent (megacfg->dev, - sizeof (mega_passthru), - &(megacfg->scbList[idx]. - dma_passthruhandle64)); + megacfg->scbList[idx].pthru = pci_alloc_consistent (megacfg->dev, sizeof (mega_passthru), &(megacfg->scbList[idx].dma_passthruhandle64)); if (megacfg->scbList[idx].pthru == NULL) { - printk (KERN_WARNING - "Can't allocate passthru for id %d\n", idx); + printk (KERN_WARNING "Can't allocate passthru for id %d\n", idx); } - megacfg->scbList[idx].epthru = - pci_alloc_consistent( - megacfg->dev, sizeof(mega_ext_passthru), + megacfg->scbList[idx].epthru = pci_alloc_consistent(megacfg->dev, sizeof(mega_ext_passthru), &(megacfg->scbList[idx].dma_ext_passthruhandle64) ); @@ -4272,16 +3421,12 @@ * Allocate a 256 Byte Bounce Buffer for handling INQ/RD_CAPA */ megacfg->scbList[idx].bounce_buffer = pci_alloc_consistent (megacfg->dev, - 256, - &(megacfg->scbList[idx]. - dma_bounce_buffer)); + 256, &(megacfg->scbList[idx].dma_bounce_buffer)); if (!megacfg->scbList[idx].bounce_buffer) - printk - ("megaraid: allocation for bounce buffer failed\n"); + printk(KERN_ERR "megaraid: allocation for bounce buffer failed\n"); megacfg->scbList[idx].dma_type = M_RD_DMA_TYPE_NONE; -#endif if (idx < MAX_COMMANDS) { /* @@ -4289,8 +3434,7 @@ * lock not required since we are loading the driver, so no * commands possible right now. */ - enq_scb_freelist (megacfg, &megacfg->scbList[idx], - NO_LOCK, INTR_ENB); + enq_scb_freelist (megacfg, &megacfg->scbList[idx], NO_LOCK, INTR_ENB); } } @@ -4338,7 +3482,6 @@ */ static int megadev_open (struct inode *inode, struct file *filep) { - MOD_INC_USE_COUNT; return 0; /* success */ } @@ -4350,9 +3493,9 @@ /* * We do not allow parallel ioctls to the driver as of now. */ - down (&mimd_entry_mtx); + down(&mimd_entry_mtx); ret = megadev_ioctl (inode, filep, cmd, arg); - up (&mimd_entry_mtx); + up(&mimd_entry_mtx); return ret; @@ -4368,22 +3511,18 @@ int nadap = numCtlrs; u8 opcode; u32 outlen; - int ret; + int ret = 0; u8 subopcode; Scsi_Cmnd *scsicmd; struct Scsi_Host *shpnt; char *uaddr; struct uioctl_t *uioc; - dma_addr_t dma_addr; - u32 length; + dma_addr_t dma_addr; + u32 length; mega_host_config *megacfg = NULL; -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) /* 0x020400 */ struct pci_dev pdev; struct pci_dev *pdevp = &pdev; -#else - char *pdevp = NULL; -#endif - IO_LOCK_T; + unsigned long io_flags; if (!inode) return -EINVAL; @@ -4394,10 +3533,6 @@ /* * Get the user ioctl structure */ - ret = verify_area (VERIFY_WRITE, (char *) arg, sizeof (struct uioctl_t)); - - if (ret) - return ret; if(copy_from_user (&ioc, (char *) arg, sizeof (struct uioctl_t))) return -EFAULT; @@ -4442,24 +3577,17 @@ adapno = GETADAP (adapno); if (adapno >= numCtlrs) - return (-ENODEV); - - ret = verify_area (VERIFY_WRITE, - ioc.data, - sizeof (struct mcontroller)); - if (ret) - return ret; + return -ENODEV; /* * Copy struct mcontroller to user area */ - copy_to_user (ioc.data, - mcontroller + adapno, - sizeof (struct mcontroller)); + if(copy_to_user(ioc.data, mcontroller + adapno, sizeof (struct mcontroller))) + return -EFAULT; return 0; default: - return (-EINVAL); + return -EINVAL; } /* inner switch */ break; @@ -4500,49 +3628,28 @@ outlen = ioc.outlen; inlen = ioc.inlen; - if(outlen) { - ret = verify_area(VERIFY_WRITE, (char *)ioc.ui.fcs.buffer, length); - if (ret) return ret; - } - if(inlen) { - ret = verify_area(VERIFY_READ, (char *) ioc.ui.fcs.buffer, length); - if (ret) return ret; - } - /* * Find this host */ shpnt = megaCtlrs[adapno]->host; if(shpnt == NULL) return -ENODEV; -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) scsicmd = (Scsi_Cmnd *)kmalloc(sizeof(Scsi_Cmnd), GFP_KERNEL|GFP_DMA); -#else - scsicmd = (Scsi_Cmnd *)scsi_init_malloc(sizeof(Scsi_Cmnd), - GFP_ATOMIC | GFP_DMA); -#endif - if(scsicmd == NULL) return -ENOMEM; + if(scsicmd == NULL) + return -ENOMEM; memset(scsicmd, 0, sizeof(Scsi_Cmnd)); scsicmd->host = shpnt; if( outlen || inlen ) { -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) pdevp = &pdev; memcpy(pdevp, megacfg->dev, sizeof(struct pci_dev)); pdevp->dma_mask = 0xffffffff; -#else - pdevp = NULL; -#endif - kvaddr = dma_alloc_consistent(pdevp, length, &dma_addr); + kvaddr = pci_alloc_consistent(pdevp, length, &dma_addr); if( kvaddr == NULL ) { printk(KERN_WARNING "megaraid:allocation failed\n"); -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) /*0x20400 */ kfree(scsicmd); -#else - scsi_init_free((char *)scsicmd, sizeof(Scsi_Cmnd)); -#endif return -ENOMEM; } @@ -4559,10 +3666,10 @@ init_MUTEX_LOCKED(&mimd_ioctl_sem); - IO_LOCK(shpnt); + spin_lock_irqsave(shpnt->host_lock, io_flags); megaraid_queue(scsicmd, megadev_ioctl_done); - IO_UNLOCK(shpnt); + spin_unlock_irqrestore(shpnt->host_lock, io_flags); down(&mimd_ioctl_sem); @@ -4580,17 +3687,14 @@ } else { put_user(1, &uioc->mbox[16]); /* numstatus */ /* status */ + put_user (scsicmd->result, &uioc->mbox[17]); } if (kvaddr) { - dma_free_consistent(pdevp, length, kvaddr, dma_addr); + pci_free_consistent(pdevp, length, kvaddr, dma_addr); } -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) /*0x20400 */ kfree (scsicmd); -#else - scsi_init_free((char *)scsicmd, sizeof(Scsi_Cmnd)); -#endif /* restore the user address */ ioc.ui.fcs.buffer = uaddr; @@ -4605,7 +3709,7 @@ adapno = GETADAP (adapno); if (adapno >= numCtlrs) - return (-ENODEV); + return -ENODEV; /* save the user address */ uaddr = ioc.data; @@ -4613,16 +3717,7 @@ inlen = ioc.inlen; if ((outlen >= IOCTL_MAX_DATALEN) || (inlen >= IOCTL_MAX_DATALEN)) - return (-EINVAL); - - if (outlen) { - ret = verify_area (VERIFY_WRITE, ioc.data, outlen); - if (ret) return ret; - } - if (inlen) { - ret = verify_area (VERIFY_READ, ioc.data, inlen); - if (ret) return ret; - } + return -EINVAL; /* * Find this host @@ -4637,7 +3732,6 @@ if( ioc.mbox[0] == FC_DEL_LOGDRV && ioc.mbox[2] == OP_DEL_LOGDRV ) { if( !megacfg->support_random_del ) { - printk("megaraid: logdrv delete on non supporting f/w.\n"); return -EINVAL; } @@ -4652,37 +3746,25 @@ return ret; } -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) scsicmd = (Scsi_Cmnd *)kmalloc(sizeof(Scsi_Cmnd), GFP_KERNEL|GFP_DMA); -#else - scsicmd = (Scsi_Cmnd *)scsi_init_malloc(sizeof(Scsi_Cmnd), - GFP_ATOMIC | GFP_DMA); -#endif - if(scsicmd == NULL) return -ENOMEM; + if(scsicmd == NULL) + return -ENOMEM; memset(scsicmd, 0, sizeof(Scsi_Cmnd)); scsicmd->host = shpnt; if (outlen || inlen) { -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) pdevp = &pdev; memcpy(pdevp, megacfg->dev, sizeof(struct pci_dev)); pdevp->dma_mask = 0xffffffff; -#else - pdevp = NULL; -#endif /* * Allocate a page of kernel space. */ - kvaddr = dma_alloc_consistent(pdevp, PAGE_SIZE, &dma_addr); + kvaddr = pci_alloc_consistent(pdevp, PAGE_SIZE, &dma_addr); if( kvaddr == NULL ) { printk (KERN_WARNING "megaraid:allocation failed\n"); -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) /*0x20400 */ kfree(scsicmd); -#else - scsi_init_free((char *)scsicmd, sizeof(Scsi_Cmnd)); -#endif return -ENOMEM; } @@ -4703,10 +3785,10 @@ init_MUTEX_LOCKED (&mimd_ioctl_sem); - IO_LOCK(shpnt); + spin_lock_irqsave(shpnt->host_lock, io_flags); megaraid_queue (scsicmd, megadev_ioctl_done); - - IO_UNLOCK(shpnt); + spin_unlock_irqrestore(shpnt->host_lock, io_flags); + down (&mimd_ioctl_sem); if (!scsicmd->result && outlen) { @@ -4730,14 +3812,10 @@ } if (kvaddr) { - dma_free_consistent(pdevp, PAGE_SIZE, kvaddr, dma_addr ); + pci_free_consistent(pdevp, PAGE_SIZE, kvaddr, dma_addr ); } -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) kfree (scsicmd); -#else - scsi_init_free((char *)scsicmd, sizeof(Scsi_Cmnd)); -#endif /* restore user pointer */ ioc.data = uaddr; @@ -4752,14 +3830,12 @@ return 0; } -static void -megadev_ioctl_done(Scsi_Cmnd *sc) +static void megadev_ioctl_done(Scsi_Cmnd *sc) { up (&mimd_ioctl_sem); } -static mega_scb * -megadev_doioctl (mega_host_config * megacfg, Scsi_Cmnd * sc) +static mega_scb *megadev_doioctl (mega_host_config * megacfg, Scsi_Cmnd * sc) { u8 cmd; struct uioctl_t *ioc = NULL; @@ -4792,14 +3868,9 @@ /* * prepare the SCB with information from the user ioctl structure */ -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) pthru = scb->pthru; -#else - pthru = &scb->pthru; -#endif memcpy (pthru, &ioc->pthru, sizeof (mega_passthru)); mboxpthru = (struct mbox_passthru *) scb->mboxData; -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) if (megacfg->flag & BOARD_64BIT) { /* This is just a sample with one element * This if executes onlu on 2.4 kernels @@ -4822,14 +3893,6 @@ pthru->numsgelements = 0; } -#else - { - mboxpthru->dataxferaddr = virt_to_bus (&scb->pthru); - pthru->dataxferaddr = virt_to_bus (ioc->data); - pthru->numsgelements = 0; - } -#endif - pthru->reqsenselen = 14; break; @@ -4852,18 +3915,12 @@ return scb; } -static int -megadev_close (struct inode *inode, struct file *filep) +static int megadev_close (struct inode *inode, struct file *filep) { -#ifdef MODULE - MOD_DEC_USE_COUNT; -#endif return 0; } - -static int -mega_support_ext_cdb(mega_host_config *this_hba) +static int mega_support_ext_cdb(mega_host_config *this_hba) { mega_mailbox *mboxpnt; unsigned char mbox[16]; @@ -4888,8 +3945,8 @@ * Find out if this controller supports random deletion and addition of * logical drives */ -static int -mega_support_random_del(mega_host_config *this_hba) + +static int mega_support_random_del(mega_host_config *this_hba) { mega_mailbox *mboxpnt; unsigned char mbox[16]; @@ -4910,11 +3967,10 @@ return !ret; } -static int -mega_del_logdrv(mega_host_config *this_hba, int logdrv) +static int mega_del_logdrv(mega_host_config *this_hba, int logdrv) { int rval; - IO_LOCK_T; + unsigned long flags; DECLARE_WAIT_QUEUE_HEAD(wq); mega_scb *scbp; @@ -4922,16 +3978,15 @@ * Stop sending commands to the controller, queue them internally. * When deletion is complete, ISR will flush the queue. */ - IO_LOCK(this_hba->host); + spin_lock_irqsave(this_hba->host->host_lock, flags); this_hba->quiescent = 1; - IO_UNLOCK(this_hba->host); + spin_unlock_irqrestore(this_hba->host->host_lock, flags); - while( this_hba->qPcnt ) { - sleep_on_timeout( &wq, 1*HZ ); /* sleep for 1s */ - } + wait_event_interruptible_timeout(wq, !this_hba->qPcnt, HZ); + rval = mega_do_del_logdrv(this_hba, logdrv); - IO_LOCK(this_hba->host); + spin_lock_irqsave(this_hba->host->host_lock, flags); /* * Attach the internal queue to the pending queue */ @@ -4965,25 +4020,19 @@ */ if( this_hba->read_ldidmap) { for( scbp = this_hba->qPendingH; scbp; scbp = scbp->next ) { -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) if( scbp->pthru->logdrv < 0x80 ) scbp->pthru->logdrv += 0x80; -#else - if( scbp->pthru.logdrv < 0x80 ) - scbp->pthru.logdrv += 0x80; -#endif } } this_hba->quiescent = 0; - IO_UNLOCK(this_hba->host); + spin_unlock_irqrestore(this_hba->host->host_lock, flags); return rval; } -static int -mega_do_del_logdrv(mega_host_config *this_hba, int logdrv) +static int mega_do_del_logdrv(mega_host_config *this_hba, int logdrv) { mega_mailbox *mboxpnt; unsigned char mbox[16]; @@ -5001,12 +4050,11 @@ /* log this event */ if( rval != 0 ) { - printk("megaraid: Attempt to delete logical drive %d failed.", - logdrv); + printk(KERN_WARNING "megaraid: Attempt to delete logical drive %d failed.", logdrv); return rval; } - printk("megaraid: logical drive %d deleted.\n", logdrv); + printk(KERN_INFO "megaraid: logical drive %d deleted.\n", logdrv); /* * After deleting first logical drive, the logical drives must be @@ -5017,100 +4065,26 @@ return rval; } -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0) -void * -dma_alloc_consistent(void *dev, size_t size, dma_addr_t *dma_addr) -{ - void *_tv; - int npages; - int order = 0; - - /* - * How many pages application needs - */ - npages = size / PAGE_SIZE; - - /* Do we need one more page */ - if(size % PAGE_SIZE) - npages++; - - order = mega_get_order(npages); - - _tv = (void *)__get_free_pages(GFP_DMA, order); - - if( _tv != NULL ) { - memset(_tv, 0, size); - *(dma_addr) = virt_to_bus(_tv); - } - return _tv; -} - -/* - * int mega_get_order(int) - * - * returns the order to be used as 2nd argument to __get_free_pages() - which - * return pages equal to pow(2, order) - AM - */ -int -mega_get_order(int n) -{ - int i = 0; - - while( pow_2(i++) < n ) - ; /* null statement */ - - return i-1; -} - -/* - * int pow_2(int) - * - * calculates pow(2, i) - */ -int -pow_2(int i) -{ - unsigned int v = 1; - - while(i--) - v <<= 1; - - return v; -} - -void -dma_free_consistent(void *dev, size_t size, void *vaddr, dma_addr_t dma_addr) -{ - int npages; - int order = 0; - - npages = size / PAGE_SIZE; - - if(size % PAGE_SIZE) - npages++; - - if (npages == 1) - order = 0; - else if (npages == 2) - order = 1; - else if (npages <= 4) - order = 2; - else - order = 3; - - free_pages((unsigned long)vaddr, order); - -} -#endif - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) -static -#endif /* LINUX VERSION 2.4.XX */ -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) || defined(MODULE) -Scsi_Host_Template driver_template = MEGARAID; +static Scsi_Host_Template driver_template = { + name: "MegaRAID", /* Driver Name */ + proc_info: megaraid_proc_info, /* /proc driver info */ + detect: megaraid_detect, /* Detect Host Adapter */ + release: megaraid_release, /* Release Host Adapter */ + info: megaraid_info, /* Driver Info Function */ + command: megaraid_command, /* Command Function */ + queuecommand: megaraid_queue, /* Queue Command Function */ + eh_abort_handler: megaraid_abort, /* Abort Command Function */ + eh_host_reset_handler: megaraid_host_reset, /* Reset Command Function */ + bios_param: megaraid_biosparam, /* Disk BIOS Parameters */ + can_queue: MAX_COMMANDS, /* Can Queue */ + this_id: 7, /* HBA Target ID */ + sg_tablesize: MAX_SGLIST, /* Scatter/Gather Table Size */ + cmd_per_lun: MAX_CMD_PER_LUN, /* SCSI Commands per LUN */ + present: 0, /* Present */ + unchecked_isa_dma: 0, /* Default Unchecked ISA DMA */ + use_clustering: ENABLE_CLUSTERING, /* Enable Clustering */ + highmem_io: 1 +}; #include "scsi_module.c" -#endif /* LINUX VERSION 2.4.XX || MODULE */ - -/* vi: set ts=4: */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/drivers/scsi/megaraid.h linux.2.5.47-ac6/drivers/scsi/megaraid.h --- linux.2.5.47/drivers/scsi/megaraid.h 2002-11-11 16:39:10.000000000 +0000 +++ linux.2.5.47-ac6/drivers/scsi/megaraid.h 2002-11-12 15:34:26.000000000 +0000 @@ -1,10 +1,6 @@ #ifndef __MEGARAID_H__ #define __MEGARAID_H__ -#ifndef LINUX_VERSION_CODE -#include -#endif - /* * For state flag. Do not use LSB(8 bits) which are * reserved for storing info about channels. @@ -13,17 +9,17 @@ #define IN_ABORT 0x40000000L #define IN_RESET 0x20000000L #define IN_QUEUE 0x10000000L -#define BOARD_QUARTZ 0x08000000L +#define BOARD_QUARTZ 0x08000000L #define BOARD_40LD 0x04000000L #define BOARD_64BIT 0x02000000L -#define SCB_FREE 0x0 -#define SCB_ACTIVE 0x1 -#define SCB_WAITQ 0x2 -#define SCB_ISSUED 0x3 -#define SCB_COMPLETE 0x4 -#define SCB_ABORTED 0x5 -#define SCB_RESET 0x6 +#define SCB_FREE 0x0 +#define SCB_ACTIVE 0x1 +#define SCB_WAITQ 0x2 +#define SCB_ISSUED 0x3 +#define SCB_COMPLETE 0x4 +#define SCB_ABORTED 0x5 +#define SCB_RESET 0x6 #define M_RD_CRLFSTR "\n" #define M_RD_IOCTL_CMD 0x80 @@ -180,52 +176,6 @@ #define AMI_SIGNATURE_471 0xCCCC #define AMI_64BIT_SIGNATURE 0x0299 -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,0) /*0x20100 */ -#define MEGARAID \ - { NULL, /* Next */\ - NULL, /* Usage Count Pointer */\ - NULL, /* proc Directory Entry */\ - megaraid_proc_info, /* proc Info Function */\ - "MegaRAID", /* Driver Name */\ - megaraid_detect, /* Detect Host Adapter */\ - megaraid_release, /* Release Host Adapter */\ - megaraid_info, /* Driver Info Function */\ - megaraid_command, /* Command Function */\ - megaraid_queue, /* Queue Command Function */\ - megaraid_abort, /* Abort Command Function */\ - megaraid_reset, /* Reset Command Function */\ - NULL, /* Slave Attach Function */\ - megaraid_biosparam, /* Disk BIOS Parameters */\ - MAX_COMMANDS, /* # of cmds that can be\ - outstanding at any time */\ - 7, /* HBA Target ID */\ - MAX_SGLIST, /* Scatter/Gather Table Size */\ - MAX_CMD_PER_LUN, /* SCSI Commands per LUN */\ - 0, /* Present */\ - 0, /* Default Unchecked ISA DMA */\ - ENABLE_CLUSTERING } /* Enable Clustering */ -#else -#define MEGARAID \ - {\ - name: "MegaRAID", /* Driver Name */\ - proc_info: megaraid_proc_info, /* /proc driver info */\ - detect: megaraid_detect, /* Detect Host Adapter */\ - release: megaraid_release, /* Release Host Adapter */\ - info: megaraid_info, /* Driver Info Function */\ - command: megaraid_command, /* Command Function */\ - queuecommand: megaraid_queue, /* Queue Command Function */\ - bios_param: megaraid_biosparam, /* Disk BIOS Parameters */\ - can_queue: MAX_COMMANDS, /* Can Queue */\ - this_id: 7, /* HBA Target ID */\ - sg_tablesize: MAX_SGLIST, /* Scatter/Gather Table Size */\ - cmd_per_lun: MAX_CMD_PER_LUN, /* SCSI Commands per LUN */\ - present: 0, /* Present */\ - unchecked_isa_dma: 0, /* Default Unchecked ISA DMA */\ - use_clustering: ENABLE_CLUSTERING, /* Enable Clustering */\ - highmem_io: 1, \ - } -#endif - /*********************************************************************** * Structure Declarations for the Firmware supporting 40 Logical Drives * and 256 Physical Drives. @@ -941,16 +891,16 @@ * *================================================================ */ -const char *megaraid_info (struct Scsi_Host *); -int megaraid_detect (Scsi_Host_Template *); -int megaraid_release (struct Scsi_Host *); -int megaraid_command (Scsi_Cmnd *); -int megaraid_abort (Scsi_Cmnd *); -int megaraid_reset (Scsi_Cmnd *, unsigned int); -int megaraid_queue (Scsi_Cmnd *, void (*done) (Scsi_Cmnd *)); -int megaraid_biosparam (struct scsi_device *, struct block_device *, +static const char *megaraid_info (struct Scsi_Host *); +static int megaraid_detect (Scsi_Host_Template *); +static int megaraid_release (struct Scsi_Host *); +static int megaraid_command (Scsi_Cmnd *); +static int megaraid_abort (Scsi_Cmnd *); +static int megaraid_host_reset (Scsi_Cmnd *); +static int megaraid_queue (Scsi_Cmnd *, void (*done) (Scsi_Cmnd *)); +static int megaraid_biosparam (struct scsi_device *, struct block_device *, sector_t, int *); -int megaraid_proc_info (char *buffer, char **start, off_t offset, +static int megaraid_proc_info (char *buffer, char **start, off_t offset, int length, int hostno, int inout); static int megaIssueCmd (mega_host_config * megaCfg, u_char * mboxData, diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/drivers/scsi/NCR53c406a.c linux.2.5.47-ac6/drivers/scsi/NCR53c406a.c --- linux.2.5.47/drivers/scsi/NCR53c406a.c 2002-11-11 16:39:10.000000000 +0000 +++ linux.2.5.47-ac6/drivers/scsi/NCR53c406a.c 2002-11-12 15:35:48.000000000 +0000 @@ -55,7 +55,6 @@ #include #include "scsi.h" #include "hosts.h" -#include "NCR53c406a.h" /* ============================================================= */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/drivers/scsi/pcmcia/aha152x.c linux.2.5.47-ac6/drivers/scsi/pcmcia/aha152x.c --- linux.2.5.47/drivers/scsi/pcmcia/aha152x.c 1970-01-01 01:00:00.000000000 +0100 +++ linux.2.5.47-ac6/drivers/scsi/pcmcia/aha152x.c 2002-11-03 01:31:31.000000000 +0000 @@ -0,0 +1,3928 @@ +/* aha152x.c -- Adaptec AHA-152x driver + * Author: Jürgen E. Fischer, fischer@norbit.de + * Copyright 1993-2000 Jürgen E. Fischer + * + * 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, 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. + * + * + * $Id: aha152x.c,v 2.5 2002/04/14 11:24:53 fischer Exp $ + * + * $Log: aha152x.c,v $ + * Revision 2.5 2002/04/14 11:24:53 fischer + * - isapnp support + * - abort fixed + * - 2.5 support + * + * Revision 2.4 2000/12/16 12:53:56 fischer + * - allow REQUEST SENSE to be queued + * - handle shared PCI interrupts + * + * Revision 2.3 2000/11/04 16:40:26 fischer + * - handle data overruns + * - extend timeout for data phases + * + * Revision 2.2 2000/08/08 19:54:53 fischer + * - minor changes + * + * Revision 2.1 2000/05/17 16:23:17 fischer + * - signature update + * - fix for data out w/o scatter gather + * + * Revision 2.0 1999/12/25 15:07:32 fischer + * - interrupt routine completly reworked + * - basic support for new eh code + * + * Revision 1.21 1999/11/10 23:46:36 fischer + * - default to synchronous operation + * - synchronous negotiation fixed + * - added timeout to loops + * - debugging output can be controlled through procfs + * + * Revision 1.20 1999/11/07 18:37:31 fischer + * - synchronous operation works + * - resid support for sg driver + * + * Revision 1.19 1999/11/02 22:39:59 fischer + * - moved leading comments to README.aha152x + * - new additional module parameters + * - updates for 2.3 + * - support for the Tripace TC1550 controller + * - interrupt handling changed + * + * Revision 1.18 1996/09/07 20:10:40 fischer + * - fixed can_queue handling (multiple outstanding commands working again) + * + * Revision 1.17 1996/08/17 16:05:14 fischer + * - biosparam improved + * - interrupt verification + * - updated documentation + * - cleanups + * + * Revision 1.16 1996/06/09 00:04:56 root + * - added configuration symbols for insmod (aha152x/aha152x1) + * + * Revision 1.15 1996/04/30 14:52:06 fischer + * - proc info fixed + * - support for extended translation for >1GB disks + * + * Revision 1.14 1996/01/17 15:11:20 fischer + * - fixed lockup in MESSAGE IN phase after reconnection + * + * Revision 1.13 1996/01/09 02:15:53 fischer + * - some cleanups + * - moved request_irq behind controller initialization + * (to avoid spurious interrupts) + * + * Revision 1.12 1995/12/16 12:26:07 fischer + * - barrier()s added + * - configurable RESET delay added + * + * Revision 1.11 1995/12/06 21:18:35 fischer + * - some minor updates + * + * Revision 1.10 1995/07/22 19:18:45 fischer + * - support for 2 controllers + * - started synchronous data transfers (not working yet) + * + * Revision 1.9 1995/03/18 09:20:24 root + * - patches for PCMCIA and modules + * + * Revision 1.8 1995/01/21 22:07:19 root + * - snarf_region => request_region + * - aha152x_intr interface change + * + * Revision 1.7 1995/01/02 23:19:36 root + * - updated COMMAND_SIZE to cmd_len + * - changed sti() to restore_flags() + * - fixed some #ifdef which generated warnings + * + * Revision 1.6 1994/11/24 20:35:27 root + * - problem with odd number of bytes in fifo fixed + * + * Revision 1.5 1994/10/30 14:39:56 root + * - abort code fixed + * - debugging improved + * + * Revision 1.4 1994/09/12 11:33:01 root + * - irqaction to request_irq + * - abortion updated + * + * Revision 1.3 1994/08/04 13:53:05 root + * - updates for mid-level-driver changes + * - accept unexpected BUSFREE phase as error condition + * - parity check now configurable + * + * Revision 1.2 1994/07/03 12:56:36 root + * - cleaned up debugging code + * - more tweaking on reset delays + * - updated abort/reset code (pretty untested...) + * + * Revision 1.1 1994/05/28 21:18:49 root + * - update for mid-level interface change (abort-reset) + * - delays after resets adjusted for some slow devices + * + * Revision 1.0 1994/03/25 12:52:00 root + * - Fixed "more data than expected" problem + * - added new BIOS signatures + * + * Revision 0.102 1994/01/31 20:44:12 root + * - minor changes in insw/outsw handling + * + * Revision 0.101 1993/12/13 01:16:27 root + * - fixed STATUS phase (non-GOOD stati were dropped sometimes; + * fixes problems with CD-ROM sector size detection & media change) + * + * Revision 0.100 1993/12/10 16:58:47 root + * - fix for unsuccessful selections in case of non-continuous id assignments + * on the scsi bus. + * + * Revision 0.99 1993/10/24 16:19:59 root + * - fixed DATA IN (rare read errors gone) + * + * Revision 0.98 1993/10/17 12:54:44 root + * - fixed some recent fixes (shame on me) + * - moved initialization of scratch area to aha152x_queue + * + * Revision 0.97 1993/10/09 18:53:53 root + * - DATA IN fixed. Rarely left data in the fifo. + * + * Revision 0.96 1993/10/03 00:53:59 root + * - minor changes on DATA IN + * + * Revision 0.95 1993/09/24 10:36:01 root + * - change handling of MSGI after reselection + * - fixed sti/cli + * - minor changes + * + * Revision 0.94 1993/09/18 14:08:22 root + * - fixed bug in multiple outstanding command code + * - changed detection + * - support for kernel command line configuration + * - reset corrected + * - changed message handling + * + * Revision 0.93 1993/09/15 20:41:19 root + * - fixed bugs with multiple outstanding commands + * + * Revision 0.92 1993/09/13 02:46:33 root + * - multiple outstanding commands work (no problems with IBM drive) + * + * Revision 0.91 1993/09/12 20:51:46 root + * added multiple outstanding commands + * (some problem with this $%&? IBM device remain) + * + * Revision 0.9 1993/09/12 11:11:22 root + * - corrected auto-configuration + * - changed the auto-configuration (added some '#define's) + * - added support for dis-/reconnection + * + * Revision 0.8 1993/09/06 23:09:39 root + * - added support for the drive activity light + * - minor changes + * + * Revision 0.7 1993/09/05 14:30:15 root + * - improved phase detection + * - now using the new snarf_region code of 0.99pl13 + * + * Revision 0.6 1993/09/02 11:01:38 root + * first public release; added some signatures and biosparam() + * + * Revision 0.5 1993/08/30 10:23:30 root + * fixed timing problems with my IBM drive + * + * Revision 0.4 1993/08/29 14:06:52 root + * fixed some problems with timeouts due incomplete commands + * + * Revision 0.3 1993/08/28 15:55:03 root + * writing data works too. mounted and worked on a dos partition + * + * Revision 0.2 1993/08/27 22:42:07 root + * reading data works. Mounted a msdos partition. + * + * Revision 0.1 1993/08/25 13:38:30 root + * first "damn thing doesn't work" version + * + * Revision 0.0 1993/08/14 19:54:25 root + * empty function bodies; detect() works. + * + * + ************************************************************************** + + see README.aha152x for configuration details + + **************************************************************************/ + +#include + +#if defined(PCMCIA) +#undef MODULE +#endif + +#include +#include +#include +#include +#include +#include "scsi.h" +#include "hosts.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "aha152x.h" +#include +#include + +#include + +/* DEFINES */ + +/* For PCMCIA cards, always use AUTOCONF */ +#if defined(PCMCIA) || defined(MODULE) +#if !defined(AUTOCONF) +#define AUTOCONF +#endif +#endif + +#if !defined(AUTOCONF) && !defined(SETUP0) +#error define AUTOCONF or SETUP0 +#endif + +#if defined(AHA152X_DEBUG) +#define DEBUG_DEFAULT debug_eh + +#define DPRINTK(when,msgs...) \ + do { if(HOSTDATA(shpnt)->debug & (when)) printk(msgs); } while(0) + +#define DO_LOCK(flags) \ + do { \ + if(spin_is_locked(&QLOCK)) { \ + DPRINTK(debug_intr, DEBUG_LEAD "(%s:%d) already locked at %s:%d\n", CMDINFO(CURRENT_SC), __FUNCTION__, __LINE__, QLOCKER, QLOCKERL); \ + } \ + DPRINTK(debug_locks, DEBUG_LEAD "(%s:%d) locking\n", CMDINFO(CURRENT_SC), __FUNCTION__, __LINE__); \ + spin_lock_irqsave(&QLOCK,flags); \ + DPRINTK(debug_locks, DEBUG_LEAD "(%s:%d) locked\n", CMDINFO(CURRENT_SC), __FUNCTION__, __LINE__); \ + QLOCKER=__FUNCTION__; \ + QLOCKERL=__LINE__; \ + } while(0) + +#define DO_UNLOCK(flags) \ + do { \ + DPRINTK(debug_locks, DEBUG_LEAD "(%s:%d) unlocking (locked at %s:%d)\n", CMDINFO(CURRENT_SC), __FUNCTION__, __LINE__, QLOCKER, QLOCKERL); \ + spin_unlock_irqrestore(&QLOCK,flags); \ + DPRINTK(debug_locks, DEBUG_LEAD "(%s:%d) unlocked\n", CMDINFO(CURRENT_SC), __FUNCTION__, __LINE__); \ + QLOCKER="(not locked)"; \ + QLOCKERL=0; \ + } while(0) + +#else +#define DPRINTK(when,msgs...) +#define DO_LOCK(flags) spin_lock_irqsave(&QLOCK,flags) +#define DO_UNLOCK(flags) spin_unlock_irqrestore(&QLOCK,flags) +#endif + +#define LEAD "(scsi%d:%d:%d) " +#define WARN_LEAD KERN_WARNING LEAD +#define INFO_LEAD KERN_INFO LEAD +#define NOTE_LEAD KERN_NOTICE LEAD +#define ERR_LEAD KERN_ERR LEAD +#define DEBUG_LEAD KERN_DEBUG LEAD +#define CMDINFO(cmd) \ + (cmd) ? ((cmd)->host->host_no) : -1, \ + (cmd) ? ((cmd)->target & 0x0f) : -1, \ + (cmd) ? ((cmd)->lun & 0x07) : -1 + +#define DELAY_DEFAULT 1000 + +#if defined(PCMCIA) +#define IRQ_MIN 0 +#define IRQ_MAX 16 +#else +#define IRQ_MIN 9 +#if defined(__PPC) +#define IRQ_MAX (NR_IRQS-1) +#else +#define IRQ_MAX 12 +#endif +#endif + +enum { + not_issued = 0x0001, /* command not yet issued */ + selecting = 0x0002, /* target is beeing selected */ + identified = 0x0004, /* IDENTIFY was sent */ + disconnected = 0x0008, /* target disconnected */ + completed = 0x0010, /* target sent COMMAND COMPLETE */ + aborted = 0x0020, /* ABORT was sent */ + resetted = 0x0040, /* BUS DEVICE RESET was sent */ + spiordy = 0x0080, /* waiting for SPIORDY to raise */ + syncneg = 0x0100, /* synchronous negotiation in progress */ + aborting = 0x0200, /* ABORT is pending */ + resetting = 0x0400, /* BUS DEVICE RESET is pending */ +}; + +#if defined(MODULE) +MODULE_AUTHOR("Jürgen Fischer"); +MODULE_DESCRIPTION(AHA152X_REVID); +MODULE_LICENSE("GPL"); + +MODULE_PARM(io, "1-2i"); +MODULE_PARM_DESC(io,"base io address of controller"); +static int io[] = {0, 0}; + +MODULE_PARM(irq, "1-2i"); +MODULE_PARM_DESC(irq,"interrupt for controller"); +static int irq[] = {0, 0}; + +MODULE_PARM(scsiid, "1-2i"); +MODULE_PARM_DESC(scsiid,"scsi id of controller"); +static int scsiid[] = {7, 7}; + +MODULE_PARM(reconnect, "1-2i"); +MODULE_PARM_DESC(reconnect,"allow targets to disconnect"); +static int reconnect[] = {1, 1}; + +MODULE_PARM(parity, "1-2i"); +MODULE_PARM_DESC(parity,"use scsi parity"); +static int parity[] = {1, 1}; + +MODULE_PARM(sync, "1-2i"); +MODULE_PARM_DESC(sync,"use synchronous transfers"); +static int sync[] = {1, 1}; + +MODULE_PARM(delay, "1-2i"); +MODULE_PARM_DESC(delay,"scsi reset delay"); +static int delay[] = {DELAY_DEFAULT, DELAY_DEFAULT}; + +MODULE_PARM(exttrans, "1-2i"); +MODULE_PARM_DESC(exttrans,"use extended translation"); +static int exttrans[] = {0, 0}; + +#if !defined(AHA152X_DEBUG) +MODULE_PARM(aha152x, "1-8i"); +MODULE_PARM_DESC(aha152x, "parameters for first controller"); +static int aha152x[] = {0, 11, 7, 1, 1, 0, DELAY_DEFAULT, 0}; + +MODULE_PARM(aha152x1, "1-8i"); +MODULE_PARM_DESC(aha152x1, "parameters for second controller"); +static int aha152x1[] = {0, 11, 7, 1, 1, 0, DELAY_DEFAULT, 0}; +#else +MODULE_PARM(debug, "1-2i"); +MODULE_PARM_DESC(debug, "flags for driver debugging"); +static int debug[] = {DEBUG_DEFAULT, DEBUG_DEFAULT}; + +MODULE_PARM(aha152x, "1-9i"); +MODULE_PARM_DESC(aha152x, "parameters for first controller"); +static int aha152x[] = {0, 11, 7, 1, 1, 1, DELAY_DEFAULT, 0, DEBUG_DEFAULT}; + +MODULE_PARM(aha152x1, "1-9i"); +MODULE_PARM_DESC(aha152x1, "parameters for second controller"); +static int aha152x1[] = {0, 11, 7, 1, 1, 1, DELAY_DEFAULT, 0, DEBUG_DEFAULT}; +#endif /* !defined(AHA152X_DEBUG) */ + +#ifdef __ISAPNP__ +static struct isapnp_device_id id_table[] __devinitdata = { + { ISAPNP_DEVICE_SINGLE('A','D','P',0x1505, 'A','D','P',0x1505), }, + { ISAPNP_DEVICE_SINGLE_END, } +}; +MODULE_DEVICE_TABLE(isapnp, id_table); +#endif /* ISAPNP */ +#endif /* MODULE */ + +/* set by aha152x_setup according to the command line */ +static int setup_count = 0; +static int registered_count = 0; +static struct aha152x_setup { + int io_port; + int irq; + int scsiid; + int reconnect; + int parity; + int synchronous; + int delay; + int ext_trans; + int tc1550; +#if defined(AHA152X_DEBUG) + int debug; +#endif + char *conf; +} setup[2]; + +static struct Scsi_Host *aha152x_host[2]; + +/* + * internal states of the host + * + */ +enum aha152x_state { + idle=0, + unknown, + seldo, + seldi, + selto, + busfree, + msgo, + cmd, + msgi, + status, + datai, + datao, + parerr, + rsti, + maxstate +}; + +/* + * current state information of the host + * + */ +struct aha152x_hostdata { + Scsi_Cmnd *issue_SC; + /* pending commands to issue */ + + Scsi_Cmnd *current_SC; + /* current command on the bus */ + + Scsi_Cmnd *disconnected_SC; + /* commands that disconnected */ + + Scsi_Cmnd *done_SC; + /* command that was completed */ + + spinlock_t lock; + /* host lock */ + +#if defined(AHA152X_DEBUG) + char *locker; /* which function has the lock */ + int lockerl; /* where did it get it */ + + int debug; /* current debugging setting */ +#endif + +#if defined(AHA152X_STAT) + int total_commands; + int disconnections; + int busfree_without_any_action; + int busfree_without_old_command; + int busfree_without_new_command; + int busfree_without_done_command; + int busfree_with_check_condition; + int count[maxstate]; + int count_trans[maxstate]; + unsigned long time[maxstate]; +#endif + + int commands; /* current number of commands */ + + int reconnect; /* disconnection allowed */ + int parity; /* parity checking enabled */ + int synchronous; /* synchronous transferes enabled */ + int delay; /* reset out delay */ + int ext_trans; /* extended translation enabled */ + + int swint; /* software-interrupt was fired during detect() */ + int service; /* bh needs to be run */ + int in_intr; /* bh is running */ + + /* current state, + previous state, + last state different from current state */ + enum aha152x_state state, prevstate, laststate; + + int target; + /* reconnecting target */ + + unsigned char syncrate[8]; + /* current synchronous transfer agreements */ + + unsigned char syncneg[8]; + /* 0: no negotiation; + * 1: negotiation in progress; + * 2: negotiation completed + */ + + int cmd_i; + /* number of sent bytes of current command */ + + int msgi_len; + /* number of received message bytes */ + unsigned char msgi[256]; + /* received message bytes */ + + int msgo_i, msgo_len; + /* number of sent bytes and length of current messages */ + unsigned char msgo[256]; + /* pending messages */ + + int data_len; + /* number of sent/received bytes in dataphase */ + + unsigned long io_port0; + unsigned long io_port1; +}; + + +/* + * host specific command extension + * + */ +struct aha152x_scdata { + Scsi_Cmnd *next; /* next sc in queue */ + Scsi_Cmnd *done; /* done command */ + struct semaphore *sem; /* semaphore to block on */ +}; + + +/* access macros for hostdata */ + +#define HOSTDATA(shpnt) ((struct aha152x_hostdata *) &shpnt->hostdata) + +#define HOSTNO ((shpnt)->host_no) + +#define CURRENT_SC (HOSTDATA(shpnt)->current_SC) +#define DONE_SC (HOSTDATA(shpnt)->done_SC) +#define ISSUE_SC (HOSTDATA(shpnt)->issue_SC) +#define DISCONNECTED_SC (HOSTDATA(shpnt)->disconnected_SC) +#define QLOCK (HOSTDATA(shpnt)->lock) +#define QLOCKER (HOSTDATA(shpnt)->locker) +#define QLOCKERL (HOSTDATA(shpnt)->lockerl) + +#define STATE (HOSTDATA(shpnt)->state) +#define PREVSTATE (HOSTDATA(shpnt)->prevstate) +#define LASTSTATE (HOSTDATA(shpnt)->laststate) + +#define RECONN_TARGET (HOSTDATA(shpnt)->target) + +#define CMD_I (HOSTDATA(shpnt)->cmd_i) + +#define MSGO(i) (HOSTDATA(shpnt)->msgo[i]) +#define MSGO_I (HOSTDATA(shpnt)->msgo_i) +#define MSGOLEN (HOSTDATA(shpnt)->msgo_len) +#define ADDMSGO(x) (MSGOLEN<256 ? MSGO(MSGOLEN++)=x : aha152x_error(shpnt,"MSGO overflow")) + +#define MSGI(i) (HOSTDATA(shpnt)->msgi[i]) +#define MSGILEN (HOSTDATA(shpnt)->msgi_len) +#define ADDMSGI(x) (MSGILEN<256 ? MSGI(MSGILEN++)=x : aha152x_error(shpnt,"MSGI overflow")) + +#define DATA_LEN (HOSTDATA(shpnt)->data_len) + +#define SYNCRATE (HOSTDATA(shpnt)->syncrate[CURRENT_SC->target]) +#define SYNCNEG (HOSTDATA(shpnt)->syncneg[CURRENT_SC->target]) + +#define DELAY (HOSTDATA(shpnt)->delay) +#define EXT_TRANS (HOSTDATA(shpnt)->ext_trans) +#define TC1550 (HOSTDATA(shpnt)->tc1550) +#define RECONNECT (HOSTDATA(shpnt)->reconnect) +#define PARITY (HOSTDATA(shpnt)->parity) +#define SYNCHRONOUS (HOSTDATA(shpnt)->synchronous) + +#define HOSTIOPORT0 (HOSTDATA(shpnt)->io_port0) +#define HOSTIOPORT1 (HOSTDATA(shpnt)->io_port1) + +#define SCDATA(SCpnt) ((struct aha152x_scdata *) (SCpnt)->host_scribble) +#define SCNEXT(SCpnt) SCDATA(SCpnt)->next +#define SCDONE(SCpnt) SCDATA(SCpnt)->done +#define SCSEM(SCpnt) SCDATA(SCpnt)->sem + +#define SG_ADDRESS(buffer) ((char *) (page_address((buffer)->page)+(buffer)->offset)) + +/* state handling */ +static void seldi_run(struct Scsi_Host *shpnt); +static void seldo_run(struct Scsi_Host *shpnt); +static void selto_run(struct Scsi_Host *shpnt); +static void busfree_run(struct Scsi_Host *shpnt); + +static void msgo_init(struct Scsi_Host *shpnt); +static void msgo_run(struct Scsi_Host *shpnt); +static void msgo_end(struct Scsi_Host *shpnt); + +static void cmd_init(struct Scsi_Host *shpnt); +static void cmd_run(struct Scsi_Host *shpnt); +static void cmd_end(struct Scsi_Host *shpnt); + +static void datai_init(struct Scsi_Host *shpnt); +static void datai_run(struct Scsi_Host *shpnt); +static void datai_end(struct Scsi_Host *shpnt); + +static void datao_init(struct Scsi_Host *shpnt); +static void datao_run(struct Scsi_Host *shpnt); +static void datao_end(struct Scsi_Host *shpnt); + +static void status_run(struct Scsi_Host *shpnt); + +static void msgi_run(struct Scsi_Host *shpnt); +static void msgi_end(struct Scsi_Host *shpnt); + +static void parerr_run(struct Scsi_Host *shpnt); +static void rsti_run(struct Scsi_Host *shpnt); + +static void is_complete(struct Scsi_Host *shpnt); + +/* + * driver states + * + */ +static struct { + char *name; + void (*init)(struct Scsi_Host *); + void (*run)(struct Scsi_Host *); + void (*end)(struct Scsi_Host *); + int spio; +} states[] = { + { "idle", 0, 0, 0, 0}, + { "unknown", 0, 0, 0, 0}, + { "seldo", 0, seldo_run, 0, 0}, + { "seldi", 0, seldi_run, 0, 0}, + { "selto", 0, selto_run, 0, 0}, + { "busfree", 0, busfree_run, 0, 0}, + { "msgo", msgo_init, msgo_run, msgo_end, 1}, + { "cmd", cmd_init, cmd_run, cmd_end, 1}, + { "msgi", 0, msgi_run, msgi_end, 1}, + { "status", 0, status_run, 0, 1}, + { "datai", datai_init, datai_run, datai_end, 0}, + { "datao", datao_init, datao_run, datao_end, 0}, + { "parerr", 0, parerr_run, 0, 0}, + { "rsti", 0, rsti_run, 0, 0}, +}; + +/* setup & interrupt */ +static void intr(int irq, void *dev_id, struct pt_regs *); +static void reset_ports(struct Scsi_Host *shpnt); +static void aha152x_error(struct Scsi_Host *shpnt, char *msg); +static void done(struct Scsi_Host *shpnt, int error); +static int checksetup(struct aha152x_setup *setup); + +/* diagnostics */ +static void disp_ports(struct Scsi_Host *shpnt); +static void show_command(Scsi_Cmnd * ptr); +static void show_queues(struct Scsi_Host *shpnt); +static void disp_enintr(struct Scsi_Host *shpnt); + +/* possible i/o addresses for the AIC-6260; default first */ +static unsigned short ports[] = { 0x340, 0x140 }; + +#if !defined(SKIP_BIOSTEST) +/* possible locations for the Adaptec BIOS; defaults first */ +static unsigned int addresses[] = +{ + 0xdc000, /* default first */ + 0xc8000, + 0xcc000, + 0xd0000, + 0xd4000, + 0xd8000, + 0xe0000, + 0xeb800, /* VTech Platinum SMP */ + 0xf0000, +}; + +/* signatures for various AIC-6[23]60 based controllers. + The point in detecting signatures is to avoid useless and maybe + harmful probes on ports. I'm not sure that all listed boards pass + auto-configuration. For those which fail the BIOS signature is + obsolete, because user intervention to supply the configuration is + needed anyway. May be an information whether or not the BIOS supports + extended translation could be also useful here. */ +static struct signature { + unsigned char *signature; + int sig_offset; + int sig_length; +} signatures[] = +{ + { "Adaptec AHA-1520 BIOS", 0x102e, 21 }, + /* Adaptec 152x */ + { "Adaptec AHA-1520B", 0x000b, 17 }, + /* Adaptec 152x rev B */ + { "Adaptec AHA-1520B", 0x0026, 17 }, + /* Iomega Jaz Jet ISA (AIC6370Q) */ + { "Adaptec ASW-B626 BIOS", 0x1029, 21 }, + /* on-board controller */ + { "Adaptec BIOS: ASW-B626", 0x000f, 22 }, + /* on-board controller */ + { "Adaptec ASW-B626 S2", 0x2e6c, 19 }, + /* on-board controller */ + { "Adaptec BIOS:AIC-6360", 0x000c, 21 }, + /* on-board controller */ + { "ScsiPro SP-360 BIOS", 0x2873, 19 }, + /* ScsiPro-Controller */ + { "GA-400 LOCAL BUS SCSI BIOS", 0x102e, 26 }, + /* Gigabyte Local-Bus-SCSI */ + { "Adaptec BIOS:AVA-282X", 0x000c, 21 }, + /* Adaptec 282x */ + { "Adaptec IBM Dock II SCSI", 0x2edd, 24 }, + /* IBM Thinkpad Dock II */ + { "Adaptec BIOS:AHA-1532P", 0x001c, 22 }, + /* IBM Thinkpad Dock II SCSI */ + { "DTC3520A Host Adapter BIOS", 0x318a, 26 }, + /* DTC 3520A ISA SCSI */ +}; +#endif + + +/* + * queue services: + * + */ +static inline void append_SC(Scsi_Cmnd **SC, Scsi_Cmnd *new_SC) +{ + Scsi_Cmnd *end; + + SCNEXT(new_SC) = NULL; + if (!*SC) + *SC = new_SC; + else { + for (end = *SC; SCNEXT(end); end = SCNEXT(end)) + ; + SCNEXT(end) = new_SC; + } +} + +static inline Scsi_Cmnd *remove_first_SC(Scsi_Cmnd ** SC) +{ + Scsi_Cmnd *ptr; + + ptr = *SC; + if (ptr) { + *SC = SCNEXT(*SC); + SCNEXT(ptr)=NULL; + } + return ptr; +} + +static inline Scsi_Cmnd *remove_lun_SC(Scsi_Cmnd ** SC, int target, int lun) +{ + Scsi_Cmnd *ptr, *prev; + + for (ptr = *SC, prev = NULL; + ptr && ((ptr->target != target) || (ptr->lun != lun)); + prev = ptr, ptr = SCNEXT(ptr)) + ; + + if (ptr) { + if (prev) + SCNEXT(prev) = SCNEXT(ptr); + else + *SC = SCNEXT(ptr); + + SCNEXT(ptr)=NULL; + } + + return ptr; +} + +static inline Scsi_Cmnd *remove_SC(Scsi_Cmnd **SC, Scsi_Cmnd *SCp) +{ + Scsi_Cmnd *ptr, *prev; + + for (ptr = *SC, prev = NULL; + ptr && SCp!=ptr; + prev = ptr, ptr = SCNEXT(ptr)) + ; + + if (ptr) { + if (prev) + SCNEXT(prev) = SCNEXT(ptr); + else + *SC = SCNEXT(ptr); + + SCNEXT(ptr)=NULL; + } + + return ptr; +} + +#if defined(PCMCIA) || !defined(MODULE) +void aha152x_setup(char *str, int *ints) +{ + if(setup_count>=ARRAY_SIZE(setup)) { + printk(KERN_ERR "aha152x: you can only configure up to two controllers\n"); + return; + } + + setup[setup_count].conf = str; + setup[setup_count].io_port = ints[0] >= 1 ? ints[1] : 0x340; + setup[setup_count].irq = ints[0] >= 2 ? ints[2] : 11; + setup[setup_count].scsiid = ints[0] >= 3 ? ints[3] : 7; + setup[setup_count].reconnect = ints[0] >= 4 ? ints[4] : 1; + setup[setup_count].parity = ints[0] >= 5 ? ints[5] : 1; + setup[setup_count].synchronous = ints[0] >= 6 ? ints[6] : 1; + setup[setup_count].delay = ints[0] >= 7 ? ints[7] : DELAY_DEFAULT; + setup[setup_count].ext_trans = ints[0] >= 8 ? ints[8] : 0; +#if defined(AHA152X_DEBUG) + setup[setup_count].debug = ints[0] >= 9 ? ints[9] : DEBUG_DEFAULT; + if (ints[0] > 9) { + printk(KERN_NOTICE "aha152x: usage: aha152x=[,[," + "[,[,[,[,[,[,]]]]]]]]\n"); +#else + if (ints[0] > 8) { /*}*/ + printk(KERN_NOTICE "aha152x: usage: aha152x=[,[," + "[,[,[,[,[,]]]]]]]\n"); +#endif + return; + } else { + setup_count++; + return; + } +} +#endif + +#if !defined(MODULE) +static int __init do_setup(char *str) +{ + +#if defined(AHA152X_DEBUG) + int ints[11]; +#else + int ints[10]; +#endif + int count=setup_count; + + get_options(str, ARRAY_SIZE(ints), ints); + aha152x_setup(str,ints); + + return countswint++; + + SETPORT(DMACNTRL0, INTEN); +} + +#ifdef __ISAPNP__ +static struct pci_dev *pnpdev[2]; +static int num_pnpdevs; +#endif +int aha152x_detect(Scsi_Host_Template * tpnt) +{ + int i, j, ok; +#if defined(AUTOCONF) + aha152x_config conf; +#ifdef __ISAPNP__ + struct pci_dev *dev = NULL; +#endif +#endif + tpnt->proc_name = "aha152x"; + + for (i = 0; i < ARRAY_SIZE(aha152x_host); i++) + aha152x_host[i] = (struct Scsi_Host *) NULL; + + if (setup_count) { + printk(KERN_INFO "aha152x: processing commandline: "); + + for (i = 0; i < setup_count; i++) + if (!checksetup(&setup[i])) { + printk(KERN_ERR "\naha152x: %s\n", setup[i].conf); + printk(KERN_ERR "aha152x: invalid line\n"); + } + printk("ok\n"); + } + +#if defined(SETUP0) + if (setup_count < ARRAY_SIZE(setup)) { + struct aha152x_setup override = SETUP0; + + if (setup_count == 0 || (override.io_port != setup[0].io_port)) { + if (!checksetup(&override)) { + printk(KERN_ERR "\naha152x: invalid override SETUP0={0x%x,%d,%d,%d,%d,%d,%d,%d}\n", + override.io_port, + override.irq, + override.scsiid, + override.reconnect, + override.parity, + override.synchronous, + override.delay, + override.ext_trans); + } else + setup[setup_count++] = override; + } + } +#endif + +#if defined(SETUP1) + if (setup_count < ARRAY_SIZE(setup)) { + struct aha152x_setup override = SETUP1; + + if (setup_count == 0 || (override.io_port != setup[0].io_port)) { + if (!checksetup(&override)) { + printk(KERN_ERR "\naha152x: invalid override SETUP1={0x%x,%d,%d,%d,%d,%d,%d,%d}\n", + override.io_port, + override.irq, + override.scsiid, + override.reconnect, + override.parity, + override.synchronous, + override.delay, + override.ext_trans); + } else + setup[setup_count++] = override; + } + } +#endif + +#if defined(MODULE) + if (setup_countprepare(dev) < 0) + continue; + if (dev->active) + continue; + if (!(dev->resource[0].flags & IORESOURCE_IO)) + continue; + dev->resource[0].flags |= IORESOURCE_AUTO; + if (dev->activate(dev) < 0) + continue; + if ( setup_count==1 && dev->resource[0].start==setup[0].io_port) { + dev->deactivate(dev); + continue; + } + setup[setup_count].io_port = dev->resource[0].start; + setup[setup_count].irq = dev->irq_resource[0].start; + setup[setup_count].scsiid = 7; + setup[setup_count].reconnect = 1; + setup[setup_count].parity = 1; + setup[setup_count].synchronous = 1; + setup[setup_count].delay = DELAY_DEFAULT; + setup[setup_count].ext_trans = 0; +#if defined(AHA152X_DEBUG) + setup[setup_count].debug = DEBUG_DEFAULT; +#endif + pnpdev[num_pnpdevs++] = dev; + printk (KERN_INFO + "aha152x: found ISAPnP AVA-1505A at io=0x%03x, irq=%d\n", + setup[setup_count].io_port, setup[setup_count].irq); + setup_count++; + } +#endif + + +#if defined(AUTOCONF) + if (setup_countio_port = setup[i].io_port; + shpnt->n_io_port = IO_RANGE; + shpnt->irq = setup[i].irq; + + if(!setup[i].tc1550) { + HOSTIOPORT0 = setup[i].io_port; + HOSTIOPORT1 = setup[i].io_port; + } else { + HOSTIOPORT0 = setup[i].io_port+0x10; + HOSTIOPORT1 = setup[i].io_port-0x10; + } + + ISSUE_SC = 0; + CURRENT_SC = 0; + DONE_SC = 0; + DISCONNECTED_SC = 0; + + QLOCK = SPIN_LOCK_UNLOCKED; + + STATE = 0; + PREVSTATE = 0; + LASTSTATE = 0; + + MSGILEN = 0; + MSGOLEN = 0; + + RECONNECT = setup[i].reconnect; + SYNCHRONOUS = setup[i].synchronous; + PARITY = setup[i].parity; + DELAY = setup[i].delay; + EXT_TRANS = setup[i].ext_trans; +#if defined(AHA152X_DEBUG) + HOSTDATA(shpnt)->debug = setup[i].debug; +#endif + HOSTDATA(shpnt)->in_intr = 0; + HOSTDATA(shpnt)->commands = 0; + +#if defined(AHA152X_STAT) + HOSTDATA(shpnt)->total_commands=0; + HOSTDATA(shpnt)->disconnections=0; + HOSTDATA(shpnt)->busfree_without_any_action=0; + HOSTDATA(shpnt)->busfree_without_old_command=0; + HOSTDATA(shpnt)->busfree_without_new_command=0; + HOSTDATA(shpnt)->busfree_without_done_command=0; + HOSTDATA(shpnt)->busfree_with_check_condition=0; + for (j = idle; jcount[j]=0; + HOSTDATA(shpnt)->count_trans[j]=0; + HOSTDATA(shpnt)->time[j]=0; + } +#endif + + for (j = 0; j < 8; j++) { + HOSTDATA(shpnt)->syncrate[j] = 0; + HOSTDATA(shpnt)->syncneg[j] = 0; + } + + SETPORT(SCSIID, setup[i].scsiid << 4); + shpnt->this_id = setup[i].scsiid; + + if (setup[i].reconnect) + shpnt->can_queue = AHA152X_MAXQUEUE; + + /* RESET OUT */ + printk("aha152x: resetting bus...\n"); + SETPORT(SCSISEQ, SCSIRSTO); + mdelay(256); + SETPORT(SCSISEQ, 0); + mdelay(DELAY); + + reset_ports(shpnt); + + printk(KERN_INFO + "aha152x%d%s: " + "vital data: rev=%x, " + "io=0x%03lx (0x%03lx/0x%03lx), " + "irq=%d, " + "scsiid=%d, " + "reconnect=%s, " + "parity=%s, " + "synchronous=%s, " + "delay=%d, " + "extended translation=%s\n", + HOSTNO, setup[i].tc1550 ? " (tc1550 mode)" : "", + GETPORT(REV) & 0x7, + shpnt->io_port, HOSTIOPORT0, HOSTIOPORT1, + shpnt->irq, + shpnt->this_id, + RECONNECT ? "enabled" : "disabled", + PARITY ? "enabled" : "disabled", + SYNCHRONOUS ? "enabled" : "disabled", + DELAY, + EXT_TRANS ? "enabled" : "disabled"); + + request_region(shpnt->io_port, IO_RANGE, "aha152x"); + + /* not expecting any interrupts */ + SETPORT(SIMODE0, 0); + SETPORT(SIMODE1, 0); + + ok = request_irq(shpnt->irq, swintr, SA_INTERRUPT|SA_SHIRQ, "aha152x", shpnt); + if (ok < 0) { + if (ok==-EINVAL) + printk(KERN_ERR "aha152x%d: bad IRQ %d.\n", HOSTNO, shpnt->irq); + else if(ok==-EBUSY) + printk(KERN_ERR "aha152x%d: IRQ %d already in use.\n", HOSTNO, shpnt->irq); + else + printk(KERN_ERR "aha152x%d: Unexpected error code %d on requesting IRQ %d.\n", HOSTNO, ok, shpnt->irq); + + printk(KERN_ERR "aha152x%d: driver needs an IRQ.\n", HOSTNO); + + scsi_unregister(shpnt); + registered_count--; + release_region(shpnt->io_port, IO_RANGE); + aha152x_host[registered_count] = 0; + shpnt = 0; + continue; + } + HOSTDATA(shpnt)->swint = 0; + + printk(KERN_INFO "aha152x%d: trying software interrupt, ", HOSTNO); + SETPORT(DMACNTRL0, SWINT|INTEN); + mdelay(1000); + free_irq(shpnt->irq, shpnt); + + if (!HOSTDATA(shpnt)->swint) { + if (TESTHI(DMASTAT, INTSTAT)) { + printk("lost.\n"); + } else { + printk("failed.\n"); + } + + SETPORT(DMACNTRL0, INTEN); + + printk(KERN_ERR "aha152x%d: IRQ %d possibly wrong. Please verify.\n", HOSTNO, shpnt->irq); + + registered_count--; + release_region(shpnt->io_port, IO_RANGE); + aha152x_host[registered_count] = 0; + scsi_unregister(shpnt); + shpnt=NULL; + continue; + } + printk("ok.\n"); + + + /* clear interrupts */ + SETPORT(SSTAT0, 0x7f); + SETPORT(SSTAT1, 0xef); + + if (request_irq(shpnt->irq, intr, SA_INTERRUPT|SA_SHIRQ, "aha152x", shpnt) < 0) { + printk(KERN_ERR "aha152x%d: failed to reassign interrupt.\n", HOSTNO); + + registered_count--; + release_region(shpnt->io_port, IO_RANGE); + aha152x_host[registered_count] = 0; + scsi_unregister(shpnt); + shpnt=NULL; + continue; + } + } + + return registered_count>0; +} + + +int aha152x_release(struct Scsi_Host *shpnt) +{ + if (shpnt->irq) + free_irq(shpnt->irq, shpnt); + + if (shpnt->io_port) + release_region(shpnt->io_port, IO_RANGE); + +#ifdef __ISAPNP__ + while (num_pnpdevs--) + pnpdev[num_pnpdevs]->deactivate(pnpdev[num_pnpdevs]); +#endif + scsi_unregister(shpnt); + + return 0; +} + +/* + * setup controller to generate interrupts depending + * on current state (lock has to be acquired) + * + */ +static int setup_expected_interrupts(struct Scsi_Host *shpnt) +{ + ASSERT_LOCK(&QLOCK,1); + + if(CURRENT_SC) { + CURRENT_SC->SCp.phase |= 1 << 16; + + if(CURRENT_SC->SCp.phase & selecting) { + DPRINTK(debug_intr, DEBUG_LEAD "expecting: (seldo) (seltimo) (seldi)\n", CMDINFO(CURRENT_SC)); + SETPORT(SSTAT1, SELTO); + SETPORT(SIMODE0, ENSELDO | (DISCONNECTED_SC ? ENSELDI : 0)); + SETPORT(SIMODE1, ENSELTIMO); + } else { + DPRINTK(debug_intr, DEBUG_LEAD "expecting: (phase change) (busfree) %s\n", CMDINFO(CURRENT_SC), CURRENT_SC->SCp.phase & spiordy ? "(spiordy)" : ""); + SETPORT(SIMODE0, (CURRENT_SC->SCp.phase & spiordy) ? ENSPIORDY : 0); + SETPORT(SIMODE1, ENPHASEMIS | ENSCSIRST | ENSCSIPERR | ENBUSFREE); + } + } else if(STATE==seldi) { + DPRINTK(debug_intr, DEBUG_LEAD "expecting: (phase change) (identify)\n", CMDINFO(CURRENT_SC)); + SETPORT(SIMODE0, 0); + SETPORT(SIMODE1, ENPHASEMIS | ENSCSIRST | ENSCSIPERR | ENBUSFREE); + } else { + DPRINTK(debug_intr, DEBUG_LEAD "expecting: %s %s\n", + CMDINFO(CURRENT_SC), + DISCONNECTED_SC ? "(reselection)" : "", + ISSUE_SC ? "(busfree)" : ""); + SETPORT(SIMODE0, DISCONNECTED_SC ? ENSELDI : 0); + SETPORT(SIMODE1, ENSCSIRST | ( (ISSUE_SC||DONE_SC) ? ENBUSFREE : 0)); + } + + if(!HOSTDATA(shpnt)->in_intr) + SETBITS(DMACNTRL0, INTEN); + + return TESTHI(DMASTAT, INTSTAT); +} + + +/* + * Queue a command and setup interrupts for a free bus. + */ +int aha152x_internal_queue(Scsi_Cmnd *SCpnt, struct semaphore *sem, int phase, Scsi_Cmnd *done_SC, void (*done)(Scsi_Cmnd *)) +{ + struct Scsi_Host *shpnt = SCpnt->host; + unsigned long flags; + +#if defined(AHA152X_DEBUG) + if (HOSTDATA(shpnt)->debug & debug_queue) { + printk(INFO_LEAD "queue: cmd_len=%d pieces=%d size=%u cmnd=", + CMDINFO(SCpnt), SCpnt->cmd_len, SCpnt->use_sg, SCpnt->request_bufflen); + print_command(SCpnt->cmnd); + } +#endif + + SCpnt->scsi_done = done; + SCpnt->resid = SCpnt->request_bufflen; + SCpnt->SCp.phase = not_issued | phase; + SCpnt->SCp.Status = CHECK_CONDITION; + SCpnt->SCp.Message = 0; + SCpnt->SCp.have_data_in = 0; + SCpnt->SCp.sent_command = 0; + SCpnt->host_scribble = kmalloc(sizeof(struct aha152x_scdata), GFP_ATOMIC); + if(!SCpnt->host_scribble) { + printk(ERR_LEAD "allocation failed\n", CMDINFO(SCpnt)); + return FAILED; + } + + SCNEXT(SCpnt) = 0; + SCDONE(SCpnt) = done_SC; + SCSEM(SCpnt) = sem; + + /* setup scratch area + SCp.ptr : buffer pointer + SCp.this_residual : buffer length + SCp.buffer : next buffer + SCp.buffers_residual : left buffers in list + SCp.phase : current state of the command */ + if (SCpnt->use_sg) { + SCpnt->SCp.buffer = (struct scatterlist *) SCpnt->request_buffer; + SCpnt->SCp.ptr = SG_ADDRESS(SCpnt->SCp.buffer); + SCpnt->SCp.this_residual = SCpnt->SCp.buffer->length; + SCpnt->SCp.buffers_residual = SCpnt->use_sg - 1; + } else { + SCpnt->SCp.ptr = (char *) SCpnt->request_buffer; + SCpnt->SCp.this_residual = SCpnt->request_bufflen; + SCpnt->SCp.buffer = NULL; + SCpnt->SCp.buffers_residual = 0; + } + + DO_LOCK(flags); + +#if defined(AHA152X_STAT) + HOSTDATA(shpnt)->total_commands++; +#endif + + /* Turn led on, when this is the first command. */ + HOSTDATA(shpnt)->commands++; + if (HOSTDATA(shpnt)->commands==1) + SETPORT(PORTA, 1); + + append_SC(&ISSUE_SC, SCpnt); + + if(!HOSTDATA(shpnt)->in_intr) + setup_expected_interrupts(shpnt); + + DO_UNLOCK(flags); + + return 0; +} + +int aha152x_queue(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *)) +{ +#if 0 + if(*SCpnt->cmnd == REQUEST_SENSE) { + SCpnt->result = 0; + done(SCpnt); + + return 0; + } +#endif + + return aha152x_internal_queue(SCpnt, 0, 0, 0, done); +} + + +/* + * run a command + * + */ +void internal_done(Scsi_Cmnd *SCpnt) +{ +#if 0 + struct Scsi_Host *shpnt = SCpnt->host; + + DPRINTK(debug_eh, INFO_LEAD "internal_done called\n", CMDINFO(SCpnt)); +#endif + if(SCSEM(SCpnt)) + up(SCSEM(SCpnt)); +} + +int aha152x_command(Scsi_Cmnd * SCpnt) +{ + DECLARE_MUTEX_LOCKED(sem); + + aha152x_internal_queue(SCpnt, &sem, 0, 0, internal_done); + down(&sem); + + return SUCCESS; +} + +/* + * Abort a command + * + */ +int aha152x_abort(Scsi_Cmnd *SCpnt) +{ + struct Scsi_Host *shpnt = SCpnt->host; + Scsi_Cmnd *ptr; + unsigned long flags; + + if(!shpnt) { + printk(ERR_LEAD "abort(%p): no host structure\n", CMDINFO(SCpnt), SCpnt); + return FAILED; + } + +#if defined(AHA152X_DEBUG) + if(HOSTDATA(shpnt)->debug & debug_eh) { + printk(DEBUG_LEAD "abort(%p)", CMDINFO(SCpnt), SCpnt); + show_queues(shpnt); + } +#endif + + DO_LOCK(flags); + + ptr=remove_SC(&ISSUE_SC, SCpnt); + + if(ptr) { + DPRINTK(debug_eh, DEBUG_LEAD "not yet issued - SUCCESS\n", CMDINFO(SCpnt)); + + HOSTDATA(shpnt)->commands--; + if (!HOSTDATA(shpnt)->commands) + SETPORT(PORTA, 0); + DO_UNLOCK(flags); + + kfree(SCpnt->host_scribble); + SCpnt->host_scribble=0; + + return SUCCESS; + } + + DO_UNLOCK(flags); + + /* + * FIXME: + * for current command: queue ABORT for message out and raise ATN + * for disconnected command: pseudo SC with ABORT message or ABORT on reselection? + * + */ + + printk(ERR_LEAD "cannot abort running or disconnected command\n", CMDINFO(SCpnt)); + + return FAILED; +} + +static void timer_expired(unsigned long p) +{ + Scsi_Cmnd *SCp = (Scsi_Cmnd *)p; + struct semaphore *sem = SCSEM(SCp); + struct Scsi_Host *shpnt = SCp->host; + + /* remove command from issue queue */ + if(remove_SC(&ISSUE_SC, SCp)) { + printk(KERN_INFO "aha152x: ABORT timed out - removed from issue queue\n"); + kfree(SCp->host_scribble); + SCp->host_scribble=0; + } else { + printk(KERN_INFO "aha152x: ABORT timed out - not on issue queue\n"); + } + + up(sem); +} + +/* + * Reset a device + * + * FIXME: never seen this live. might lockup... + * + */ +int aha152x_device_reset(Scsi_Cmnd * SCpnt) +{ + struct Scsi_Host *shpnt = SCpnt->host; + DECLARE_MUTEX_LOCKED(sem); + struct timer_list timer; + Scsi_Cmnd cmnd; + +#if defined(AHA152X_DEBUG) + if(HOSTDATA(shpnt)->debug & debug_eh) { + printk(INFO_LEAD "aha152x_device_reset(%p)", CMDINFO(SCpnt), SCpnt); + show_queues(shpnt); + } +#endif + + if(CURRENT_SC==SCpnt) { + printk(ERR_LEAD "cannot reset current device\n", CMDINFO(SCpnt)); + return FAILED; + } + + cmnd.cmd_len = 0; + cmnd.host = SCpnt->host; + cmnd.target = SCpnt->target; + cmnd.lun = SCpnt->lun; + cmnd.use_sg = 0; + cmnd.request_buffer = 0; + cmnd.request_bufflen = 0; + + init_timer(&timer); + timer.data = (unsigned long) &cmnd; + timer.expires = jiffies + 100*HZ; /* 10s */ + timer.function = (void (*)(unsigned long)) timer_expired; + + aha152x_internal_queue(&cmnd, &sem, resetting, 0, internal_done); + + add_timer(&timer); + down(&sem); + + del_timer(&timer); + + if(cmnd.SCp.phase & resetted) { + return SUCCESS; + } else { + return FAILED; + } +} + +void free_hard_reset_SCs(struct Scsi_Host *shpnt, Scsi_Cmnd **SCs) +{ + Scsi_Cmnd *ptr; + unsigned long flags; + + DO_LOCK(flags); + + ptr=*SCs; + while(ptr) { + Scsi_Cmnd *next = SCNEXT(ptr); + + if (!ptr->device->soft_reset) { + DPRINTK(debug_eh, DEBUG_LEAD "disconnected command %p removed\n", CMDINFO(ptr), ptr); + remove_SC(SCs, ptr); + HOSTDATA(shpnt)->commands--; + kfree(ptr->host_scribble); + ptr->host_scribble=0; + } + + ptr = next; + } + + DO_UNLOCK(flags); +} + +/* + * Reset the bus + * + */ +int aha152x_bus_reset(Scsi_Cmnd *SCpnt) +{ + struct Scsi_Host *shpnt = SCpnt->host; + unsigned long flags; + +#if defined(AHA152X_DEBUG) + if(HOSTDATA(shpnt)->debug & debug_eh) { + printk(DEBUG_LEAD "aha152x_bus_reset(%p)", CMDINFO(SCpnt), SCpnt); + show_queues(shpnt); + } +#endif + + free_hard_reset_SCs(shpnt, &ISSUE_SC); + free_hard_reset_SCs(shpnt, &DISCONNECTED_SC); + + DPRINTK(debug_eh, DEBUG_LEAD "resetting bus\n", CMDINFO(SCpnt)); + + SETPORT(SCSISEQ, SCSIRSTO); + mdelay(256); + SETPORT(SCSISEQ, 0); + mdelay(DELAY); + + DPRINTK(debug_eh, DEBUG_LEAD "bus reset returns\n", CMDINFO(SCpnt)); + + DO_LOCK(flags); + setup_expected_interrupts(shpnt); + if(HOSTDATA(shpnt)->commands==0) + SETPORT(PORTA, 0); + DO_UNLOCK(flags); + + return SUCCESS; +} + + +/* + * Restore default values to the AIC-6260 registers and reset the fifos + * + */ +static void reset_ports(struct Scsi_Host *shpnt) +{ + unsigned long flags; + + /* disable interrupts */ + SETPORT(DMACNTRL0, RSTFIFO); + + SETPORT(SCSISEQ, 0); + + SETPORT(SXFRCTL1, 0); + SETPORT(SCSISIG, 0); + SETRATE(0); + + /* clear all interrupt conditions */ + SETPORT(SSTAT0, 0x7f); + SETPORT(SSTAT1, 0xef); + + SETPORT(SSTAT4, SYNCERR | FWERR | FRERR); + + SETPORT(DMACNTRL0, 0); + SETPORT(DMACNTRL1, 0); + + SETPORT(BRSTCNTRL, 0xf1); + + /* clear SCSI fifos and transfer count */ + SETPORT(SXFRCTL0, CH1|CLRCH1|CLRSTCNT); + SETPORT(SXFRCTL0, CH1); + + DO_LOCK(flags); + setup_expected_interrupts(shpnt); + DO_UNLOCK(flags); +} + +/* + * Reset the host (bus and controller) + * + */ +int aha152x_host_reset(Scsi_Cmnd * SCpnt) +{ +#if defined(AHA152X_DEBUG) + struct Scsi_Host *shpnt = SCpnt->host; +#endif + + DPRINTK(debug_eh, DEBUG_LEAD "aha152x_host_reset(%p)\n", CMDINFO(SCpnt), SCpnt); + + aha152x_bus_reset(SCpnt); + + DPRINTK(debug_eh, DEBUG_LEAD "resetting ports\n", CMDINFO(SCpnt)); + reset_ports(SCpnt->host); + + return SUCCESS; +} + +/* + * Return the "logical geometry" + * + */ +int aha152x_biosparam(struct scsi_device *sdev, struct block_device *bdev, + sector_t capacity, int *info_array) +{ + struct Scsi_Host *shpnt = sdev->host; + + /* try default translation */ + info_array[0] = 64; + info_array[1] = 32; + info_array[2] = (unsigned long)capacity / (64 * 32); + + /* for disks >1GB do some guessing */ + if (info_array[2] >= 1024) { + int info[3]; + + /* try to figure out the geometry from the partition table */ + if (scsicam_bios_param(bdev, capacity, info) < 0 || + !((info[0] == 64 && info[1] == 32) || (info[0] == 255 && info[1] == 63))) { + if (EXT_TRANS) { + printk(KERN_NOTICE + "aha152x: unable to verify geometry for disk with >1GB.\n" + " using extended translation.\n"); + info_array[0] = 255; + info_array[1] = 63; + info_array[2] = (unsigned long)capacity / (255 * 63); + } else { + printk(KERN_NOTICE + "aha152x: unable to verify geometry for disk with >1GB.\n" + " Using default translation. Please verify yourself.\n" + " Perhaps you need to enable extended translation in the driver.\n" + " See /usr/src/linux/drivers/scsi/README.aha152x for details.\n"); + } + } else { + info_array[0] = info[0]; + info_array[1] = info[1]; + info_array[2] = info[2]; + + if (info[0] == 255 && !EXT_TRANS) { + printk(KERN_NOTICE + "aha152x: current partition table is using extended translation.\n" + " using it also, although it's not explicitly enabled.\n"); + } + } + } + + return 0; +} + +/* + * Internal done function + * + */ +static void done(struct Scsi_Host *shpnt, int error) +{ + if (CURRENT_SC) { + if(DONE_SC) + printk(ERR_LEAD "there's already a completed command %p - will cause abort\n", CMDINFO(CURRENT_SC), DONE_SC); + + DONE_SC = CURRENT_SC; + CURRENT_SC = 0; + DONE_SC->result = error; + } else + printk(KERN_ERR "aha152x: done() called outside of command\n"); +} + +static struct work_struct aha152x_tq; + +/* + * Run service completions on the card with interrupts enabled. + * + */ +static void run(void) +{ + int i; + for (i = 0; iservice) { + HOSTDATA(shpnt)->service=0; + is_complete(shpnt); + } + } +} + +/* + * Interrupts handler + * + */ + +static void intr(int irqno, void *dev_id, struct pt_regs *regs) +{ + struct Scsi_Host *shpnt = lookup_irq(irqno); + + if (!shpnt) { + printk(KERN_ERR "aha152x: catched interrupt %d for unknown controller.\n", irqno); + return; + } + + /* no more interrupts from the controller, while we're busy. + INTEN is restored by the BH handler */ + CLRBITS(DMACNTRL0, INTEN); + +#if 0 + /* check if there is already something to be + serviced; should not happen */ + if(HOSTDATA(shpnt)->service) { + printk(KERN_ERR "aha152x%d: lost interrupt (%d)\n", HOSTNO, HOSTDATA(shpnt)->service); + show_queues(shpnt); + } +#endif + + /* Poke the BH handler */ + HOSTDATA(shpnt)->service++; + INIT_WORK(&aha152x_tq, (void *) run, NULL); + schedule_work(&aha152x_tq); +} + +/* + * busfree phase + * - handle completition/disconnection/error of current command + * - start selection for next command (if any) + */ +static void busfree_run(struct Scsi_Host *shpnt) +{ + unsigned long flags; +#if defined(AHA152X_STAT) + int action=0; +#endif + + SETPORT(SXFRCTL0, CH1|CLRCH1|CLRSTCNT); + SETPORT(SXFRCTL0, CH1); + + SETPORT(SSTAT1, CLRBUSFREE); + + if(CURRENT_SC) { +#if defined(AHA152X_STAT) + action++; +#endif + CURRENT_SC->SCp.phase &= ~syncneg; + + if(CURRENT_SC->SCp.phase & completed) { + /* target sent COMMAND COMPLETE */ + done(shpnt, (CURRENT_SC->SCp.Status & 0xff) | ((CURRENT_SC->SCp.Message & 0xff) << 8) | (DID_OK << 16)); + + } else if(CURRENT_SC->SCp.phase & aborted) { + DPRINTK(debug_eh, DEBUG_LEAD "ABORT sent\n", CMDINFO(CURRENT_SC)); + done(shpnt, (CURRENT_SC->SCp.Status & 0xff) | ((CURRENT_SC->SCp.Message & 0xff) << 8) | (DID_ABORT << 16)); + + } else if(CURRENT_SC->SCp.phase & resetted) { + DPRINTK(debug_eh, DEBUG_LEAD "BUS DEVICE RESET sent\n", CMDINFO(CURRENT_SC)); + done(shpnt, (CURRENT_SC->SCp.Status & 0xff) | ((CURRENT_SC->SCp.Message & 0xff) << 8) | (DID_RESET << 16)); + + } else if(CURRENT_SC->SCp.phase & disconnected) { + /* target sent DISCONNECT */ + DPRINTK(debug_selection, DEBUG_LEAD "target disconnected at %d/%d\n", + CMDINFO(CURRENT_SC), + CURRENT_SC->resid, + CURRENT_SC->request_bufflen); +#if defined(AHA152X_STAT) + HOSTDATA(shpnt)->disconnections++; +#endif + append_SC(&DISCONNECTED_SC, CURRENT_SC); + CURRENT_SC->SCp.phase |= 1 << 16; + CURRENT_SC = 0; + + } else { + done(shpnt, DID_ERROR << 16); + } +#if defined(AHA152X_STAT) + } else { + HOSTDATA(shpnt)->busfree_without_old_command++; +#endif + } + + DO_LOCK(flags); + + if(DONE_SC) { +#if defined(AHA152X_STAT) + action++; +#endif + if(SCDONE(DONE_SC)) { + Scsi_Cmnd *ptr=DONE_SC; + DONE_SC=SCDONE(DONE_SC); + +#if 0 + if(HOSTDATA(shpnt)->debug & debug_eh) { + printk(ERR_LEAD "received sense: ", CMDINFO(ptr)); + print_sense("bh", DONE_SC); + } +#endif + + HOSTDATA(shpnt)->commands--; + if (!HOSTDATA(shpnt)->commands) + SETPORT(PORTA, 0); /* turn led off */ + + kfree(ptr->host_scribble); + kfree(ptr); + } else if(DONE_SC->SCp.Status==0x02) { +#if defined(AHA152X_STAT) + HOSTDATA(shpnt)->busfree_with_check_condition++; +#endif +#if 0 + DPRINTK(debug_eh, ERR_LEAD "CHECK CONDITION found\n", CMDINFO(DONE_SC)); +#endif + + if(!(DONE_SC->SCp.Status & not_issued)) { + Scsi_Cmnd *cmnd = kmalloc(sizeof(Scsi_Cmnd), GFP_ATOMIC); + + if(cmnd) { + Scsi_Cmnd *ptr=DONE_SC; + DONE_SC=0; + +#if 0 + DPRINTK(debug_eh, ERR_LEAD "requesting sense\n", CMDINFO(ptr)); +#endif + + cmnd->cmnd[0] = REQUEST_SENSE; + cmnd->cmnd[1] = 0; + cmnd->cmnd[2] = 0; + cmnd->cmnd[3] = 0; + cmnd->cmnd[4] = sizeof(ptr->sense_buffer); + cmnd->cmnd[5] = 0; + cmnd->cmd_len = 6; + cmnd->host = ptr->host; + cmnd->target = ptr->target; + cmnd->lun = ptr->lun; + cmnd->use_sg = 0; + cmnd->request_buffer = ptr->sense_buffer; + cmnd->request_bufflen = sizeof(ptr->sense_buffer); + + DO_UNLOCK(flags); + aha152x_internal_queue(cmnd, 0, 0, ptr, internal_done); + DO_LOCK(flags); + } else { + printk(ERR_LEAD "allocation failed\n", CMDINFO(CURRENT_SC)); + if(cmnd) + kfree(cmnd); + } + } else { +#if 0 + DPRINTK(debug_eh, ERR_LEAD "command not issued - CHECK CONDITION ignored\n", CMDINFO(DONE_SC)); +#endif + } + } + + if(DONE_SC && DONE_SC->scsi_done) { + /* turn led off, when no commands are in the driver */ + HOSTDATA(shpnt)->commands--; + if (!HOSTDATA(shpnt)->commands) + SETPORT(PORTA, 0); /* turn led off */ + + DO_UNLOCK(flags); + DPRINTK(debug_done, DEBUG_LEAD "calling scsi_done(%p)\n", CMDINFO(DONE_SC), DONE_SC); + DONE_SC->scsi_done(DONE_SC); + DPRINTK(debug_done, DEBUG_LEAD "scsi_done(%p) returned\n", CMDINFO(DONE_SC), DONE_SC); + DO_LOCK(flags); + + kfree(DONE_SC->host_scribble); + DONE_SC->host_scribble=0; + } + + DONE_SC=0; +#if defined(AHA152X_STAT) + } else { + HOSTDATA(shpnt)->busfree_without_done_command++; +#endif + } + + if(ISSUE_SC) + CURRENT_SC = remove_first_SC(&ISSUE_SC); + + DO_UNLOCK(flags); + + if(CURRENT_SC) { +#if defined(AHA152X_STAT) + action++; +#endif + CURRENT_SC->SCp.phase |= selecting; + + DPRINTK(debug_selection, DEBUG_LEAD "selecting target\n", CMDINFO(CURRENT_SC)); + + /* clear selection timeout */ + SETPORT(SSTAT1, SELTO); + + SETPORT(SCSIID, (shpnt->this_id << OID_) | CURRENT_SC->target); + SETPORT(SXFRCTL1, (PARITY ? ENSPCHK : 0 ) | ENSTIMER); + SETPORT(SCSISEQ, ENSELO | ENAUTOATNO | (DISCONNECTED_SC ? ENRESELI : 0)); + } else { +#if defined(AHA152X_STAT) + HOSTDATA(shpnt)->busfree_without_new_command++; +#endif + SETPORT(SCSISEQ, DISCONNECTED_SC ? ENRESELI : 0); + } + +#if defined(AHA152X_STAT) + if(!action) + HOSTDATA(shpnt)->busfree_without_any_action++; +#endif +} + +/* + * Selection done (OUT) + * - queue IDENTIFY message and SDTR to selected target for message out + * (ATN asserted automagically via ENAUTOATNO in busfree()) + */ +static void seldo_run(struct Scsi_Host *shpnt) +{ + SETPORT(SCSISIG, 0); + SETPORT(SSTAT1, CLRBUSFREE); + SETPORT(SSTAT1, CLRPHASECHG); + + CURRENT_SC->SCp.phase &= ~(selecting|not_issued); + + SETPORT(SCSISEQ, 0); + + if (TESTLO(SSTAT0, SELDO)) { + printk(ERR_LEAD "aha152x: passing bus free condition\n", CMDINFO(CURRENT_SC)); + done(shpnt, DID_NO_CONNECT << 16); + return; + } + + SETPORT(SSTAT0, CLRSELDO); + + ADDMSGO(IDENTIFY(RECONNECT, CURRENT_SC->lun)); + + if (CURRENT_SC->SCp.phase & aborting) { + ADDMSGO(ABORT); + } else if (CURRENT_SC->SCp.phase & resetting) { + ADDMSGO(BUS_DEVICE_RESET); + } else if (SYNCNEG==0 && SYNCHRONOUS) { + CURRENT_SC->SCp.phase |= syncneg; + ADDMSGO(EXTENDED_MESSAGE); + ADDMSGO(3); + ADDMSGO(EXTENDED_SDTR); + ADDMSGO(50); /* 200ns */ + ADDMSGO(8); /* 8 byte req/ack offset */ + + SYNCNEG=1; /* negotiation in progress */ + } + + SETRATE(SYNCRATE); +} + +/* + * Selection timeout + * - return command to mid-level with failure cause + * + */ +static void selto_run(struct Scsi_Host *shpnt) +{ + SETPORT(SCSISEQ, 0); + SETPORT(SSTAT1, CLRSELTIMO); + + DPRINTK(debug_selection, DEBUG_LEAD "selection timeout\n", CMDINFO(CURRENT_SC)); + + if(!CURRENT_SC) { + DPRINTK(debug_selection, DEBUG_LEAD "!CURRENT_SC\n", CMDINFO(CURRENT_SC)); + return; + } + + CURRENT_SC->SCp.phase &= ~selecting; + + if (CURRENT_SC->SCp.phase & aborted) { + DPRINTK(debug_selection, DEBUG_LEAD "aborted\n", CMDINFO(CURRENT_SC)); + done(shpnt, DID_ABORT << 16); + } else if (TESTLO(SSTAT0, SELINGO)) { + DPRINTK(debug_selection, DEBUG_LEAD "arbitration not won\n", CMDINFO(CURRENT_SC)); + done(shpnt, DID_BUS_BUSY << 16); + } else { + /* ARBITRATION won, but SELECTION failed */ + DPRINTK(debug_selection, DEBUG_LEAD "selection failed\n", CMDINFO(CURRENT_SC)); + done(shpnt, DID_NO_CONNECT << 16); + } +} + +/* + * Selection in done + * - put current command back to issue queue + * (reconnection of a disconnected nexus instead + * of successful selection out) + * + */ +static void seldi_run(struct Scsi_Host *shpnt) +{ + int selid; + int target; + unsigned long flags; + + SETPORT(SCSISIG, 0); + SETPORT(SSTAT0, CLRSELDI); + SETPORT(SSTAT1, CLRBUSFREE); + SETPORT(SSTAT1, CLRPHASECHG); + + if(CURRENT_SC) { + if(!(CURRENT_SC->SCp.phase & not_issued)) + printk(ERR_LEAD "command should not have been issued yet\n", CMDINFO(CURRENT_SC)); + + DPRINTK(debug_selection, ERR_LEAD "command requeued - reselection\n", CMDINFO(CURRENT_SC)); + + DO_LOCK(flags); + append_SC(&ISSUE_SC, CURRENT_SC); + DO_UNLOCK(flags); + + CURRENT_SC = 0; + } + + if(!DISCONNECTED_SC) { + DPRINTK(debug_selection, DEBUG_LEAD "unexpected SELDI ", CMDINFO(CURRENT_SC)); + return; + } + + RECONN_TARGET=-1; + + selid = GETPORT(SELID) & ~(1 << shpnt->this_id); + + if (selid==0) { + printk("aha152x%d: target id unknown (%02x)\n", HOSTNO, selid); + return; + } + + for(target=7; !(selid & (1 << target)); target--) + ; + + if(selid & ~(1 << target)) { + printk("aha152x%d: multiple targets reconnected (%02x)\n", + HOSTNO, selid); + } + + + SETPORT(SCSIID, (shpnt->this_id << OID_) | target); + SETPORT(SCSISEQ, 0); + + SETRATE(HOSTDATA(shpnt)->syncrate[target]); + + RECONN_TARGET=target; + DPRINTK(debug_selection, DEBUG_LEAD "target %d reselected (%02x).\n", CMDINFO(CURRENT_SC), target, selid); +} + +/* + * message in phase + * - handle initial message after reconnection to identify + * reconnecting nexus + * - queue command on DISCONNECTED_SC on DISCONNECT message + * - set completed flag on COMMAND COMPLETE + * (other completition code moved to busfree_run) + * - handle response to SDTR + * - clear synchronous transfer agreements on BUS RESET + * + * FIXME: what about SAVE POINTERS, RESTORE POINTERS? + * + */ +static void msgi_run(struct Scsi_Host *shpnt) +{ + for(;;) { + int sstat1 = GETPORT(SSTAT1); + + if(sstat1 & (PHASECHG|PHASEMIS|BUSFREE) || !(sstat1 & REQINIT)) + return; + + if(TESTLO(SSTAT0,SPIORDY)) { + DPRINTK(debug_msgi, DEBUG_LEAD "!SPIORDY\n", CMDINFO(CURRENT_SC)); + return; + } + + ADDMSGI(GETPORT(SCSIDAT)); + +#if defined(AHA152X_DEBUG) + if (HOSTDATA(shpnt)->debug & debug_msgi) { + printk(INFO_LEAD "inbound message %02x ", CMDINFO(CURRENT_SC), MSGI(0)); + print_msg(&MSGI(0)); + printk("\n"); + } +#endif + + if(!CURRENT_SC) { + if(LASTSTATE!=seldi) { + printk(KERN_ERR "aha152x%d: message in w/o current command not after reselection\n", HOSTNO); + } + + /* + * Handle reselection + */ + if(!(MSGI(0) & IDENTIFY_BASE)) { + printk(KERN_ERR "aha152x%d: target didn't identify after reselection\n", HOSTNO); + continue; + } + + CURRENT_SC = remove_lun_SC(&DISCONNECTED_SC, RECONN_TARGET, MSGI(0) & 0x3f); + + if (!CURRENT_SC) { + show_queues(shpnt); + printk(KERN_ERR "aha152x%d: no disconnected command for target %d/%d\n", HOSTNO, RECONN_TARGET, MSGI(0) & 0x3f); + continue; + } + + DPRINTK(debug_msgi, DEBUG_LEAD "target reconnected\n", CMDINFO(CURRENT_SC)); + + CURRENT_SC->SCp.Message = MSGI(0); + CURRENT_SC->SCp.phase &= ~disconnected; + + MSGILEN=0; + + /* next message if any */ + continue; + } + + CURRENT_SC->SCp.Message = MSGI(0); + + switch (MSGI(0)) { + case DISCONNECT: + if (!RECONNECT) + printk(WARN_LEAD "target was not allowed to disconnect\n", CMDINFO(CURRENT_SC)); + + CURRENT_SC->SCp.phase |= disconnected; + break; + + case COMMAND_COMPLETE: + if(CURRENT_SC->SCp.phase & completed) + DPRINTK(debug_msgi, DEBUG_LEAD "again COMMAND COMPLETE\n", CMDINFO(CURRENT_SC)); + + CURRENT_SC->SCp.phase |= completed; + break; + + case MESSAGE_REJECT: + if (SYNCNEG==1) { + printk(INFO_LEAD "Synchronous Data Transfer Request was rejected\n", CMDINFO(CURRENT_SC)); + SYNCNEG=2; /* negotiation completed */ + } else + printk(INFO_LEAD "inbound message (MESSAGE REJECT)\n", CMDINFO(CURRENT_SC)); + break; + + case SAVE_POINTERS: + break; + + case RESTORE_POINTERS: + break; + + case EXTENDED_MESSAGE: + if(MSGILEN<2 || MSGILENsynchronous) + break; + + printk(INFO_LEAD, CMDINFO(CURRENT_SC)); + print_msg(&MSGI(0)); + printk("\n"); + + ticks = (MSGI(3) * 4 + 49) / 50; + + if (syncneg) { + /* negotiation in progress */ + if (ticks > 9 || MSGI(4) < 1 || MSGI(4) > 8) { + ADDMSGO(MESSAGE_REJECT); + printk(INFO_LEAD "received Synchronous Data Transfer Request invalid - rejected\n", CMDINFO(CURRENT_SC)); + break; + } + + SYNCRATE |= ((ticks - 2) << 4) + MSGI(4); + } else if (ticks <= 9 && MSGI(4) >= 1) { + ADDMSGO(EXTENDED_MESSAGE); + ADDMSGO(3); + ADDMSGO(EXTENDED_SDTR); + if (ticks < 4) { + ticks = 4; + ADDMSGO(50); + } else + ADDMSGO(MSGI(3)); + + if (MSGI(4) > 8) + MSGI(4) = 8; + + ADDMSGO(MSGI(4)); + + SYNCRATE |= ((ticks - 2) << 4) + MSGI(4); + } else { + /* requested SDTR is too slow, do it asynchronously */ + printk(INFO_LEAD "Synchronous Data Transfer Request too slow - Rejecting\n", CMDINFO(CURRENT_SC)); + ADDMSGO(MESSAGE_REJECT); + } + + SYNCNEG=2; /* negotiation completed */ + SETRATE(SYNCRATE); + } + break; + + case BUS_DEVICE_RESET: + { + int i; + + for(i=0; i<8; i++) { + HOSTDATA(shpnt)->syncrate[i]=0; + HOSTDATA(shpnt)->syncneg[i]=0; + } + + } + break; + + case EXTENDED_MODIFY_DATA_POINTER: + case EXTENDED_EXTENDED_IDENTIFY: + case EXTENDED_WDTR: + default: + ADDMSGO(MESSAGE_REJECT); + break; + } + break; + } + + MSGILEN=0; + } +} + +static void msgi_end(struct Scsi_Host *shpnt) +{ + if(MSGILEN>0) + printk(WARN_LEAD "target left before message completed (%d)\n", CMDINFO(CURRENT_SC), MSGILEN); + + if (MSGOLEN > 0 && !(GETPORT(SSTAT1) & BUSFREE)) { + DPRINTK(debug_msgi, DEBUG_LEAD "msgo pending\n", CMDINFO(CURRENT_SC)); + SETPORT(SCSISIG, P_MSGI | SIG_ATNO); + } +} + +/* + * message out phase + * + */ +static void msgo_init(struct Scsi_Host *shpnt) +{ + if(MSGOLEN==0) { + if((CURRENT_SC->SCp.phase & syncneg) && SYNCNEG==2 && SYNCRATE==0) { + ADDMSGO(IDENTIFY(RECONNECT, CURRENT_SC->lun)); + } else { + printk(INFO_LEAD "unexpected MESSAGE OUT phase; rejecting\n", CMDINFO(CURRENT_SC)); + ADDMSGO(MESSAGE_REJECT); + } + } + +#if defined(AHA152X_DEBUG) + if(HOSTDATA(shpnt)->debug & debug_msgo) { + int i; + + printk(DEBUG_LEAD "messages( ", CMDINFO(CURRENT_SC)); + for (i=0; iSCp.phase |= identified; + + if (MSGO(MSGO_I)==ABORT) + CURRENT_SC->SCp.phase |= aborted; + + if (MSGO(MSGO_I)==BUS_DEVICE_RESET) + CURRENT_SC->SCp.phase |= resetted; + + SETPORT(SCSIDAT, MSGO(MSGO_I++)); + } +} + +static void msgo_end(struct Scsi_Host *shpnt) +{ + if(MSGO_ISCp.sent_command) { + printk(ERR_LEAD "command already sent\n", CMDINFO(CURRENT_SC)); + done(shpnt, DID_ERROR << 16); + return; + } + +#if defined(AHA152X_DEBUG) + if (HOSTDATA(shpnt)->debug & debug_cmd) { + printk(DEBUG_LEAD "cmd_init: ", CMDINFO(CURRENT_SC)); + print_command(CURRENT_SC->cmnd); + } +#endif + + CMD_I=0; +} + +/* + * command phase + * + */ +static void cmd_run(struct Scsi_Host *shpnt) +{ + if(CMD_I==CURRENT_SC->cmd_len) { + DPRINTK(debug_cmd, DEBUG_LEAD "command already completely sent (%d/%d)", CMDINFO(CURRENT_SC), CMD_I, CURRENT_SC->cmd_len); + disp_ports(shpnt); + } + + while(CMD_Icmd_len) { + DPRINTK(debug_cmd, DEBUG_LEAD "command byte %02x (%d/%d)\n", CMDINFO(CURRENT_SC), CURRENT_SC->cmnd[CMD_I], CMD_I, CURRENT_SC->cmd_len); + + if(TESTLO(SSTAT0, SPIORDY)) { + DPRINTK(debug_cmd, DEBUG_LEAD "!SPIORDY\n", CMDINFO(CURRENT_SC)); + return; + } + + SETPORT(SCSIDAT, CURRENT_SC->cmnd[CMD_I++]); + } +} + +static void cmd_end(struct Scsi_Host *shpnt) +{ + if(CMD_Icmd_len) + printk(ERR_LEAD "command sent incompletely (%d/%d)\n", CMDINFO(CURRENT_SC), CMD_I, CURRENT_SC->cmd_len); + else + CURRENT_SC->SCp.sent_command++; +} + +/* + * status phase + * + */ +static void status_run(struct Scsi_Host *shpnt) +{ + if(TESTLO(SSTAT0,SPIORDY)) { + DPRINTK(debug_status, DEBUG_LEAD "!SPIORDY\n", CMDINFO(CURRENT_SC)); + return; + } + + CURRENT_SC->SCp.Status = GETPORT(SCSIDAT); + +#if defined(AHA152X_DEBUG) + if (HOSTDATA(shpnt)->debug & debug_status) { + printk(DEBUG_LEAD "inbound status %02x ", CMDINFO(CURRENT_SC), CURRENT_SC->SCp.Status); + print_status(CURRENT_SC->SCp.Status); + printk("\n"); + } +#endif +} + +/* + * data in phase + * + */ +static void datai_init(struct Scsi_Host *shpnt) +{ + SETPORT(DMACNTRL0, RSTFIFO); + SETPORT(DMACNTRL0, RSTFIFO|ENDMA); + + SETPORT(SXFRCTL0, CH1|CLRSTCNT); + SETPORT(SXFRCTL0, CH1|SCSIEN|DMAEN); + + SETPORT(SIMODE0, 0); + SETPORT(SIMODE1, ENSCSIPERR | ENSCSIRST | ENPHASEMIS | ENBUSFREE); + + DATA_LEN=0; + DPRINTK(debug_datai, + DEBUG_LEAD "datai_init: request_bufflen=%d resid=%d\n", + CMDINFO(CURRENT_SC), CURRENT_SC->request_bufflen, CURRENT_SC->resid); +} + +static void datai_run(struct Scsi_Host *shpnt) +{ + unsigned int the_time; + int fifodata, data_count; + + /* + * loop while the phase persists or the fifos are not empty + * + */ + while(TESTLO(DMASTAT, INTSTAT) || TESTLO(DMASTAT, DFIFOEMP) || TESTLO(SSTAT2, SEMPTY)) { + /* FIXME: maybe this should be done by setting up + * STCNT to trigger ENSWRAP interrupt, instead of + * polling for DFIFOFULL + */ + the_time=jiffies + 10*HZ; + while(TESTLO(DMASTAT, DFIFOFULL|INTSTAT) && time_before(jiffies,the_time)) + barrier(); + + if(TESTLO(DMASTAT, DFIFOFULL|INTSTAT)) { + printk(ERR_LEAD "datai timeout", CMDINFO(CURRENT_SC)); + disp_ports(shpnt); + break; + } + + if(TESTHI(DMASTAT, DFIFOFULL)) { + fifodata = 128; + } else { + the_time=jiffies + 10*HZ; + while(TESTLO(SSTAT2, SEMPTY) && time_before(jiffies,the_time)) + barrier(); + + if(TESTLO(SSTAT2, SEMPTY)) { + printk(ERR_LEAD "datai sempty timeout", CMDINFO(CURRENT_SC)); + disp_ports(shpnt); + break; + } + + fifodata = GETPORT(FIFOSTAT); + } + + if(CURRENT_SC->SCp.this_residual>0) { + while(fifodata>0 && CURRENT_SC->SCp.this_residual>0) { + data_count = fifodata>CURRENT_SC->SCp.this_residual ? + CURRENT_SC->SCp.this_residual : + fifodata; + fifodata -= data_count; + + if(data_count & 1) { + DPRINTK(debug_datai, DEBUG_LEAD "8bit\n", CMDINFO(CURRENT_SC)); + SETPORT(DMACNTRL0, ENDMA|_8BIT); + *CURRENT_SC->SCp.ptr++ = GETPORT(DATAPORT); + CURRENT_SC->SCp.this_residual--; + DATA_LEN++; + SETPORT(DMACNTRL0, ENDMA); + } + + if(data_count > 1) { + DPRINTK(debug_datai, DEBUG_LEAD "16bit(%d)\n", CMDINFO(CURRENT_SC), data_count); + data_count >>= 1; + insw(DATAPORT, CURRENT_SC->SCp.ptr, data_count); + CURRENT_SC->SCp.ptr += 2 * data_count; + CURRENT_SC->SCp.this_residual -= 2 * data_count; + DATA_LEN += 2 * data_count; + } + + if(CURRENT_SC->SCp.this_residual==0 && CURRENT_SC->SCp.buffers_residual>0) { + /* advance to next buffer */ + CURRENT_SC->SCp.buffers_residual--; + CURRENT_SC->SCp.buffer++; + CURRENT_SC->SCp.ptr = SG_ADDRESS(CURRENT_SC->SCp.buffer); + CURRENT_SC->SCp.this_residual = CURRENT_SC->SCp.buffer->length; + } + } + } else if(fifodata>0) { + printk(ERR_LEAD "no buffers left for %d(%d) bytes (data overrun!?)\n", CMDINFO(CURRENT_SC), fifodata, GETPORT(FIFOSTAT)); + SETPORT(DMACNTRL0, ENDMA|_8BIT); + while(fifodata>0) { + int data; + data=GETPORT(DATAPORT); + DPRINTK(debug_datai, DEBUG_LEAD "data=%02x\n", CMDINFO(CURRENT_SC), data); + fifodata--; + DATA_LEN++; + } + SETPORT(DMACNTRL0, ENDMA|_8BIT); + } + } + + if(TESTLO(DMASTAT, INTSTAT) || + TESTLO(DMASTAT, DFIFOEMP) || + TESTLO(SSTAT2, SEMPTY) || + GETPORT(FIFOSTAT)>0) { + /* + * something went wrong, if there's something left in the fifos + * or the phase didn't change + */ + printk(ERR_LEAD "fifos should be empty and phase should have changed\n", CMDINFO(CURRENT_SC)); + disp_ports(shpnt); + } + + if(DATA_LEN!=GETSTCNT()) { + printk(ERR_LEAD + "manual transfer count differs from automatic (count=%d;stcnt=%d;diff=%d;fifostat=%d)", + CMDINFO(CURRENT_SC), DATA_LEN, GETSTCNT(), GETSTCNT()-DATA_LEN, GETPORT(FIFOSTAT)); + disp_ports(shpnt); + mdelay(10000); + } +} + +static void datai_end(struct Scsi_Host *shpnt) +{ + CURRENT_SC->resid -= GETSTCNT(); + + DPRINTK(debug_datai, + DEBUG_LEAD "datai_end: request_bufflen=%d resid=%d stcnt=%d\n", + CMDINFO(CURRENT_SC), CURRENT_SC->request_bufflen, CURRENT_SC->resid, GETSTCNT()); + + SETPORT(SXFRCTL0, CH1|CLRSTCNT); + SETPORT(DMACNTRL0, 0); +} + +/* + * data out phase + * + */ +static void datao_init(struct Scsi_Host *shpnt) +{ + SETPORT(DMACNTRL0, WRITE_READ | RSTFIFO); + SETPORT(DMACNTRL0, WRITE_READ | ENDMA); + + SETPORT(SXFRCTL0, CH1|CLRSTCNT); + SETPORT(SXFRCTL0, CH1|SCSIEN|DMAEN); + + SETPORT(SIMODE0, 0); + SETPORT(SIMODE1, ENSCSIPERR | ENSCSIRST | ENPHASEMIS | ENBUSFREE ); + + DATA_LEN = CURRENT_SC->resid; + + DPRINTK(debug_datao, + DEBUG_LEAD "datao_init: request_bufflen=%d; resid=%d\n", + CMDINFO(CURRENT_SC), CURRENT_SC->request_bufflen, CURRENT_SC->resid); +} + +static void datao_run(struct Scsi_Host *shpnt) +{ + unsigned int the_time; + int data_count; + + /* until phase changes or all data sent */ + while(TESTLO(DMASTAT, INTSTAT) && CURRENT_SC->SCp.this_residual>0) { + data_count = 128; + if(data_count > CURRENT_SC->SCp.this_residual) + data_count=CURRENT_SC->SCp.this_residual; + + if(TESTLO(DMASTAT, DFIFOEMP)) { + printk(ERR_LEAD "datao fifo not empty (%d)", CMDINFO(CURRENT_SC), GETPORT(FIFOSTAT)); + disp_ports(shpnt); + break; + } + + if(data_count & 1) { + SETPORT(DMACNTRL0,WRITE_READ|ENDMA|_8BIT); + SETPORT(DATAPORT, *CURRENT_SC->SCp.ptr++); + CURRENT_SC->SCp.this_residual--; + CURRENT_SC->resid--; + SETPORT(DMACNTRL0,WRITE_READ|ENDMA); + } + + if(data_count > 1) { + data_count >>= 1; + outsw(DATAPORT, CURRENT_SC->SCp.ptr, data_count); + CURRENT_SC->SCp.ptr += 2 * data_count; + CURRENT_SC->SCp.this_residual -= 2 * data_count; + CURRENT_SC->resid -= 2 * data_count; + } + + if(CURRENT_SC->SCp.this_residual==0 && CURRENT_SC->SCp.buffers_residual>0) { + /* advance to next buffer */ + CURRENT_SC->SCp.buffers_residual--; + CURRENT_SC->SCp.buffer++; + CURRENT_SC->SCp.ptr = SG_ADDRESS(CURRENT_SC->SCp.buffer); + CURRENT_SC->SCp.this_residual = CURRENT_SC->SCp.buffer->length; + } + + the_time=jiffies + 10*HZ; + while(TESTLO(DMASTAT, DFIFOEMP|INTSTAT) && time_before(jiffies,the_time)) + barrier(); + + if(TESTLO(DMASTAT, DFIFOEMP|INTSTAT)) { + printk(ERR_LEAD "dataout timeout", CMDINFO(CURRENT_SC)); + disp_ports(shpnt); + break; + } + } +} + +static void datao_end(struct Scsi_Host *shpnt) +{ + if(TESTLO(DMASTAT, DFIFOEMP)) { + int data_count = (DATA_LEN - CURRENT_SC->resid) - GETSTCNT(); + + DPRINTK(debug_datao, DEBUG_LEAD "datao: %d bytes to resend (%d written, %d transferred)\n", + CMDINFO(CURRENT_SC), + data_count, + DATA_LEN-CURRENT_SC->resid, + GETSTCNT()); + + CURRENT_SC->resid += data_count; + + if(CURRENT_SC->use_sg) { + data_count -= CURRENT_SC->SCp.ptr - SG_ADDRESS(CURRENT_SC->SCp.buffer); + while(data_count>0) { + CURRENT_SC->SCp.buffer--; + CURRENT_SC->SCp.buffers_residual++; + data_count -= CURRENT_SC->SCp.buffer->length; + } + CURRENT_SC->SCp.ptr = SG_ADDRESS(CURRENT_SC->SCp.buffer) - data_count; + CURRENT_SC->SCp.this_residual = CURRENT_SC->SCp.buffer->length + data_count; + } else { + CURRENT_SC->SCp.ptr -= data_count; + CURRENT_SC->SCp.this_residual += data_count; + } + } + + DPRINTK(debug_datao, DEBUG_LEAD "datao_end: request_bufflen=%d; resid=%d; stcnt=%d\n", + CMDINFO(CURRENT_SC), + CURRENT_SC->request_bufflen, + CURRENT_SC->resid, + GETSTCNT()); + + SETPORT(SXFRCTL0, CH1|CLRCH1|CLRSTCNT); + SETPORT(SXFRCTL0, CH1); + + SETPORT(DMACNTRL0, 0); +} + +/* + * figure out what state we're in + * + */ +static int update_state(struct Scsi_Host *shpnt) +{ + int dataphase=0; + unsigned int stat0 = GETPORT(SSTAT0); + unsigned int stat1 = GETPORT(SSTAT1); + + PREVSTATE = STATE; + STATE=unknown; + + if(stat1 & SCSIRSTI) { + STATE=rsti; + SETPORT(SCSISEQ,0); + SETPORT(SSTAT1,SCSIRSTI); + } else if(stat0 & SELDI && PREVSTATE==busfree) { + STATE=seldi; + } else if(stat0 & SELDO && CURRENT_SC && (CURRENT_SC->SCp.phase & selecting)) { + STATE=seldo; + } else if(stat1 & SELTO) { + STATE=selto; + } else if(stat1 & BUSFREE) { + STATE=busfree; + SETPORT(SSTAT1,BUSFREE); + } else if(stat1 & SCSIPERR) { + STATE=parerr; + SETPORT(SSTAT1,SCSIPERR); + } else if(stat1 & REQINIT) { + switch(GETPORT(SCSISIG) & P_MASK) { + case P_MSGI: STATE=msgi; break; + case P_MSGO: STATE=msgo; break; + case P_DATAO: STATE=datao; break; + case P_DATAI: STATE=datai; break; + case P_STATUS: STATE=status; break; + case P_CMD: STATE=cmd; break; + } + dataphase=1; + } + + if((stat0 & SELDI) && STATE!=seldi && !dataphase) { + printk(INFO_LEAD "reselection missed?", CMDINFO(CURRENT_SC)); + disp_ports(shpnt); + } + + if(STATE!=PREVSTATE) { + LASTSTATE=PREVSTATE; + } + + return dataphase; +} + +/* + * handle parity error + * + * FIXME: in which phase? + * + */ +static void parerr_run(struct Scsi_Host *shpnt) +{ + printk(ERR_LEAD "parity error\n", CMDINFO(CURRENT_SC)); + done(shpnt, DID_PARITY << 16); +} + +/* + * handle reset in + * + */ +static void rsti_run(struct Scsi_Host *shpnt) +{ + Scsi_Cmnd *ptr; + + printk(KERN_NOTICE "aha152x%d: scsi reset in\n", HOSTNO); + + ptr=DISCONNECTED_SC; + while(ptr) { + Scsi_Cmnd *next = SCNEXT(ptr); + + if (!ptr->device->soft_reset) { + remove_SC(&DISCONNECTED_SC, ptr); + + ptr->result = DID_RESET << 16; + ptr->scsi_done(ptr); + + kfree(ptr->host_scribble); + ptr->host_scribble=0; + } + + ptr = next; + } + + if(CURRENT_SC && !CURRENT_SC->device->soft_reset) + done(shpnt, DID_RESET << 16 ); +} + + +/* + * bottom-half handler + * + */ +static void is_complete(struct Scsi_Host *shpnt) +{ + int dataphase; + unsigned long flags; + int pending; + + DO_LOCK(flags); + if(HOSTDATA(shpnt)->in_intr!=0) { + DO_UNLOCK(flags); + /* aha152x_error never returns.. */ + aha152x_error(shpnt, "bottom-half already running!?"); + } + HOSTDATA(shpnt)->in_intr++; + DO_UNLOCK(flags); + + /* + * loop while there are interrupt conditions pending + * + */ + do { + unsigned long start = jiffies; + dataphase=update_state(shpnt); + + DPRINTK(debug_phases, LEAD "start %s %s(%s)\n", CMDINFO(CURRENT_SC), states[STATE].name, states[PREVSTATE].name, states[LASTSTATE].name); + + /* + * end previous state + * + */ + if(PREVSTATE!=STATE && states[PREVSTATE].end) + states[PREVSTATE].end(shpnt); + + /* + * disable SPIO mode if previous phase used it + * and this one doesn't + * + */ + if(states[PREVSTATE].spio && !states[STATE].spio) { + SETPORT(SXFRCTL0, CH1); + SETPORT(DMACNTRL0, 0); + if(CURRENT_SC) + CURRENT_SC->SCp.phase &= ~spiordy; + } + + /* + * accept current dataphase phase + * + */ + if(dataphase) { + SETPORT(SSTAT0, REQINIT); + SETPORT(SCSISIG, GETPORT(SCSISIG) & P_MASK); + SETPORT(SSTAT1, PHASECHG); + } + + /* + * enable SPIO mode if previous didn't use it + * and this one does + * + */ + if(!states[PREVSTATE].spio && states[STATE].spio) { + SETPORT(DMACNTRL0, 0); + SETPORT(SXFRCTL0, CH1|SPIOEN); + if(CURRENT_SC) + CURRENT_SC->SCp.phase |= spiordy; + } + + /* + * initialize for new state + * + */ + if(PREVSTATE!=STATE && states[STATE].init) + states[STATE].init(shpnt); + + /* + * handle current state + * + */ + if(states[STATE].run) + states[STATE].run(shpnt); + else + printk(ERR_LEAD "unexpected state (%x)\n", CMDINFO(CURRENT_SC), STATE); + + /* + * setup controller to interrupt on + * the next expected condition and + * loop if it's already there + * + */ + DO_LOCK(flags); + pending=setup_expected_interrupts(shpnt); +#if defined(AHA152X_STAT) + HOSTDATA(shpnt)->count[STATE]++; + if(PREVSTATE!=STATE) + HOSTDATA(shpnt)->count_trans[STATE]++; + HOSTDATA(shpnt)->time[STATE] += jiffies-start; +#endif + DO_UNLOCK(flags); + + DPRINTK(debug_phases, LEAD "end %s %s(%s)\n", CMDINFO(CURRENT_SC), states[STATE].name, states[PREVSTATE].name, states[LASTSTATE].name); + } while(pending); + + /* + * enable interrupts and leave bottom-half + * + */ + DO_LOCK(flags); + HOSTDATA(shpnt)->in_intr--; + SETBITS(DMACNTRL0, INTEN); + DO_UNLOCK(flags); +} + + +/* + * Dump the current driver status and panic + */ +static void aha152x_error(struct Scsi_Host *shpnt, char *msg) +{ + printk(KERN_EMERG "\naha152x%d: %s\n", HOSTNO, msg); + show_queues(shpnt); + panic("aha152x panic\n"); +} + +/* + * Display registers of AIC-6260 + */ +static void disp_ports(struct Scsi_Host *shpnt) +{ +#if defined(AHA152X_DEBUG) + int s; + + printk("\n%s: %s(%s) ", + CURRENT_SC ? "busy" : "waiting", + states[STATE].name, + states[PREVSTATE].name); + + s = GETPORT(SCSISEQ); + printk("SCSISEQ( "); + if (s & TEMODEO) + printk("TARGET MODE "); + if (s & ENSELO) + printk("SELO "); + if (s & ENSELI) + printk("SELI "); + if (s & ENRESELI) + printk("RESELI "); + if (s & ENAUTOATNO) + printk("AUTOATNO "); + if (s & ENAUTOATNI) + printk("AUTOATNI "); + if (s & ENAUTOATNP) + printk("AUTOATNP "); + if (s & SCSIRSTO) + printk("SCSIRSTO "); + printk(");"); + + printk(" SCSISIG("); + s = GETPORT(SCSISIG); + switch (s & P_MASK) { + case P_DATAO: + printk("DATA OUT"); + break; + case P_DATAI: + printk("DATA IN"); + break; + case P_CMD: + printk("COMMAND"); + break; + case P_STATUS: + printk("STATUS"); + break; + case P_MSGO: + printk("MESSAGE OUT"); + break; + case P_MSGI: + printk("MESSAGE IN"); + break; + default: + printk("*illegal*"); + break; + } + + printk("); "); + + printk("INTSTAT (%s); ", TESTHI(DMASTAT, INTSTAT) ? "hi" : "lo"); + + printk("SSTAT( "); + s = GETPORT(SSTAT0); + if (s & TARGET) + printk("TARGET "); + if (s & SELDO) + printk("SELDO "); + if (s & SELDI) + printk("SELDI "); + if (s & SELINGO) + printk("SELINGO "); + if (s & SWRAP) + printk("SWRAP "); + if (s & SDONE) + printk("SDONE "); + if (s & SPIORDY) + printk("SPIORDY "); + if (s & DMADONE) + printk("DMADONE "); + + s = GETPORT(SSTAT1); + if (s & SELTO) + printk("SELTO "); + if (s & ATNTARG) + printk("ATNTARG "); + if (s & SCSIRSTI) + printk("SCSIRSTI "); + if (s & PHASEMIS) + printk("PHASEMIS "); + if (s & BUSFREE) + printk("BUSFREE "); + if (s & SCSIPERR) + printk("SCSIPERR "); + if (s & PHASECHG) + printk("PHASECHG "); + if (s & REQINIT) + printk("REQINIT "); + printk("); "); + + + printk("SSTAT( "); + + s = GETPORT(SSTAT0) & GETPORT(SIMODE0); + + if (s & TARGET) + printk("TARGET "); + if (s & SELDO) + printk("SELDO "); + if (s & SELDI) + printk("SELDI "); + if (s & SELINGO) + printk("SELINGO "); + if (s & SWRAP) + printk("SWRAP "); + if (s & SDONE) + printk("SDONE "); + if (s & SPIORDY) + printk("SPIORDY "); + if (s & DMADONE) + printk("DMADONE "); + + s = GETPORT(SSTAT1) & GETPORT(SIMODE1); + + if (s & SELTO) + printk("SELTO "); + if (s & ATNTARG) + printk("ATNTARG "); + if (s & SCSIRSTI) + printk("SCSIRSTI "); + if (s & PHASEMIS) + printk("PHASEMIS "); + if (s & BUSFREE) + printk("BUSFREE "); + if (s & SCSIPERR) + printk("SCSIPERR "); + if (s & PHASECHG) + printk("PHASECHG "); + if (s & REQINIT) + printk("REQINIT "); + printk("); "); + + printk("SXFRCTL0( "); + + s = GETPORT(SXFRCTL0); + if (s & SCSIEN) + printk("SCSIEN "); + if (s & DMAEN) + printk("DMAEN "); + if (s & CH1) + printk("CH1 "); + if (s & CLRSTCNT) + printk("CLRSTCNT "); + if (s & SPIOEN) + printk("SPIOEN "); + if (s & CLRCH1) + printk("CLRCH1 "); + printk("); "); + + printk("SIGNAL( "); + + s = GETPORT(SCSISIG); + if (s & SIG_ATNI) + printk("ATNI "); + if (s & SIG_SELI) + printk("SELI "); + if (s & SIG_BSYI) + printk("BSYI "); + if (s & SIG_REQI) + printk("REQI "); + if (s & SIG_ACKI) + printk("ACKI "); + printk("); "); + + printk("SELID (%02x), ", GETPORT(SELID)); + + printk("STCNT (%d), ", GETSTCNT()); + + printk("SSTAT2( "); + + s = GETPORT(SSTAT2); + if (s & SOFFSET) + printk("SOFFSET "); + if (s & SEMPTY) + printk("SEMPTY "); + if (s & SFULL) + printk("SFULL "); + printk("); SFCNT (%d); ", s & (SFULL | SFCNT)); + + s = GETPORT(SSTAT3); + printk("SCSICNT (%d), OFFCNT(%d), ", (s & 0xf0) >> 4, s & 0x0f); + + printk("SSTAT4( "); + s = GETPORT(SSTAT4); + if (s & SYNCERR) + printk("SYNCERR "); + if (s & FWERR) + printk("FWERR "); + if (s & FRERR) + printk("FRERR "); + printk("); "); + + printk("DMACNTRL0( "); + s = GETPORT(DMACNTRL0); + printk("%s ", s & _8BIT ? "8BIT" : "16BIT"); + printk("%s ", s & DMA ? "DMA" : "PIO"); + printk("%s ", s & WRITE_READ ? "WRITE" : "READ"); + if (s & ENDMA) + printk("ENDMA "); + if (s & INTEN) + printk("INTEN "); + if (s & RSTFIFO) + printk("RSTFIFO "); + if (s & SWINT) + printk("SWINT "); + printk("); "); + + printk("DMASTAT( "); + s = GETPORT(DMASTAT); + if (s & ATDONE) + printk("ATDONE "); + if (s & WORDRDY) + printk("WORDRDY "); + if (s & DFIFOFULL) + printk("DFIFOFULL "); + if (s & DFIFOEMP) + printk("DFIFOEMP "); + printk(")\n"); +#endif +} + +/* + * display enabled interrupts + */ +static void disp_enintr(struct Scsi_Host *shpnt) +{ + int s; + + printk(KERN_DEBUG "enabled interrupts ( "); + + s = GETPORT(SIMODE0); + if (s & ENSELDO) + printk("ENSELDO "); + if (s & ENSELDI) + printk("ENSELDI "); + if (s & ENSELINGO) + printk("ENSELINGO "); + if (s & ENSWRAP) + printk("ENSWRAP "); + if (s & ENSDONE) + printk("ENSDONE "); + if (s & ENSPIORDY) + printk("ENSPIORDY "); + if (s & ENDMADONE) + printk("ENDMADONE "); + + s = GETPORT(SIMODE1); + if (s & ENSELTIMO) + printk("ENSELTIMO "); + if (s & ENATNTARG) + printk("ENATNTARG "); + if (s & ENPHASEMIS) + printk("ENPHASEMIS "); + if (s & ENBUSFREE) + printk("ENBUSFREE "); + if (s & ENSCSIPERR) + printk("ENSCSIPERR "); + if (s & ENPHASECHG) + printk("ENPHASECHG "); + if (s & ENREQINIT) + printk("ENREQINIT "); + printk(")\n"); +} + +/* + * Show the command data of a command + */ +static void show_command(Scsi_Cmnd *ptr) +{ + printk(KERN_DEBUG "0x%08x: target=%d; lun=%d; cmnd=(", + (unsigned int) ptr, ptr->target, ptr->lun); + + print_command(ptr->cmnd); + + printk(KERN_DEBUG "); request_bufflen=%d; resid=%d; phase |", + ptr->request_bufflen, ptr->resid); + + if (ptr->SCp.phase & not_issued) + printk("not issued|"); + if (ptr->SCp.phase & selecting) + printk("selecting|"); + if (ptr->SCp.phase & identified) + printk("identified|"); + if (ptr->SCp.phase & disconnected) + printk("disconnected|"); + if (ptr->SCp.phase & completed) + printk("completed|"); + if (ptr->SCp.phase & spiordy) + printk("spiordy|"); + if (ptr->SCp.phase & syncneg) + printk("syncneg|"); + if (ptr->SCp.phase & aborted) + printk("aborted|"); + if (ptr->SCp.phase & resetted) + printk("resetted|"); + printk("; next=0x%p\n", SCNEXT(ptr)); +} + +/* + * Dump the queued data + */ +static void show_queues(struct Scsi_Host *shpnt) +{ + Scsi_Cmnd *ptr; + unsigned long flags; + + DO_LOCK(flags); + printk(KERN_DEBUG "\nqueue status:\nissue_SC:\n"); + for (ptr = ISSUE_SC; ptr; ptr = SCNEXT(ptr)) + show_command(ptr); + DO_UNLOCK(flags); + + printk(KERN_DEBUG "current_SC:\n"); + if (CURRENT_SC) + show_command(CURRENT_SC); + else + printk(KERN_DEBUG "none\n"); + + printk(KERN_DEBUG "disconnected_SC:\n"); + for (ptr = DISCONNECTED_SC; ptr; ptr = SCNEXT(ptr)) + show_command(ptr); + + disp_ports(shpnt); + disp_enintr(shpnt); +} + +#undef SPRINTF +#define SPRINTF(args...) pos += sprintf(pos, ## args) + +static int get_command(char *pos, Scsi_Cmnd * ptr) +{ + char *start = pos; + int i; + + SPRINTF("0x%08x: target=%d; lun=%d; cmnd=( ", + (unsigned int) ptr, ptr->target, ptr->lun); + + for (i = 0; i < COMMAND_SIZE(ptr->cmnd[0]); i++) + SPRINTF("0x%02x ", ptr->cmnd[i]); + + SPRINTF("); resid=%d; residual=%d; buffers=%d; phase |", + ptr->resid, ptr->SCp.this_residual, ptr->SCp.buffers_residual); + + if (ptr->SCp.phase & not_issued) + SPRINTF("not issued|"); + if (ptr->SCp.phase & selecting) + SPRINTF("selecting|"); + if (ptr->SCp.phase & disconnected) + SPRINTF("disconnected|"); + if (ptr->SCp.phase & aborted) + SPRINTF("aborted|"); + if (ptr->SCp.phase & identified) + SPRINTF("identified|"); + if (ptr->SCp.phase & completed) + SPRINTF("completed|"); + if (ptr->SCp.phase & spiordy) + SPRINTF("spiordy|"); + if (ptr->SCp.phase & syncneg) + SPRINTF("syncneg|"); + SPRINTF("; next=0x%p\n", SCNEXT(ptr)); + + return (pos - start); +} + +static int get_ports(struct Scsi_Host *shpnt, char *pos) +{ + char *start = pos; + int s; + + SPRINTF("\n%s: %s(%s) ", CURRENT_SC ? "on bus" : "waiting", states[STATE].name, states[PREVSTATE].name); + + s = GETPORT(SCSISEQ); + SPRINTF("SCSISEQ( "); + if (s & TEMODEO) + SPRINTF("TARGET MODE "); + if (s & ENSELO) + SPRINTF("SELO "); + if (s & ENSELI) + SPRINTF("SELI "); + if (s & ENRESELI) + SPRINTF("RESELI "); + if (s & ENAUTOATNO) + SPRINTF("AUTOATNO "); + if (s & ENAUTOATNI) + SPRINTF("AUTOATNI "); + if (s & ENAUTOATNP) + SPRINTF("AUTOATNP "); + if (s & SCSIRSTO) + SPRINTF("SCSIRSTO "); + SPRINTF(");"); + + SPRINTF(" SCSISIG("); + s = GETPORT(SCSISIG); + switch (s & P_MASK) { + case P_DATAO: + SPRINTF("DATA OUT"); + break; + case P_DATAI: + SPRINTF("DATA IN"); + break; + case P_CMD: + SPRINTF("COMMAND"); + break; + case P_STATUS: + SPRINTF("STATUS"); + break; + case P_MSGO: + SPRINTF("MESSAGE OUT"); + break; + case P_MSGI: + SPRINTF("MESSAGE IN"); + break; + default: + SPRINTF("*illegal*"); + break; + } + + SPRINTF("); "); + + SPRINTF("INTSTAT (%s); ", TESTHI(DMASTAT, INTSTAT) ? "hi" : "lo"); + + SPRINTF("SSTAT( "); + s = GETPORT(SSTAT0); + if (s & TARGET) + SPRINTF("TARGET "); + if (s & SELDO) + SPRINTF("SELDO "); + if (s & SELDI) + SPRINTF("SELDI "); + if (s & SELINGO) + SPRINTF("SELINGO "); + if (s & SWRAP) + SPRINTF("SWRAP "); + if (s & SDONE) + SPRINTF("SDONE "); + if (s & SPIORDY) + SPRINTF("SPIORDY "); + if (s & DMADONE) + SPRINTF("DMADONE "); + + s = GETPORT(SSTAT1); + if (s & SELTO) + SPRINTF("SELTO "); + if (s & ATNTARG) + SPRINTF("ATNTARG "); + if (s & SCSIRSTI) + SPRINTF("SCSIRSTI "); + if (s & PHASEMIS) + SPRINTF("PHASEMIS "); + if (s & BUSFREE) + SPRINTF("BUSFREE "); + if (s & SCSIPERR) + SPRINTF("SCSIPERR "); + if (s & PHASECHG) + SPRINTF("PHASECHG "); + if (s & REQINIT) + SPRINTF("REQINIT "); + SPRINTF("); "); + + + SPRINTF("SSTAT( "); + + s = GETPORT(SSTAT0) & GETPORT(SIMODE0); + + if (s & TARGET) + SPRINTF("TARGET "); + if (s & SELDO) + SPRINTF("SELDO "); + if (s & SELDI) + SPRINTF("SELDI "); + if (s & SELINGO) + SPRINTF("SELINGO "); + if (s & SWRAP) + SPRINTF("SWRAP "); + if (s & SDONE) + SPRINTF("SDONE "); + if (s & SPIORDY) + SPRINTF("SPIORDY "); + if (s & DMADONE) + SPRINTF("DMADONE "); + + s = GETPORT(SSTAT1) & GETPORT(SIMODE1); + + if (s & SELTO) + SPRINTF("SELTO "); + if (s & ATNTARG) + SPRINTF("ATNTARG "); + if (s & SCSIRSTI) + SPRINTF("SCSIRSTI "); + if (s & PHASEMIS) + SPRINTF("PHASEMIS "); + if (s & BUSFREE) + SPRINTF("BUSFREE "); + if (s & SCSIPERR) + SPRINTF("SCSIPERR "); + if (s & PHASECHG) + SPRINTF("PHASECHG "); + if (s & REQINIT) + SPRINTF("REQINIT "); + SPRINTF("); "); + + SPRINTF("SXFRCTL0( "); + + s = GETPORT(SXFRCTL0); + if (s & SCSIEN) + SPRINTF("SCSIEN "); + if (s & DMAEN) + SPRINTF("DMAEN "); + if (s & CH1) + SPRINTF("CH1 "); + if (s & CLRSTCNT) + SPRINTF("CLRSTCNT "); + if (s & SPIOEN) + SPRINTF("SPIOEN "); + if (s & CLRCH1) + SPRINTF("CLRCH1 "); + SPRINTF("); "); + + SPRINTF("SIGNAL( "); + + s = GETPORT(SCSISIG); + if (s & SIG_ATNI) + SPRINTF("ATNI "); + if (s & SIG_SELI) + SPRINTF("SELI "); + if (s & SIG_BSYI) + SPRINTF("BSYI "); + if (s & SIG_REQI) + SPRINTF("REQI "); + if (s & SIG_ACKI) + SPRINTF("ACKI "); + SPRINTF("); "); + + SPRINTF("SELID(%02x), ", GETPORT(SELID)); + + SPRINTF("STCNT(%d), ", GETSTCNT()); + + SPRINTF("SSTAT2( "); + + s = GETPORT(SSTAT2); + if (s & SOFFSET) + SPRINTF("SOFFSET "); + if (s & SEMPTY) + SPRINTF("SEMPTY "); + if (s & SFULL) + SPRINTF("SFULL "); + SPRINTF("); SFCNT (%d); ", s & (SFULL | SFCNT)); + + s = GETPORT(SSTAT3); + SPRINTF("SCSICNT (%d), OFFCNT(%d), ", (s & 0xf0) >> 4, s & 0x0f); + + SPRINTF("SSTAT4( "); + s = GETPORT(SSTAT4); + if (s & SYNCERR) + SPRINTF("SYNCERR "); + if (s & FWERR) + SPRINTF("FWERR "); + if (s & FRERR) + SPRINTF("FRERR "); + SPRINTF("); "); + + SPRINTF("DMACNTRL0( "); + s = GETPORT(DMACNTRL0); + SPRINTF("%s ", s & _8BIT ? "8BIT" : "16BIT"); + SPRINTF("%s ", s & DMA ? "DMA" : "PIO"); + SPRINTF("%s ", s & WRITE_READ ? "WRITE" : "READ"); + if (s & ENDMA) + SPRINTF("ENDMA "); + if (s & INTEN) + SPRINTF("INTEN "); + if (s & RSTFIFO) + SPRINTF("RSTFIFO "); + if (s & SWINT) + SPRINTF("SWINT "); + SPRINTF("); "); + + SPRINTF("DMASTAT( "); + s = GETPORT(DMASTAT); + if (s & ATDONE) + SPRINTF("ATDONE "); + if (s & WORDRDY) + SPRINTF("WORDRDY "); + if (s & DFIFOFULL) + SPRINTF("DFIFOFULL "); + if (s & DFIFOEMP) + SPRINTF("DFIFOEMP "); + SPRINTF(")\n"); + + SPRINTF("enabled interrupts( "); + + s = GETPORT(SIMODE0); + if (s & ENSELDO) + SPRINTF("ENSELDO "); + if (s & ENSELDI) + SPRINTF("ENSELDI "); + if (s & ENSELINGO) + SPRINTF("ENSELINGO "); + if (s & ENSWRAP) + SPRINTF("ENSWRAP "); + if (s & ENSDONE) + SPRINTF("ENSDONE "); + if (s & ENSPIORDY) + SPRINTF("ENSPIORDY "); + if (s & ENDMADONE) + SPRINTF("ENDMADONE "); + + s = GETPORT(SIMODE1); + if (s & ENSELTIMO) + SPRINTF("ENSELTIMO "); + if (s & ENATNTARG) + SPRINTF("ENATNTARG "); + if (s & ENPHASEMIS) + SPRINTF("ENPHASEMIS "); + if (s & ENBUSFREE) + SPRINTF("ENBUSFREE "); + if (s & ENSCSIPERR) + SPRINTF("ENSCSIPERR "); + if (s & ENPHASECHG) + SPRINTF("ENPHASECHG "); + if (s & ENREQINIT) + SPRINTF("ENREQINIT "); + SPRINTF(")\n"); + + return (pos - start); +} + +int aha152x_set_info(char *buffer, int length, struct Scsi_Host *shpnt) +{ + if(!shpnt || !buffer || length<8 || strncmp("aha152x ", buffer, 8)!=0) + return -EINVAL; + +#if defined(AHA152X_DEBUG) + if(length>14 && strncmp("debug ", buffer+8, 6)==0) { + int debug = HOSTDATA(shpnt)->debug; + + HOSTDATA(shpnt)->debug = simple_strtoul(buffer+14, NULL, 0); + + printk(KERN_INFO "aha152x%d: debugging options set to 0x%04x (were 0x%04x)\n", HOSTNO, HOSTDATA(shpnt)->debug, debug); + } else +#endif +#if defined(AHA152X_STAT) + if(length>13 && strncmp("reset", buffer+8, 5)==0) { + int i; + + HOSTDATA(shpnt)->total_commands=0; + HOSTDATA(shpnt)->disconnections=0; + HOSTDATA(shpnt)->busfree_without_any_action=0; + HOSTDATA(shpnt)->busfree_without_old_command=0; + HOSTDATA(shpnt)->busfree_without_new_command=0; + HOSTDATA(shpnt)->busfree_without_done_command=0; + HOSTDATA(shpnt)->busfree_with_check_condition=0; + for (i = idle; icount[i]=0; + HOSTDATA(shpnt)->count_trans[i]=0; + HOSTDATA(shpnt)->time[i]=0; + } + + printk(KERN_INFO "aha152x%d: stats reseted.\n", HOSTNO); + + } else +#endif + { + return -EINVAL; + } + + + return length; +} + +#undef SPRINTF +#define SPRINTF(args...) \ + do { if(pos < buffer + length) pos += sprintf(pos, ## args); } while(0) + +int aha152x_proc_info(char *buffer, char **start, + off_t offset, int length, int hostno, int inout) +{ + int i; + char *pos = buffer; + struct Scsi_Host *shpnt; + Scsi_Cmnd *ptr; + unsigned long flags; + int thislength; + + for (i = 0, shpnt = (struct Scsi_Host *) NULL; ihost_no == hostno) + shpnt = aha152x_host[i]; + + if (!shpnt) + return -ESRCH; + + DPRINTK(debug_procinfo, + KERN_DEBUG "aha152x_proc_info: buffer=%p offset=%ld length=%d hostno=%d inout=%d\n", + buffer, offset, length, hostno, inout); + + + if (inout) + return aha152x_set_info(buffer, length, shpnt); + + SPRINTF(AHA152X_REVID "\n"); + + SPRINTF("ioports 0x%04lx to 0x%04lx\n", + shpnt->io_port, shpnt->io_port + shpnt->n_io_port - 1); + SPRINTF("interrupt 0x%02x\n", shpnt->irq); + SPRINTF("disconnection/reconnection %s\n", + RECONNECT ? "enabled" : "disabled"); + SPRINTF("parity checking %s\n", + PARITY ? "enabled" : "disabled"); + SPRINTF("synchronous transfers %s\n", + SYNCHRONOUS ? "enabled" : "disabled"); + SPRINTF("%d commands currently queued\n", HOSTDATA(shpnt)->commands); + + if(SYNCHRONOUS) { + SPRINTF("synchronously operating targets (tick=50 ns):\n"); + for (i = 0; i < 8; i++) + if (HOSTDATA(shpnt)->syncrate[i] & 0x7f) + SPRINTF("target %d: period %dT/%dns; req/ack offset %d\n", + i, + (((HOSTDATA(shpnt)->syncrate[i] & 0x70) >> 4) + 2), + (((HOSTDATA(shpnt)->syncrate[i] & 0x70) >> 4) + 2) * 50, + HOSTDATA(shpnt)->syncrate[i] & 0x0f); + } +#if defined(AHA152X_DEBUG) +#define PDEBUG(flags,txt) \ + if(HOSTDATA(shpnt)->debug & flags) SPRINTF("(%s) ", txt); + + SPRINTF("enabled debugging options: "); + + PDEBUG(debug_procinfo, "procinfo"); + PDEBUG(debug_queue, "queue"); + PDEBUG(debug_intr, "interrupt"); + PDEBUG(debug_selection, "selection"); + PDEBUG(debug_msgo, "message out"); + PDEBUG(debug_msgi, "message in"); + PDEBUG(debug_status, "status"); + PDEBUG(debug_cmd, "command"); + PDEBUG(debug_datai, "data in"); + PDEBUG(debug_datao, "data out"); + PDEBUG(debug_eh, "eh"); + PDEBUG(debug_locks, "locks"); + PDEBUG(debug_phases, "phases"); + + SPRINTF("\n"); +#endif + + SPRINTF("\nqueue status:\n"); + DO_LOCK(flags); + if (ISSUE_SC) { + SPRINTF("not yet issued commands:\n"); + for (ptr = ISSUE_SC; ptr; ptr = SCNEXT(ptr)) + pos += get_command(pos, ptr); + } else + SPRINTF("no not yet issued commands\n"); + DO_UNLOCK(flags); + + if (CURRENT_SC) { + SPRINTF("current command:\n"); + pos += get_command(pos, CURRENT_SC); + } else + SPRINTF("no current command\n"); + + if (DISCONNECTED_SC) { + SPRINTF("disconnected commands:\n"); + for (ptr = DISCONNECTED_SC; ptr; ptr = SCNEXT(ptr)) + pos += get_command(pos, ptr); + } else + SPRINTF("no disconnected commands\n"); + + pos += get_ports(shpnt, pos); + +#if defined(AHA152X_STAT) + SPRINTF("statistics:\n" + "total commands: %d\n" + "disconnections: %d\n" + "busfree with check condition: %d\n" + "busfree without old command: %d\n" + "busfree without new command: %d\n" + "busfree without done command: %d\n" + "busfree without any action: %d\n" + "state " + "transitions " + "count " + "time\n", + HOSTDATA(shpnt)->total_commands, + HOSTDATA(shpnt)->disconnections, + HOSTDATA(shpnt)->busfree_with_check_condition, + HOSTDATA(shpnt)->busfree_without_old_command, + HOSTDATA(shpnt)->busfree_without_new_command, + HOSTDATA(shpnt)->busfree_without_done_command, + HOSTDATA(shpnt)->busfree_without_any_action); + for(i=0; icount_trans[i], + HOSTDATA(shpnt)->count[i], + HOSTDATA(shpnt)->time[i]); + } +#endif + + DPRINTK(debug_procinfo, KERN_DEBUG "aha152x_proc_info: pos=%p\n", pos); + + thislength = pos - (buffer + offset); + DPRINTK(debug_procinfo, KERN_DEBUG "aha152x_proc_info: length=%d thislength=%d\n", length, thislength); + + if(thislength<0) { + DPRINTK(debug_procinfo, KERN_DEBUG "aha152x_proc_info: output too short\n"); + *start = 0; + return 0; + } + + thislength = thislength + + * 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, 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. + + ************************************************************************** + + SUMMARY: + + Future Domain BIOS versions supported for autodetect: + 2.0, 3.0, 3.2, 3.4 (1.0), 3.5 (2.0), 3.6, 3.61 + Chips are supported: + TMC-1800, TMC-18C50, TMC-18C30, TMC-36C70 + Boards supported: + Future Domain TMC-1650, TMC-1660, TMC-1670, TMC-1680, TMC-1610M/MER/MEX + Future Domain TMC-3260 (PCI) + Quantum ISA-200S, ISA-250MG + Adaptec AHA-2920A (PCI) [BUT *NOT* AHA-2920C -- use aic7xxx instead] + IBM ? + LILO/INSMOD command-line options: + fdomain=,[,] + + + + NOTE: + + The Adaptec AHA-2920C has an Adaptec AIC-7850 chip on it. + Use the aic7xxx driver for this board. + + The Adaptec AHA-2920A has a Future Domain chip on it, so this is the right + driver for that card. Unfortunately, the boxes will probably just say + "2920", so you'll have to look on the card for a Future Domain logo, or a + letter after the 2920. + + + + THANKS: + + Thanks to Adaptec for providing PCI boards for testing. This finally + enabled me to test the PCI detection and correct it for PCI boards that do + not have a BIOS at a standard ISA location. For PCI boards, LILO/INSMOD + command-line options should no longer be needed. --RF 18Nov98 + + + + DESCRIPTION: + + This is the Linux low-level SCSI driver for Future Domain TMC-1660/1680 + TMC-1650/1670, and TMC-3260 SCSI host adapters. The 1650 and 1670 have a + 25-pin external connector, whereas the 1660 and 1680 have a SCSI-2 50-pin + high-density external connector. The 1670 and 1680 have floppy disk + controllers built in. The TMC-3260 is a PCI bus card. + + Future Domain's older boards are based on the TMC-1800 chip, and this + driver was originally written for a TMC-1680 board with the TMC-1800 chip. + More recently, boards are being produced with the TMC-18C50 and TMC-18C30 + chips. The latest and greatest board may not work with this driver. If + you have to patch this driver so that it will recognize your board's BIOS + signature, then the driver may fail to function after the board is + detected. + + Please note that the drive ordering that Future Domain implemented in BIOS + versions 3.4 and 3.5 is the opposite of the order (currently) used by the + rest of the SCSI industry. If you have BIOS version 3.4 or 3.5, and have + more than one drive, then the drive ordering will be the reverse of that + which you see under DOS. For example, under DOS SCSI ID 0 will be D: and + SCSI ID 1 will be C: (the boot device). Under Linux, SCSI ID 0 will be + /dev/sda and SCSI ID 1 will be /dev/sdb. The Linux ordering is consistent + with that provided by all the other SCSI drivers for Linux. If you want + this changed, you will probably have to patch the higher level SCSI code. + If you do so, please send me patches that are protected by #ifdefs. + + If you have a TMC-8xx or TMC-9xx board, then this is not the driver for + your board. Please refer to the Seagate driver for more information and + possible support. + + + + HISTORY: + + Linux Driver Driver + Version Version Date Support/Notes + + 0.0 3 May 1992 V2.0 BIOS; 1800 chip + 0.97 1.9 28 Jul 1992 + 0.98.6 3.1 27 Nov 1992 + 0.99 3.2 9 Dec 1992 + + 0.99.3 3.3 10 Jan 1993 V3.0 BIOS + 0.99.5 3.5 18 Feb 1993 + 0.99.10 3.6 15 May 1993 V3.2 BIOS; 18C50 chip + 0.99.11 3.17 3 Jul 1993 (now under RCS) + 0.99.12 3.18 13 Aug 1993 + 0.99.14 5.6 31 Oct 1993 (reselection code removed) + + 0.99.15 5.9 23 Jan 1994 V3.4 BIOS (preliminary) + 1.0.8/1.1.1 5.15 1 Apr 1994 V3.4 BIOS; 18C30 chip (preliminary) + 1.0.9/1.1.3 5.16 7 Apr 1994 V3.4 BIOS; 18C30 chip + 1.1.38 5.18 30 Jul 1994 36C70 chip (PCI version of 18C30) + 1.1.62 5.20 2 Nov 1994 V3.5 BIOS + 1.1.73 5.22 7 Dec 1994 Quantum ISA-200S board; V2.0 BIOS + + 1.1.82 5.26 14 Jan 1995 V3.5 BIOS; TMC-1610M/MER/MEX board + 1.2.10 5.28 5 Jun 1995 Quantum ISA-250MG board; V2.0, V2.01 BIOS + 1.3.4 5.31 23 Jun 1995 PCI BIOS-32 detection (preliminary) + 1.3.7 5.33 4 Jul 1995 PCI BIOS-32 detection + 1.3.28 5.36 17 Sep 1995 V3.61 BIOS; LILO command-line support + 1.3.34 5.39 12 Oct 1995 V3.60 BIOS; /proc + 1.3.72 5.39 8 Feb 1996 Adaptec AHA-2920 board + 1.3.85 5.41 4 Apr 1996 + 2.0.12 5.44 8 Aug 1996 Use ID 7 for all PCI cards + 2.1.1 5.45 2 Oct 1996 Update ROM accesses for 2.1.x + 2.1.97 5.46 23 Apr 1998 Rewritten PCI detection routines [mj] + 2.1.11x 5.47 9 Aug 1998 Touched for 8 SCSI disk majors support + 5.48 18 Nov 1998 BIOS no longer needed for PCI detection + 2.2.0 5.50 28 Dec 1998 Support insmod parameters + + + REFERENCES USED: + + "TMC-1800 SCSI Chip Specification (FDC-1800T)", Future Domain Corporation, + 1990. + + "Technical Reference Manual: 18C50 SCSI Host Adapter Chip", Future Domain + Corporation, January 1992. + + "LXT SCSI Products: Specifications and OEM Technical Manual (Revision + B/September 1991)", Maxtor Corporation, 1991. + + "7213S product Manual (Revision P3)", Maxtor Corporation, 1992. + + "Draft Proposed American National Standard: Small Computer System + Interface - 2 (SCSI-2)", Global Engineering Documents. (X3T9.2/86-109, + revision 10h, October 17, 1991) + + Private communications, Drew Eckhardt (drew@cs.colorado.edu) and Eric + Youngdale (ericy@cais.com), 1992. + + Private communication, Tuong Le (Future Domain Engineering department), + 1994. (Disk geometry computations for Future Domain BIOS version 3.4, and + TMC-18C30 detection.) + + Hogan, Thom. The Programmer's PC Sourcebook. Microsoft Press, 1988. Page + 60 (2.39: Disk Partition Table Layout). + + "18C30 Technical Reference Manual", Future Domain Corporation, 1993, page + 6-1. + + + + NOTES ON REFERENCES: + + The Maxtor manuals were free. Maxtor telephone technical support is + great! + + The Future Domain manuals were $25 and $35. They document the chip, not + the TMC-16x0 boards, so some information I had to guess at. In 1992, + Future Domain sold DOS BIOS source for $250 and the UN*X driver source was + $750, but these required a non-disclosure agreement, so even if I could + have afforded them, they would *not* have been useful for writing this + publically distributable driver. Future Domain technical support has + provided some information on the phone and have sent a few useful FAXs. + They have been much more helpful since they started to recognize that the + word "Linux" refers to an operating system :-). + + + + ALPHA TESTERS: + + There are many other alpha testers that come and go as the driver + develops. The people listed here were most helpful in times of greatest + need (mostly early on -- I've probably left out a few worthy people in + more recent times): + + Todd Carrico (todd@wutc.wustl.edu), Dan Poirier (poirier@cs.unc.edu ), Ken + Corey (kenc@sol.acs.unt.edu), C. de Bruin (bruin@bruin@sterbbs.nl), Sakari + Aaltonen (sakaria@vipunen.hit.fi), John Rice (rice@xanth.cs.odu.edu), Brad + Yearwood (brad@optilink.com), and Ray Toy (toy@soho.crd.ge.com). + + Special thanks to Tien-Wan Yang (twyang@cs.uh.edu), who graciously lent me + his 18C50-based card for debugging. He is the sole reason that this + driver works with the 18C50 chip. + + Thanks to Dave Newman (dnewman@crl.com) for providing initial patches for + the version 3.4 BIOS. + + Thanks to James T. McKinley (mckinley@msupa.pa.msu.edu) for providing + patches that support the TMC-3260, a PCI bus card with the 36C70 chip. + The 36C70 chip appears to be "completely compatible" with the 18C30 chip. + + Thanks to Eric Kasten (tigger@petroglyph.cl.msu.edu) for providing the + patch for the version 3.5 BIOS. + + Thanks for Stephen Henson (shenson@nyx10.cs.du.edu) for providing the + patch for the Quantum ISA-200S SCSI adapter. + + Thanks to Adam Bowen for the signature to the 1610M/MER/MEX scsi cards, to + Martin Andrews (andrewm@ccfadm.eeg.ccf.org) for the signature to some + random TMC-1680 repackaged by IBM; and to Mintak Ng (mintak@panix.com) for + the version 3.61 BIOS signature. + + Thanks for Mark Singer (elf@netcom.com) and Richard Simpson + (rsimpson@ewrcsdra.demon.co.uk) for more Quantum signatures and detective + work on the Quantum RAM layout. + + Special thanks to James T. McKinley (mckinley@msupa.pa.msu.edu) for + providing patches for proper PCI BIOS32-mediated detection of the TMC-3260 + card (a PCI bus card with the 36C70 chip). Please send James PCI-related + bug reports. + + Thanks to Tom Cavin (tec@usa1.com) for preliminary command-line option + patches. + + New PCI detection code written by Martin Mares + + Insmod parameter code based on patches from Daniel Graham + . + + All of the alpha testers deserve much thanks. + + + + NOTES ON USER DEFINABLE OPTIONS: + + DEBUG: This turns on the printing of various debug information. + + ENABLE_PARITY: This turns on SCSI parity checking. With the current + driver, all attached devices must support SCSI parity. If none of your + devices support parity, then you can probably get the driver to work by + turning this option off. I have no way of testing this, however, and it + would appear that no one ever uses this option. + + FIFO_COUNT: The host adapter has an 8K cache (host adapters based on the + 18C30 chip have a 2k cache). When this many 512 byte blocks are filled by + the SCSI device, an interrupt will be raised. Therefore, this could be as + low as 0, or as high as 16. Note, however, that values which are too high + or too low seem to prevent any interrupts from occurring, and thereby lock + up the machine. I have found that 2 is a good number, but throughput may + be increased by changing this value to values which are close to 2. + Please let me know if you try any different values. + + DO_DETECT: This activates some old scan code which was needed before the + high level drivers got fixed. If you are having trouble with the driver, + turning this on should not hurt, and might help. Please let me know if + this is the case, since this code will be removed from future drivers. + + RESELECTION: This is no longer an option, since I gave up trying to + implement it in version 4.x of this driver. It did not improve + performance at all and made the driver unstable (because I never found one + of the two race conditions which were introduced by the multiple + outstanding command code). The instability seems a very high price to pay + just so that you don't have to wait for the tape to rewind. If you want + this feature implemented, send me patches. I'll be happy to send a copy + of my (broken) driver to anyone who would like to see a copy. + + **************************************************************************/ + +#include + +#ifdef PCMCIA +#undef MODULE +#endif + +#include +#include +#include +#include +#include "scsi.h" +#include "hosts.h" +#include "fdomain.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include /* for CONFIG_PCI */ + +#define VERSION "$Revision: 5.50 $" + +/* START OF USER DEFINABLE OPTIONS */ + +#define DEBUG 1 /* Enable debugging output */ +#define ENABLE_PARITY 1 /* Enable SCSI Parity */ +#define FIFO_COUNT 2 /* Number of 512 byte blocks before INTR */ +#define DO_DETECT 0 /* Do device detection here (see scsi.c) */ + +/* END OF USER DEFINABLE OPTIONS */ + +#if DEBUG +#define EVERY_ACCESS 0 /* Write a line on every scsi access */ +#define ERRORS_ONLY 1 /* Only write a line if there is an error */ +#define DEBUG_DETECT 0 /* Debug fdomain_16x0_detect() */ +#define DEBUG_MESSAGES 1 /* Debug MESSAGE IN phase */ +#define DEBUG_ABORT 1 /* Debug abort() routine */ +#define DEBUG_RESET 1 /* Debug reset() routine */ +#define DEBUG_RACE 1 /* Debug interrupt-driven race condition */ +#else +#define EVERY_ACCESS 0 /* LEAVE THESE ALONE--CHANGE THE ONES ABOVE */ +#define ERRORS_ONLY 0 +#define DEBUG_DETECT 0 +#define DEBUG_MESSAGES 0 +#define DEBUG_ABORT 0 +#define DEBUG_RESET 0 +#define DEBUG_RACE 0 +#endif + +/* Errors are reported on the line, so we don't need to report them again */ +#if EVERY_ACCESS +#undef ERRORS_ONLY +#define ERRORS_ONLY 0 +#endif + +#if ENABLE_PARITY +#define PARITY_MASK 0x08 +#else +#define PARITY_MASK 0x00 +#endif + +enum chip_type { + unknown = 0x00, + tmc1800 = 0x01, + tmc18c50 = 0x02, + tmc18c30 = 0x03, +}; + +enum { + in_arbitration = 0x02, + in_selection = 0x04, + in_other = 0x08, + disconnect = 0x10, + aborted = 0x20, + sent_ident = 0x40, +}; + +enum in_port_type { + Read_SCSI_Data = 0, + SCSI_Status = 1, + TMC_Status = 2, + FIFO_Status = 3, /* tmc18c50/tmc18c30 only */ + Interrupt_Cond = 4, /* tmc18c50/tmc18c30 only */ + LSB_ID_Code = 5, + MSB_ID_Code = 6, + Read_Loopback = 7, + SCSI_Data_NoACK = 8, + Interrupt_Status = 9, + Configuration1 = 10, + Configuration2 = 11, /* tmc18c50/tmc18c30 only */ + Read_FIFO = 12, + FIFO_Data_Count = 14 +}; + +enum out_port_type { + Write_SCSI_Data = 0, + SCSI_Cntl = 1, + Interrupt_Cntl = 2, + SCSI_Mode_Cntl = 3, + TMC_Cntl = 4, + Memory_Cntl = 5, /* tmc18c50/tmc18c30 only */ + Write_Loopback = 7, + IO_Control = 11, /* tmc18c30 only */ + Write_FIFO = 12 +}; + +/* .bss will zero all the static variables below */ +static int port_base; +static unsigned long bios_base; +static int bios_major; +static int bios_minor; +static int PCI_bus; +static int Quantum; /* Quantum board variant */ +static int interrupt_level; +static volatile int in_command; +static Scsi_Cmnd *current_SC; +static enum chip_type chip = unknown; +static int adapter_mask; +static int this_id; +static int setup_called; + +#if DEBUG_RACE +static volatile int in_interrupt_flag; +#endif + +static int SCSI_Mode_Cntl_port; +static int FIFO_Data_Count_port; +static int Interrupt_Cntl_port; +static int Interrupt_Status_port; +static int Read_FIFO_port; +static int Read_SCSI_Data_port; +static int SCSI_Cntl_port; +static int SCSI_Data_NoACK_port; +static int SCSI_Status_port; +static int TMC_Cntl_port; +static int TMC_Status_port; +static int Write_FIFO_port; +static int Write_SCSI_Data_port; + +static int FIFO_Size = 0x2000; /* 8k FIFO for + pre-tmc18c30 chips */ + +static void do_fdomain_16x0_intr( int irq, void *dev_id, + struct pt_regs * regs ); + +#ifdef MODULE + /* Allow insmod parameters to be like LILO + parameters. For example: + insmod fdomain fdomain=0x140,11 + */ +static char * fdomain = NULL; +MODULE_PARM(fdomain, "s"); +#endif + +static unsigned long addresses[] = { + 0xc8000, + 0xca000, + 0xce000, + 0xde000, + 0xcc000, /* Extra addresses for PCI boards */ + 0xd0000, + 0xe0000, +}; +#define ADDRESS_COUNT (sizeof( addresses ) / sizeof( unsigned )) + +static unsigned short ports[] = { 0x140, 0x150, 0x160, 0x170 }; +#define PORT_COUNT (sizeof( ports ) / sizeof( unsigned short )) + +static unsigned short ints[] = { 3, 5, 10, 11, 12, 14, 15, 0 }; + +/* + + READ THIS BEFORE YOU ADD A SIGNATURE! + + READING THIS SHORT NOTE CAN SAVE YOU LOTS OF TIME! + + READ EVERY WORD, ESPECIALLY THE WORD *NOT* + + This driver works *ONLY* for Future Domain cards using the TMC-1800, + TMC-18C50, or TMC-18C30 chip. This includes models TMC-1650, 1660, 1670, + and 1680. These are all 16-bit cards. + + The following BIOS signature signatures are for boards which do *NOT* + work with this driver (these TMC-8xx and TMC-9xx boards may work with the + Seagate driver): + + FUTURE DOMAIN CORP. (C) 1986-1988 V4.0I 03/16/88 + FUTURE DOMAIN CORP. (C) 1986-1989 V5.0C2/14/89 + FUTURE DOMAIN CORP. (C) 1986-1989 V6.0A7/28/89 + FUTURE DOMAIN CORP. (C) 1986-1990 V6.0105/31/90 + FUTURE DOMAIN CORP. (C) 1986-1990 V6.0209/18/90 + FUTURE DOMAIN CORP. (C) 1986-1990 V7.009/18/90 + FUTURE DOMAIN CORP. (C) 1992 V8.00.004/02/92 + + (The cards which do *NOT* work are all 8-bit cards -- although some of + them have a 16-bit form-factor, the upper 8-bits are used only for IRQs + and are *NOT* used for data. You can tell the difference by following + the tracings on the circuit board -- if only the IRQ lines are involved, + you have a "8-bit" card, and should *NOT* use this driver.) + +*/ + +struct signature { + const char *signature; + int sig_offset; + int sig_length; + int major_bios_version; + int minor_bios_version; + int flag; /* 1 == PCI_bus, 2 == ISA_200S, 3 == ISA_250MG, 4 == ISA_200S */ +} signatures[] = { + /* 1 2 3 4 5 6 */ + /* 123456789012345678901234567890123456789012345678901234567890 */ + { "FUTURE DOMAIN CORP. (C) 1986-1990 1800-V2.07/28/89", 5, 50, 2, 0, 0 }, + { "FUTURE DOMAIN CORP. (C) 1986-1990 1800-V1.07/28/89", 5, 50, 2, 0, 0 }, + { "FUTURE DOMAIN CORP. (C) 1986-1990 1800-V2.07/28/89", 72, 50, 2, 0, 2 }, + { "FUTURE DOMAIN CORP. (C) 1986-1990 1800-V2.0", 73, 43, 2, 0, 3 }, + { "FUTURE DOMAIN CORP. (C) 1991 1800-V2.0.", 72, 39, 2, 0, 4 }, + { "FUTURE DOMAIN CORP. (C) 1992 V3.00.004/02/92", 5, 44, 3, 0, 0 }, + { "FUTURE DOMAIN TMC-18XX (C) 1993 V3.203/12/93", 5, 44, 3, 2, 0 }, + { "IBM F1 P2 BIOS v1.0104/29/93", 5, 28, 3, -1, 0 }, + { "Future Domain Corp. V1.0008/18/93", 5, 33, 3, 4, 0 }, + { "Future Domain Corp. V1.0008/18/93", 26, 33, 3, 4, 1 }, + { "Adaptec AHA-2920 PCI-SCSI Card", 42, 31, 3, -1, 1 }, + { "IBM F1 P264/32", 5, 14, 3, -1, 1 }, + /* This next signature may not be a 3.5 bios */ + { "Future Domain Corp. V2.0108/18/93", 5, 33, 3, 5, 0 }, + { "FUTURE DOMAIN CORP. V3.5008/18/93", 5, 34, 3, 5, 0 }, + { "FUTURE DOMAIN 18c30/18c50/1800 (C) 1994 V3.5", 5, 44, 3, 5, 0 }, + { "FUTURE DOMAIN CORP. V3.6008/18/93", 5, 34, 3, 6, 0 }, + { "FUTURE DOMAIN CORP. V3.6108/18/93", 5, 34, 3, 6, 0 }, + { "FUTURE DOMAIN TMC-18XX", 5, 22, -1, -1, 0 }, + + /* READ NOTICE ABOVE *BEFORE* YOU WASTE YOUR TIME ADDING A SIGNATURE + Also, fix the disk geometry code for your signature and send your + changes for faith@cs.unc.edu. Above all, do *NOT* change any old + signatures! + + Note that the last line will match a "generic" 18XX bios. Because + Future Domain has changed the host SCSI ID and/or the location of the + geometry information in the on-board RAM area for each of the first + three BIOS's, it is still important to enter a fully qualified + signature in the table for any new BIOS's (after the host SCSI ID and + geometry location are verified). */ +}; + +#define SIGNATURE_COUNT (sizeof( signatures ) / sizeof( struct signature )) + +static void print_banner( struct Scsi_Host *shpnt ) +{ + if (!shpnt) return; /* This won't ever happen */ + + if (bios_major < 0 && bios_minor < 0) { + printk(KERN_INFO "scsi%d: No BIOS; using scsi id %d\n", + shpnt->host_no, shpnt->this_id); + } else { + printk(KERN_INFO "scsi%d: BIOS version ", shpnt->host_no); + + if (bios_major >= 0) printk("%d.", bios_major); + else printk("?."); + + if (bios_minor >= 0) printk("%d", bios_minor); + else printk("?."); + + printk( " at 0x%lx using scsi id %d\n", + bios_base, shpnt->this_id ); + } + + /* If this driver works for later FD PCI + boards, we will have to modify banner + for additional PCI cards, but for now if + it's PCI it's a TMC-3260 - JTM */ + printk(KERN_INFO "scsi%d: %s chip at 0x%x irq ", + shpnt->host_no, + chip == tmc1800 ? "TMC-1800" : (chip == tmc18c50 ? "TMC-18C50" : (chip == tmc18c30 ? (PCI_bus ? "TMC-36C70 (PCI bus)" : "TMC-18C30") : "Unknown")), + port_base); + + if (interrupt_level) + printk("%d", interrupt_level); + else + printk(""); + + printk( "\n" ); +} + +static int __init fdomain_setup(char *str) +{ + int ints[4]; + + (void)get_options(str, ARRAY_SIZE(ints), ints); + + if (setup_called++ || ints[0] < 2 || ints[0] > 3) { + printk(KERN_INFO "scsi: Usage: fdomain=,[,]\n"); + printk(KERN_ERR "scsi: Bad LILO/INSMOD parameters?\n"); + return 0; + } + + port_base = ints[0] >= 1 ? ints[1] : 0; + interrupt_level = ints[0] >= 2 ? ints[2] : 0; + this_id = ints[0] >= 3 ? ints[3] : 0; + + bios_major = bios_minor = -1; /* Use geometry for BIOS version >= 3.4 */ + ++setup_called; + return 1; +} + +__setup("fdomain=", fdomain_setup); + + +static void do_pause(unsigned amount) /* Pause for amount*10 milliseconds */ +{ + mdelay(10*amount); +} + +inline static void fdomain_make_bus_idle( void ) +{ + outb( 0, SCSI_Cntl_port ); + outb( 0, SCSI_Mode_Cntl_port ); + if (chip == tmc18c50 || chip == tmc18c30) + outb( 0x21 | PARITY_MASK, TMC_Cntl_port ); /* Clear forced intr. */ + else + outb( 0x01 | PARITY_MASK, TMC_Cntl_port ); +} + +static int fdomain_is_valid_port( int port ) +{ +#if DEBUG_DETECT + printk( " (%x%x),", + inb( port + MSB_ID_Code ), inb( port + LSB_ID_Code ) ); +#endif + + /* The MCA ID is a unique id for each MCA compatible board. We + are using ISA boards, but Future Domain provides the MCA ID + anyway. We can use this ID to ensure that this is a Future + Domain TMC-1660/TMC-1680. + */ + + if (inb( port + LSB_ID_Code ) != 0xe9) { /* test for 0x6127 id */ + if (inb( port + LSB_ID_Code ) != 0x27) return 0; + if (inb( port + MSB_ID_Code ) != 0x61) return 0; + chip = tmc1800; + } else { /* test for 0xe960 id */ + if (inb( port + MSB_ID_Code ) != 0x60) return 0; + chip = tmc18c50; + + /* Try to toggle 32-bit mode. This only + works on an 18c30 chip. (User reports + say this works, so we should switch to + it in the near future.) */ + + outb( 0x80, port + IO_Control ); + if ((inb( port + Configuration2 ) & 0x80) == 0x80) { + outb( 0x00, port + IO_Control ); + if ((inb( port + Configuration2 ) & 0x80) == 0x00) { + chip = tmc18c30; + FIFO_Size = 0x800; /* 2k FIFO */ + } + } + /* If that failed, we are an 18c50. */ + } + + return 1; +} + +static int fdomain_test_loopback( void ) +{ + int i; + int result; + + for (i = 0; i < 255; i++) { + outb( i, port_base + Write_Loopback ); + result = inb( port_base + Read_Loopback ); + if (i != result) + return 1; + } + return 0; +} + +/* fdomain_get_irq assumes that we have a valid MCA ID for a + TMC-1660/TMC-1680 Future Domain board. Now, check to be sure the + bios_base matches these ports. If someone was unlucky enough to have + purchased more than one Future Domain board, then they will have to + modify this code, as we only detect one board here. [The one with the + lowest bios_base.] + + Note that this routine is only used for systems without a PCI BIOS32 + (e.g., ISA bus). For PCI bus systems, this routine will likely fail + unless one of the IRQs listed in the ints array is used by the board. + Sometimes it is possible to use the computer's BIOS setup screen to + configure a PCI system so that one of these IRQs will be used by the + Future Domain card. */ + +static int fdomain_get_irq( int base ) +{ + int options = inb(base + Configuration1); + +#if DEBUG_DETECT + printk("scsi: Options = %x\n", options); +#endif + + /* Check for board with lowest bios_base -- + this isn't valid for the 18c30 or for + boards on the PCI bus, so just assume we + have the right board. */ + + if (chip != tmc18c30 && !PCI_bus && addresses[(options & 0xc0) >> 6 ] != bios_base) + return 0; + return ints[(options & 0x0e) >> 1]; +} + +static int fdomain_isa_detect( int *irq, int *iobase ) +{ + int i, j; + int base = 0xdeadbeef; + int flag = 0; + +#if DEBUG_DETECT + printk( "scsi: fdomain_isa_detect:" ); +#endif + + for (i = 0; !bios_base && i < ADDRESS_COUNT; i++) { +#if DEBUG_DETECT + printk( " %lx(%lx),", addresses[i], bios_base ); +#endif + for (j = 0; !bios_base && j < SIGNATURE_COUNT; j++) { + if (isa_check_signature(addresses[i] + signatures[j].sig_offset, + signatures[j].signature, + signatures[j].sig_length )) { + bios_major = signatures[j].major_bios_version; + bios_minor = signatures[j].minor_bios_version; + PCI_bus = (signatures[j].flag == 1); + Quantum = (signatures[j].flag > 1) ? signatures[j].flag : 0; + bios_base = addresses[i]; + } + } + } + + if (bios_major == 2) { + /* The TMC-1660/TMC-1680 has a RAM area just after the BIOS ROM. + Assuming the ROM is enabled (otherwise we wouldn't have been + able to read the ROM signature :-), then the ROM sets up the + RAM area with some magic numbers, such as a list of port + base addresses and a list of the disk "geometry" reported to + DOS (this geometry has nothing to do with physical geometry). + */ + + switch (Quantum) { + case 2: /* ISA_200S */ + case 3: /* ISA_250MG */ + base = readb(bios_base + 0x1fa2) + (readb(bios_base + 0x1fa3) << 8); + break; + case 4: /* ISA_200S (another one) */ + base = readb(bios_base + 0x1fa3) + (readb(bios_base + 0x1fa4) << 8); + break; + default: + base = readb(bios_base + 0x1fcc) + (readb(bios_base + 0x1fcd) << 8); + break; + } + +#if DEBUG_DETECT + printk( " %x,", base ); +#endif + + for (flag = 0, i = 0; !flag && i < PORT_COUNT; i++) { + if (base == ports[i]) + ++flag; + } + + if (flag && fdomain_is_valid_port( base )) { + *irq = fdomain_get_irq( base ); + *iobase = base; + return 1; + } + + /* This is a bad sign. It usually means that someone patched the + BIOS signature list (the signatures variable) to contain a BIOS + signature for a board *OTHER THAN* the TMC-1660/TMC-1680. */ + +#if DEBUG_DETECT + printk( " RAM FAILED, " ); +#endif + } + + /* Anyway, the alternative to finding the address in the RAM is to just + search through every possible port address for one that is attached + to the Future Domain card. Don't panic, though, about reading all + these random port addresses -- there are rumors that the Future + Domain BIOS does something very similar. + + Do not, however, check ports which the kernel knows are being used by + another driver. */ + + for (i = 0; i < PORT_COUNT; i++) { + base = ports[i]; + if (check_region( base, 0x10 )) { +#if DEBUG_DETECT + printk( " (%x inuse),", base ); +#endif + continue; + } +#if DEBUG_DETECT + printk( " %x,", base ); +#endif + if ((flag = fdomain_is_valid_port( base ))) break; + } + +#if DEBUG_DETECT + if (flag) printk( " SUCCESS\n" ); + else printk( " FAILURE\n" ); +#endif + + if (!flag) return 0; /* iobase not found */ + + *irq = fdomain_get_irq( base ); + *iobase = base; + + return 1; /* success */ +} + +/* PCI detection function: int fdomain_pci_bios_detect(int* irq, int* + iobase) This function gets the Interrupt Level and I/O base address from + the PCI configuration registers. */ + +#ifdef CONFIG_PCI +static int fdomain_pci_bios_detect( int *irq, int *iobase, struct pci_dev **ret_pdev ) +{ + unsigned int pci_irq; /* PCI interrupt line */ + unsigned long pci_base; /* PCI I/O base address */ + struct pci_dev *pdev = NULL; + +#if DEBUG_DETECT + /* Tell how to print a list of the known PCI devices from bios32 and + list vendor and device IDs being used if in debug mode. */ + + printk( "scsi: INFO: use lspci -v to see list of PCI devices\n" ); + printk( "scsi: TMC-3260 detect:" + " Using Vendor ID: 0x%x and Device ID: 0x%x\n", + PCI_VENDOR_ID_FD, + PCI_DEVICE_ID_FD_36C70 ); +#endif + + if ((pdev = pci_find_device(PCI_VENDOR_ID_FD, PCI_DEVICE_ID_FD_36C70, pdev)) == NULL) + return 0; + if (pci_enable_device(pdev)) return 0; + +#if DEBUG_DETECT + printk( "scsi: TMC-3260 detect:" + " PCI bus %u, device %u, function %u\n", + pdev->bus->number, + PCI_SLOT(pdev->devfn), + PCI_FUNC(pdev->devfn)); +#endif + + /* We now have the appropriate device function for the FD board so we + just read the PCI config info from the registers. */ + + pci_base = pci_resource_start(pdev, 0); + pci_irq = pdev->irq; + + /* Now we have the I/O base address and interrupt from the PCI + configuration registers. */ + + *irq = pci_irq; + *iobase = pci_base; + *ret_pdev = pdev; + +#if DEBUG_DETECT + printk( "scsi: TMC-3260 detect:" + " IRQ = %d, I/O base = 0x%x [0x%lx]\n", *irq, *iobase, pci_base ); +#endif + + if (!fdomain_is_valid_port( *iobase )) { + printk(KERN_ERR "scsi: PCI card detected, but driver not loaded (invalid port)\n" ); + return 0; + } + + /* Fill in a few global variables. Ugh. */ + bios_major = bios_minor = -1; + PCI_bus = 1; + Quantum = 0; + bios_base = 0; + + return 1; +} +#endif + +static int fdomain_16x0_detect( Scsi_Host_Template *tpnt ) +{ + int retcode; + struct Scsi_Host *shpnt; + struct pci_dev *pdev = NULL; +#if DO_DETECT + int i = 0; + int j = 0; + const int buflen = 255; + Scsi_Cmnd SCinit; + unsigned char do_inquiry[] = { INQUIRY, 0, 0, 0, buflen, 0 }; + unsigned char do_request_sense[] = { REQUEST_SENSE, 0, 0, 0, buflen, 0 }; + unsigned char do_read_capacity[] = { READ_CAPACITY, + 0, 0, 0, 0, 0, 0, 0, 0, 0 }; + unsigned char buf[buflen]; +#endif + + tpnt->proc_name = "fdomain"; + +#ifdef MODULE + if (fdomain) + fdomain_setup(fdomain); +#endif + + if (setup_called) { +#if DEBUG_DETECT + printk( "scsi: No BIOS, using port_base = 0x%x, irq = %d\n", + port_base, interrupt_level ); +#endif + if (!fdomain_is_valid_port( port_base )) { + printk( "scsi: Cannot locate chip at port base 0x%x\n", + port_base ); + printk( "scsi: Bad LILO/INSMOD parameters?\n" ); + return 0; + } + } else { + int flag = 0; + +#ifdef CONFIG_PCI + /* Try PCI detection first */ + flag = fdomain_pci_bios_detect( &interrupt_level, &port_base, &pdev ); +#endif + if (!flag) { + /* Then try ISA bus detection */ + flag = fdomain_isa_detect( &interrupt_level, &port_base ); + + if (!flag) { + printk( "scsi: Detection failed (no card)\n" ); + return 0; + } + } + } + + SCSI_Mode_Cntl_port = port_base + SCSI_Mode_Cntl; + FIFO_Data_Count_port = port_base + FIFO_Data_Count; + Interrupt_Cntl_port = port_base + Interrupt_Cntl; + Interrupt_Status_port = port_base + Interrupt_Status; + Read_FIFO_port = port_base + Read_FIFO; + Read_SCSI_Data_port = port_base + Read_SCSI_Data; + SCSI_Cntl_port = port_base + SCSI_Cntl; + SCSI_Data_NoACK_port = port_base + SCSI_Data_NoACK; + SCSI_Status_port = port_base + SCSI_Status; + TMC_Cntl_port = port_base + TMC_Cntl; + TMC_Status_port = port_base + TMC_Status; + Write_FIFO_port = port_base + Write_FIFO; + Write_SCSI_Data_port = port_base + Write_SCSI_Data; + + fdomain_16x0_bus_reset( NULL); + + if (fdomain_test_loopback()) { + printk(KERN_ERR "scsi: Detection failed (loopback test failed at port base 0x%x)\n", port_base); + if (setup_called) { + printk(KERN_ERR "scsi: Bad LILO/INSMOD parameters?\n"); + } + return 0; + } + + if (this_id) { + tpnt->this_id = (this_id & 0x07); + adapter_mask = (1 << tpnt->this_id); + } else { + if (PCI_bus || (bios_major == 3 && bios_minor >= 2) || bios_major < 0) { + tpnt->this_id = 7; + adapter_mask = 0x80; + } else { + tpnt->this_id = 6; + adapter_mask = 0x40; + } + } + +/* Print out a banner here in case we can't + get resources. */ + + shpnt = scsi_register( tpnt, 0 ); + if(shpnt == NULL) + return 0; + shpnt->irq = interrupt_level; + shpnt->io_port = port_base; + scsi_set_pci_device(shpnt, pdev); + shpnt->n_io_port = 0x10; + print_banner( shpnt ); + + /* Log IRQ with kernel */ + if (!interrupt_level) { + printk(KERN_ERR "scsi: Card Detected, but driver not loaded (no IRQ)\n" ); + return 0; + } else { + /* Register the IRQ with the kernel */ + + retcode = request_irq( interrupt_level, + do_fdomain_16x0_intr, pdev?SA_SHIRQ:0, "fdomain", shpnt); + + if (retcode < 0) { + if (retcode == -EINVAL) { + printk(KERN_ERR "scsi: IRQ %d is bad!\n", interrupt_level ); + printk(KERN_ERR " This shouldn't happen!\n" ); + printk(KERN_ERR " Send mail to faith@acm.org\n" ); + } else if (retcode == -EBUSY) { + printk(KERN_ERR "scsi: IRQ %d is already in use!\n", interrupt_level ); + printk(KERN_ERR " Please use another IRQ!\n" ); + } else { + printk(KERN_ERR "scsi: Error getting IRQ %d\n", interrupt_level ); + printk(KERN_ERR " This shouldn't happen!\n" ); + printk(KERN_ERR " Send mail to faith@acm.org\n" ); + } + printk(KERN_ERR "scsi: Detected, but driver not loaded (IRQ)\n" ); + return 0; + } + } + + /* Log I/O ports with kernel */ + request_region( port_base, 0x10, "fdomain" ); + +#if DO_DETECT + + /* These routines are here because of the way the SCSI bus behaves after + a reset. This appropriate behavior was not handled correctly by the + higher level SCSI routines when I first wrote this driver. Now, + however, correct scan routines are part of scsi.c and these routines + are no longer needed. However, this code is still good for + debugging. */ + + SCinit.request_buffer = SCinit.buffer = buf; + SCinit.request_bufflen = SCinit.bufflen = sizeof(buf)-1; + SCinit.use_sg = 0; + SCinit.lun = 0; + + printk( "scsi: detection routine scanning for devices:\n" ); + for (i = 0; i < 8; i++) { + SCinit.target = i; + if (i == tpnt->this_id) /* Skip host adapter */ + continue; + memcpy(SCinit.cmnd, do_request_sense, sizeof(do_request_sense)); + retcode = fdomain_16x0_command(&SCinit); + if (!retcode) { + memcpy(SCinit.cmnd, do_inquiry, sizeof(do_inquiry)); + retcode = fdomain_16x0_command(&SCinit); + if (!retcode) { + printk( " SCSI ID %d: ", i ); + for (j = 8; j < (buf[4] < 32 ? buf[4] : 32); j++) + printk( "%c", buf[j] >= 20 ? buf[j] : ' ' ); + memcpy(SCinit.cmnd, do_read_capacity, sizeof(do_read_capacity)); + retcode = fdomain_16x0_command(&SCinit); + if (!retcode) { + unsigned long blocks, size, capacity; + + blocks = (buf[0] << 24) | (buf[1] << 16) + | (buf[2] << 8) | buf[3]; + size = (buf[4] << 24) | (buf[5] << 16) | (buf[6] << 8) | buf[7]; + capacity = +( +(blocks / 1024L) * +(size * 10L)) / 1024L; + + printk( "%lu MB (%lu byte blocks)", + ((capacity + 5L) / 10L), size ); + } else { + memcpy(SCinit.cmnd, do_request_sense, sizeof(do_request_sense)); + retcode = fdomain_16x0_command(&SCinit); + } + printk ("\n" ); + } else { + memcpy(SCinit.cmnd, do_request_sense, sizeof(do_request_sense)); + retcode = fdomain_16x0_command(&SCinit); + } + } + } +#endif + + return 1; /* Maximum of one adapter will be detected. */ +} + +static const char *fdomain_16x0_info( struct Scsi_Host *ignore ) +{ + static char buffer[128]; + char *pt; + + strcpy( buffer, "Future Domain 16-bit SCSI Driver Version" ); + if (strchr( VERSION, ':')) { /* Assume VERSION is an RCS Revision string */ + strcat( buffer, strchr( VERSION, ':' ) + 1 ); + pt = strrchr( buffer, '$') - 1; + if (!pt) /* Stripped RCS Revision string? */ + pt = buffer + strlen( buffer ) - 1; + if (*pt != ' ') + ++pt; + *pt = '\0'; + } else { /* Assume VERSION is a number */ + strcat( buffer, " " VERSION ); + } + + return buffer; +} + + /* First pass at /proc information routine. */ +/* + * inout : decides on the direction of the dataflow and the meaning of the + * variables + * buffer: If inout==FALSE data is being written to it else read from it + * *start: If inout==FALSE start of the valid data in the buffer + * offset: If inout==FALSE offset from the beginning of the imaginary file + * from which we start writing into the buffer + * length: If inout==FALSE max number of bytes to be written into the buffer + * else number of bytes in the buffer + */ +static int fdomain_16x0_proc_info( char *buffer, char **start, off_t offset, + int length, int hostno, int inout ) +{ + const char *info = fdomain_16x0_info( NULL ); + int len; + int pos; + int begin; + + if (inout) return(-EINVAL); + + begin = 0; + strcpy( buffer, info ); + strcat( buffer, "\n" ); + + pos = len = strlen( buffer ); + + if(pos < offset) { + len = 0; + begin = pos; + } + + *start = buffer + (offset - begin); /* Start of wanted data */ + len -= (offset - begin); + if(len > length) len = length; + + return(len); +} + +#if 0 +static int fdomain_arbitrate( void ) +{ + int status = 0; + unsigned long timeout; + +#if EVERY_ACCESS + printk( "fdomain_arbitrate()\n" ); +#endif + + outb( 0x00, SCSI_Cntl_port ); /* Disable data drivers */ + outb( adapter_mask, port_base + SCSI_Data_NoACK ); /* Set our id bit */ + outb( 0x04 | PARITY_MASK, TMC_Cntl_port ); /* Start arbitration */ + + timeout = 500; + do { + status = inb( TMC_Status_port ); /* Read adapter status */ + if (status & 0x02) /* Arbitration complete */ + return 0; + mdelay(1); /* Wait one millisecond */ + } while (--timeout); + + /* Make bus idle */ + fdomain_make_bus_idle(); + +#if EVERY_ACCESS + printk( "Arbitration failed, status = %x\n", status ); +#endif +#if ERRORS_ONLY + printk( "scsi: Arbitration failed, status = %x\n", status ); +#endif + return 1; +} +#endif + +static int fdomain_select( int target ) +{ + int status; + unsigned long timeout; + static int flag = 0; + + + outb( 0x82, SCSI_Cntl_port ); /* Bus Enable + Select */ + outb( adapter_mask | (1 << target), SCSI_Data_NoACK_port ); + + /* Stop arbitration and enable parity */ + outb( PARITY_MASK, TMC_Cntl_port ); + + timeout = 350; /* 350 msec */ + + do { + status = inb( SCSI_Status_port ); /* Read adapter status */ + if (status & 1) { /* Busy asserted */ + /* Enable SCSI Bus (on error, should make bus idle with 0) */ + outb( 0x80, SCSI_Cntl_port ); + return 0; + } + mdelay(1); /* wait one msec */ + } while (--timeout); + /* Make bus idle */ + fdomain_make_bus_idle(); +#if EVERY_ACCESS + if (!target) printk( "Selection failed\n" ); +#endif +#if ERRORS_ONLY + if (!target) { + if (!flag) /* Skip first failure for all chips. */ + ++flag; + else + printk( "scsi: Selection failed\n" ); + } +#endif + return 1; +} + +static void my_done(int error) +{ + if (in_command) { + in_command = 0; + outb( 0x00, Interrupt_Cntl_port ); + fdomain_make_bus_idle(); + current_SC->result = error; + if (current_SC->scsi_done) + current_SC->scsi_done( current_SC ); + else panic( "scsi: current_SC->scsi_done() == NULL" ); + } else { + panic( "scsi: my_done() called outside of command\n" ); + } +#if DEBUG_RACE + in_interrupt_flag = 0; +#endif +} + +static void do_fdomain_16x0_intr( int irq, void *dev_id, struct pt_regs * regs ) +{ + unsigned long flags; + int status; + int done = 0; + unsigned data_count; + + /* The fdomain_16x0_intr is only called via + the interrupt handler. The goal of the + sti() here is to allow other + interruptions while this routine is + running. */ + + /* Check for other IRQ sources */ + if((inb(TMC_Status_port)&0x01)==0) + return; + + /* It is our IRQ */ + outb( 0x00, Interrupt_Cntl_port ); + + /* We usually have one spurious interrupt after each command. Ignore it. */ + if (!in_command || !current_SC) { /* Spurious interrupt */ +#if EVERY_ACCESS + printk( "Spurious interrupt, in_command = %d, current_SC = %x\n", + in_command, current_SC ); +#endif + return; + } + + /* Abort calls my_done, so we do nothing here. */ + if (current_SC->SCp.phase & aborted) { +#if DEBUG_ABORT + printk( "scsi: Interrupt after abort, ignoring\n" ); +#endif + /* + return; */ + } + +#if DEBUG_RACE + ++in_interrupt_flag; +#endif + + if (current_SC->SCp.phase & in_arbitration) { + status = inb( TMC_Status_port ); /* Read adapter status */ + if (!(status & 0x02)) { +#if EVERY_ACCESS + printk( " AFAIL " ); +#endif + spin_lock_irqsave(current_SC->host->host_lock, flags); + my_done( DID_BUS_BUSY << 16 ); + spin_unlock_irqrestore(current_SC->host->host_lock, flags); + return; + } + current_SC->SCp.phase = in_selection; + + outb( 0x40 | FIFO_COUNT, Interrupt_Cntl_port ); + + outb( 0x82, SCSI_Cntl_port ); /* Bus Enable + Select */ + outb( adapter_mask | (1 << current_SC->target), SCSI_Data_NoACK_port ); + + /* Stop arbitration and enable parity */ + outb( 0x10 | PARITY_MASK, TMC_Cntl_port ); +#if DEBUG_RACE + in_interrupt_flag = 0; +#endif + return; + } else if (current_SC->SCp.phase & in_selection) { + status = inb( SCSI_Status_port ); + if (!(status & 0x01)) { + /* Try again, for slow devices */ + if (fdomain_select( current_SC->target )) { +#if EVERY_ACCESS + printk( " SFAIL " ); +#endif + spin_lock_irqsave(current_SC->host->host_lock, flags); + my_done( DID_NO_CONNECT << 16 ); + spin_unlock_irqrestore(current_SC->host->host_lock, flags); + return; + } else { +#if EVERY_ACCESS + printk( " AltSel " ); +#endif + /* Stop arbitration and enable parity */ + outb( 0x10 | PARITY_MASK, TMC_Cntl_port ); + } + } + current_SC->SCp.phase = in_other; + outb( 0x90 | FIFO_COUNT, Interrupt_Cntl_port ); + outb( 0x80, SCSI_Cntl_port ); +#if DEBUG_RACE + in_interrupt_flag = 0; +#endif + return; + } + + /* current_SC->SCp.phase == in_other: this is the body of the routine */ + + status = inb( SCSI_Status_port ); + + if (status & 0x10) { /* REQ */ + + switch (status & 0x0e) { + + case 0x08: /* COMMAND OUT */ + outb( current_SC->cmnd[current_SC->SCp.sent_command++], + Write_SCSI_Data_port ); +#if EVERY_ACCESS + printk( "CMD = %x,", + current_SC->cmnd[ current_SC->SCp.sent_command - 1] ); +#endif + break; + case 0x00: /* DATA OUT -- tmc18c50/tmc18c30 only */ + if (chip != tmc1800 && !current_SC->SCp.have_data_in) { + current_SC->SCp.have_data_in = -1; + outb( 0xd0 | PARITY_MASK, TMC_Cntl_port ); + } + break; + case 0x04: /* DATA IN -- tmc18c50/tmc18c30 only */ + if (chip != tmc1800 && !current_SC->SCp.have_data_in) { + current_SC->SCp.have_data_in = 1; + outb( 0x90 | PARITY_MASK, TMC_Cntl_port ); + } + break; + case 0x0c: /* STATUS IN */ + current_SC->SCp.Status = inb( Read_SCSI_Data_port ); +#if EVERY_ACCESS + printk( "Status = %x, ", current_SC->SCp.Status ); +#endif +#if ERRORS_ONLY + if (current_SC->SCp.Status + && current_SC->SCp.Status != 2 + && current_SC->SCp.Status != 8) { + printk( "scsi: target = %d, command = %x, status = %x\n", + current_SC->target, + current_SC->cmnd[0], + current_SC->SCp.Status ); + } +#endif + break; + case 0x0a: /* MESSAGE OUT */ + outb( MESSAGE_REJECT, Write_SCSI_Data_port ); /* Reject */ + break; + case 0x0e: /* MESSAGE IN */ + current_SC->SCp.Message = inb( Read_SCSI_Data_port ); +#if EVERY_ACCESS + printk( "Message = %x, ", current_SC->SCp.Message ); +#endif + if (!current_SC->SCp.Message) ++done; +#if DEBUG_MESSAGES || EVERY_ACCESS + if (current_SC->SCp.Message) { + printk( "scsi: message = %x\n", + current_SC->SCp.Message ); + } +#endif + break; + } + } + + if (chip == tmc1800 && !current_SC->SCp.have_data_in + && (current_SC->SCp.sent_command >= current_SC->cmd_len)) { + + if(scsi_to_pci_dma_dir(current_SC->sc_data_direction) == PCI_DMA_TODEVICE) + { + current_SC->SCp.have_data_in = -1; + outb( 0xd0 | PARITY_MASK, TMC_Cntl_port ); + } + else + { + current_SC->SCp.have_data_in = 1; + outb( 0x90 | PARITY_MASK, TMC_Cntl_port ); + } + } + + if (current_SC->SCp.have_data_in == -1) { /* DATA OUT */ + while ( (data_count = FIFO_Size - inw( FIFO_Data_Count_port )) > 512 ) { +#if EVERY_ACCESS + printk( "DC=%d, ", data_count ) ; +#endif + if (data_count > current_SC->SCp.this_residual) + data_count = current_SC->SCp.this_residual; + if (data_count > 0) { +#if EVERY_ACCESS + printk( "%d OUT, ", data_count ); +#endif + if (data_count == 1) { + outb( *current_SC->SCp.ptr++, Write_FIFO_port ); + --current_SC->SCp.this_residual; + } else { + data_count >>= 1; + outsw( Write_FIFO_port, current_SC->SCp.ptr, data_count ); + current_SC->SCp.ptr += 2 * data_count; + current_SC->SCp.this_residual -= 2 * data_count; + } + } + if (!current_SC->SCp.this_residual) { + if (current_SC->SCp.buffers_residual) { + --current_SC->SCp.buffers_residual; + ++current_SC->SCp.buffer; + current_SC->SCp.ptr = page_address(current_SC->SCp.buffer->page) + current_SC->SCp.buffer->offset; + current_SC->SCp.this_residual = current_SC->SCp.buffer->length; + } else + break; + } + } + } + + if (current_SC->SCp.have_data_in == 1) { /* DATA IN */ + while ((data_count = inw( FIFO_Data_Count_port )) > 0) { +#if EVERY_ACCESS + printk( "DC=%d, ", data_count ); +#endif + if (data_count > current_SC->SCp.this_residual) + data_count = current_SC->SCp.this_residual; + if (data_count) { +#if EVERY_ACCESS + printk( "%d IN, ", data_count ); +#endif + if (data_count == 1) { + *current_SC->SCp.ptr++ = inb( Read_FIFO_port ); + --current_SC->SCp.this_residual; + } else { + data_count >>= 1; /* Number of words */ + insw( Read_FIFO_port, current_SC->SCp.ptr, data_count ); + current_SC->SCp.ptr += 2 * data_count; + current_SC->SCp.this_residual -= 2 * data_count; + } + } + if (!current_SC->SCp.this_residual + && current_SC->SCp.buffers_residual) { + --current_SC->SCp.buffers_residual; + ++current_SC->SCp.buffer; + current_SC->SCp.ptr = page_address(current_SC->SCp.buffer->page) + current_SC->SCp.buffer->offset; + current_SC->SCp.this_residual = current_SC->SCp.buffer->length; + } + } + } + + if (done) { +#if EVERY_ACCESS + printk( " ** IN DONE %d ** ", current_SC->SCp.have_data_in ); +#endif + +#if ERRORS_ONLY + if (current_SC->cmnd[0] == REQUEST_SENSE && !current_SC->SCp.Status) { + if ((unsigned char)(*((char *)current_SC->request_buffer+2)) & 0x0f) { + unsigned char key; + unsigned char code; + unsigned char qualifier; + + key = (unsigned char)(*((char *)current_SC->request_buffer + 2)) + & 0x0f; + code = (unsigned char)(*((char *)current_SC->request_buffer + 12)); + qualifier = (unsigned char)(*((char *)current_SC->request_buffer + + 13)); + + if (key != UNIT_ATTENTION + && !(key == NOT_READY + && code == 0x04 + && (!qualifier || qualifier == 0x02 || qualifier == 0x01)) + && !(key == ILLEGAL_REQUEST && (code == 0x25 + || code == 0x24 + || !code))) + + printk( "scsi: REQUEST SENSE" + " Key = %x, Code = %x, Qualifier = %x\n", + key, code, qualifier ); + } + } +#endif +#if EVERY_ACCESS + printk( "BEFORE MY_DONE. . ." ); +#endif + spin_lock_irqsave(current_SC->host->host_lock, flags); + my_done( (current_SC->SCp.Status & 0xff) + | ((current_SC->SCp.Message & 0xff) << 8) | (DID_OK << 16) ); + spin_unlock_irqrestore(current_SC->host->host_lock, flags); +#if EVERY_ACCESS + printk( "RETURNING.\n" ); +#endif + + } else { + if (current_SC->SCp.phase & disconnect) { + outb( 0xd0 | FIFO_COUNT, Interrupt_Cntl_port ); + outb( 0x00, SCSI_Cntl_port ); + } else { + outb( 0x90 | FIFO_COUNT, Interrupt_Cntl_port ); + } + } +#if DEBUG_RACE + in_interrupt_flag = 0; +#endif + return; +} + +static int fdomain_16x0_queue( Scsi_Cmnd * SCpnt, void (*done)(Scsi_Cmnd *)) +{ + if (in_command) { + panic( "scsi: fdomain_16x0_queue() NOT REENTRANT!\n" ); + } +#if EVERY_ACCESS + printk( "queue: target = %d cmnd = 0x%02x pieces = %d size = %u\n", + SCpnt->target, + *(unsigned char *)SCpnt->cmnd, + SCpnt->use_sg, + SCpnt->request_bufflen ); +#endif + + fdomain_make_bus_idle(); + + current_SC = SCpnt; /* Save this for the done function */ + current_SC->scsi_done = done; + + /* Initialize static data */ + + if (current_SC->use_sg) { + current_SC->SCp.buffer = + (struct scatterlist *)current_SC->request_buffer; + current_SC->SCp.ptr = page_address(current_SC->SCp.buffer->page) + current_SC->SCp.buffer->offset; + current_SC->SCp.this_residual = current_SC->SCp.buffer->length; + current_SC->SCp.buffers_residual = current_SC->use_sg - 1; + } else { + current_SC->SCp.ptr = (char *)current_SC->request_buffer; + current_SC->SCp.this_residual = current_SC->request_bufflen; + current_SC->SCp.buffer = NULL; + current_SC->SCp.buffers_residual = 0; + } + + + current_SC->SCp.Status = 0; + current_SC->SCp.Message = 0; + current_SC->SCp.have_data_in = 0; + current_SC->SCp.sent_command = 0; + current_SC->SCp.phase = in_arbitration; + + /* Start arbitration */ + outb( 0x00, Interrupt_Cntl_port ); + outb( 0x00, SCSI_Cntl_port ); /* Disable data drivers */ + outb( adapter_mask, SCSI_Data_NoACK_port ); /* Set our id bit */ + ++in_command; + outb( 0x20, Interrupt_Cntl_port ); + outb( 0x14 | PARITY_MASK, TMC_Cntl_port ); /* Start arbitration */ + + return 0; +} + +/* The following code, which simulates the old-style command function, was + taken from Tommy Thorn's aha1542.c file. This code is Copyright (C) + 1992 Tommy Thorn. */ + +static volatile int internal_done_flag = 0; +static volatile int internal_done_errcode = 0; + +static void internal_done(Scsi_Cmnd *SCpnt) +{ + internal_done_errcode = SCpnt->result; + ++internal_done_flag; +} + +static int fdomain_16x0_command(Scsi_Cmnd *SCpnt) +{ + fdomain_16x0_queue(SCpnt, internal_done); + + while (!internal_done_flag) + cpu_relax(); + internal_done_flag = 0; + return internal_done_errcode; +} + +/* End of code derived from Tommy Thorn's work. */ + +static void print_info(Scsi_Cmnd *SCpnt) +{ + unsigned int imr; + unsigned int irr; + unsigned int isr; + + if (!SCpnt || !SCpnt->host) { + printk(KERN_WARNING "scsi: Cannot provide detailed information\n"); + return; + } + + printk(KERN_INFO "%s\n", fdomain_16x0_info( SCpnt->host ) ); + print_banner(SCpnt->host); + switch (SCpnt->SCp.phase) { + case in_arbitration: printk("arbitration"); break; + case in_selection: printk("selection"); break; + case in_other: printk("other"); break; + default: printk("unknown"); break; + } + + printk( " (%d), target = %d cmnd = 0x%02x pieces = %d size = %u\n", + SCpnt->SCp.phase, + SCpnt->target, + *(unsigned char *)SCpnt->cmnd, + SCpnt->use_sg, + SCpnt->request_bufflen ); + printk( "sent_command = %d, have_data_in = %d, timeout = %d\n", + SCpnt->SCp.sent_command, + SCpnt->SCp.have_data_in, + SCpnt->timeout ); +#if DEBUG_RACE + printk( "in_interrupt_flag = %d\n", in_interrupt_flag ); +#endif + + imr = (inb( 0x0a1 ) << 8) + inb( 0x21 ); + outb( 0x0a, 0xa0 ); + irr = inb( 0xa0 ) << 8; + outb( 0x0a, 0x20 ); + irr += inb( 0x20 ); + outb( 0x0b, 0xa0 ); + isr = inb( 0xa0 ) << 8; + outb( 0x0b, 0x20 ); + isr += inb( 0x20 ); + + /* Print out interesting information */ + printk( "IMR = 0x%04x", imr ); + if (imr & (1 << interrupt_level)) + printk( " (masked)" ); + printk( ", IRR = 0x%04x, ISR = 0x%04x\n", irr, isr ); + + printk( "SCSI Status = 0x%02x\n", inb( SCSI_Status_port ) ); + printk( "TMC Status = 0x%02x", inb( TMC_Status_port ) ); + if (inb( TMC_Status_port & 1)) + printk( " (interrupt)" ); + printk( "\n" ); + printk( "Interrupt Status = 0x%02x", inb( Interrupt_Status_port ) ); + if (inb( Interrupt_Status_port ) & 0x08) + printk( " (enabled)" ); + printk( "\n" ); + if (chip == tmc18c50 || chip == tmc18c30) { + printk( "FIFO Status = 0x%02x\n", inb( port_base + FIFO_Status ) ); + printk( "Int. Condition = 0x%02x\n", + inb( port_base + Interrupt_Cond ) ); + } + printk( "Configuration 1 = 0x%02x\n", inb( port_base + Configuration1 ) ); + if (chip == tmc18c50 || chip == tmc18c30) + printk( "Configuration 2 = 0x%02x\n", + inb( port_base + Configuration2 ) ); +} + +static int fdomain_16x0_abort( Scsi_Cmnd *SCpnt) +{ +#if EVERY_ACCESS || ERRORS_ONLY || DEBUG_ABORT + printk( "scsi: abort " ); +#endif + + if (!in_command) { +#if EVERY_ACCESS || ERRORS_ONLY + printk( " (not in command)\n" ); +#endif + return FAILED; + } else printk( "\n" ); + +#if DEBUG_ABORT + print_info( SCpnt ); +#endif + + fdomain_make_bus_idle(); + current_SC->SCp.phase |= aborted; + current_SC->result = DID_ABORT << 16; + + /* Aborts are not done well. . . */ + my_done(DID_ABORT << 16); + return SUCCESS; +} + +static int fdomain_16x0_bus_reset(Scsi_Cmnd *SCpnt) +{ + outb( 1, SCSI_Cntl_port ); + do_pause( 2 ); + outb( 0, SCSI_Cntl_port ); + do_pause( 115 ); + outb( 0, SCSI_Mode_Cntl_port ); + outb( PARITY_MASK, TMC_Cntl_port ); + return SUCCESS; +} + +static int fdomain_16x0_host_reset(Scsi_Cmnd *SCpnt) +{ + return FAILED; +} + +static int fdomain_16x0_device_reset(Scsi_Cmnd *SCpnt) +{ + return FAILED; +} + +#include + +static int fdomain_16x0_biosparam(struct scsi_device *sdev, + struct block_device *bdev, + sector_t capacity, int *info_array) +{ + int drive; + unsigned char buf[512 + sizeof (Scsi_Ioctl_Command)]; + Scsi_Ioctl_Command *sic = (Scsi_Ioctl_Command *) buf; + int size = capacity; + unsigned char *data = sic->data; + unsigned char do_read[] = { READ_6, 0, 0, 0, 1, 0 }; + int retcode; + unsigned long offset; + struct drive_info { + unsigned short cylinders; + unsigned char heads; + unsigned char sectors; + } i; + + /* NOTES: + The RAM area starts at 0x1f00 from the bios_base address. + + For BIOS Version 2.0: + + The drive parameter table seems to start at 0x1f30. + The first byte's purpose is not known. + Next is the cylinder, head, and sector information. + The last 4 bytes appear to be the drive's size in sectors. + The other bytes in the drive parameter table are unknown. + If anyone figures them out, please send me mail, and I will + update these notes. + + Tape drives do not get placed in this table. + + There is another table at 0x1fea: + If the byte is 0x01, then the SCSI ID is not in use. + If the byte is 0x18 or 0x48, then the SCSI ID is in use, + although tapes don't seem to be in this table. I haven't + seen any other numbers (in a limited sample). + + 0x1f2d is a drive count (i.e., not including tapes) + + The table at 0x1fcc are I/O ports addresses for the various + operations. I calculate these by hand in this driver code. + + + + For the ISA-200S version of BIOS Version 2.0: + + The drive parameter table starts at 0x1f33. + + WARNING: Assume that the table entry is 25 bytes long. Someone needs + to check this for the Quantum ISA-200S card. + + + + For BIOS Version 3.2: + + The drive parameter table starts at 0x1f70. Each entry is + 0x0a bytes long. Heads are one less than we need to report. + */ + + if (MAJOR(bdev->bd_dev) != SCSI_DISK0_MAJOR) { + printk("scsi: fdomain_16x0_biosparam: too many disks"); + return 0; + } + drive = MINOR(bdev->bd_dev) >> 4; + + if (bios_major == 2) { + switch (Quantum) { + case 2: /* ISA_200S */ + /* The value of 25 has never been verified. + It should probably be 15. */ + offset = bios_base + 0x1f33 + drive * 25; + break; + case 3: /* ISA_250MG */ + offset = bios_base + 0x1f36 + drive * 15; + break; + case 4: /* ISA_200S (another one) */ + offset = bios_base + 0x1f34 + drive * 15; + break; + default: + offset = bios_base + 0x1f31 + drive * 25; + break; + } + memcpy_fromio( &i, offset, sizeof( struct drive_info ) ); + info_array[0] = i.heads; + info_array[1] = i.sectors; + info_array[2] = i.cylinders; + } else if (bios_major == 3 + && bios_minor >= 0 + && bios_minor < 4) { /* 3.0 and 3.2 BIOS */ + memcpy_fromio( &i, bios_base + 0x1f71 + drive * 10, + sizeof( struct drive_info ) ); + info_array[0] = i.heads + 1; + info_array[1] = i.sectors; + info_array[2] = i.cylinders; + } else { /* 3.4 BIOS (and up?) */ + /* This algorithm was provided by Future Domain (much thanks!). */ + + sic->inlen = 0; /* zero bytes out */ + sic->outlen = 512; /* one sector in */ + memcpy( data, do_read, sizeof( do_read ) ); + retcode = kernel_scsi_ioctl( sdev, + SCSI_IOCTL_SEND_COMMAND, + sic ); + if (!retcode /* SCSI command ok */ + && data[511] == 0xaa && data[510] == 0x55 /* Partition table valid */ + && data[0x1c2]) { /* Partition type */ + + /* The partition table layout is as follows: + + Start: 0x1b3h + Offset: 0 = partition status + 1 = starting head + 2 = starting sector and cylinder (word, encoded) + 4 = partition type + 5 = ending head + 6 = ending sector and cylinder (word, encoded) + 8 = starting absolute sector (double word) + c = number of sectors (double word) + Signature: 0x1fe = 0x55aa + + So, this algorithm assumes: + 1) the first partition table is in use, + 2) the data in the first entry is correct, and + 3) partitions never divide cylinders + + Note that (1) may be FALSE for NetBSD (and other BSD flavors), + as well as for Linux. Note also, that Linux doesn't pay any + attention to the fields that are used by this algorithm -- it + only uses the absolute sector data. Recent versions of Linux's + fdisk(1) will fill this data in correctly, and forthcoming + versions will check for consistency. + + Checking for a non-zero partition type is not part of the + Future Domain algorithm, but it seemed to be a reasonable thing + to do, especially in the Linux and BSD worlds. */ + + info_array[0] = data[0x1c3] + 1; /* heads */ + info_array[1] = data[0x1c4] & 0x3f; /* sectors */ + } else { + + /* Note that this new method guarantees that there will always be + less than 1024 cylinders on a platter. This is good for drives + up to approximately 7.85GB (where 1GB = 1024 * 1024 kB). */ + + if ((unsigned int)size >= 0x7e0000U) { + info_array[0] = 0xff; /* heads = 255 */ + info_array[1] = 0x3f; /* sectors = 63 */ + } else if ((unsigned int)size >= 0x200000U) { + info_array[0] = 0x80; /* heads = 128 */ + info_array[1] = 0x3f; /* sectors = 63 */ + } else { + info_array[0] = 0x40; /* heads = 64 */ + info_array[1] = 0x20; /* sectors = 32 */ + } + } + /* For both methods, compute the cylinders */ + info_array[2] = (unsigned int)size / (info_array[0] * info_array[1] ); + } + + return 0; +} + +static int fdomain_16x0_release(struct Scsi_Host *shpnt) +{ + if (shpnt->irq) + free_irq(shpnt->irq, shpnt); + if (shpnt->io_port && shpnt->n_io_port) + release_region(shpnt->io_port, shpnt->n_io_port); + return 0; +} + +MODULE_LICENSE("GPL"); + +/* Eventually this will go into an include file, but this will be later */ +static Scsi_Host_Template driver_template = FDOMAIN_16X0; + +#include "scsi_module.c" diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/drivers/scsi/pcmcia/fdomain_stub.c linux.2.5.47-ac6/drivers/scsi/pcmcia/fdomain_stub.c --- linux.2.5.47/drivers/scsi/pcmcia/fdomain_stub.c 2002-10-31 14:57:12.000000000 +0000 +++ linux.2.5.47-ac6/drivers/scsi/pcmcia/fdomain_stub.c 2002-10-31 15:05:33.000000000 +0000 @@ -92,7 +92,8 @@ static dev_link_t *fdomain_attach(void); static void fdomain_detach(dev_link_t *); -static Scsi_Host_Template driver_template = FDOMAIN_16X0; +#define driver_template fdomain_driver_template +extern Scsi_Host_Template fdomain_driver_template; static dev_link_t *dev_list = NULL; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/drivers/scsi/pcmcia/Makefile linux.2.5.47-ac6/drivers/scsi/pcmcia/Makefile --- linux.2.5.47/drivers/scsi/pcmcia/Makefile 2002-10-31 14:57:12.000000000 +0000 +++ linux.2.5.47-ac6/drivers/scsi/pcmcia/Makefile 2002-10-31 15:05:33.000000000 +0000 @@ -7,12 +7,14 @@ obj-n := obj- := -vpath %c .. +vpath %c drivers/scsi CFLAGS_aha152x.o = -DPCMCIA -D__NO_VERSION__ -DAHA152X_STAT CFLAGS_fdomain.o = -DPCMCIA -D__NO_VERSION__ CFLAGS_qlogicfas.o = -DPCMCIA -D__NO_VERSION__ +EXTRA_CFLAGS := -Idrivers/scsi + # 16-bit client drivers obj-$(CONFIG_PCMCIA_QLOGIC) += qlogic_cs.o obj-$(CONFIG_PCMCIA_FDOMAIN) += fdomain_cs.o @@ -24,3 +26,12 @@ qlogic_cs-objs := qlogic_stub.o qlogicfas.o include $(TOPDIR)/Rules.make + +drivers/scsi/pcmcia/aha152x.c: drivers/scsi/aha152x.c + cp drivers/scsi/aha152x.c drivers/scsi/pcmcia + +drivers/scsi/pcmcia/fdomain.c: drivers/scsi/fdomain.c + cp drivers/scsi/fdomain.c drivers/scsi/pcmcia + +drivers/scsi/pcmcia/qlogicfas.c: drivers/scsi/qlogicfas.c + cp drivers/scsi/qlogicfas.c drivers/scsi/pcmcia diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/drivers/scsi/pcmcia/nsp_cs.h linux.2.5.47-ac6/drivers/scsi/pcmcia/nsp_cs.h --- linux.2.5.47/drivers/scsi/pcmcia/nsp_cs.h 2002-11-11 16:39:10.000000000 +0000 +++ linux.2.5.47-ac6/drivers/scsi/pcmcia/nsp_cs.h 2002-11-11 17:00:08.000000000 +0000 @@ -285,6 +285,7 @@ int length, int hostno, int inout); static int nsp_queuecommand(Scsi_Cmnd *, void (* done)(Scsi_Cmnd *)); + /*static int nsp_eh_abort(Scsi_Cmnd * SCpnt);*/ /*static int nsp_eh_device_reset(Scsi_Cmnd *SCpnt);*/ static int nsp_eh_bus_reset(Scsi_Cmnd *SCpnt); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/drivers/scsi/pcmcia/qlogicfas.c linux.2.5.47-ac6/drivers/scsi/pcmcia/qlogicfas.c --- linux.2.5.47/drivers/scsi/pcmcia/qlogicfas.c 1970-01-01 01:00:00.000000000 +0100 +++ linux.2.5.47-ac6/drivers/scsi/pcmcia/qlogicfas.c 2002-11-11 20:00:29.000000000 +0000 @@ -0,0 +1,824 @@ +/*----------------------------------------------------------------*/ +/* + Qlogic linux driver - work in progress. No Warranty express or implied. + Use at your own risk. Support Tort Reform so you won't have to read all + these silly disclaimers. + + Copyright 1994, Tom Zerucha. + tz@execpc.com + + Additional Code, and much appreciated help by + Michael A. Griffith + grif@cs.ucr.edu + + Thanks to Eric Youngdale and Dave Hinds for loadable module and PCMCIA + help respectively, and for suffering through my foolishness during the + debugging process. + + Reference Qlogic FAS408 Technical Manual, 53408-510-00A, May 10, 1994 + (you can reference it, but it is incomplete and inaccurate in places) + + Version 0.46 1/30/97 - kernel 1.2.0+ + + Functions as standalone, loadable, and PCMCIA driver, the latter from + Dave Hinds' PCMCIA package. + + Cleaned up 26/10/2002 by Alan Cox as part of the 2.5 + SCSI driver cleanup and audit. This driver still needs work on the + following + - Non terminating hardware waits + - Support multiple cards at a time + - Some layering violations with its pcmcia stub + + Redistributable under terms of the GNU General Public License + + For the avoidance of doubt the "preferred form" of this code is one which + is in an open non patent encumbered format. Where cryptographic key signing + forms part of the process of creating an executable the information + including keys needed to generate an equivalently functional executable + are deemed to be part of the source code. + +*/ +/*----------------------------------------------------------------*/ +/* Configuration */ + +/* Set the following to 2 to use normal interrupt (active high/totempole- + tristate), otherwise use 0 (REQUIRED FOR PCMCIA) for active low, open + drain */ + +#define QL_INT_ACTIVE_HIGH 2 + +/* Set the following to 1 to enable the use of interrupts. Note that 0 tends + to be more stable, but slower (or ties up the system more) */ + +#define QL_USE_IRQ 1 + +/* Set the following to max out the speed of the PIO PseudoDMA transfers, + again, 0 tends to be slower, but more stable. */ + +#define QL_TURBO_PDMA 1 + +/* This should be 1 to enable parity detection */ + +#define QL_ENABLE_PARITY 1 + +/* This will reset all devices when the driver is initialized (during bootup). + The other linux drivers don't do this, but the DOS drivers do, and after + using DOS or some kind of crash or lockup this will bring things back + without requiring a cold boot. It does take some time to recover from a + reset, so it is slower, and I have seen timeouts so that devices weren't + recognized when this was set. */ + +#define QL_RESET_AT_START 0 + +/* crystal frequency in megahertz (for offset 5 and 9) + Please set this for your card. Most Qlogic cards are 40 Mhz. The + Control Concepts ISA (not VLB) is 24 Mhz */ + +#define XTALFREQ 40 + +/**********/ +/* DANGER! modify these at your own risk */ +/* SLOWCABLE can usually be reset to zero if you have a clean setup and + proper termination. The rest are for synchronous transfers and other + advanced features if your device can transfer faster than 5Mb/sec. + If you are really curious, email me for a quick howto until I have + something official */ +/**********/ + +/*****/ +/* config register 1 (offset 8) options */ +/* This needs to be set to 1 if your cabling is long or noisy */ +#define SLOWCABLE 1 + +/*****/ +/* offset 0xc */ +/* This will set fast (10Mhz) synchronous timing when set to 1 + For this to have an effect, FASTCLK must also be 1 */ +#define FASTSCSI 0 + +/* This when set to 1 will set a faster sync transfer rate */ +#define FASTCLK 0 /*(XTALFREQ>25?1:0)*/ + +/*****/ +/* offset 6 */ +/* This is the sync transfer divisor, XTALFREQ/X will be the maximum + achievable data rate (assuming the rest of the system is capable + and set properly) */ +#define SYNCXFRPD 5 /*(XTALFREQ/5)*/ + +/*****/ +/* offset 7 */ +/* This is the count of how many synchronous transfers can take place + i.e. how many reqs can occur before an ack is given. + The maximum value for this is 15, the upper bits can modify + REQ/ACK assertion and deassertion during synchronous transfers + If this is 0, the bus will only transfer asynchronously */ +#define SYNCOFFST 0 +/* for the curious, bits 7&6 control the deassertion delay in 1/2 cycles + of the 40Mhz clock. If FASTCLK is 1, specifying 01 (1/2) will + cause the deassertion to be early by 1/2 clock. Bits 5&4 control + the assertion delay, also in 1/2 clocks (FASTCLK is ignored here). */ + +/*----------------------------------------------------------------*/ +#ifdef PCMCIA +#undef QL_INT_ACTIVE_HIGH +#define QL_INT_ACTIVE_HIGH 0 +#endif + +#include + +#ifdef PCMCIA +#undef MODULE +#endif + +#include /* to get disk capacity */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "scsi.h" +#include "hosts.h" +#include "qlogicfas.h" +#include + +/*----------------------------------------------------------------*/ +/* driver state info, local to driver */ +static int qbase; /* Port */ +static int qinitid; /* initiator ID */ +static int qabort; /* Flag to cause an abort */ +static int qlirq = -1; /* IRQ being used */ +static char qinfo[80]; /* description */ +static Scsi_Cmnd *qlcmd; /* current command being processed */ + +static int qlcfg5 = (XTALFREQ << 5); /* 15625/512 */ +static int qlcfg6 = SYNCXFRPD; +static int qlcfg7 = SYNCOFFST; +static int qlcfg8 = (SLOWCABLE << 7) | (QL_ENABLE_PARITY << 4); +static int qlcfg9 = ((XTALFREQ + 4) / 5); +static int qlcfgc = (FASTCLK << 3) | (FASTSCSI << 4); + +/*----------------------------------------------------------------*/ +/* The qlogic card uses two register maps - These macros select which one */ +#define REG0 ( outb( inb( qbase + 0xd ) & 0x7f , qbase + 0xd ), outb( 4 , qbase + 0xd )) +#define REG1 ( outb( inb( qbase + 0xd ) | 0x80 , qbase + 0xd ), outb( 0xb4 | QL_INT_ACTIVE_HIGH , qbase + 0xd )) + +/* following is watchdog timeout in microseconds */ +#define WATCHDOG 5000000 + +/*----------------------------------------------------------------*/ +/* the following will set the monitor border color (useful to find + where something crashed or gets stuck at and as a simple profiler) */ + +#if 0 +#define rtrc(i) {inb(0x3da);outb(0x31,0x3c0);outb((i),0x3c0);} +#else +#define rtrc(i) {} +#endif + +/*----------------------------------------------------------------*/ +/* local functions */ +/*----------------------------------------------------------------*/ + +/* error recovery - reset everything */ + +static void ql_zap(void) +{ + int x; + + x = inb(qbase + 0xd); + REG0; + outb(3, qbase + 3); /* reset SCSI */ + outb(2, qbase + 3); /* reset chip */ + if (x & 0x80) + REG1; +} + +/* + * Do a pseudo-dma tranfer + */ + +static int ql_pdma(int phase, char *request, int reqlen) +{ + int j; + j = 0; + if (phase & 1) { /* in */ +#if QL_TURBO_PDMA + rtrc(4) + /* empty fifo in large chunks */ + if (reqlen >= 128 && (inb(qbase + 8) & 2)) { /* full */ + insl(qbase + 4, request, 32); + reqlen -= 128; + request += 128; + } + while (reqlen >= 84 && !(j & 0xc0)) /* 2/3 */ + if ((j = inb(qbase + 8)) & 4) + { + insl(qbase + 4, request, 21); + reqlen -= 84; + request += 84; + } + if (reqlen >= 44 && (inb(qbase + 8) & 8)) { /* 1/3 */ + insl(qbase + 4, request, 11); + reqlen -= 44; + request += 44; + } +#endif + /* until both empty and int (or until reclen is 0) */ + rtrc(7) + j = 0; + while (reqlen && !((j & 0x10) && (j & 0xc0))) + { + /* while bytes to receive and not empty */ + j &= 0xc0; + while (reqlen && !((j = inb(qbase + 8)) & 0x10)) + { + *request++ = inb(qbase + 4); + reqlen--; + } + if (j & 0x10) + j = inb(qbase + 8); + + } + } else { /* out */ +#if QL_TURBO_PDMA + rtrc(4) + if (reqlen >= 128 && inb(qbase + 8) & 0x10) { /* empty */ + outsl(qbase + 4, request, 32); + reqlen -= 128; + request += 128; + } + while (reqlen >= 84 && !(j & 0xc0)) /* 1/3 */ + if (!((j = inb(qbase + 8)) & 8)) { + outsl(qbase + 4, request, 21); + reqlen -= 84; + request += 84; + } + if (reqlen >= 40 && !(inb(qbase + 8) & 4)) { /* 2/3 */ + outsl(qbase + 4, request, 10); + reqlen -= 40; + request += 40; + } +#endif + /* until full and int (or until reclen is 0) */ + rtrc(7) + j = 0; + while (reqlen && !((j & 2) && (j & 0xc0))) { + /* while bytes to send and not full */ + while (reqlen && !((j = inb(qbase + 8)) & 2)) + { + outb(*request++, qbase + 4); + reqlen--; + } + if (j & 2) + j = inb(qbase + 8); + } + } + /* maybe return reqlen */ + return inb(qbase + 8) & 0xc0; +} + +/* + * Wait for interrupt flag (polled - not real hardware interrupt) + */ + +static int ql_wai(void) +{ + int i, k; + k = 0; + i = jiffies + WATCHDOG; + while (time_before(jiffies, i) && !qabort && !((k = inb(qbase + 4)) & 0xe0)) { + barrier(); + cpu_relax(); + } + if (time_after_eq(jiffies, i)) + return (DID_TIME_OUT); + if (qabort) + return (qabort == 1 ? DID_ABORT : DID_RESET); + if (k & 0x60) + ql_zap(); + if (k & 0x20) + return (DID_PARITY); + if (k & 0x40) + return (DID_ERROR); + return 0; +} + +/* + * Initiate scsi command - queueing handler + * caller must hold host lock + */ + +static void ql_icmd(Scsi_Cmnd * cmd) +{ + unsigned int i; + + qabort = 0; + + REG0; + /* clearing of interrupts and the fifo is needed */ + + inb(qbase + 5); /* clear interrupts */ + if (inb(qbase + 5)) /* if still interrupting */ + outb(2, qbase + 3); /* reset chip */ + else if (inb(qbase + 7) & 0x1f) + outb(1, qbase + 3); /* clear fifo */ + while (inb(qbase + 5)); /* clear ints */ + REG1; + outb(1, qbase + 8); /* set for PIO pseudo DMA */ + outb(0, qbase + 0xb); /* disable ints */ + inb(qbase + 8); /* clear int bits */ + REG0; + outb(0x40, qbase + 0xb); /* enable features */ + + /* configurables */ + outb(qlcfgc, qbase + 0xc); + /* config: no reset interrupt, (initiator) bus id */ + outb(0x40 | qlcfg8 | qinitid, qbase + 8); + outb(qlcfg7, qbase + 7); + outb(qlcfg6, qbase + 6); + /**/ outb(qlcfg5, qbase + 5); /* select timer */ + outb(qlcfg9 & 7, qbase + 9); /* prescaler */ +/* outb(0x99, qbase + 5); */ + outb(cmd->target, qbase + 4); + + for (i = 0; i < cmd->cmd_len; i++) + outb(cmd->cmnd[i], qbase + 2); + + qlcmd = cmd; + outb(0x41, qbase + 3); /* select and send command */ +} + +/* + * Process scsi command - usually after interrupt + */ + +static unsigned int ql_pcmd(Scsi_Cmnd * cmd) +{ + unsigned int i, j, k; + unsigned int result; /* ultimate return result */ + unsigned int status; /* scsi returned status */ + unsigned int message; /* scsi returned message */ + unsigned int phase; /* recorded scsi phase */ + unsigned int reqlen; /* total length of transfer */ + struct scatterlist *sglist; /* scatter-gather list pointer */ + unsigned int sgcount; /* sg counter */ + char *buf; + + rtrc(1) + j = inb(qbase + 6); + i = inb(qbase + 5); + if (i == 0x20) { + return (DID_NO_CONNECT << 16); + } + i |= inb(qbase + 5); /* the 0x10 bit can be set after the 0x08 */ + if (i != 0x18) { + printk(KERN_ERR "Ql:Bad Interrupt status:%02x\n", i); + ql_zap(); + return (DID_BAD_INTR << 16); + } + j &= 7; /* j = inb( qbase + 7 ) >> 5; */ + + /* correct status is supposed to be step 4 */ + /* it sometimes returns step 3 but with 0 bytes left to send */ + /* We can try stuffing the FIFO with the max each time, but we will get a + sequence of 3 if any bytes are left (but we do flush the FIFO anyway */ + + if (j != 3 && j != 4) { + printk(KERN_ERR "Ql:Bad sequence for command %d, int %02X, cmdleft = %d\n", + j, i, inb(qbase + 7) & 0x1f); + ql_zap(); + return (DID_ERROR << 16); + } + result = DID_OK; + if (inb(qbase + 7) & 0x1f) /* if some bytes in fifo */ + outb(1, qbase + 3); /* clear fifo */ + /* note that request_bufflen is the total xfer size when sg is used */ + reqlen = cmd->request_bufflen; + /* note that it won't work if transfers > 16M are requested */ + if (reqlen && !((phase = inb(qbase + 4)) & 6)) { /* data phase */ + rtrc(2) + outb(reqlen, qbase); /* low-mid xfer cnt */ + outb(reqlen >> 8, qbase + 1); /* low-mid xfer cnt */ + outb(reqlen >> 16, qbase + 0xe); /* high xfer cnt */ + outb(0x90, qbase + 3); /* command do xfer */ + /* PIO pseudo DMA to buffer or sglist */ + REG1; + if (!cmd->use_sg) + ql_pdma(phase, cmd->request_buffer, + cmd->request_bufflen); + else { + sgcount = cmd->use_sg; + sglist = cmd->request_buffer; + while (sgcount--) { + if (qabort) { + REG0; + return ((qabort == 1 ? DID_ABORT : DID_RESET) << 16); + } + buf = page_address(sglist->page) + sglist->offset; + if (ql_pdma(phase, buf, sglist->length)) + break; + sglist++; + } + } + REG0; + rtrc(2) + /* + * Wait for irq (split into second state of irq handler + * if this can take time) + */ + if ((k = ql_wai())) + return (k << 16); + k = inb(qbase + 5); /* should be 0x10, bus service */ + } + + /* + * Enter Status (and Message In) Phase + */ + + k = jiffies + WATCHDOG; + + while (time_before(jiffies, k) && !qabort && !(inb(qbase + 4) & 6)) + cpu_relax(); /* wait for status phase */ + + if (time_after_eq(jiffies, k)) { + ql_zap(); + return (DID_TIME_OUT << 16); + } + + /* FIXME: timeout ?? */ + while (inb(qbase + 5)) + cpu_relax(); /* clear pending ints */ + + if (qabort) + return ((qabort == 1 ? DID_ABORT : DID_RESET) << 16); + + outb(0x11, qbase + 3); /* get status and message */ + if ((k = ql_wai())) + return (k << 16); + i = inb(qbase + 5); /* get chip irq stat */ + j = inb(qbase + 7) & 0x1f; /* and bytes rec'd */ + status = inb(qbase + 2); + message = inb(qbase + 2); + + /* + * Should get function complete int if Status and message, else + * bus serv if only status + */ + if (!((i == 8 && j == 2) || (i == 0x10 && j == 1))) { + printk(KERN_ERR "Ql:Error during status phase, int=%02X, %d bytes recd\n", i, j); + result = DID_ERROR; + } + outb(0x12, qbase + 3); /* done, disconnect */ + rtrc(1) + if ((k = ql_wai())) + return (k << 16); + + /* + * Should get bus service interrupt and disconnect interrupt + */ + + i = inb(qbase + 5); /* should be bus service */ + while (!qabort && ((i & 0x20) != 0x20)) { + barrier(); + cpu_relax(); + i |= inb(qbase + 5); + } + rtrc(0) + + if (qabort) + return ((qabort == 1 ? DID_ABORT : DID_RESET) << 16); + + return (result << 16) | (message << 8) | (status & STATUS_MASK); +} + +#if QL_USE_IRQ + +/* + * Interrupt handler + */ + +static void ql_ihandl(int irq, void *dev_id, struct pt_regs *regs) +{ + Scsi_Cmnd *icmd; + REG0; + + if (!(inb(qbase + 4) & 0x80)) /* false alarm? */ + return; + + if (qlcmd == NULL) { /* no command to process? */ + int i; + i = 16; + while (i-- && inb(qbase + 5)); /* maybe also ql_zap() */ + return; + } + icmd = qlcmd; + icmd->result = ql_pcmd(icmd); + qlcmd = NULL; + /* + * If result is CHECK CONDITION done calls qcommand to request + * sense + */ + (icmd->scsi_done) (icmd); +} + +static void do_ql_ihandl(int irq, void *dev_id, struct pt_regs *regs) +{ + unsigned long flags; + struct Scsi_Host *host = dev_id; + + spin_lock_irqsave(host->host_lock, flags); + ql_ihandl(irq, dev_id, regs); + spin_unlock_irqrestore(host->host_lock, flags); +} + +#endif + +#if QL_USE_IRQ + +static void qlidone(Scsi_Cmnd * cmd) +{ +} /* null function */ + +#endif + +/* + * Synchronous command processing + */ + +static int qlogicfas_command(Scsi_Cmnd * cmd) +{ + int k; +#if QL_USE_IRQ + if (qlirq >= 0) { + qlogicfas_queuecommand(cmd, qlidone); + while (qlcmd != NULL) + { + cpu_relax(); + barrier(); + } + return cmd->result; + } +#endif + + /* + * Non-irq version + */ + + if (cmd->target == qinitid) + return (DID_BAD_TARGET << 16); + ql_icmd(cmd); + if ((k = ql_wai())) + return (k << 16); + return ql_pcmd(cmd); + +} + +#if QL_USE_IRQ + +/* + * Queued command + */ + +int qlogicfas_queuecommand(Scsi_Cmnd * cmd, void (*done) (Scsi_Cmnd *)) +{ + if (cmd->target == qinitid) { + cmd->result = DID_BAD_TARGET << 16; + done(cmd); + return 0; + } + + cmd->scsi_done = done; + /* wait for the last command's interrupt to finish */ + while (qlcmd != NULL) { + barrier(); + cpu_relax(); + } + ql_icmd(cmd); + return 0; +} +#else +int qlogicfas_queuecommand(Scsi_Cmnd * cmd, void (*done) (Scsi_Cmnd *)) +{ + return 1; +} +#endif + +#ifdef PCMCIA + +/* + * Allow PCMCIA code to preset the port + * port should be 0 and irq to -1 respectively for autoprobing + */ + +void qlogicfas_preset(int port, int irq) +{ + qbase = port; + qlirq = irq; +} + +#endif + +/* + * Look for qlogic card and init if found + */ + +int __devinit qlogicfas_detect(Scsi_Host_Template * host) +{ + int i, j; /* these are only used by IRQ detect */ + int qltyp; /* type of chip */ + struct Scsi_Host *hreg; /* registered host structure */ + + host->proc_name = "qlogicfas"; + + /* Qlogic Cards only exist at 0x230 or 0x330 (the chip itself + * decodes the address - I check 230 first since MIDI cards are + * typically at 0x330 + * + * Theoretically, two Qlogic cards can coexist in the same system. + * This should work by simply using this as a loadable module for + * the second card, but I haven't tested this. + */ + + if (!qbase) { + for (qbase = 0x230; qbase < 0x430; qbase += 0x100) { + if (!request_region(qbase, 0x10, "qlogicfas")) + continue; + REG1; + if (((inb(qbase + 0xe) ^ inb(qbase + 0xe)) == 7) + && ((inb(qbase + 0xe) ^ inb(qbase + 0xe)) == 7)) + break; + release_region(qbase, 0x10); + } + if (qbase == 0x430) + return 0; + } else + printk(KERN_INFO "Ql: Using preset base address of %03x\n", qbase); + + qltyp = inb(qbase + 0xe) & 0xf8; + qinitid = host->this_id; + if (qinitid < 0) + qinitid = 7; /* if no ID, use 7 */ + outb(1, qbase + 8); /* set for PIO pseudo DMA */ + REG0; + outb(0x40 | qlcfg8 | qinitid, qbase + 8); /* (ini) bus id, disable scsi rst */ + outb(qlcfg5, qbase + 5); /* select timer */ + outb(qlcfg9, qbase + 9); /* prescaler */ + +#if QL_RESET_AT_START + outb(3, qbase + 3); + REG1; + /* FIXME: timeout */ + while (inb(qbase + 0xf) & 4) + cpu_relax(); + REG0; +#endif + +#if QL_USE_IRQ + /* + * IRQ probe - toggle pin and check request pending + */ + + if (qlirq == -1) { + i = 0xffff; + j = 3; + outb(0x90, qbase + 3); /* illegal command - cause interrupt */ + REG1; + outb(10, 0x20); /* access pending interrupt map */ + outb(10, 0xa0); + while (j--) { + outb(0xb0 | QL_INT_ACTIVE_HIGH, qbase + 0xd); /* int pin off */ + i &= ~(inb(0x20) | (inb(0xa0) << 8)); /* find IRQ off */ + outb(0xb4 | QL_INT_ACTIVE_HIGH, qbase + 0xd); /* int pin on */ + i &= inb(0x20) | (inb(0xa0) << 8); /* find IRQ on */ + } + REG0; + while (inb(qbase + 5)); /* purge int */ + j = -1; + while (i) /* find on bit */ + i >>= 1, j++; /* should check for exactly 1 on */ + qlirq = j; + } else + printk(KERN_INFO "Ql: Using preset IRQ %d\n", qlirq); + + if (qlirq >= 0 && !request_irq(qlirq, do_ql_ihandl, 0, "qlogicfas", NULL)) + host->can_queue = 1; +#endif + hreg = scsi_register(host, 0); /* no host data */ + if (!hreg) + goto err_release_mem; + hreg->io_port = qbase; + hreg->n_io_port = 16; + hreg->dma_channel = -1; + if (qlirq != -1) + hreg->irq = qlirq; + + sprintf(qinfo, + "Qlogicfas Driver version 0.46, chip %02X at %03X, IRQ %d, TPdma:%d", + qltyp, qbase, qlirq, QL_TURBO_PDMA); + host->name = qinfo; + + return 1; + +err_release_mem: + release_region(qbase, 0x10); + if (host->can_queue) + free_irq(qlirq, do_ql_ihandl); + return 0; + +} + +/* + * Return bios parameters + */ + +int qlogicfas_biosparam(struct scsi_device * disk, + struct block_device *dev, + sector_t capacity, int ip[]) +{ +/* This should mimic the DOS Qlogic driver's behavior exactly */ + ip[0] = 0x40; + ip[1] = 0x20; + ip[2] = (unsigned long) capacity / (ip[0] * ip[1]); + if (ip[2] > 1024) { + ip[0] = 0xff; + ip[1] = 0x3f; + ip[2] = (unsigned long) capacity / (ip[0] * ip[1]); +#if 0 + if (ip[2] > 1023) + ip[2] = 1023; +#endif + } + return 0; +} + +/* + * Abort a command in progress + */ + +static int qlogicfas_abort(Scsi_Cmnd * cmd) +{ + qabort = 1; + ql_zap(); + return SUCCESS; +} + +/* + * Reset SCSI bus + * FIXME: This function is invoked with cmd = NULL directly by + * the PCMCIA qlogic_stub code. This wants fixing + */ + +static int qlogicfas_bus_reset(Scsi_Cmnd * cmd) +{ + qabort = 2; + ql_zap(); + return SUCCESS; +} + +/* + * Reset SCSI host controller + */ + +static int qlogicfas_host_reset(Scsi_Cmnd * cmd) +{ + return FAILED; +} + +/* + * Reset SCSI device + */ + +static int qlogicfas_device_reset(Scsi_Cmnd * cmd) +{ + return FAILED; +} + +/* + * Return info string + */ + +static const char *qlogicfas_info(struct Scsi_Host *host) +{ + return qinfo; +} + +MODULE_AUTHOR("Tom Zerucha, Michael Griffith"); +MODULE_DESCRIPTION("Driver for the Qlogic FAS SCSI controllers"); +MODULE_LICENSE("GPL"); + +/* + * The driver template is also needed for PCMCIA + */ + +Scsi_Host_Template qlogicfas_driver_template = QLOGICFAS; +#define driver_template qlogicfas_driver_template + +#include "scsi_module.c" + diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/drivers/scsi/pcmcia/qlogic_stub.c linux.2.5.47-ac6/drivers/scsi/pcmcia/qlogic_stub.c --- linux.2.5.47/drivers/scsi/pcmcia/qlogic_stub.c 2002-10-31 14:57:12.000000000 +0000 +++ linux.2.5.47-ac6/drivers/scsi/pcmcia/qlogic_stub.c 2002-10-31 15:05:33.000000000 +0000 @@ -50,8 +50,6 @@ #include <../drivers/scsi/qlogicfas.h> -#define qlogic_reset(h) qlogicfas_reset(h, 0) - #include #include #include @@ -65,8 +63,7 @@ static int pc_debug = PCMCIA_DEBUG; MODULE_PARM(pc_debug, "i"); #define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args) -static char *version = -"qlogic_cs.c 1.79 2000/06/12 21:27:26 (David Hinds)"; +static char *version = "qlogic_cs.c 1.79-ac 2002/10/26 (David Hinds)"; #else #define DEBUG(n, args...) #endif @@ -76,7 +73,7 @@ /* Parameters that can be set with 'insmod' */ /* Bit map of interrupts to choose from */ -static u_int irq_mask = 0xdeb8; +static unsigned int irq_mask = 0xdeb8; static int irq_list[4] = { -1 }; MODULE_PARM(irq_mask, "i"); @@ -85,20 +82,21 @@ /*====================================================================*/ typedef struct scsi_info_t { - dev_link_t link; - u_short manf_id; - int ndev; - dev_node_t node[8]; + dev_link_t link; + unsigned short manf_id; + int ndev; + dev_node_t node[8]; } scsi_info_t; static void qlogic_release(u_long arg); -static int qlogic_event(event_t event, int priority, - event_callback_args_t *args); +static int qlogic_event(event_t event, int priority, event_callback_args_t * args); static dev_link_t *qlogic_attach(void); static void qlogic_detach(dev_link_t *); -static Scsi_Host_Template driver_template = QLOGICFAS; +/* Import our driver template */ +extern Scsi_Host_Template qlogicfas_driver_template; +#define driver_template qlogicfas_driver_template static dev_link_t *dev_list = NULL; @@ -108,97 +106,97 @@ static void cs_error(client_handle_t handle, int func, int ret) { - error_info_t err = { func, ret }; - CardServices(ReportError, handle, &err); + error_info_t err = { func, ret }; + CardServices(ReportError, handle, &err); } /*====================================================================*/ static dev_link_t *qlogic_attach(void) { - scsi_info_t *info; - client_reg_t client_reg; - dev_link_t *link; - int i, ret; - - DEBUG(0, "qlogic_attach()\n"); - - /* Create new SCSI device */ - info = kmalloc(sizeof(*info), GFP_KERNEL); - if (!info) return NULL; - memset(info, 0, sizeof(*info)); - link = &info->link; link->priv = info; - link->release.function = &qlogic_release; - link->release.data = (u_long)link; - - link->io.NumPorts1 = 16; - link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO; - link->io.IOAddrLines = 10; - link->irq.Attributes = IRQ_TYPE_EXCLUSIVE; - link->irq.IRQInfo1 = IRQ_INFO2_VALID|IRQ_LEVEL_ID; - if (irq_list[0] == -1) - link->irq.IRQInfo2 = irq_mask; - else - for (i = 0; i < 4; i++) - link->irq.IRQInfo2 |= 1 << irq_list[i]; - link->conf.Attributes = CONF_ENABLE_IRQ; - link->conf.Vcc = 50; - link->conf.IntType = INT_MEMORY_AND_IO; - link->conf.Present = PRESENT_OPTION; - - /* Register with Card Services */ - link->next = dev_list; - dev_list = link; - client_reg.dev_info = &dev_info; - client_reg.Attributes = INFO_IO_CLIENT | INFO_CARD_SHARE; - client_reg.event_handler = &qlogic_event; - client_reg.EventMask = - CS_EVENT_RESET_REQUEST | CS_EVENT_CARD_RESET | - CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL | - CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME; - client_reg.Version = 0x0210; - client_reg.event_callback_args.client_data = link; - ret = CardServices(RegisterClient, &link->handle, &client_reg); - if (ret != 0) { - cs_error(link->handle, RegisterClient, ret); - qlogic_detach(link); - return NULL; - } - - return link; -} /* qlogic_attach */ + scsi_info_t *info; + client_reg_t client_reg; + dev_link_t *link; + int i, ret; + + DEBUG(0, "qlogic_attach()\n"); + + /* Create new SCSI device */ + info = kmalloc(sizeof(*info), GFP_KERNEL); + if (!info) + return NULL; + memset(info, 0, sizeof(*info)); + link = &info->link; + link->priv = info; + link->release.function = &qlogic_release; + link->release.data = (u_long) link; + + link->io.NumPorts1 = 16; + link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO; + link->io.IOAddrLines = 10; + link->irq.Attributes = IRQ_TYPE_EXCLUSIVE; + link->irq.IRQInfo1 = IRQ_INFO2_VALID | IRQ_LEVEL_ID; + if (irq_list[0] == -1) + link->irq.IRQInfo2 = irq_mask; + else + for (i = 0; i < 4; i++) + link->irq.IRQInfo2 |= 1 << irq_list[i]; + link->conf.Attributes = CONF_ENABLE_IRQ; + link->conf.Vcc = 50; + link->conf.IntType = INT_MEMORY_AND_IO; + link->conf.Present = PRESENT_OPTION; + + /* Register with Card Services */ + link->next = dev_list; + dev_list = link; + client_reg.dev_info = &dev_info; + client_reg.Attributes = INFO_IO_CLIENT | INFO_CARD_SHARE; + client_reg.event_handler = &qlogic_event; + client_reg.EventMask = CS_EVENT_RESET_REQUEST | CS_EVENT_CARD_RESET | CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL | CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME; + client_reg.Version = 0x0210; + client_reg.event_callback_args.client_data = link; + ret = CardServices(RegisterClient, &link->handle, &client_reg); + if (ret != 0) { + cs_error(link->handle, RegisterClient, ret); + qlogic_detach(link); + return NULL; + } + + return link; +} /* qlogic_attach */ /*====================================================================*/ -static void qlogic_detach(dev_link_t *link) +static void qlogic_detach(dev_link_t * link) { - dev_link_t **linkp; + dev_link_t **linkp; - DEBUG(0, "qlogic_detach(0x%p)\n", link); - - /* Locate device structure */ - for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next) - if (*linkp == link) break; - if (*linkp == NULL) - return; + DEBUG(0, "qlogic_detach(0x%p)\n", link); - del_timer(&link->release); - if (link->state & DEV_CONFIG) { - qlogic_release((u_long)link); - if (link->state & DEV_STALE_CONFIG) { - link->state |= DEV_STALE_LINK; - return; + /* Locate device structure */ + for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next) + if (*linkp == link) + break; + if (*linkp == NULL) + return; + + del_timer_sync(&link->release); + if (link->state & DEV_CONFIG) { + qlogic_release((u_long) link); + if (link->state & DEV_STALE_CONFIG) { + link->state |= DEV_STALE_LINK; + return; + } } - } - if (link->handle) - CardServices(DeregisterClient, link->handle); - - /* Unlink device structure, free bits */ - *linkp = link->next; - kfree(link->priv); - -} /* qlogic_detach */ + if (link->handle) + CardServices(DeregisterClient, link->handle); + + /* Unlink device structure, free bits */ + *linkp = link->next; + kfree(link->priv); + +} /* qlogic_detach */ /*====================================================================*/ @@ -208,220 +206,216 @@ #define CFG_CHECK(fn, args...) \ if (CardServices(fn, args) != 0) goto next_entry -static void qlogic_config(dev_link_t *link) +static void qlogic_config(dev_link_t * link) { - client_handle_t handle = link->handle; - scsi_info_t *info = link->priv; - tuple_t tuple; - cisparse_t parse; - int i, last_ret, last_fn; - u_short tuple_data[32]; - Scsi_Device *dev; - dev_node_t **tail, *node; - struct Scsi_Host *host; - - DEBUG(0, "qlogic_config(0x%p)\n", link); - - tuple.TupleData = (cisdata_t *)tuple_data; - tuple.TupleDataMax = 64; - tuple.TupleOffset = 0; - tuple.DesiredTuple = CISTPL_CONFIG; - CS_CHECK(GetFirstTuple, handle, &tuple); - CS_CHECK(GetTupleData, handle, &tuple); - CS_CHECK(ParseTuple, handle, &tuple, &parse); - link->conf.ConfigBase = parse.config.base; - - tuple.DesiredTuple = CISTPL_MANFID; - if ((CardServices(GetFirstTuple, handle, &tuple) == CS_SUCCESS) && - (CardServices(GetTupleData, handle, &tuple) == CS_SUCCESS)) - info->manf_id = le16_to_cpu(tuple.TupleData[0]); - - /* Configure card */ - driver_template.module = &__this_module; - link->state |= DEV_CONFIG; - - tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY; - CS_CHECK(GetFirstTuple, handle, &tuple); - while (1) { - CFG_CHECK(GetTupleData, handle, &tuple); - CFG_CHECK(ParseTuple, handle, &tuple, &parse); - link->conf.ConfigIndex = parse.cftable_entry.index; - link->io.BasePort1 = parse.cftable_entry.io.win[0].base; - link->io.NumPorts1 = parse.cftable_entry.io.win[0].len; - if (link->io.BasePort1 != 0) { - i = CardServices(RequestIO, handle, &link->io); - if (i == CS_SUCCESS) break; + client_handle_t handle = link->handle; + scsi_info_t *info = link->priv; + tuple_t tuple; + cisparse_t parse; + int i, last_ret, last_fn; + unsigned short tuple_data[32]; + Scsi_Device *dev; + dev_node_t **tail, *node; + struct Scsi_Host *host; + + DEBUG(0, "qlogic_config(0x%p)\n", link); + + tuple.TupleData = (cisdata_t *) tuple_data; + tuple.TupleDataMax = 64; + tuple.TupleOffset = 0; + tuple.DesiredTuple = CISTPL_CONFIG; + CS_CHECK(GetFirstTuple, handle, &tuple); + CS_CHECK(GetTupleData, handle, &tuple); + CS_CHECK(ParseTuple, handle, &tuple, &parse); + link->conf.ConfigBase = parse.config.base; + + tuple.DesiredTuple = CISTPL_MANFID; + if ((CardServices(GetFirstTuple, handle, &tuple) == CS_SUCCESS) && (CardServices(GetTupleData, handle, &tuple) == CS_SUCCESS)) + info->manf_id = le16_to_cpu(tuple.TupleData[0]); + + /* Configure card */ + driver_template.module = &__this_module; + link->state |= DEV_CONFIG; + + tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY; + CS_CHECK(GetFirstTuple, handle, &tuple); + while (1) { + CFG_CHECK(GetTupleData, handle, &tuple); + CFG_CHECK(ParseTuple, handle, &tuple, &parse); + link->conf.ConfigIndex = parse.cftable_entry.index; + link->io.BasePort1 = parse.cftable_entry.io.win[0].base; + link->io.NumPorts1 = parse.cftable_entry.io.win[0].len; + if (link->io.BasePort1 != 0) { + i = CardServices(RequestIO, handle, &link->io); + if (i == CS_SUCCESS) + break; + } + next_entry: + CS_CHECK(GetNextTuple, handle, &tuple); } - next_entry: - CS_CHECK(GetNextTuple, handle, &tuple); - } - - CS_CHECK(RequestIRQ, handle, &link->irq); - CS_CHECK(RequestConfiguration, handle, &link->conf); - - if ((info->manf_id == MANFID_MACNICA) || - (info->manf_id == MANFID_PIONEER) || - (info->manf_id == 0x0098)) { - /* set ATAcmd */ - outb(0xb4, link->io.BasePort1+0xd); - outb(0x24, link->io.BasePort1+0x9); - outb(0x04, link->io.BasePort1+0xd); - } - - /* A bad hack... */ - release_region(link->io.BasePort1, link->io.NumPorts1); - - /* The KXL-810AN has a bigger IO port window */ - if (link->io.NumPorts1 == 32) - qlogicfas_preset(link->io.BasePort1+16, link->irq.AssignedIRQ); - else - qlogicfas_preset(link->io.BasePort1, link->irq.AssignedIRQ); - - scsi_register_host(&driver_template); - - tail = &link->dev; - info->ndev = 0; - for (host = scsi_host_get_next(NULL); host; - host = scsi_host_get_next(host)) - if (host->hostt == &driver_template) - for (dev = host->host_queue; dev; dev = dev->next) { - u_long arg[2], id; - kernel_scsi_ioctl(dev, SCSI_IOCTL_GET_IDLUN, arg); - id = (arg[0]&0x0f) + ((arg[0]>>4)&0xf0) + - ((arg[0]>>8)&0xf00) + ((arg[0]>>12)&0xf000); - node = &info->node[info->ndev]; - node->minor = 0; - switch (dev->type) { - case TYPE_TAPE: - node->major = SCSI_TAPE_MAJOR; - sprintf(node->dev_name, "st#%04lx", id); - break; - case TYPE_DISK: - case TYPE_MOD: - node->major = SCSI_DISK0_MAJOR; - sprintf(node->dev_name, "sd#%04lx", id); - break; - case TYPE_ROM: - case TYPE_WORM: - node->major = SCSI_CDROM_MAJOR; - sprintf(node->dev_name, "sr#%04lx", id); - break; - default: - node->major = SCSI_GENERIC_MAJOR; - sprintf(node->dev_name, "sg#%04lx", id); - break; - } - *tail = node; tail = &node->next; - info->ndev++; + + CS_CHECK(RequestIRQ, handle, &link->irq); + CS_CHECK(RequestConfiguration, handle, &link->conf); + + if ((info->manf_id == MANFID_MACNICA) || (info->manf_id == MANFID_PIONEER) || (info->manf_id == 0x0098)) { + /* set ATAcmd */ + outb(0xb4, link->io.BasePort1 + 0xd); + outb(0x24, link->io.BasePort1 + 0x9); + outb(0x04, link->io.BasePort1 + 0xd); } - *tail = NULL; - if (info->ndev == 0) - printk(KERN_INFO "qlogic_cs: no SCSI devices found\n"); - - link->state &= ~DEV_CONFIG_PENDING; - return; + + /* A bad hack... */ + release_region(link->io.BasePort1, link->io.NumPorts1); + + /* The KXL-810AN has a bigger IO port window */ + if (link->io.NumPorts1 == 32) + qlogicfas_preset(link->io.BasePort1 + 16, link->irq.AssignedIRQ); + else + qlogicfas_preset(link->io.BasePort1, link->irq.AssignedIRQ); + + scsi_register_host(&driver_template); + + tail = &link->dev; + info->ndev = 0; + for (host = scsi_host_get_next(NULL); host; host = scsi_host_get_next(host)) + if (host->hostt == &driver_template) + for (dev = host->host_queue; dev; dev = dev->next) { + u_long arg[2], id; + kernel_scsi_ioctl(dev, SCSI_IOCTL_GET_IDLUN, arg); + id = (arg[0] & 0x0f) + ((arg[0] >> 4) & 0xf0) + ((arg[0] >> 8) & 0xf00) + ((arg[0] >> 12) & 0xf000); + node = &info->node[info->ndev]; + node->minor = 0; + switch (dev->type) { + case TYPE_TAPE: + node->major = SCSI_TAPE_MAJOR; + sprintf(node->dev_name, "st#%04lx", id); + break; + case TYPE_DISK: + case TYPE_MOD: + node->major = SCSI_DISK0_MAJOR; + sprintf(node->dev_name, "sd#%04lx", id); + break; + case TYPE_ROM: + case TYPE_WORM: + node->major = SCSI_CDROM_MAJOR; + sprintf(node->dev_name, "sr#%04lx", id); + break; + default: + node->major = SCSI_GENERIC_MAJOR; + sprintf(node->dev_name, "sg#%04lx", id); + break; + } + *tail = node; + tail = &node->next; + info->ndev++; + } + *tail = NULL; + if (info->ndev == 0) + printk(KERN_INFO "qlogic_cs: no SCSI devices found\n"); + + link->state &= ~DEV_CONFIG_PENDING; + return; cs_failed: - cs_error(link->handle, last_fn, last_ret); - qlogic_release((u_long)link); - return; + cs_error(link->handle, last_fn, last_ret); + qlogic_release((u_long) link); + return; -} /* qlogic_config */ +} /* qlogic_config */ /*====================================================================*/ static void qlogic_release(u_long arg) { - dev_link_t *link = (dev_link_t *)arg; + dev_link_t *link = (dev_link_t *) arg; - DEBUG(0, "qlogic_release(0x%p)\n", link); + DEBUG(0, "qlogic_release(0x%p)\n", link); - if (GET_USE_COUNT(&__this_module) != 0) { - DEBUG(0, "qlogic_cs: release postponed, device still open\n"); - link->state |= DEV_STALE_CONFIG; - return; - } + if (GET_USE_COUNT(&__this_module) != 0) { + DEBUG(0, "qlogic_cs: release postponed, device still open\n"); + link->state |= DEV_STALE_CONFIG; + return; + } + + scsi_unregister_host(&driver_template); + link->dev = NULL; - scsi_unregister_host(&driver_template); - link->dev = NULL; - - CardServices(ReleaseConfiguration, link->handle); - CardServices(ReleaseIO, link->handle, &link->io); - CardServices(ReleaseIRQ, link->handle, &link->irq); - - link->state &= ~DEV_CONFIG; - if (link->state & DEV_STALE_LINK) - qlogic_detach(link); - -} /* qlogic_release */ + CardServices(ReleaseConfiguration, link->handle); + CardServices(ReleaseIO, link->handle, &link->io); + CardServices(ReleaseIRQ, link->handle, &link->irq); + + link->state &= ~DEV_CONFIG; + if (link->state & DEV_STALE_LINK) + qlogic_detach(link); + +} /* qlogic_release */ /*====================================================================*/ -static int qlogic_event(event_t event, int priority, - event_callback_args_t *args) +static int qlogic_event(event_t event, int priority, event_callback_args_t * args) { - dev_link_t *link = args->client_data; + dev_link_t *link = args->client_data; - DEBUG(1, "qlogic_event(0x%06x)\n", event); - - switch (event) { - case CS_EVENT_CARD_REMOVAL: - link->state &= ~DEV_PRESENT; - if (link->state & DEV_CONFIG) - mod_timer(&link->release, jiffies + HZ/20); - break; - case CS_EVENT_CARD_INSERTION: - link->state |= DEV_PRESENT | DEV_CONFIG_PENDING; - qlogic_config(link); - break; - case CS_EVENT_PM_SUSPEND: - link->state |= DEV_SUSPEND; - /* Fall through... */ - case CS_EVENT_RESET_PHYSICAL: - if (link->state & DEV_CONFIG) - CardServices(ReleaseConfiguration, link->handle); - break; - case CS_EVENT_PM_RESUME: - link->state &= ~DEV_SUSPEND; - /* Fall through... */ - case CS_EVENT_CARD_RESET: - if (link->state & DEV_CONFIG) { - scsi_info_t *info = link->priv; - CardServices(RequestConfiguration, link->handle, &link->conf); - if ((info->manf_id == MANFID_MACNICA) || - (info->manf_id == MANFID_PIONEER) || - (info->manf_id == 0x0098)) { - outb( 0x80, link->io.BasePort1+0xd); - outb( 0x24, link->io.BasePort1+0x9); - outb( 0x04, link->io.BasePort1+0xd); - } - qlogic_reset(NULL); + DEBUG(1, "qlogic_event(0x%06x)\n", event); + + switch (event) { + case CS_EVENT_CARD_REMOVAL: + link->state &= ~DEV_PRESENT; + if (link->state & DEV_CONFIG) + mod_timer(&link->release, jiffies + HZ / 20); + break; + case CS_EVENT_CARD_INSERTION: + link->state |= DEV_PRESENT | DEV_CONFIG_PENDING; + qlogic_config(link); + break; + case CS_EVENT_PM_SUSPEND: + link->state |= DEV_SUSPEND; + /* Fall through... */ + case CS_EVENT_RESET_PHYSICAL: + if (link->state & DEV_CONFIG) + CardServices(ReleaseConfiguration, link->handle); + break; + case CS_EVENT_PM_RESUME: + link->state &= ~DEV_SUSPEND; + /* Fall through... */ + case CS_EVENT_CARD_RESET: + if (link->state & DEV_CONFIG) { + scsi_info_t *info = link->priv; + CardServices(RequestConfiguration, link->handle, &link->conf); + if ((info->manf_id == MANFID_MACNICA) || (info->manf_id == MANFID_PIONEER) || (info->manf_id == 0x0098)) { + outb(0x80, link->io.BasePort1 + 0xd); + outb(0x24, link->io.BasePort1 + 0x9); + outb(0x04, link->io.BasePort1 + 0xd); + } + /* Ugggglllyyyy!!! */ + driver_template.eh_bus_reset_handler(NULL); + } + break; } - break; - } - return 0; -} /* qlogic_event */ + return 0; +} /* qlogic_event */ /*====================================================================*/ -static int __init init_qlogic_cs(void) { - servinfo_t serv; - DEBUG(0, "%s\n", version); - CardServices(GetCardServicesInfo, &serv); - if (serv.Revision != CS_RELEASE_CODE) { - printk(KERN_NOTICE "qlogic_cs: Card Services release " - "does not match!\n"); - return -1; - } - register_pccard_driver(&dev_info, &qlogic_attach, &qlogic_detach); - return 0; +static int __init init_qlogic_cs(void) +{ + servinfo_t serv; + DEBUG(0, "%s\n", version); + CardServices(GetCardServicesInfo, &serv); + if (serv.Revision != CS_RELEASE_CODE) { + printk(KERN_NOTICE "qlogic_cs: Card Services release " "does not match!\n"); + return -1; + } + register_pccard_driver(&dev_info, &qlogic_attach, &qlogic_detach); + return 0; } -static void __exit exit_qlogic_cs(void) { - DEBUG(0, "qlogic_cs: unloading\n"); - unregister_pccard_driver(&dev_info); - while (dev_list != NULL) - qlogic_detach(dev_list); +static void __exit exit_qlogic_cs(void) +{ + DEBUG(0, "qlogic_cs: unloading\n"); + unregister_pccard_driver(&dev_info); + while (dev_list != NULL) + qlogic_detach(dev_list); } module_init(init_qlogic_cs); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/drivers/scsi/README.nsp_cs linux.2.5.47-ac6/drivers/scsi/README.nsp_cs --- linux.2.5.47/drivers/scsi/README.nsp_cs 1970-01-01 01:00:00.000000000 +0100 +++ linux.2.5.47-ac6/drivers/scsi/README.nsp_cs 2002-10-31 15:05:34.000000000 +0000 @@ -0,0 +1,129 @@ + + WorkBiT NinjaSCSI-3/32Bi driver for Linux + +1. Comment + This is Workbit corp.'s(http://www.workbit.co.jp/) NinjaSCSI-3 +(http://www.workbit.co.jp/ts/z_nj3r.html) and NinjaSCSI-32Bi +(http://www.workbit.co.jp/ts/z_njsc32bi.html) PCMCIA card driver module +for Linux. + +2. My Linux environment +Linux kernel: 2.4.17 / 2.2.20 +pcmcia-cs: 3.1.30 +gcc: gcc-2.95.4 +PC card: I-O data PCSC-F (NinjaSCSI-3) + I-O data CBSC-II in 16 bit mode (NinjaSCSI-32Bi) +SCSI device: I-O data CDPS-PX24 (CD-ROM drive) + Media Intelligent MMO-640GT (Optical disk drive) + +3. Install +[1] Check your PC card is true "NinjaSCSI-3" card. + If you installed pcmcia-cs already, pcmcia reports your card as UNKNOWN + card, and write ["WBT", "NinjaSCSI-3", "R1.0"] or some other string to + your console or log file. + You can also use "cardctl" program (this program is in pcmcia-cs source + code) to get more info. + +# cat /var/log/messgaes +... +Jan 2 03:45:06 lindberg cardmgr[78]: unsupported card in socket 1 +Jan 2 03:45:06 lindberg cardmgr[78]: product info: "WBT", "NinjaSCSI-3", "R1.0" +... +# cardctl ident +Socket 0: + no product info available +Socket 1: + product info: "IO DATA", "CBSC16 ", "1" + + +[2] Get Linux kernel source, and extract it to /usr/src. + Because NinjaSCSI driver requiers some SCSI header files in Linux kernel + source. + I recomend rebuilding your kernel. This eliminate some versioning problem. +$ cd /usr/src +$ tar -zxvf linux-x.x.x.tar.gz +$ cd linux +$ make config +... + +[3] If you use this driver with Kernel 2.2, Unpack pcmcia-cs in some directory + and make & install. This driver requies pcmcia-cs header file. +$ cd /usr/src +$ tar zxvf cs-pcmcia-cs-3.x.x.tar.gz +... + +[4] Extract this driver's archive somewhere, and edit Makefile, then do make. +$ tar -zxvf nsp_cs-x.x.tar.gz +$ cd nsp_cs-x.x +$ emacs Makefile +... +$ make + +[5] Copy nsp_cs.o to suitable plase, like /lib/modules//pcmcia/ . + +[6] Add these lines to /etc/pcmcia/config . + If you yse pcmcia-cs-3.1.8 or later, we can use "nsp_cs.conf" file. + So, you don't need to edit file. Just copy to /etc/pcmcia/ . + +------------------------------------- +device "nsp_cs" + class "scsi" module "nsp_cs" + +card "WorkBit NinjaSCSI-3" + version "WBT", "NinjaSCSI-3", "R1.0" + bind "nsp_cs" + +card "WorkBit NinjaSCSI-32Bi (16bit)" + version "WORKBIT", "UltraNinja-16", "1" + bind "nsp_cs" + +# OEM +card "WorkBit NinjaSCSI-32Bi (16bit) / IO-DATA" + version "IO DATA", "CBSC16 ", "1" + bind "nsp_cs" + +# OEM +card "WorkBit NinjaSCSI-32Bi (16bit) / KME-1" + version "KME ", "SCSI-CARD-001", "1" + bind "nsp_cs" +card "WorkBit NinjaSCSI-32Bi (16bit) / KME-2" + version "KME ", "SCSI-CARD-002", "1" + bind "nsp_cs" +card "WorkBit NinjaSCSI-32Bi (16bit) / KME-3" + version "KME ", "SCSI-CARD-003", "1" + bind "nsp_cs" +card "WorkBit NinjaSCSI-32Bi (16bit) / KME-4" + version "KME ", "SCSI-CARD-004", "1" + bind "nsp_cs" +------------------------------------- + +[7] Start (or restart) pcmcia-cs. +# /etc/rc.d/rc.pcmcia start (BSD style) +or +# /etc/init.d/pcmcia start (SYSV style) + + +4. History +See README.nin_cs . + +5. Caution + If you eject card when doing some operation for your SCSI device or suspend +your computer, you encount some *BAD* error like disk crash. + It works good when I using this driver right way. But I'm not guarantee +your data. Please backup your data when you use this driver. + +6. Known Bugs + Many bugs in this driver. Be careful! + +7. Testing + Please send me some reports(bug reports etc..) of this software. +When you send report, please tell me these or more. + card name + kernel version + your SCSI device name(hard drive, CD-ROM, etc...) + +8. Copyright + See GPL. + + +2002/01/17 yokota@netlab.is.tsukuba.ac.jp diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/drivers/scsi/sd.c linux.2.5.47-ac6/drivers/scsi/sd.c --- linux.2.5.47/drivers/scsi/sd.c 2002-11-11 16:39:10.000000000 +0000 +++ linux.2.5.47-ac6/drivers/scsi/sd.c 2002-11-15 15:34:48.000000000 +0000 @@ -758,7 +758,6 @@ sd_spinup_disk(struct scsi_disk *sdkp, char *diskname, struct scsi_request *SRpnt, unsigned char *buffer) { unsigned char cmd[10]; - struct scsi_device *sdp = sdkp->device; unsigned long spintime_value = 0; int the_result, retries, spintime; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/drivers/scsi/sim710.c linux.2.5.47-ac6/drivers/scsi/sim710.c --- linux.2.5.47/drivers/scsi/sim710.c 2002-10-31 14:57:12.000000000 +0000 +++ linux.2.5.47-ac6/drivers/scsi/sim710.c 2002-10-31 15:05:32.000000000 +0000 @@ -296,15 +296,15 @@ " 04 socl: %02x sodl: %02x sxfer: %02x scid: %02x\n" " 08 sbcl: %02x sbdl: %02x sidl: %02x sfbr: %02x\n" " 0C sstat2:%02x sstat1:%02x sstat0:%02x dstat: %02x\n" - " 10 dsa: %08x\n" + " 10 dsa: %08lx\n" " 14 ctest3:%02x ctest2:%02x ctest1:%02x ctest0:%02x\n" " 18 ctest7:%02x ctest6:%02x ctest5:%02x ctest4:%02x\n" " 1C temp: %08x\n" " 20 lcrc: %02x ctest8:%02x istat: %02x dfifo: %02x\n" - " 24 dbc: %08x dnad: %08x dsp: %08x\n" - " 30 dsps: %08x scratch:%08x\n" + " 24 dbc: %08lx dnad: %08lx dsp: %08lx\n" + " 30 dsps: %08lx scratch:%08lx\n" " 38 dcntl: %02x dwt: %02x dien: %02x dmode: %02x\n" - " 3C adder: %08x\n", + " 3C adder: %08lx\n", NCR_read8(SIEN_REG), NCR_read8(SDID_REG), NCR_read8(SCNTL1_REG), NCR_read8(SCNTL0_REG), NCR_read8(SOCL_REG), NCR_read8(SODL_REG), NCR_read8(SXFER_REG), NCR_read8(SCID_REG), NCR_read8(SBCL_REG), @@ -1018,7 +1018,7 @@ if (!cmd) { printk("scsi%d: No active command!\n", host->host_no); printk("scsi%d: Int %d, istat %02x, sstat0 %02x " - "dstat %02x, dsp [%04x], scratch %02x, dsps %08x\n", + "dstat %02x, dsp [%04x], scratch %02lx, dsps %08x\n", host->host_no, sim710_intrs, istat, sstat0, dstat, (u32 *)(isa_bus_to_virt(NCR_read32(DSP_REG))) - hostdata->script, NCR_read32(SCRATCH_REG), dsps); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/drivers/scsi/sim710_d.h linux.2.5.47-ac6/drivers/scsi/sim710_d.h --- linux.2.5.47/drivers/scsi/sim710_d.h 1970-01-01 01:00:00.000000000 +0100 +++ linux.2.5.47-ac6/drivers/scsi/sim710_d.h 2002-11-12 17:23:42.000000000 +0000 @@ -0,0 +1,2452 @@ +/* DO NOT EDIT - Generated automatically by script_asm.pl */ +static u32 SCRIPT[] = { +/* + + + + + + +ABSOLUTE dsa_select = 0 +ABSOLUTE dsa_msgout = 8 +ABSOLUTE dsa_cmnd = 16 +ABSOLUTE dsa_status = 24 +ABSOLUTE dsa_msgin = 32 +ABSOLUTE dsa_datain = 40 +ABSOLUTE dsa_dataout = 1064 +ABSOLUTE dsa_size = 2088 + +ABSOLUTE reselected_identify = 0 +ABSOLUTE msgin_buf = 0 +ABSOLUTE msg_reject = 0 +ABSOLUTE test1_src = 0 +ABSOLUTE test1_dst = 0 + + + +ABSOLUTE int_bad_msg1 = 0xab930006 +ABSOLUTE int_bad_msg2 = 0xab930007 +ABSOLUTE int_bad_msg3 = 0xab930008 +ABSOLUTE int_cmd_bad_phase = 0xab930009 +ABSOLUTE int_cmd_complete = 0xab93000a +ABSOLUTE int_data_bad_phase = 0xab93000b +ABSOLUTE int_msg_sdtr1 = 0xab93000c +ABSOLUTE int_msg_sdtr2 = 0xab93000d +ABSOLUTE int_msg_sdtr3 = 0xab93000e +ABSOLUTE int_no_msgout1 = 0xab93000f +ABSOLUTE int_no_msgout2 = 0xab930010 +ABSOLUTE int_no_msgout3 = 0xab930011 +ABSOLUTE int_not_cmd_complete = 0xab930012 +ABSOLUTE int_sel_no_ident = 0xab930013 +ABSOLUTE int_sel_not_cmd = 0xab930014 +ABSOLUTE int_status_not_msgin = 0xab930015 +ABSOLUTE int_resel_not_msgin = 0xab930016 +ABSOLUTE int_reselected = 0xab930017 +ABSOLUTE int_selected = 0xab930018 +ABSOLUTE int_disc1 = 0xab930019 +ABSOLUTE int_disc2 = 0xab93001a +ABSOLUTE int_disc3 = 0xab93001b +ABSOLUTE int_not_rej = 0xab93001c +ABSOLUTE int_test1 = 0xab93001d + + + +ABSOLUTE had_select = 0x01 +ABSOLUTE had_msgout = 0x02 +ABSOLUTE had_cmdout = 0x04 +ABSOLUTE had_datain = 0x08 +ABSOLUTE had_dataout = 0x10 +ABSOLUTE had_status = 0x20 +ABSOLUTE had_msgin = 0x40 +ABSOLUTE had_extmsg = 0x80 + + + +ABSOLUTE did_reject = 0x01 + + + + + +ENTRY do_select +do_select: + CLEAR TARGET + +at 0x00000000 : */ 0x60000200,0x00000000, +/* + ; Enable selection timer + MOVE CTEST7 & 0xef TO CTEST7 + +at 0x00000002 : */ 0x7c1bef00,0x00000000, +/* + SELECT ATN FROM dsa_select, reselect + +at 0x00000004 : */ 0x43000000,0x00000cd0, +/* + JUMP get_status, WHEN STATUS + +at 0x00000006 : */ 0x830b0000,0x00000098, +/* + ; Disable selection timer + MOVE CTEST7 | 0x10 TO CTEST7 + +at 0x00000008 : */ 0x7a1b1000,0x00000000, +/* + MOVE SCRATCH0 | had_select TO SCRATCH0 + +at 0x0000000a : */ 0x7a340100,0x00000000, +/* + INT int_sel_no_ident, IF NOT MSG_OUT + +at 0x0000000c : */ 0x9e020000,0xab930013, +/* + MOVE SCRATCH0 | had_msgout TO SCRATCH0 + +at 0x0000000e : */ 0x7a340200,0x00000000, +/* + MOVE FROM dsa_msgout, when MSG_OUT + +at 0x00000010 : */ 0x1e000000,0x00000008, +/* +ENTRY done_ident +done_ident: + JUMP get_status, IF STATUS + +at 0x00000012 : */ 0x830a0000,0x00000098, +/* +redo_msgin1: + JUMP get_msgin1, WHEN MSG_IN + +at 0x00000014 : */ 0x870b0000,0x00000918, +/* + INT int_sel_not_cmd, IF NOT CMD + +at 0x00000016 : */ 0x9a020000,0xab930014, +/* +ENTRY resume_cmd +resume_cmd: + MOVE SCRATCH0 | had_cmdout TO SCRATCH0 + +at 0x00000018 : */ 0x7a340400,0x00000000, +/* + MOVE FROM dsa_cmnd, WHEN CMD + +at 0x0000001a : */ 0x1a000000,0x00000010, +/* +ENTRY resume_pmm +resume_pmm: +redo_msgin2: + JUMP get_msgin2, WHEN MSG_IN + +at 0x0000001c : */ 0x870b0000,0x00000a48, +/* + JUMP get_status, IF STATUS + +at 0x0000001e : */ 0x830a0000,0x00000098, +/* + JUMP input_data, IF DATA_IN + +at 0x00000020 : */ 0x810a0000,0x000000d8, +/* + JUMP output_data, IF DATA_OUT + +at 0x00000022 : */ 0x800a0000,0x000004f0, +/* + INT int_cmd_bad_phase + +at 0x00000024 : */ 0x98080000,0xab930009, +/* + +get_status: + ; Disable selection timer + MOVE CTEST7 | 0x10 TO CTEST7 + +at 0x00000026 : */ 0x7a1b1000,0x00000000, +/* + MOVE FROM dsa_status, WHEN STATUS + +at 0x00000028 : */ 0x1b000000,0x00000018, +/* + INT int_status_not_msgin, WHEN NOT MSG_IN + +at 0x0000002a : */ 0x9f030000,0xab930015, +/* + MOVE FROM dsa_msgin, WHEN MSG_IN + +at 0x0000002c : */ 0x1f000000,0x00000020, +/* + INT int_not_cmd_complete, IF NOT 0x00 + +at 0x0000002e : */ 0x98040000,0xab930012, +/* + CLEAR ACK + +at 0x00000030 : */ 0x60000040,0x00000000, +/* +ENTRY wait_disc_complete +wait_disc_complete: + WAIT DISCONNECT + +at 0x00000032 : */ 0x48000000,0x00000000, +/* + INT int_cmd_complete + +at 0x00000034 : */ 0x98080000,0xab93000a, +/* + +input_data: + MOVE SCRATCH0 | had_datain TO SCRATCH0 + +at 0x00000036 : */ 0x7a340800,0x00000000, +/* +ENTRY patch_input_data +patch_input_data: + JUMP 0 + +at 0x00000038 : */ 0x80080000,0x00000000, +/* + MOVE FROM dsa_datain+0x0000, WHEN DATA_IN + +at 0x0000003a : */ 0x19000000,0x00000028, +/* + MOVE FROM dsa_datain+0x0008, WHEN DATA_IN + +at 0x0000003c : */ 0x19000000,0x00000030, +/* + MOVE FROM dsa_datain+0x0010, WHEN DATA_IN + +at 0x0000003e : */ 0x19000000,0x00000038, +/* + MOVE FROM dsa_datain+0x0018, WHEN DATA_IN + +at 0x00000040 : */ 0x19000000,0x00000040, +/* + MOVE FROM dsa_datain+0x0020, WHEN DATA_IN + +at 0x00000042 : */ 0x19000000,0x00000048, +/* + MOVE FROM dsa_datain+0x0028, WHEN DATA_IN + +at 0x00000044 : */ 0x19000000,0x00000050, +/* + MOVE FROM dsa_datain+0x0030, WHEN DATA_IN + +at 0x00000046 : */ 0x19000000,0x00000058, +/* + MOVE FROM dsa_datain+0x0038, WHEN DATA_IN + +at 0x00000048 : */ 0x19000000,0x00000060, +/* + MOVE FROM dsa_datain+0x0040, WHEN DATA_IN + +at 0x0000004a : */ 0x19000000,0x00000068, +/* + MOVE FROM dsa_datain+0x0048, WHEN DATA_IN + +at 0x0000004c : */ 0x19000000,0x00000070, +/* + MOVE FROM dsa_datain+0x0050, WHEN DATA_IN + +at 0x0000004e : */ 0x19000000,0x00000078, +/* + MOVE FROM dsa_datain+0x0058, WHEN DATA_IN + +at 0x00000050 : */ 0x19000000,0x00000080, +/* + MOVE FROM dsa_datain+0x0060, WHEN DATA_IN + +at 0x00000052 : */ 0x19000000,0x00000088, +/* + MOVE FROM dsa_datain+0x0068, WHEN DATA_IN + +at 0x00000054 : */ 0x19000000,0x00000090, +/* + MOVE FROM dsa_datain+0x0070, WHEN DATA_IN + +at 0x00000056 : */ 0x19000000,0x00000098, +/* + MOVE FROM dsa_datain+0x0078, WHEN DATA_IN + +at 0x00000058 : */ 0x19000000,0x000000a0, +/* + MOVE FROM dsa_datain+0x0080, WHEN DATA_IN + +at 0x0000005a : */ 0x19000000,0x000000a8, +/* + MOVE FROM dsa_datain+0x0088, WHEN DATA_IN + +at 0x0000005c : */ 0x19000000,0x000000b0, +/* + MOVE FROM dsa_datain+0x0090, WHEN DATA_IN + +at 0x0000005e : */ 0x19000000,0x000000b8, +/* + MOVE FROM dsa_datain+0x0098, WHEN DATA_IN + +at 0x00000060 : */ 0x19000000,0x000000c0, +/* + MOVE FROM dsa_datain+0x00a0, WHEN DATA_IN + +at 0x00000062 : */ 0x19000000,0x000000c8, +/* + MOVE FROM dsa_datain+0x00a8, WHEN DATA_IN + +at 0x00000064 : */ 0x19000000,0x000000d0, +/* + MOVE FROM dsa_datain+0x00b0, WHEN DATA_IN + +at 0x00000066 : */ 0x19000000,0x000000d8, +/* + MOVE FROM dsa_datain+0x00b8, WHEN DATA_IN + +at 0x00000068 : */ 0x19000000,0x000000e0, +/* + MOVE FROM dsa_datain+0x00c0, WHEN DATA_IN + +at 0x0000006a : */ 0x19000000,0x000000e8, +/* + MOVE FROM dsa_datain+0x00c8, WHEN DATA_IN + +at 0x0000006c : */ 0x19000000,0x000000f0, +/* + MOVE FROM dsa_datain+0x00d0, WHEN DATA_IN + +at 0x0000006e : */ 0x19000000,0x000000f8, +/* + MOVE FROM dsa_datain+0x00d8, WHEN DATA_IN + +at 0x00000070 : */ 0x19000000,0x00000100, +/* + MOVE FROM dsa_datain+0x00e0, WHEN DATA_IN + +at 0x00000072 : */ 0x19000000,0x00000108, +/* + MOVE FROM dsa_datain+0x00e8, WHEN DATA_IN + +at 0x00000074 : */ 0x19000000,0x00000110, +/* + MOVE FROM dsa_datain+0x00f0, WHEN DATA_IN + +at 0x00000076 : */ 0x19000000,0x00000118, +/* + MOVE FROM dsa_datain+0x00f8, WHEN DATA_IN + +at 0x00000078 : */ 0x19000000,0x00000120, +/* + MOVE FROM dsa_datain+0x0100, WHEN DATA_IN + +at 0x0000007a : */ 0x19000000,0x00000128, +/* + MOVE FROM dsa_datain+0x0108, WHEN DATA_IN + +at 0x0000007c : */ 0x19000000,0x00000130, +/* + MOVE FROM dsa_datain+0x0110, WHEN DATA_IN + +at 0x0000007e : */ 0x19000000,0x00000138, +/* + MOVE FROM dsa_datain+0x0118, WHEN DATA_IN + +at 0x00000080 : */ 0x19000000,0x00000140, +/* + MOVE FROM dsa_datain+0x0120, WHEN DATA_IN + +at 0x00000082 : */ 0x19000000,0x00000148, +/* + MOVE FROM dsa_datain+0x0128, WHEN DATA_IN + +at 0x00000084 : */ 0x19000000,0x00000150, +/* + MOVE FROM dsa_datain+0x0130, WHEN DATA_IN + +at 0x00000086 : */ 0x19000000,0x00000158, +/* + MOVE FROM dsa_datain+0x0138, WHEN DATA_IN + +at 0x00000088 : */ 0x19000000,0x00000160, +/* + MOVE FROM dsa_datain+0x0140, WHEN DATA_IN + +at 0x0000008a : */ 0x19000000,0x00000168, +/* + MOVE FROM dsa_datain+0x0148, WHEN DATA_IN + +at 0x0000008c : */ 0x19000000,0x00000170, +/* + MOVE FROM dsa_datain+0x0150, WHEN DATA_IN + +at 0x0000008e : */ 0x19000000,0x00000178, +/* + MOVE FROM dsa_datain+0x0158, WHEN DATA_IN + +at 0x00000090 : */ 0x19000000,0x00000180, +/* + MOVE FROM dsa_datain+0x0160, WHEN DATA_IN + +at 0x00000092 : */ 0x19000000,0x00000188, +/* + MOVE FROM dsa_datain+0x0168, WHEN DATA_IN + +at 0x00000094 : */ 0x19000000,0x00000190, +/* + MOVE FROM dsa_datain+0x0170, WHEN DATA_IN + +at 0x00000096 : */ 0x19000000,0x00000198, +/* + MOVE FROM dsa_datain+0x0178, WHEN DATA_IN + +at 0x00000098 : */ 0x19000000,0x000001a0, +/* + MOVE FROM dsa_datain+0x0180, WHEN DATA_IN + +at 0x0000009a : */ 0x19000000,0x000001a8, +/* + MOVE FROM dsa_datain+0x0188, WHEN DATA_IN + +at 0x0000009c : */ 0x19000000,0x000001b0, +/* + MOVE FROM dsa_datain+0x0190, WHEN DATA_IN + +at 0x0000009e : */ 0x19000000,0x000001b8, +/* + MOVE FROM dsa_datain+0x0198, WHEN DATA_IN + +at 0x000000a0 : */ 0x19000000,0x000001c0, +/* + MOVE FROM dsa_datain+0x01a0, WHEN DATA_IN + +at 0x000000a2 : */ 0x19000000,0x000001c8, +/* + MOVE FROM dsa_datain+0x01a8, WHEN DATA_IN + +at 0x000000a4 : */ 0x19000000,0x000001d0, +/* + MOVE FROM dsa_datain+0x01b0, WHEN DATA_IN + +at 0x000000a6 : */ 0x19000000,0x000001d8, +/* + MOVE FROM dsa_datain+0x01b8, WHEN DATA_IN + +at 0x000000a8 : */ 0x19000000,0x000001e0, +/* + MOVE FROM dsa_datain+0x01c0, WHEN DATA_IN + +at 0x000000aa : */ 0x19000000,0x000001e8, +/* + MOVE FROM dsa_datain+0x01c8, WHEN DATA_IN + +at 0x000000ac : */ 0x19000000,0x000001f0, +/* + MOVE FROM dsa_datain+0x01d0, WHEN DATA_IN + +at 0x000000ae : */ 0x19000000,0x000001f8, +/* + MOVE FROM dsa_datain+0x01d8, WHEN DATA_IN + +at 0x000000b0 : */ 0x19000000,0x00000200, +/* + MOVE FROM dsa_datain+0x01e0, WHEN DATA_IN + +at 0x000000b2 : */ 0x19000000,0x00000208, +/* + MOVE FROM dsa_datain+0x01e8, WHEN DATA_IN + +at 0x000000b4 : */ 0x19000000,0x00000210, +/* + MOVE FROM dsa_datain+0x01f0, WHEN DATA_IN + +at 0x000000b6 : */ 0x19000000,0x00000218, +/* + MOVE FROM dsa_datain+0x01f8, WHEN DATA_IN + +at 0x000000b8 : */ 0x19000000,0x00000220, +/* + MOVE FROM dsa_datain+0x0200, WHEN DATA_IN + +at 0x000000ba : */ 0x19000000,0x00000228, +/* + MOVE FROM dsa_datain+0x0208, WHEN DATA_IN + +at 0x000000bc : */ 0x19000000,0x00000230, +/* + MOVE FROM dsa_datain+0x0210, WHEN DATA_IN + +at 0x000000be : */ 0x19000000,0x00000238, +/* + MOVE FROM dsa_datain+0x0218, WHEN DATA_IN + +at 0x000000c0 : */ 0x19000000,0x00000240, +/* + MOVE FROM dsa_datain+0x0220, WHEN DATA_IN + +at 0x000000c2 : */ 0x19000000,0x00000248, +/* + MOVE FROM dsa_datain+0x0228, WHEN DATA_IN + +at 0x000000c4 : */ 0x19000000,0x00000250, +/* + MOVE FROM dsa_datain+0x0230, WHEN DATA_IN + +at 0x000000c6 : */ 0x19000000,0x00000258, +/* + MOVE FROM dsa_datain+0x0238, WHEN DATA_IN + +at 0x000000c8 : */ 0x19000000,0x00000260, +/* + MOVE FROM dsa_datain+0x0240, WHEN DATA_IN + +at 0x000000ca : */ 0x19000000,0x00000268, +/* + MOVE FROM dsa_datain+0x0248, WHEN DATA_IN + +at 0x000000cc : */ 0x19000000,0x00000270, +/* + MOVE FROM dsa_datain+0x0250, WHEN DATA_IN + +at 0x000000ce : */ 0x19000000,0x00000278, +/* + MOVE FROM dsa_datain+0x0258, WHEN DATA_IN + +at 0x000000d0 : */ 0x19000000,0x00000280, +/* + MOVE FROM dsa_datain+0x0260, WHEN DATA_IN + +at 0x000000d2 : */ 0x19000000,0x00000288, +/* + MOVE FROM dsa_datain+0x0268, WHEN DATA_IN + +at 0x000000d4 : */ 0x19000000,0x00000290, +/* + MOVE FROM dsa_datain+0x0270, WHEN DATA_IN + +at 0x000000d6 : */ 0x19000000,0x00000298, +/* + MOVE FROM dsa_datain+0x0278, WHEN DATA_IN + +at 0x000000d8 : */ 0x19000000,0x000002a0, +/* + MOVE FROM dsa_datain+0x0280, WHEN DATA_IN + +at 0x000000da : */ 0x19000000,0x000002a8, +/* + MOVE FROM dsa_datain+0x0288, WHEN DATA_IN + +at 0x000000dc : */ 0x19000000,0x000002b0, +/* + MOVE FROM dsa_datain+0x0290, WHEN DATA_IN + +at 0x000000de : */ 0x19000000,0x000002b8, +/* + MOVE FROM dsa_datain+0x0298, WHEN DATA_IN + +at 0x000000e0 : */ 0x19000000,0x000002c0, +/* + MOVE FROM dsa_datain+0x02a0, WHEN DATA_IN + +at 0x000000e2 : */ 0x19000000,0x000002c8, +/* + MOVE FROM dsa_datain+0x02a8, WHEN DATA_IN + +at 0x000000e4 : */ 0x19000000,0x000002d0, +/* + MOVE FROM dsa_datain+0x02b0, WHEN DATA_IN + +at 0x000000e6 : */ 0x19000000,0x000002d8, +/* + MOVE FROM dsa_datain+0x02b8, WHEN DATA_IN + +at 0x000000e8 : */ 0x19000000,0x000002e0, +/* + MOVE FROM dsa_datain+0x02c0, WHEN DATA_IN + +at 0x000000ea : */ 0x19000000,0x000002e8, +/* + MOVE FROM dsa_datain+0x02c8, WHEN DATA_IN + +at 0x000000ec : */ 0x19000000,0x000002f0, +/* + MOVE FROM dsa_datain+0x02d0, WHEN DATA_IN + +at 0x000000ee : */ 0x19000000,0x000002f8, +/* + MOVE FROM dsa_datain+0x02d8, WHEN DATA_IN + +at 0x000000f0 : */ 0x19000000,0x00000300, +/* + MOVE FROM dsa_datain+0x02e0, WHEN DATA_IN + +at 0x000000f2 : */ 0x19000000,0x00000308, +/* + MOVE FROM dsa_datain+0x02e8, WHEN DATA_IN + +at 0x000000f4 : */ 0x19000000,0x00000310, +/* + MOVE FROM dsa_datain+0x02f0, WHEN DATA_IN + +at 0x000000f6 : */ 0x19000000,0x00000318, +/* + MOVE FROM dsa_datain+0x02f8, WHEN DATA_IN + +at 0x000000f8 : */ 0x19000000,0x00000320, +/* + MOVE FROM dsa_datain+0x0300, WHEN DATA_IN + +at 0x000000fa : */ 0x19000000,0x00000328, +/* + MOVE FROM dsa_datain+0x0308, WHEN DATA_IN + +at 0x000000fc : */ 0x19000000,0x00000330, +/* + MOVE FROM dsa_datain+0x0310, WHEN DATA_IN + +at 0x000000fe : */ 0x19000000,0x00000338, +/* + MOVE FROM dsa_datain+0x0318, WHEN DATA_IN + +at 0x00000100 : */ 0x19000000,0x00000340, +/* + MOVE FROM dsa_datain+0x0320, WHEN DATA_IN + +at 0x00000102 : */ 0x19000000,0x00000348, +/* + MOVE FROM dsa_datain+0x0328, WHEN DATA_IN + +at 0x00000104 : */ 0x19000000,0x00000350, +/* + MOVE FROM dsa_datain+0x0330, WHEN DATA_IN + +at 0x00000106 : */ 0x19000000,0x00000358, +/* + MOVE FROM dsa_datain+0x0338, WHEN DATA_IN + +at 0x00000108 : */ 0x19000000,0x00000360, +/* + MOVE FROM dsa_datain+0x0340, WHEN DATA_IN + +at 0x0000010a : */ 0x19000000,0x00000368, +/* + MOVE FROM dsa_datain+0x0348, WHEN DATA_IN + +at 0x0000010c : */ 0x19000000,0x00000370, +/* + MOVE FROM dsa_datain+0x0350, WHEN DATA_IN + +at 0x0000010e : */ 0x19000000,0x00000378, +/* + MOVE FROM dsa_datain+0x0358, WHEN DATA_IN + +at 0x00000110 : */ 0x19000000,0x00000380, +/* + MOVE FROM dsa_datain+0x0360, WHEN DATA_IN + +at 0x00000112 : */ 0x19000000,0x00000388, +/* + MOVE FROM dsa_datain+0x0368, WHEN DATA_IN + +at 0x00000114 : */ 0x19000000,0x00000390, +/* + MOVE FROM dsa_datain+0x0370, WHEN DATA_IN + +at 0x00000116 : */ 0x19000000,0x00000398, +/* + MOVE FROM dsa_datain+0x0378, WHEN DATA_IN + +at 0x00000118 : */ 0x19000000,0x000003a0, +/* + MOVE FROM dsa_datain+0x0380, WHEN DATA_IN + +at 0x0000011a : */ 0x19000000,0x000003a8, +/* + MOVE FROM dsa_datain+0x0388, WHEN DATA_IN + +at 0x0000011c : */ 0x19000000,0x000003b0, +/* + MOVE FROM dsa_datain+0x0390, WHEN DATA_IN + +at 0x0000011e : */ 0x19000000,0x000003b8, +/* + MOVE FROM dsa_datain+0x0398, WHEN DATA_IN + +at 0x00000120 : */ 0x19000000,0x000003c0, +/* + MOVE FROM dsa_datain+0x03a0, WHEN DATA_IN + +at 0x00000122 : */ 0x19000000,0x000003c8, +/* + MOVE FROM dsa_datain+0x03a8, WHEN DATA_IN + +at 0x00000124 : */ 0x19000000,0x000003d0, +/* + MOVE FROM dsa_datain+0x03b0, WHEN DATA_IN + +at 0x00000126 : */ 0x19000000,0x000003d8, +/* + MOVE FROM dsa_datain+0x03b8, WHEN DATA_IN + +at 0x00000128 : */ 0x19000000,0x000003e0, +/* + MOVE FROM dsa_datain+0x03c0, WHEN DATA_IN + +at 0x0000012a : */ 0x19000000,0x000003e8, +/* + MOVE FROM dsa_datain+0x03c8, WHEN DATA_IN + +at 0x0000012c : */ 0x19000000,0x000003f0, +/* + MOVE FROM dsa_datain+0x03d0, WHEN DATA_IN + +at 0x0000012e : */ 0x19000000,0x000003f8, +/* + MOVE FROM dsa_datain+0x03d8, WHEN DATA_IN + +at 0x00000130 : */ 0x19000000,0x00000400, +/* + MOVE FROM dsa_datain+0x03e0, WHEN DATA_IN + +at 0x00000132 : */ 0x19000000,0x00000408, +/* + MOVE FROM dsa_datain+0x03e8, WHEN DATA_IN + +at 0x00000134 : */ 0x19000000,0x00000410, +/* + MOVE FROM dsa_datain+0x03f0, WHEN DATA_IN + +at 0x00000136 : */ 0x19000000,0x00000418, +/* + MOVE FROM dsa_datain+0x03f8, WHEN DATA_IN + +at 0x00000138 : */ 0x19000000,0x00000420, +/* + JUMP end_data_trans + +at 0x0000013a : */ 0x80080000,0x00000900, +/* + +output_data: + MOVE SCRATCH0 | had_dataout TO SCRATCH0 + +at 0x0000013c : */ 0x7a341000,0x00000000, +/* +ENTRY patch_output_data +patch_output_data: + JUMP 0 + +at 0x0000013e : */ 0x80080000,0x00000000, +/* + MOVE FROM dsa_dataout+0x0000, WHEN DATA_OUT + +at 0x00000140 : */ 0x18000000,0x00000428, +/* + MOVE FROM dsa_dataout+0x0008, WHEN DATA_OUT + +at 0x00000142 : */ 0x18000000,0x00000430, +/* + MOVE FROM dsa_dataout+0x0010, WHEN DATA_OUT + +at 0x00000144 : */ 0x18000000,0x00000438, +/* + MOVE FROM dsa_dataout+0x0018, WHEN DATA_OUT + +at 0x00000146 : */ 0x18000000,0x00000440, +/* + MOVE FROM dsa_dataout+0x0020, WHEN DATA_OUT + +at 0x00000148 : */ 0x18000000,0x00000448, +/* + MOVE FROM dsa_dataout+0x0028, WHEN DATA_OUT + +at 0x0000014a : */ 0x18000000,0x00000450, +/* + MOVE FROM dsa_dataout+0x0030, WHEN DATA_OUT + +at 0x0000014c : */ 0x18000000,0x00000458, +/* + MOVE FROM dsa_dataout+0x0038, WHEN DATA_OUT + +at 0x0000014e : */ 0x18000000,0x00000460, +/* + MOVE FROM dsa_dataout+0x0040, WHEN DATA_OUT + +at 0x00000150 : */ 0x18000000,0x00000468, +/* + MOVE FROM dsa_dataout+0x0048, WHEN DATA_OUT + +at 0x00000152 : */ 0x18000000,0x00000470, +/* + MOVE FROM dsa_dataout+0x0050, WHEN DATA_OUT + +at 0x00000154 : */ 0x18000000,0x00000478, +/* + MOVE FROM dsa_dataout+0x0058, WHEN DATA_OUT + +at 0x00000156 : */ 0x18000000,0x00000480, +/* + MOVE FROM dsa_dataout+0x0060, WHEN DATA_OUT + +at 0x00000158 : */ 0x18000000,0x00000488, +/* + MOVE FROM dsa_dataout+0x0068, WHEN DATA_OUT + +at 0x0000015a : */ 0x18000000,0x00000490, +/* + MOVE FROM dsa_dataout+0x0070, WHEN DATA_OUT + +at 0x0000015c : */ 0x18000000,0x00000498, +/* + MOVE FROM dsa_dataout+0x0078, WHEN DATA_OUT + +at 0x0000015e : */ 0x18000000,0x000004a0, +/* + MOVE FROM dsa_dataout+0x0080, WHEN DATA_OUT + +at 0x00000160 : */ 0x18000000,0x000004a8, +/* + MOVE FROM dsa_dataout+0x0088, WHEN DATA_OUT + +at 0x00000162 : */ 0x18000000,0x000004b0, +/* + MOVE FROM dsa_dataout+0x0090, WHEN DATA_OUT + +at 0x00000164 : */ 0x18000000,0x000004b8, +/* + MOVE FROM dsa_dataout+0x0098, WHEN DATA_OUT + +at 0x00000166 : */ 0x18000000,0x000004c0, +/* + MOVE FROM dsa_dataout+0x00a0, WHEN DATA_OUT + +at 0x00000168 : */ 0x18000000,0x000004c8, +/* + MOVE FROM dsa_dataout+0x00a8, WHEN DATA_OUT + +at 0x0000016a : */ 0x18000000,0x000004d0, +/* + MOVE FROM dsa_dataout+0x00b0, WHEN DATA_OUT + +at 0x0000016c : */ 0x18000000,0x000004d8, +/* + MOVE FROM dsa_dataout+0x00b8, WHEN DATA_OUT + +at 0x0000016e : */ 0x18000000,0x000004e0, +/* + MOVE FROM dsa_dataout+0x00c0, WHEN DATA_OUT + +at 0x00000170 : */ 0x18000000,0x000004e8, +/* + MOVE FROM dsa_dataout+0x00c8, WHEN DATA_OUT + +at 0x00000172 : */ 0x18000000,0x000004f0, +/* + MOVE FROM dsa_dataout+0x00d0, WHEN DATA_OUT + +at 0x00000174 : */ 0x18000000,0x000004f8, +/* + MOVE FROM dsa_dataout+0x00d8, WHEN DATA_OUT + +at 0x00000176 : */ 0x18000000,0x00000500, +/* + MOVE FROM dsa_dataout+0x00e0, WHEN DATA_OUT + +at 0x00000178 : */ 0x18000000,0x00000508, +/* + MOVE FROM dsa_dataout+0x00e8, WHEN DATA_OUT + +at 0x0000017a : */ 0x18000000,0x00000510, +/* + MOVE FROM dsa_dataout+0x00f0, WHEN DATA_OUT + +at 0x0000017c : */ 0x18000000,0x00000518, +/* + MOVE FROM dsa_dataout+0x00f8, WHEN DATA_OUT + +at 0x0000017e : */ 0x18000000,0x00000520, +/* + MOVE FROM dsa_dataout+0x0100, WHEN DATA_OUT + +at 0x00000180 : */ 0x18000000,0x00000528, +/* + MOVE FROM dsa_dataout+0x0108, WHEN DATA_OUT + +at 0x00000182 : */ 0x18000000,0x00000530, +/* + MOVE FROM dsa_dataout+0x0110, WHEN DATA_OUT + +at 0x00000184 : */ 0x18000000,0x00000538, +/* + MOVE FROM dsa_dataout+0x0118, WHEN DATA_OUT + +at 0x00000186 : */ 0x18000000,0x00000540, +/* + MOVE FROM dsa_dataout+0x0120, WHEN DATA_OUT + +at 0x00000188 : */ 0x18000000,0x00000548, +/* + MOVE FROM dsa_dataout+0x0128, WHEN DATA_OUT + +at 0x0000018a : */ 0x18000000,0x00000550, +/* + MOVE FROM dsa_dataout+0x0130, WHEN DATA_OUT + +at 0x0000018c : */ 0x18000000,0x00000558, +/* + MOVE FROM dsa_dataout+0x0138, WHEN DATA_OUT + +at 0x0000018e : */ 0x18000000,0x00000560, +/* + MOVE FROM dsa_dataout+0x0140, WHEN DATA_OUT + +at 0x00000190 : */ 0x18000000,0x00000568, +/* + MOVE FROM dsa_dataout+0x0148, WHEN DATA_OUT + +at 0x00000192 : */ 0x18000000,0x00000570, +/* + MOVE FROM dsa_dataout+0x0150, WHEN DATA_OUT + +at 0x00000194 : */ 0x18000000,0x00000578, +/* + MOVE FROM dsa_dataout+0x0158, WHEN DATA_OUT + +at 0x00000196 : */ 0x18000000,0x00000580, +/* + MOVE FROM dsa_dataout+0x0160, WHEN DATA_OUT + +at 0x00000198 : */ 0x18000000,0x00000588, +/* + MOVE FROM dsa_dataout+0x0168, WHEN DATA_OUT + +at 0x0000019a : */ 0x18000000,0x00000590, +/* + MOVE FROM dsa_dataout+0x0170, WHEN DATA_OUT + +at 0x0000019c : */ 0x18000000,0x00000598, +/* + MOVE FROM dsa_dataout+0x0178, WHEN DATA_OUT + +at 0x0000019e : */ 0x18000000,0x000005a0, +/* + MOVE FROM dsa_dataout+0x0180, WHEN DATA_OUT + +at 0x000001a0 : */ 0x18000000,0x000005a8, +/* + MOVE FROM dsa_dataout+0x0188, WHEN DATA_OUT + +at 0x000001a2 : */ 0x18000000,0x000005b0, +/* + MOVE FROM dsa_dataout+0x0190, WHEN DATA_OUT + +at 0x000001a4 : */ 0x18000000,0x000005b8, +/* + MOVE FROM dsa_dataout+0x0198, WHEN DATA_OUT + +at 0x000001a6 : */ 0x18000000,0x000005c0, +/* + MOVE FROM dsa_dataout+0x01a0, WHEN DATA_OUT + +at 0x000001a8 : */ 0x18000000,0x000005c8, +/* + MOVE FROM dsa_dataout+0x01a8, WHEN DATA_OUT + +at 0x000001aa : */ 0x18000000,0x000005d0, +/* + MOVE FROM dsa_dataout+0x01b0, WHEN DATA_OUT + +at 0x000001ac : */ 0x18000000,0x000005d8, +/* + MOVE FROM dsa_dataout+0x01b8, WHEN DATA_OUT + +at 0x000001ae : */ 0x18000000,0x000005e0, +/* + MOVE FROM dsa_dataout+0x01c0, WHEN DATA_OUT + +at 0x000001b0 : */ 0x18000000,0x000005e8, +/* + MOVE FROM dsa_dataout+0x01c8, WHEN DATA_OUT + +at 0x000001b2 : */ 0x18000000,0x000005f0, +/* + MOVE FROM dsa_dataout+0x01d0, WHEN DATA_OUT + +at 0x000001b4 : */ 0x18000000,0x000005f8, +/* + MOVE FROM dsa_dataout+0x01d8, WHEN DATA_OUT + +at 0x000001b6 : */ 0x18000000,0x00000600, +/* + MOVE FROM dsa_dataout+0x01e0, WHEN DATA_OUT + +at 0x000001b8 : */ 0x18000000,0x00000608, +/* + MOVE FROM dsa_dataout+0x01e8, WHEN DATA_OUT + +at 0x000001ba : */ 0x18000000,0x00000610, +/* + MOVE FROM dsa_dataout+0x01f0, WHEN DATA_OUT + +at 0x000001bc : */ 0x18000000,0x00000618, +/* + MOVE FROM dsa_dataout+0x01f8, WHEN DATA_OUT + +at 0x000001be : */ 0x18000000,0x00000620, +/* + MOVE FROM dsa_dataout+0x0200, WHEN DATA_OUT + +at 0x000001c0 : */ 0x18000000,0x00000628, +/* + MOVE FROM dsa_dataout+0x0208, WHEN DATA_OUT + +at 0x000001c2 : */ 0x18000000,0x00000630, +/* + MOVE FROM dsa_dataout+0x0210, WHEN DATA_OUT + +at 0x000001c4 : */ 0x18000000,0x00000638, +/* + MOVE FROM dsa_dataout+0x0218, WHEN DATA_OUT + +at 0x000001c6 : */ 0x18000000,0x00000640, +/* + MOVE FROM dsa_dataout+0x0220, WHEN DATA_OUT + +at 0x000001c8 : */ 0x18000000,0x00000648, +/* + MOVE FROM dsa_dataout+0x0228, WHEN DATA_OUT + +at 0x000001ca : */ 0x18000000,0x00000650, +/* + MOVE FROM dsa_dataout+0x0230, WHEN DATA_OUT + +at 0x000001cc : */ 0x18000000,0x00000658, +/* + MOVE FROM dsa_dataout+0x0238, WHEN DATA_OUT + +at 0x000001ce : */ 0x18000000,0x00000660, +/* + MOVE FROM dsa_dataout+0x0240, WHEN DATA_OUT + +at 0x000001d0 : */ 0x18000000,0x00000668, +/* + MOVE FROM dsa_dataout+0x0248, WHEN DATA_OUT + +at 0x000001d2 : */ 0x18000000,0x00000670, +/* + MOVE FROM dsa_dataout+0x0250, WHEN DATA_OUT + +at 0x000001d4 : */ 0x18000000,0x00000678, +/* + MOVE FROM dsa_dataout+0x0258, WHEN DATA_OUT + +at 0x000001d6 : */ 0x18000000,0x00000680, +/* + MOVE FROM dsa_dataout+0x0260, WHEN DATA_OUT + +at 0x000001d8 : */ 0x18000000,0x00000688, +/* + MOVE FROM dsa_dataout+0x0268, WHEN DATA_OUT + +at 0x000001da : */ 0x18000000,0x00000690, +/* + MOVE FROM dsa_dataout+0x0270, WHEN DATA_OUT + +at 0x000001dc : */ 0x18000000,0x00000698, +/* + MOVE FROM dsa_dataout+0x0278, WHEN DATA_OUT + +at 0x000001de : */ 0x18000000,0x000006a0, +/* + MOVE FROM dsa_dataout+0x0280, WHEN DATA_OUT + +at 0x000001e0 : */ 0x18000000,0x000006a8, +/* + MOVE FROM dsa_dataout+0x0288, WHEN DATA_OUT + +at 0x000001e2 : */ 0x18000000,0x000006b0, +/* + MOVE FROM dsa_dataout+0x0290, WHEN DATA_OUT + +at 0x000001e4 : */ 0x18000000,0x000006b8, +/* + MOVE FROM dsa_dataout+0x0298, WHEN DATA_OUT + +at 0x000001e6 : */ 0x18000000,0x000006c0, +/* + MOVE FROM dsa_dataout+0x02a0, WHEN DATA_OUT + +at 0x000001e8 : */ 0x18000000,0x000006c8, +/* + MOVE FROM dsa_dataout+0x02a8, WHEN DATA_OUT + +at 0x000001ea : */ 0x18000000,0x000006d0, +/* + MOVE FROM dsa_dataout+0x02b0, WHEN DATA_OUT + +at 0x000001ec : */ 0x18000000,0x000006d8, +/* + MOVE FROM dsa_dataout+0x02b8, WHEN DATA_OUT + +at 0x000001ee : */ 0x18000000,0x000006e0, +/* + MOVE FROM dsa_dataout+0x02c0, WHEN DATA_OUT + +at 0x000001f0 : */ 0x18000000,0x000006e8, +/* + MOVE FROM dsa_dataout+0x02c8, WHEN DATA_OUT + +at 0x000001f2 : */ 0x18000000,0x000006f0, +/* + MOVE FROM dsa_dataout+0x02d0, WHEN DATA_OUT + +at 0x000001f4 : */ 0x18000000,0x000006f8, +/* + MOVE FROM dsa_dataout+0x02d8, WHEN DATA_OUT + +at 0x000001f6 : */ 0x18000000,0x00000700, +/* + MOVE FROM dsa_dataout+0x02e0, WHEN DATA_OUT + +at 0x000001f8 : */ 0x18000000,0x00000708, +/* + MOVE FROM dsa_dataout+0x02e8, WHEN DATA_OUT + +at 0x000001fa : */ 0x18000000,0x00000710, +/* + MOVE FROM dsa_dataout+0x02f0, WHEN DATA_OUT + +at 0x000001fc : */ 0x18000000,0x00000718, +/* + MOVE FROM dsa_dataout+0x02f8, WHEN DATA_OUT + +at 0x000001fe : */ 0x18000000,0x00000720, +/* + MOVE FROM dsa_dataout+0x0300, WHEN DATA_OUT + +at 0x00000200 : */ 0x18000000,0x00000728, +/* + MOVE FROM dsa_dataout+0x0308, WHEN DATA_OUT + +at 0x00000202 : */ 0x18000000,0x00000730, +/* + MOVE FROM dsa_dataout+0x0310, WHEN DATA_OUT + +at 0x00000204 : */ 0x18000000,0x00000738, +/* + MOVE FROM dsa_dataout+0x0318, WHEN DATA_OUT + +at 0x00000206 : */ 0x18000000,0x00000740, +/* + MOVE FROM dsa_dataout+0x0320, WHEN DATA_OUT + +at 0x00000208 : */ 0x18000000,0x00000748, +/* + MOVE FROM dsa_dataout+0x0328, WHEN DATA_OUT + +at 0x0000020a : */ 0x18000000,0x00000750, +/* + MOVE FROM dsa_dataout+0x0330, WHEN DATA_OUT + +at 0x0000020c : */ 0x18000000,0x00000758, +/* + MOVE FROM dsa_dataout+0x0338, WHEN DATA_OUT + +at 0x0000020e : */ 0x18000000,0x00000760, +/* + MOVE FROM dsa_dataout+0x0340, WHEN DATA_OUT + +at 0x00000210 : */ 0x18000000,0x00000768, +/* + MOVE FROM dsa_dataout+0x0348, WHEN DATA_OUT + +at 0x00000212 : */ 0x18000000,0x00000770, +/* + MOVE FROM dsa_dataout+0x0350, WHEN DATA_OUT + +at 0x00000214 : */ 0x18000000,0x00000778, +/* + MOVE FROM dsa_dataout+0x0358, WHEN DATA_OUT + +at 0x00000216 : */ 0x18000000,0x00000780, +/* + MOVE FROM dsa_dataout+0x0360, WHEN DATA_OUT + +at 0x00000218 : */ 0x18000000,0x00000788, +/* + MOVE FROM dsa_dataout+0x0368, WHEN DATA_OUT + +at 0x0000021a : */ 0x18000000,0x00000790, +/* + MOVE FROM dsa_dataout+0x0370, WHEN DATA_OUT + +at 0x0000021c : */ 0x18000000,0x00000798, +/* + MOVE FROM dsa_dataout+0x0378, WHEN DATA_OUT + +at 0x0000021e : */ 0x18000000,0x000007a0, +/* + MOVE FROM dsa_dataout+0x0380, WHEN DATA_OUT + +at 0x00000220 : */ 0x18000000,0x000007a8, +/* + MOVE FROM dsa_dataout+0x0388, WHEN DATA_OUT + +at 0x00000222 : */ 0x18000000,0x000007b0, +/* + MOVE FROM dsa_dataout+0x0390, WHEN DATA_OUT + +at 0x00000224 : */ 0x18000000,0x000007b8, +/* + MOVE FROM dsa_dataout+0x0398, WHEN DATA_OUT + +at 0x00000226 : */ 0x18000000,0x000007c0, +/* + MOVE FROM dsa_dataout+0x03a0, WHEN DATA_OUT + +at 0x00000228 : */ 0x18000000,0x000007c8, +/* + MOVE FROM dsa_dataout+0x03a8, WHEN DATA_OUT + +at 0x0000022a : */ 0x18000000,0x000007d0, +/* + MOVE FROM dsa_dataout+0x03b0, WHEN DATA_OUT + +at 0x0000022c : */ 0x18000000,0x000007d8, +/* + MOVE FROM dsa_dataout+0x03b8, WHEN DATA_OUT + +at 0x0000022e : */ 0x18000000,0x000007e0, +/* + MOVE FROM dsa_dataout+0x03c0, WHEN DATA_OUT + +at 0x00000230 : */ 0x18000000,0x000007e8, +/* + MOVE FROM dsa_dataout+0x03c8, WHEN DATA_OUT + +at 0x00000232 : */ 0x18000000,0x000007f0, +/* + MOVE FROM dsa_dataout+0x03d0, WHEN DATA_OUT + +at 0x00000234 : */ 0x18000000,0x000007f8, +/* + MOVE FROM dsa_dataout+0x03d8, WHEN DATA_OUT + +at 0x00000236 : */ 0x18000000,0x00000800, +/* + MOVE FROM dsa_dataout+0x03e0, WHEN DATA_OUT + +at 0x00000238 : */ 0x18000000,0x00000808, +/* + MOVE FROM dsa_dataout+0x03e8, WHEN DATA_OUT + +at 0x0000023a : */ 0x18000000,0x00000810, +/* + MOVE FROM dsa_dataout+0x03f0, WHEN DATA_OUT + +at 0x0000023c : */ 0x18000000,0x00000818, +/* + MOVE FROM dsa_dataout+0x03f8, WHEN DATA_OUT + +at 0x0000023e : */ 0x18000000,0x00000820, +/* +ENTRY end_data_trans +end_data_trans: +redo_msgin3: + JUMP get_status, WHEN STATUS + +at 0x00000240 : */ 0x830b0000,0x00000098, +/* + JUMP get_msgin3, WHEN MSG_IN + +at 0x00000242 : */ 0x870b0000,0x00000b78, +/* + INT int_data_bad_phase + +at 0x00000244 : */ 0x98080000,0xab93000b, +/* + +get_msgin1: + MOVE SCRATCH0 | had_msgin TO SCRATCH0 + +at 0x00000246 : */ 0x7a344000,0x00000000, +/* + MOVE 1, msgin_buf, WHEN MSG_IN + +at 0x00000248 : */ 0x0f000001,0x00000000, +/* + JUMP ext_msg1, IF 0x01 ; Extended Message + +at 0x0000024a : */ 0x800c0001,0x00000960, +/* + JUMP ignore_msg1, IF 0x02 ; Save Data Pointers + +at 0x0000024c : */ 0x800c0002,0x00000950, +/* + JUMP ignore_msg1, IF 0x03 ; Save Restore Pointers + +at 0x0000024e : */ 0x800c0003,0x00000950, +/* + JUMP disc1, IF 0x04 ; Disconnect + +at 0x00000250 : */ 0x800c0004,0x000009f0, +/* + INT int_bad_msg1 + +at 0x00000252 : */ 0x98080000,0xab930006, +/* +ignore_msg1: + CLEAR ACK + +at 0x00000254 : */ 0x60000040,0x00000000, +/* + JUMP redo_msgin1 + +at 0x00000256 : */ 0x80080000,0x00000050, +/* +ext_msg1: + MOVE SCRATCH0 | had_extmsg TO SCRATCH0 + +at 0x00000258 : */ 0x7a348000,0x00000000, +/* + CLEAR ACK + +at 0x0000025a : */ 0x60000040,0x00000000, +/* + MOVE 1, msgin_buf + 1, WHEN MSG_IN + +at 0x0000025c : */ 0x0f000001,0x00000001, +/* + JUMP reject_msg1, IF NOT 0x03 ; Only handle SDTR + +at 0x0000025e : */ 0x80040003,0x000009b0, +/* + CLEAR ACK + +at 0x00000260 : */ 0x60000040,0x00000000, +/* + MOVE 1, msgin_buf + 2, WHEN MSG_IN + +at 0x00000262 : */ 0x0f000001,0x00000002, +/* + JUMP reject_msg1, IF NOT 0x01 ; Only handle SDTR + +at 0x00000264 : */ 0x80040001,0x000009b0, +/* + CLEAR ACK + +at 0x00000266 : */ 0x60000040,0x00000000, +/* + MOVE 2, msgin_buf + 3, WHEN MSG_IN + +at 0x00000268 : */ 0x0f000002,0x00000003, +/* + INT int_msg_sdtr1 + +at 0x0000026a : */ 0x98080000,0xab93000c, +/* +reject_msg1: + MOVE SCRATCH1 | did_reject TO SCRATCH1 + +at 0x0000026c : */ 0x7a350100,0x00000000, +/* + SET ATN + +at 0x0000026e : */ 0x58000008,0x00000000, +/* + CLEAR ACK + +at 0x00000270 : */ 0x60000040,0x00000000, +/* + JUMP reject_msg1a, WHEN NOT MSG_IN + +at 0x00000272 : */ 0x87030000,0x000009e0, +/* + MOVE 1, msgin_buf + 7, WHEN MSG_IN + +at 0x00000274 : */ 0x0f000001,0x00000007, +/* + JUMP reject_msg1 + +at 0x00000276 : */ 0x80080000,0x000009b0, +/* +reject_msg1a: + MOVE 1, msg_reject, WHEN MSG_OUT + +at 0x00000278 : */ 0x0e000001,0x00000000, +/* + JUMP redo_msgin1 + +at 0x0000027a : */ 0x80080000,0x00000050, +/* +disc1: + CLEAR ACK + +at 0x0000027c : */ 0x60000040,0x00000000, +/* +ENTRY wait_disc1 +wait_disc1: + WAIT DISCONNECT + +at 0x0000027e : */ 0x48000000,0x00000000, +/* + INT int_disc1 + +at 0x00000280 : */ 0x98080000,0xab930019, +/* +ENTRY resume_msgin1a +resume_msgin1a: + CLEAR ACK + +at 0x00000282 : */ 0x60000040,0x00000000, +/* + JUMP redo_msgin1 + +at 0x00000284 : */ 0x80080000,0x00000050, +/* +ENTRY resume_msgin1b +resume_msgin1b: + SET ATN + +at 0x00000286 : */ 0x58000008,0x00000000, +/* + CLEAR ACK + +at 0x00000288 : */ 0x60000040,0x00000000, +/* + INT int_no_msgout1, WHEN NOT MSG_OUT + +at 0x0000028a : */ 0x9e030000,0xab93000f, +/* + MOVE SCRATCH0 | had_msgout TO SCRATCH0 + +at 0x0000028c : */ 0x7a340200,0x00000000, +/* + MOVE FROM dsa_msgout, when MSG_OUT + +at 0x0000028e : */ 0x1e000000,0x00000008, +/* + JUMP redo_msgin1 + +at 0x00000290 : */ 0x80080000,0x00000050, +/* + +get_msgin2: + MOVE SCRATCH0 | had_msgin TO SCRATCH0 + +at 0x00000292 : */ 0x7a344000,0x00000000, +/* + MOVE 1, msgin_buf, WHEN MSG_IN + +at 0x00000294 : */ 0x0f000001,0x00000000, +/* + JUMP ext_msg2, IF 0x01 ; Extended Message + +at 0x00000296 : */ 0x800c0001,0x00000a90, +/* + JUMP ignore_msg2, IF 0x02 ; Save Data Pointers + +at 0x00000298 : */ 0x800c0002,0x00000a80, +/* + JUMP ignore_msg2, IF 0x03 ; Save Restore Pointers + +at 0x0000029a : */ 0x800c0003,0x00000a80, +/* + JUMP disc2, IF 0x04 ; Disconnect + +at 0x0000029c : */ 0x800c0004,0x00000b20, +/* + INT int_bad_msg2 + +at 0x0000029e : */ 0x98080000,0xab930007, +/* +ignore_msg2: + CLEAR ACK + +at 0x000002a0 : */ 0x60000040,0x00000000, +/* + JUMP redo_msgin2 + +at 0x000002a2 : */ 0x80080000,0x00000070, +/* +ext_msg2: + MOVE SCRATCH0 | had_extmsg TO SCRATCH0 + +at 0x000002a4 : */ 0x7a348000,0x00000000, +/* + CLEAR ACK + +at 0x000002a6 : */ 0x60000040,0x00000000, +/* + MOVE 1, msgin_buf + 1, WHEN MSG_IN + +at 0x000002a8 : */ 0x0f000001,0x00000001, +/* + JUMP reject_msg2, IF NOT 0x03 ; Only handle SDTR + +at 0x000002aa : */ 0x80040003,0x00000ae0, +/* + CLEAR ACK + +at 0x000002ac : */ 0x60000040,0x00000000, +/* + MOVE 1, msgin_buf + 2, WHEN MSG_IN + +at 0x000002ae : */ 0x0f000001,0x00000002, +/* + JUMP reject_msg2, IF NOT 0x01 ; Only handle SDTR + +at 0x000002b0 : */ 0x80040001,0x00000ae0, +/* + CLEAR ACK + +at 0x000002b2 : */ 0x60000040,0x00000000, +/* + MOVE 2, msgin_buf + 3, WHEN MSG_IN + +at 0x000002b4 : */ 0x0f000002,0x00000003, +/* + INT int_msg_sdtr2 + +at 0x000002b6 : */ 0x98080000,0xab93000d, +/* +reject_msg2: + MOVE SCRATCH1 | did_reject TO SCRATCH1 + +at 0x000002b8 : */ 0x7a350100,0x00000000, +/* + SET ATN + +at 0x000002ba : */ 0x58000008,0x00000000, +/* + CLEAR ACK + +at 0x000002bc : */ 0x60000040,0x00000000, +/* + JUMP reject_msg2a, WHEN NOT MSG_IN + +at 0x000002be : */ 0x87030000,0x00000b10, +/* + MOVE 1, msgin_buf + 7, WHEN MSG_IN + +at 0x000002c0 : */ 0x0f000001,0x00000007, +/* + JUMP reject_msg2 + +at 0x000002c2 : */ 0x80080000,0x00000ae0, +/* +reject_msg2a: + MOVE 1, msg_reject, WHEN MSG_OUT + +at 0x000002c4 : */ 0x0e000001,0x00000000, +/* + JUMP redo_msgin2 + +at 0x000002c6 : */ 0x80080000,0x00000070, +/* +disc2: + CLEAR ACK + +at 0x000002c8 : */ 0x60000040,0x00000000, +/* +ENTRY wait_disc2 +wait_disc2: + WAIT DISCONNECT + +at 0x000002ca : */ 0x48000000,0x00000000, +/* + INT int_disc2 + +at 0x000002cc : */ 0x98080000,0xab93001a, +/* +ENTRY resume_msgin2a +resume_msgin2a: + CLEAR ACK + +at 0x000002ce : */ 0x60000040,0x00000000, +/* + JUMP redo_msgin2 + +at 0x000002d0 : */ 0x80080000,0x00000070, +/* +ENTRY resume_msgin2b +resume_msgin2b: + SET ATN + +at 0x000002d2 : */ 0x58000008,0x00000000, +/* + CLEAR ACK + +at 0x000002d4 : */ 0x60000040,0x00000000, +/* + INT int_no_msgout2, WHEN NOT MSG_OUT + +at 0x000002d6 : */ 0x9e030000,0xab930010, +/* + MOVE SCRATCH0 | had_msgout TO SCRATCH0 + +at 0x000002d8 : */ 0x7a340200,0x00000000, +/* + MOVE FROM dsa_msgout, when MSG_OUT + +at 0x000002da : */ 0x1e000000,0x00000008, +/* + JUMP redo_msgin2 + +at 0x000002dc : */ 0x80080000,0x00000070, +/* + +get_msgin3: + MOVE SCRATCH0 | had_msgin TO SCRATCH0 + +at 0x000002de : */ 0x7a344000,0x00000000, +/* + MOVE 1, msgin_buf, WHEN MSG_IN + +at 0x000002e0 : */ 0x0f000001,0x00000000, +/* + JUMP ext_msg3, IF 0x01 ; Extended Message + +at 0x000002e2 : */ 0x800c0001,0x00000bc0, +/* + JUMP ignore_msg3, IF 0x02 ; Save Data Pointers + +at 0x000002e4 : */ 0x800c0002,0x00000bb0, +/* + JUMP ignore_msg3, IF 0x03 ; Save Restore Pointers + +at 0x000002e6 : */ 0x800c0003,0x00000bb0, +/* + JUMP disc3, IF 0x04 ; Disconnect + +at 0x000002e8 : */ 0x800c0004,0x00000c50, +/* + INT int_bad_msg3 + +at 0x000002ea : */ 0x98080000,0xab930008, +/* +ignore_msg3: + CLEAR ACK + +at 0x000002ec : */ 0x60000040,0x00000000, +/* + JUMP redo_msgin3 + +at 0x000002ee : */ 0x80080000,0x00000900, +/* +ext_msg3: + MOVE SCRATCH0 | had_extmsg TO SCRATCH0 + +at 0x000002f0 : */ 0x7a348000,0x00000000, +/* + CLEAR ACK + +at 0x000002f2 : */ 0x60000040,0x00000000, +/* + MOVE 1, msgin_buf + 1, WHEN MSG_IN + +at 0x000002f4 : */ 0x0f000001,0x00000001, +/* + JUMP reject_msg3, IF NOT 0x03 ; Only handle SDTR + +at 0x000002f6 : */ 0x80040003,0x00000c10, +/* + CLEAR ACK + +at 0x000002f8 : */ 0x60000040,0x00000000, +/* + MOVE 1, msgin_buf + 2, WHEN MSG_IN + +at 0x000002fa : */ 0x0f000001,0x00000002, +/* + JUMP reject_msg3, IF NOT 0x01 ; Only handle SDTR + +at 0x000002fc : */ 0x80040001,0x00000c10, +/* + CLEAR ACK + +at 0x000002fe : */ 0x60000040,0x00000000, +/* + MOVE 2, msgin_buf + 3, WHEN MSG_IN + +at 0x00000300 : */ 0x0f000002,0x00000003, +/* + INT int_msg_sdtr3 + +at 0x00000302 : */ 0x98080000,0xab93000e, +/* +reject_msg3: + MOVE SCRATCH1 | did_reject TO SCRATCH1 + +at 0x00000304 : */ 0x7a350100,0x00000000, +/* + SET ATN + +at 0x00000306 : */ 0x58000008,0x00000000, +/* + CLEAR ACK + +at 0x00000308 : */ 0x60000040,0x00000000, +/* + JUMP reject_msg3a, WHEN NOT MSG_IN + +at 0x0000030a : */ 0x87030000,0x00000c40, +/* + MOVE 1, msgin_buf + 7, WHEN MSG_IN + +at 0x0000030c : */ 0x0f000001,0x00000007, +/* + JUMP reject_msg3 + +at 0x0000030e : */ 0x80080000,0x00000c10, +/* +reject_msg3a: + MOVE 1, msg_reject, WHEN MSG_OUT + +at 0x00000310 : */ 0x0e000001,0x00000000, +/* + JUMP redo_msgin3 + +at 0x00000312 : */ 0x80080000,0x00000900, +/* +disc3: + CLEAR ACK + +at 0x00000314 : */ 0x60000040,0x00000000, +/* +ENTRY wait_disc3 +wait_disc3: + WAIT DISCONNECT + +at 0x00000316 : */ 0x48000000,0x00000000, +/* + INT int_disc3 + +at 0x00000318 : */ 0x98080000,0xab93001b, +/* +ENTRY resume_msgin3a +resume_msgin3a: + CLEAR ACK + +at 0x0000031a : */ 0x60000040,0x00000000, +/* + JUMP redo_msgin3 + +at 0x0000031c : */ 0x80080000,0x00000900, +/* +ENTRY resume_msgin3b +resume_msgin3b: + SET ATN + +at 0x0000031e : */ 0x58000008,0x00000000, +/* + CLEAR ACK + +at 0x00000320 : */ 0x60000040,0x00000000, +/* + INT int_no_msgout3, WHEN NOT MSG_OUT + +at 0x00000322 : */ 0x9e030000,0xab930011, +/* + MOVE SCRATCH0 | had_msgout TO SCRATCH0 + +at 0x00000324 : */ 0x7a340200,0x00000000, +/* + MOVE FROM dsa_msgout, when MSG_OUT + +at 0x00000326 : */ 0x1e000000,0x00000008, +/* + JUMP redo_msgin3 + +at 0x00000328 : */ 0x80080000,0x00000900, +/* + +ENTRY resume_rej_ident +resume_rej_ident: + CLEAR ATN + +at 0x0000032a : */ 0x60000008,0x00000000, +/* + MOVE 1, msgin_buf, WHEN MSG_IN + +at 0x0000032c : */ 0x0f000001,0x00000000, +/* + INT int_not_rej, IF NOT 0x07 ; Reject + +at 0x0000032e : */ 0x98040007,0xab93001c, +/* + CLEAR ACK + +at 0x00000330 : */ 0x60000040,0x00000000, +/* + JUMP done_ident + +at 0x00000332 : */ 0x80080000,0x00000048, +/* + +ENTRY reselect +reselect: + ; Disable selection timer + MOVE CTEST7 | 0x10 TO CTEST7 + +at 0x00000334 : */ 0x7a1b1000,0x00000000, +/* + WAIT RESELECT resel_err + +at 0x00000336 : */ 0x50000000,0x00000cf8, +/* + INT int_resel_not_msgin, WHEN NOT MSG_IN + +at 0x00000338 : */ 0x9f030000,0xab930016, +/* + MOVE 1, reselected_identify, WHEN MSG_IN + +at 0x0000033a : */ 0x0f000001,0x00000000, +/* + INT int_reselected + +at 0x0000033c : */ 0x98080000,0xab930017, +/* +resel_err: + MOVE CTEST2 & 0x40 TO SFBR + +at 0x0000033e : */ 0x74164000,0x00000000, +/* + JUMP selected, IF 0x00 + +at 0x00000340 : */ 0x800c0000,0x00000d38, +/* + MOVE SFBR & 0 TO SFBR + +at 0x00000342 : */ 0x7c080000,0x00000000, +/* +ENTRY patch_new_dsa +patch_new_dsa: + MOVE SFBR | 0x11 TO DSA0 + +at 0x00000344 : */ 0x6a101100,0x00000000, +/* + MOVE SFBR | 0x22 TO DSA1 + +at 0x00000346 : */ 0x6a112200,0x00000000, +/* + MOVE SFBR | 0x33 TO DSA2 + +at 0x00000348 : */ 0x6a123300,0x00000000, +/* + MOVE SFBR | 0x44 TO DSA3 + +at 0x0000034a : */ 0x6a134400,0x00000000, +/* + JUMP do_select + +at 0x0000034c : */ 0x80080000,0x00000000, +/* + +selected: + INT int_selected + +at 0x0000034e : */ 0x98080000,0xab930018, +/* + +ENTRY test1 +test1: + MOVE MEMORY 4, test1_src, test1_dst + +at 0x00000350 : */ 0xc0000004,0x00000000,0x00000000, +/* + INT int_test1 + +at 0x00000353 : */ 0x98080000,0xab93001d, +}; + +#define A_did_reject 0x00000001 +static u32 A_did_reject_used[] __attribute((unused)) = { + 0x0000026c, + 0x000002b8, + 0x00000304, +}; + +#define A_dsa_cmnd 0x00000010 +static u32 A_dsa_cmnd_used[] __attribute((unused)) = { + 0x0000001b, +}; + +#define A_dsa_datain 0x00000028 +static u32 A_dsa_datain_used[] __attribute((unused)) = { + 0x0000003b, + 0x0000003d, + 0x0000003f, + 0x00000041, + 0x00000043, + 0x00000045, + 0x00000047, + 0x00000049, + 0x0000004b, + 0x0000004d, + 0x0000004f, + 0x00000051, + 0x00000053, + 0x00000055, + 0x00000057, + 0x00000059, + 0x0000005b, + 0x0000005d, + 0x0000005f, + 0x00000061, + 0x00000063, + 0x00000065, + 0x00000067, + 0x00000069, + 0x0000006b, + 0x0000006d, + 0x0000006f, + 0x00000071, + 0x00000073, + 0x00000075, + 0x00000077, + 0x00000079, + 0x0000007b, + 0x0000007d, + 0x0000007f, + 0x00000081, + 0x00000083, + 0x00000085, + 0x00000087, + 0x00000089, + 0x0000008b, + 0x0000008d, + 0x0000008f, + 0x00000091, + 0x00000093, + 0x00000095, + 0x00000097, + 0x00000099, + 0x0000009b, + 0x0000009d, + 0x0000009f, + 0x000000a1, + 0x000000a3, + 0x000000a5, + 0x000000a7, + 0x000000a9, + 0x000000ab, + 0x000000ad, + 0x000000af, + 0x000000b1, + 0x000000b3, + 0x000000b5, + 0x000000b7, + 0x000000b9, + 0x000000bb, + 0x000000bd, + 0x000000bf, + 0x000000c1, + 0x000000c3, + 0x000000c5, + 0x000000c7, + 0x000000c9, + 0x000000cb, + 0x000000cd, + 0x000000cf, + 0x000000d1, + 0x000000d3, + 0x000000d5, + 0x000000d7, + 0x000000d9, + 0x000000db, + 0x000000dd, + 0x000000df, + 0x000000e1, + 0x000000e3, + 0x000000e5, + 0x000000e7, + 0x000000e9, + 0x000000eb, + 0x000000ed, + 0x000000ef, + 0x000000f1, + 0x000000f3, + 0x000000f5, + 0x000000f7, + 0x000000f9, + 0x000000fb, + 0x000000fd, + 0x000000ff, + 0x00000101, + 0x00000103, + 0x00000105, + 0x00000107, + 0x00000109, + 0x0000010b, + 0x0000010d, + 0x0000010f, + 0x00000111, + 0x00000113, + 0x00000115, + 0x00000117, + 0x00000119, + 0x0000011b, + 0x0000011d, + 0x0000011f, + 0x00000121, + 0x00000123, + 0x00000125, + 0x00000127, + 0x00000129, + 0x0000012b, + 0x0000012d, + 0x0000012f, + 0x00000131, + 0x00000133, + 0x00000135, + 0x00000137, + 0x00000139, +}; + +#define A_dsa_dataout 0x00000428 +static u32 A_dsa_dataout_used[] __attribute((unused)) = { + 0x00000141, + 0x00000143, + 0x00000145, + 0x00000147, + 0x00000149, + 0x0000014b, + 0x0000014d, + 0x0000014f, + 0x00000151, + 0x00000153, + 0x00000155, + 0x00000157, + 0x00000159, + 0x0000015b, + 0x0000015d, + 0x0000015f, + 0x00000161, + 0x00000163, + 0x00000165, + 0x00000167, + 0x00000169, + 0x0000016b, + 0x0000016d, + 0x0000016f, + 0x00000171, + 0x00000173, + 0x00000175, + 0x00000177, + 0x00000179, + 0x0000017b, + 0x0000017d, + 0x0000017f, + 0x00000181, + 0x00000183, + 0x00000185, + 0x00000187, + 0x00000189, + 0x0000018b, + 0x0000018d, + 0x0000018f, + 0x00000191, + 0x00000193, + 0x00000195, + 0x00000197, + 0x00000199, + 0x0000019b, + 0x0000019d, + 0x0000019f, + 0x000001a1, + 0x000001a3, + 0x000001a5, + 0x000001a7, + 0x000001a9, + 0x000001ab, + 0x000001ad, + 0x000001af, + 0x000001b1, + 0x000001b3, + 0x000001b5, + 0x000001b7, + 0x000001b9, + 0x000001bb, + 0x000001bd, + 0x000001bf, + 0x000001c1, + 0x000001c3, + 0x000001c5, + 0x000001c7, + 0x000001c9, + 0x000001cb, + 0x000001cd, + 0x000001cf, + 0x000001d1, + 0x000001d3, + 0x000001d5, + 0x000001d7, + 0x000001d9, + 0x000001db, + 0x000001dd, + 0x000001df, + 0x000001e1, + 0x000001e3, + 0x000001e5, + 0x000001e7, + 0x000001e9, + 0x000001eb, + 0x000001ed, + 0x000001ef, + 0x000001f1, + 0x000001f3, + 0x000001f5, + 0x000001f7, + 0x000001f9, + 0x000001fb, + 0x000001fd, + 0x000001ff, + 0x00000201, + 0x00000203, + 0x00000205, + 0x00000207, + 0x00000209, + 0x0000020b, + 0x0000020d, + 0x0000020f, + 0x00000211, + 0x00000213, + 0x00000215, + 0x00000217, + 0x00000219, + 0x0000021b, + 0x0000021d, + 0x0000021f, + 0x00000221, + 0x00000223, + 0x00000225, + 0x00000227, + 0x00000229, + 0x0000022b, + 0x0000022d, + 0x0000022f, + 0x00000231, + 0x00000233, + 0x00000235, + 0x00000237, + 0x00000239, + 0x0000023b, + 0x0000023d, + 0x0000023f, +}; + +#define A_dsa_msgin 0x00000020 +static u32 A_dsa_msgin_used[] __attribute((unused)) = { + 0x0000002d, +}; + +#define A_dsa_msgout 0x00000008 +static u32 A_dsa_msgout_used[] __attribute((unused)) = { + 0x00000011, + 0x0000028f, + 0x000002db, + 0x00000327, +}; + +#define A_dsa_select 0x00000000 +static u32 A_dsa_select_used[] __attribute((unused)) = { + 0x00000004, +}; + +#define A_dsa_size 0x00000828 +static u32 A_dsa_size_used[] __attribute((unused)) = { +}; + +#define A_dsa_status 0x00000018 +static u32 A_dsa_status_used[] __attribute((unused)) = { + 0x00000029, +}; + +#define A_had_cmdout 0x00000004 +static u32 A_had_cmdout_used[] __attribute((unused)) = { + 0x00000018, +}; + +#define A_had_datain 0x00000008 +static u32 A_had_datain_used[] __attribute((unused)) = { + 0x00000036, +}; + +#define A_had_dataout 0x00000010 +static u32 A_had_dataout_used[] __attribute((unused)) = { + 0x0000013c, +}; + +#define A_had_extmsg 0x00000080 +static u32 A_had_extmsg_used[] __attribute((unused)) = { + 0x00000258, + 0x000002a4, + 0x000002f0, +}; + +#define A_had_msgin 0x00000040 +static u32 A_had_msgin_used[] __attribute((unused)) = { + 0x00000246, + 0x00000292, + 0x000002de, +}; + +#define A_had_msgout 0x00000002 +static u32 A_had_msgout_used[] __attribute((unused)) = { + 0x0000000e, + 0x0000028c, + 0x000002d8, + 0x00000324, +}; + +#define A_had_select 0x00000001 +static u32 A_had_select_used[] __attribute((unused)) = { + 0x0000000a, +}; + +#define A_had_status 0x00000020 +static u32 A_had_status_used[] __attribute((unused)) = { +}; + +#define A_int_bad_msg1 0xab930006 +static u32 A_int_bad_msg1_used[] __attribute((unused)) = { + 0x00000253, +}; + +#define A_int_bad_msg2 0xab930007 +static u32 A_int_bad_msg2_used[] __attribute((unused)) = { + 0x0000029f, +}; + +#define A_int_bad_msg3 0xab930008 +static u32 A_int_bad_msg3_used[] __attribute((unused)) = { + 0x000002eb, +}; + +#define A_int_cmd_bad_phase 0xab930009 +static u32 A_int_cmd_bad_phase_used[] __attribute((unused)) = { + 0x00000025, +}; + +#define A_int_cmd_complete 0xab93000a +static u32 A_int_cmd_complete_used[] __attribute((unused)) = { + 0x00000035, +}; + +#define A_int_data_bad_phase 0xab93000b +static u32 A_int_data_bad_phase_used[] __attribute((unused)) = { + 0x00000245, +}; + +#define A_int_disc1 0xab930019 +static u32 A_int_disc1_used[] __attribute((unused)) = { + 0x00000281, +}; + +#define A_int_disc2 0xab93001a +static u32 A_int_disc2_used[] __attribute((unused)) = { + 0x000002cd, +}; + +#define A_int_disc3 0xab93001b +static u32 A_int_disc3_used[] __attribute((unused)) = { + 0x00000319, +}; + +#define A_int_msg_sdtr1 0xab93000c +static u32 A_int_msg_sdtr1_used[] __attribute((unused)) = { + 0x0000026b, +}; + +#define A_int_msg_sdtr2 0xab93000d +static u32 A_int_msg_sdtr2_used[] __attribute((unused)) = { + 0x000002b7, +}; + +#define A_int_msg_sdtr3 0xab93000e +static u32 A_int_msg_sdtr3_used[] __attribute((unused)) = { + 0x00000303, +}; + +#define A_int_no_msgout1 0xab93000f +static u32 A_int_no_msgout1_used[] __attribute((unused)) = { + 0x0000028b, +}; + +#define A_int_no_msgout2 0xab930010 +static u32 A_int_no_msgout2_used[] __attribute((unused)) = { + 0x000002d7, +}; + +#define A_int_no_msgout3 0xab930011 +static u32 A_int_no_msgout3_used[] __attribute((unused)) = { + 0x00000323, +}; + +#define A_int_not_cmd_complete 0xab930012 +static u32 A_int_not_cmd_complete_used[] __attribute((unused)) = { + 0x0000002f, +}; + +#define A_int_not_rej 0xab93001c +static u32 A_int_not_rej_used[] __attribute((unused)) = { + 0x0000032f, +}; + +#define A_int_resel_not_msgin 0xab930016 +static u32 A_int_resel_not_msgin_used[] __attribute((unused)) = { + 0x00000339, +}; + +#define A_int_reselected 0xab930017 +static u32 A_int_reselected_used[] __attribute((unused)) = { + 0x0000033d, +}; + +#define A_int_sel_no_ident 0xab930013 +static u32 A_int_sel_no_ident_used[] __attribute((unused)) = { + 0x0000000d, +}; + +#define A_int_sel_not_cmd 0xab930014 +static u32 A_int_sel_not_cmd_used[] __attribute((unused)) = { + 0x00000017, +}; + +#define A_int_selected 0xab930018 +static u32 A_int_selected_used[] __attribute((unused)) = { + 0x0000034f, +}; + +#define A_int_status_not_msgin 0xab930015 +static u32 A_int_status_not_msgin_used[] __attribute((unused)) = { + 0x0000002b, +}; + +#define A_int_test1 0xab93001d +static u32 A_int_test1_used[] __attribute((unused)) = { + 0x00000354, +}; + +#define A_msg_reject 0x00000000 +static u32 A_msg_reject_used[] __attribute((unused)) = { + 0x00000279, + 0x000002c5, + 0x00000311, +}; + +#define A_msgin_buf 0x00000000 +static u32 A_msgin_buf_used[] __attribute((unused)) = { + 0x00000249, + 0x0000025d, + 0x00000263, + 0x00000269, + 0x00000275, + 0x00000295, + 0x000002a9, + 0x000002af, + 0x000002b5, + 0x000002c1, + 0x000002e1, + 0x000002f5, + 0x000002fb, + 0x00000301, + 0x0000030d, + 0x0000032d, +}; + +#define A_reselected_identify 0x00000000 +static u32 A_reselected_identify_used[] __attribute((unused)) = { + 0x0000033b, +}; + +#define A_test1_dst 0x00000000 +static u32 A_test1_dst_used[] __attribute((unused)) = { + 0x00000352, +}; + +#define A_test1_src 0x00000000 +static u32 A_test1_src_used[] __attribute((unused)) = { + 0x00000351, +}; + +#define Ent_do_select 0x00000000 +#define Ent_done_ident 0x00000048 +#define Ent_end_data_trans 0x00000900 +#define Ent_patch_input_data 0x000000e0 +#define Ent_patch_new_dsa 0x00000d10 +#define Ent_patch_output_data 0x000004f8 +#define Ent_reselect 0x00000cd0 +#define Ent_resume_cmd 0x00000060 +#define Ent_resume_msgin1a 0x00000a08 +#define Ent_resume_msgin1b 0x00000a18 +#define Ent_resume_msgin2a 0x00000b38 +#define Ent_resume_msgin2b 0x00000b48 +#define Ent_resume_msgin3a 0x00000c68 +#define Ent_resume_msgin3b 0x00000c78 +#define Ent_resume_pmm 0x00000070 +#define Ent_resume_rej_ident 0x00000ca8 +#define Ent_test1 0x00000d40 +#define Ent_wait_disc1 0x000009f8 +#define Ent_wait_disc2 0x00000b28 +#define Ent_wait_disc3 0x00000c58 +#define Ent_wait_disc_complete 0x000000c8 +static u32 LABELPATCHES[] __attribute((unused)) = { + 0x00000005, + 0x00000007, + 0x00000013, + 0x00000015, + 0x0000001d, + 0x0000001f, + 0x00000021, + 0x00000023, + 0x0000013b, + 0x00000241, + 0x00000243, + 0x0000024b, + 0x0000024d, + 0x0000024f, + 0x00000251, + 0x00000257, + 0x0000025f, + 0x00000265, + 0x00000273, + 0x00000277, + 0x0000027b, + 0x00000285, + 0x00000291, + 0x00000297, + 0x00000299, + 0x0000029b, + 0x0000029d, + 0x000002a3, + 0x000002ab, + 0x000002b1, + 0x000002bf, + 0x000002c3, + 0x000002c7, + 0x000002d1, + 0x000002dd, + 0x000002e3, + 0x000002e5, + 0x000002e7, + 0x000002e9, + 0x000002ef, + 0x000002f7, + 0x000002fd, + 0x0000030b, + 0x0000030f, + 0x00000313, + 0x0000031d, + 0x00000329, + 0x00000333, + 0x00000337, + 0x00000341, + 0x0000034d, +}; + +static struct { + u32 offset; + void *address; +} EXTERNAL_PATCHES[] __attribute((unused)) = { +}; + +static u32 INSTRUCTIONS __attribute((unused)) = 426; +static u32 PATCHES __attribute((unused)) = 51; +static u32 EXTERNAL_PATCHES_LEN __attribute((unused)) = 0; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/drivers/scsi/ultrastor.c linux.2.5.47-ac6/drivers/scsi/ultrastor.c --- linux.2.5.47/drivers/scsi/ultrastor.c 2002-11-11 16:39:10.000000000 +0000 +++ linux.2.5.47-ac6/drivers/scsi/ultrastor.c 2002-11-18 17:35:29.000000000 +0000 @@ -1047,7 +1047,7 @@ printk("Ux4F interrupt: bad MSCP address %x\n", (unsigned int) mscp); /* A command has been lost. Reset and report an error for all commands. */ - ultrastor_reset(NULL, 0); + ultrastor_host_reset(dev_id); return; } #endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.2.5.47/drivers/video/68328fb.c linux.2.5.47-ac6/drivers/video/68328fb.c --- linux.2.5.47/drivers/video/68328fb.c 1970-01-01 01:00:00.000000000 +0100 +++ linux.2.5.47-ac6/drivers/video/68328fb.c 2002-10-31 15:05:24.000000000 +0000 @@ -0,0 +1,986 @@ +/* + * linux/arch/m68knommu/console/68328fb.c -- Low level implementation of the + * mc68328 LCD frame buffer device + * + * Copyright (C) 1998,1999 Kenneth Albanowski , + * The Silver Hammer Group, Ltd. + * + * + * This file is based on the Amiga CyberVision frame buffer device (Cyberfb.c): + * + * Copyright (C) 1996 Martin Apel + * Geert Uytterhoeven + * + * + * This file is based on the Amiga frame buffer device (amifb.c): + * + * Copyright (C) 1995 Geert Uytterhoeven + * + * + * History: + * - 17 Feb 98: Original version by Kenneth Albanowski + * + * + * 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. + */ + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include