diff -u --recursive --new-file v1.3.6/linux/CREDITS linux/CREDITS --- v1.3.6/linux/CREDITS Tue Jun 27 14:11:30 1995 +++ linux/CREDITS Wed Jul 5 13:06:26 1995 @@ -639,6 +639,17 @@ S: FIN-00330 Helsingfors S: Finland +N: Jonathan Naylor +E: jsn@cs.nott.ac.uk +E: g4klx@amsat.org +E: G4KLX@GB7DAD (Packet Radio) +D: AX.25 and NET/ROM protocol suites +S: 24 Castle View Drive +S: Cromford +S: Matlock +S: Derbyshire DE4 3RL +S: United Kingdom + N: Michael Neuffer E: neuffer@goofy.zdv.uni-mainz.de D: developer and maintainer of the eata_dma SCSI driver diff -u --recursive --new-file v1.3.6/linux/Makefile linux/Makefile --- v1.3.6/linux/Makefile Fri Jun 30 16:22:25 1995 +++ linux/Makefile Fri Jun 30 16:23:10 1995 @@ -1,6 +1,6 @@ VERSION = 1 PATCHLEVEL = 3 -SUBLEVEL = 6 +SUBLEVEL = 7 ARCH = i386 diff -u --recursive --new-file v1.3.6/linux/README.modules linux/README.modules --- v1.3.6/linux/README.modules Sun Mar 26 11:56:23 1995 +++ linux/README.modules Sat Jul 1 19:05:58 1995 @@ -42,12 +42,19 @@ eexpress, depca, ewrk3, apricot + Most CDROM drivers: + aztcd: Aztech,Orchid,Okano,Wearnes + cm206: Philips/LMS CM206 + gscd: Goldstar GCDR-420 + mcd, mcdx: Mitsumi LU005, FX001 + optcd: Optics Storage Dolphin 8000AT + sbpcd: Matsushita/Panasonic CR52x, CR56x, CD200, + Longshine LCS-7260, TEAC CD-55A + sonycd535: Sony CDU-531/535, CDU-510/515 + Some misc modules: lp: line printer binfmt_elf: elf loader - sbpcd: CDROM-driver for Matsushita,Panasonic CR52x,CR56x - sonycd535: CDROM-driver for Sony CD535 - aztcd: CDROM-driver for Aztech,Orchid,Okano,Wearnes When you have made the kernel, you create the modules by doing: diff -u --recursive --new-file v1.3.6/linux/arch/alpha/config.in linux/arch/alpha/config.in --- v1.3.6/linux/arch/alpha/config.in Thu Jun 29 19:02:38 1995 +++ linux/arch/alpha/config.in Thu Jul 6 13:22:04 1995 @@ -27,7 +27,7 @@ bool ' PCI bridge optimisation (experimental)' CONFIG_PCI_OPTIMIZE n fi bool 'System V IPC' CONFIG_SYSVIPC y -bool 'Kernel support for ELF binaries' CONFIG_BINFMT_ELF y +bool 'Kernel support for ELF binaries' CONFIG_BINFMT_ELF n comment 'Loadable module support' bool 'Set version information on all symbols for modules' CONFIG_MODVERSIONS n @@ -150,7 +150,7 @@ fi bool '3c509/3c579 support' CONFIG_EL3 y fi -bool 'Other ISA cards' CONFIG_NET_ISA n +bool 'Other ISA cards' CONFIG_NET_ISA y if [ "$CONFIG_NET_ISA" = "y" ]; then bool 'Arcnet support' CONFIG_ARCNET n bool 'Cabletron E21xx support' CONFIG_E2100 n diff -u --recursive --new-file v1.3.6/linux/arch/alpha/lib/checksum.c linux/arch/alpha/lib/checksum.c --- v1.3.6/linux/arch/alpha/lib/checksum.c Fri Jun 16 22:02:54 1995 +++ linux/arch/alpha/lib/checksum.c Thu Jul 6 13:22:04 1995 @@ -4,15 +4,22 @@ * This file contains network checksum routines that are better done * in an architecture-specific manner due to speed.. */ + +#include -/* - * This is a version of ip_compute_csum() optimized for IP headers, - * which always checksum on 4 octet boundaries. - */ -unsigned short ip_fast_csum(unsigned char * iph, unsigned int ihl) +#include + +static inline unsigned short from64to16(unsigned long x) { - /* not yet */ - return 0; + /* add up 32-bit words for 33 bits */ + x = (x & 0xffffffff) + (x >> 32); + /* add up 16-bit and 17-bit words for 17+c bits */ + x = (x & 0xffff) + (x >> 16); + /* add up 16-bit and 2-bit for 16+c bit */ + x = (x & 0xffff) + (x >> 16); + /* add up carry.. */ + x = (x & 0xffff) + (x >> 16); + return x; } /* @@ -25,8 +32,84 @@ unsigned short proto, unsigned int sum) { - /* not yet */ - return 0; + return ~from64to16(saddr + daddr + sum + (ntohs(len) << 16) + (proto << 8)); +} + +/* + * Do a 64-bit checksum on an arbitrary memory area.. + * + * This isn't a great routine, but it's not _horrible_ either. The + * inner loop could be unrolled a bit further, and there are better + * ways to do the carry, but this is reasonable. + */ +static inline unsigned long do_csum(unsigned char * buff, int len) +{ + int odd, count; + unsigned long result = 0; + + if (len <= 0) + goto out; + odd = 1 & (unsigned long) buff; + if (odd) { + result = *buff << 8; + len--; + buff++; + } + count = len >> 1; /* nr of 16-bit words.. */ + if (count) { + if (2 & (unsigned long) buff) { + result += *(unsigned short *) buff; + count--; + len -= 2; + buff += 2; + } + count >>= 1; /* nr of 32-bit words.. */ + if (count) { + if (4 & (unsigned long) buff) { + result += *(unsigned int *) buff; + count--; + len -= 4; + buff += 4; + } + count >>= 1; /* nr of 64-bit words.. */ + if (count) { + unsigned long carry = 0; + do { + unsigned long w = *(unsigned long *) buff; + count--; + buff += 8; + result += carry; + result += w; + carry = (w > result); + } while (count); + result += carry; + } + if (len & 4) { + result += *(unsigned int *) buff; + buff += 4; + } + } + if (len & 2) { + result += *(unsigned short *) buff; + buff += 2; + } + } + if (len & 1) + result += *buff; + result = from64to16(result); + if (odd) + result = ((result >> 8) & 0xff) | ((result & 0xff) << 8); +out: + return result; +} + +/* + * This is a version of ip_compute_csum() optimized for IP headers, + * which always checksum on 4 octet boundaries. + */ +unsigned short ip_fast_csum(unsigned char * iph, unsigned int ihl) +{ + return ~do_csum(iph,ihl*4); } /* @@ -43,31 +126,42 @@ */ unsigned int csum_partial(unsigned char * buff, int len, unsigned int sum) { - /* not yet */ - return 0; + unsigned long result = do_csum(buff, len); + + /* add in old sum, and carry.. */ + result += sum; + /* 32+c bits -> 32 bits */ + result = (result & 0xffffffff) + (result >> 32); + return result; } /* - * the same as csum_partial, but copies from fs:src while it + * the same as csum_partial, but copies from src while it * checksums * * here even more important to align src and dst on a 32-bit (or even * better 64-bit) boundary */ -unsigned int csum_partial_copyffs( char *src, char *dst, int len, int sum) +unsigned int csum_partial_copy(char *src, char *dst, int len, int sum) { - /* not yet */ - return 0; + /* + * The whole idea is to do the copy and the checksum at + * the same time, but we do it the easy way now. + * + * At least csum on the source, not destination, for cache + * reasons.. + */ + sum = csum_partial(src, len, sum); + memcpy(dst, src, len); + return sum; } - /* * this routine is used for miscellaneous IP-like checksums, mainly * in icmp.c */ unsigned short ip_compute_csum(unsigned char * buff, int len) { - /* not yet */ - return 0; + return ~from64to16(do_csum(buff,len)); } diff -u --recursive --new-file v1.3.6/linux/arch/alpha/lib/io.c linux/arch/alpha/lib/io.c --- v1.3.6/linux/arch/alpha/lib/io.c Thu Jun 29 19:02:38 1995 +++ linux/arch/alpha/lib/io.c Thu Jul 6 13:22:04 1995 @@ -82,7 +82,7 @@ #undef writeb -void writeb(unsigned short b, unsigned long addr) +void writeb(unsigned char b, unsigned long addr) { __writeb(b, addr); } @@ -264,6 +264,7 @@ * Copy data from IO memory space to "real" memory space. * This needs to be optimized. */ +#undef memcpy_fromio void memcpy_fromio(void * to, unsigned long from, unsigned long count) { while (count) { @@ -278,6 +279,7 @@ * Copy data from "real" memory space to IO memory space. * This needs to be optimized. */ +#undef memcpy_toio void memcpy_toio(unsigned long to, void * from, unsigned long count) { while (count) { @@ -292,6 +294,7 @@ * "memset" on IO memory space. * This needs to be optimized. */ +#undef memset_io void memset_io(unsigned long dst, int c, unsigned long count) { while (count) { diff -u --recursive --new-file v1.3.6/linux/arch/alpha/lib/memcpy.c linux/arch/alpha/lib/memcpy.c --- v1.3.6/linux/arch/alpha/lib/memcpy.c Thu Jun 1 13:22:06 1995 +++ linux/arch/alpha/lib/memcpy.c Wed Jul 5 12:53:22 1995 @@ -5,70 +5,111 @@ */ /* - * This is reasonably optimized for the quad-word-aligned case, which - * happens with page/buffer copies. It's horribly bad for the unaligned - * case: it could be made much better, but that would require lots of - * assembly (unaligned 8-byte load + shift + aligned 4-byte store, for - * example). + * This is a reasonably optimized memcpy() routine. */ -#include +/* + * Note that the C code is written to be optimized into good assembly. However, + * at this point gcc is unable to sanely compile "if (n >= 0)", resulting in a + * explicit compare against 0 (instead of just using the proper "blt reg, xx" or + * "bge reg, xx"). I hope alpha-gcc will be fixed to notice this eventually.. + */ -static inline void __memcpy_b(unsigned long d, unsigned long s, long n) -{ - while (--n >= 0) - *(char *) (d++) = *(char *) (s++); -} +#include -static inline void __memcpy_q(unsigned long d, unsigned long s, long n) -{ - /* this first part could be done in one go with ldq_u*2/mask/stq_u */ - while (d & 7) { - if (--n < 0) - return; - *(char *) d = *(char *) s; - d++; - s++; +/* + * This should be done in one go with ldq_u*2/mask/stq_u. Do it + * with a macro so that we can fix it up later.. + */ +#define ALIGN_DEST_TO8(d,s,n) \ + while (d & 7) { \ + if (n <= 0) return; \ + n--; \ + *(char *) d = *(char *) s; \ + d++; s++; \ } - while ((n -= 8) >= 0) { - *(unsigned long *) d = *(unsigned long *) s; - d += 8; - s += 8; + +/* + * This should similarly be done with ldq_u*2/mask/stq. The destination + * is aligned, but we don't fill in a full quad-word + */ +#define DO_REST(d,s,n) \ + while (n > 0) { \ + n--; \ + *(char *) d = *(char *) s; \ + d++; s++; \ } - /* as could this.. */ - __memcpy_b(d,s,n+8); -} -static inline void __memcpy_l(unsigned long d, unsigned long s, long n) +/* + * This should be done with ldq/mask/stq. The source and destination are + * aligned, but we don't fill in a full quad-word + */ +#define DO_REST_ALIGNED(d,s,n) DO_REST(d,s,n) + +/* + * This does unaligned memory copies. We want to avoid storing to + * an unaligned address, as that would do a read-modify-write cycle. + * We also want to avoid double-reading the unaligned reads. + * + * Note the ordering to try to avoid load (and address generation) latencies. + */ +static inline void __memcpy_unaligned(unsigned long d, unsigned long s, long n) { - while (d & 3) { - if (--n < 0) - return; - *(char *) d = *(char *) s; - d++; - s++; + ALIGN_DEST_TO8(d,s,n); + n -= 8; /* to avoid compare against 8 in the loop */ + if (n >= 0) { + unsigned long low_word, high_word; + __asm__("ldq_u %0,%1":"=r" (low_word):"m" (*(unsigned long *) s)); + do { + unsigned long tmp; + __asm__("ldq_u %0,%1":"=r" (high_word):"m" (*(unsigned long *)(s+8))); + n -= 8; + __asm__("extql %1,%2,%0" + :"=r" (low_word) + :"r" (low_word), "r" (s)); + __asm__("extqh %1,%2,%0" + :"=r" (tmp) + :"r" (high_word), "r" (s)); + s += 8; + *(unsigned long *) d = low_word | tmp; + d += 8; + low_word = high_word; + } while (n >= 0); } - while ((n -= 4) >= 0) { - *(unsigned int *) d = *(unsigned int *) s; - d += 4; - s += 4; + n += 8; + DO_REST(d,s,n); +} + +/* + * Hmm.. Strange. The __asm__ here is there to make gcc use a integer register + * for the load-store. I don't know why, but it would seem that using a floating + * point register for the move seems to slow things down (very small difference, + * though). + * + * Note the ordering to try to avoid load (and address generation) latencies. + */ +static inline void __memcpy_aligned(unsigned long d, unsigned long s, long n) +{ + ALIGN_DEST_TO8(d,s,n); + n -= 8; + while (n >= 0) { + unsigned long tmp; + __asm__("ldq %0,%1":"=r" (tmp):"m" (*(unsigned long *) s)); + n -= 8; + s += 8; + *(unsigned long *) d = tmp; + d += 8; } - __memcpy_b(d,s,n+4); -} + n += 8; + DO_REST_ALIGNED(d,s,n); +} void * __memcpy(void * dest, const void *src, size_t n) { - unsigned long differ; - differ = ((unsigned long) dest ^ (unsigned long) src) & 7; - - if (!differ) { - __memcpy_q((unsigned long) dest, (unsigned long) src, n); - return dest; - } - if (differ == 4) { - __memcpy_l((unsigned long) dest, (unsigned long) src, n); + if (!(((unsigned long) dest ^ (unsigned long) src) & 7)) { + __memcpy_aligned((unsigned long) dest, (unsigned long) src, n); return dest; } - __memcpy_b((unsigned long) dest, (unsigned long) src, n); + __memcpy_unaligned((unsigned long) dest, (unsigned long) src, n); return dest; } diff -u --recursive --new-file v1.3.6/linux/arch/alpha/lib/memset.c linux/arch/alpha/lib/memset.c --- v1.3.6/linux/arch/alpha/lib/memset.c Mon Jan 30 06:39:28 1995 +++ linux/arch/alpha/lib/memset.c Wed Jul 5 12:53:22 1995 @@ -10,7 +10,7 @@ #include -void * __constant_c_memset(void * s, unsigned long c, long count) +inline void * __constant_c_memset(void * s, unsigned long c, long count) { unsigned long xs = (unsigned long) s; @@ -35,10 +35,6 @@ void * __memset(void * s,char c,size_t count) { - char *xs = (char *) s; - - while (count--) - *xs++ = c; - + __constant_c_memset(s,0x0101010101010101UL * (unsigned char) c, count); return s; } diff -u --recursive --new-file v1.3.6/linux/arch/i386/Makefile linux/arch/i386/Makefile --- v1.3.6/linux/arch/i386/Makefile Thu Jun 29 19:02:39 1995 +++ linux/arch/i386/Makefile Mon Jul 3 10:08:51 1995 @@ -29,11 +29,11 @@ CPP=$(CC) -E -D__ELF__ OBJDUMP =objdump OBJDUMP_FLAGS=-k -q -LDFLAGS=-e startup_32 +ZLDFLAGS=-e startup_32 LDFLAGS=-e stext ZIMAGE_OFFSET=0x1000 IMAGE_OFFSET=0x100000 -ZLINKFLAGS =-Ttext $(ZIMAGE_OFFSET) $(LDFLAGS) +ZLINKFLAGS =-Ttext $(ZIMAGE_OFFSET) $(ZLDFLAGS) LINKFLAGS =-Ttext $(IMAGE_OFFSET) $(LDFLAGS) else diff -u --recursive --new-file v1.3.6/linux/arch/i386/config.in linux/arch/i386/config.in --- v1.3.6/linux/arch/i386/config.in Fri Jun 30 16:22:25 1995 +++ linux/arch/i386/config.in Mon Jul 3 10:10:52 1995 @@ -30,6 +30,9 @@ fi bool 'System V IPC' CONFIG_SYSVIPC y bool 'Kernel support for ELF binaries' CONFIG_BINFMT_ELF y +if [ "$CONFIG_BINFMT_ELF" = "y" ]; then +bool 'Compile kernel as ELF - if your GCC is ELF-GCC' CONFIG_KERNEL_ELF n +fi #bool 'Use -mpentium flag for Pentium-specific optimizations' CONFIG_M586 n #if [ "$CONFIG_M586" = "n" ]; then bool 'Use -m486 flag for 486-specific optimizations' CONFIG_M486 y @@ -209,9 +212,10 @@ comment 'CD-ROM drivers (not for SCSI or IDE/ATAPI drives)' -bool 'Sony CDU31A/CDU33A CDROM driver support' CONFIG_CDU31A n -bool 'Mitsumi (not IDE/ATAPI) CDROM driver support' CONFIG_MCD n -bool 'Matsushita/Panasonic CDROM driver support' CONFIG_SBPCD n +bool 'Sony CDU31A/CDU33A CDROM support' CONFIG_CDU31A n +bool 'Standard Mitsumi [no XA/Multisession] CDROM support' CONFIG_MCD n +bool 'Experimental Mitsumi [XA/MultiSession, no Audio] support' CONFIG_MCDX n +bool 'Matsushita/Panasonic CDROM support' CONFIG_SBPCD n if [ "$CONFIG_SBPCD" = "y" ]; then bool 'Matsushita/Panasonic second CDROM controller support' CONFIG_SBPCD2 n if [ "$CONFIG_SBPCD2" = "y" ]; then @@ -222,7 +226,11 @@ fi fi bool 'Aztech/Orchid/Okano/Wearnes (non IDE) CDROM support' CONFIG_AZTCD n -bool 'Sony CDU535 CDROM driver support' CONFIG_CDU535 n +bool 'Sony CDU535 CDROM support' CONFIG_CDU535 n +bool 'Goldstar R420 CDROM support' CONFIG_GSCD n +bool 'Philips/LMS CM206 CDROM support' CONFIG_CM206 n +bool 'Experimental Optics Storage DOLPHIN 8000AT CDROM support' CONFIG_OPTCD n +bool 'Experimental Sanyo H94A CDROM support' CONFIG_SJCD n comment 'Filesystems' @@ -238,13 +246,14 @@ if [ "$CONFIG_INET" = "y" ]; then bool 'NFS filesystem support' CONFIG_NFS_FS y fi -if [ "$CONFIG_BLK_DEV_SR" = "y" -o "$CONFIG_CDU31A" = "y" -o "$CONFIG_MCD" = "y" -o "$CONFIG_SBPCD" = "y" -o "$CONFIG_BLK_DEV_IDECD" = "y" -o "$CONFIG_AZTCD" = "y" -o "$CONFIG_CDU535" = "y" ]; then +if [ "$CONFIG_BLK_DEV_SR" = "y" -o "$CONFIG_BLK_DEV_IDECD" = "y" -o "$CONFIG_CDU31A" = "y" -o "$CONFIG_MCDX" = "y" -o "$CONFIG_MCD" = "y" -o "$CONFIG_SBPCD" = "y" -o "$CONFIG_AZTCD" = "y" -o "$CONFIG_CDU535" = "y" -o "$CONFIG_GSCD" = "y" -o "$CONFIG_CM206" = "y" -o "$CONFIG_OPTCD" = "y" -o "$CONFIG_SJCD" = "y" ]; then bool 'ISO9660 cdrom filesystem support' CONFIG_ISO9660_FS y else bool 'ISO9660 cdrom filesystem support' CONFIG_ISO9660_FS n fi bool 'OS/2 HPFS filesystem support (read only)' CONFIG_HPFS_FS n bool 'System V and Coherent filesystem support' CONFIG_SYSV_FS n +bool 'SMB filesystem (to mount WfW shares etc..) support' CONFIG_SMB_FS n comment 'character devices' diff -u --recursive --new-file v1.3.6/linux/arch/i386/lib/checksum.c linux/arch/i386/lib/checksum.c --- v1.3.6/linux/arch/i386/lib/checksum.c Fri Jun 30 16:22:25 1995 +++ linux/arch/i386/lib/checksum.c Thu Jul 6 13:35:59 1995 @@ -101,7 +101,7 @@ * copy from fs while checksumming, otherwise like csum_partial */ -unsigned int csum_partial_copyffs( char *src, char *dst, +unsigned int csum_partial_copy_fromuser( char *src, char *dst, int len, int sum) { __asm__(" testl $2, %%edi # Check alignment. @@ -175,15 +175,15 @@ jz 7f cmpl $2, %%ecx jb 5f - movw %%fs:(%%esi), %%dx + movw %%fs:(%%esi), %%cx leal 2(%%esi), %%esi - movw %%dx, (%%edi) + movw %%cx, (%%edi) leal 2(%%edi), %%edi je 6f shll $16,%%edx -5: movb %%fs:(%%esi), %%dl - movb %%dl, (%%edi) -6: addl %%edx, %%eax +5: movb %%fs:(%%esi), %%cl + movb %%cl, (%%edi) +6: addl %%ecx, %%eax adcl $0, %%eax 7: " @@ -192,6 +192,98 @@ : "bx", "cx", "dx", "si", "di" ); return(sum); } +/* + * copy from ds while checksumming, otherwise like csum_partial + */ +unsigned int csum_partial_copy( char *src, char *dst, + int len, int sum) { + __asm__(" + testl $2, %%edi # Check alignment. + jz 2f # Jump if alignment is ok. + subl $2, %%ecx # Alignment uses up two bytes. + jae 1f # Jump if we had at least two bytes. + addl $2, %%ecx # ecx was < 2. Deal with it. + jmp 4f +1: movw (%%esi), %%bx + addl $2, %%esi + movw %%bx, (%%edi) + addl $2, %%edi + addw %%bx, %%ax + adcl $0, %%eax +2: + movl %%ecx, %%edx + shrl $5, %%ecx + jz 2f + testl %%esi, %%esi +1: movl (%%esi), %%ebx + adcl %%ebx, %%eax + movl %%ebx, (%%edi) + + movl 4(%%esi), %%ebx + adcl %%ebx, %%eax + movl %%ebx, 4(%%edi) + + movl 8(%%esi), %%ebx + adcl %%ebx, %%eax + movl %%ebx, 8(%%edi) + + movl 12(%%esi), %%ebx + adcl %%ebx, %%eax + movl %%ebx, 12(%%edi) + movl 16(%%esi), %%ebx + adcl %%ebx, %%eax + movl %%ebx, 16(%%edi) + + movl 20(%%esi), %%ebx + adcl %%ebx, %%eax + movl %%ebx, 20(%%edi) + + movl 24(%%esi), %%ebx + adcl %%ebx, %%eax + movl %%ebx, 24(%%edi) + movl 28(%%esi), %%ebx + adcl %%ebx, %%eax + movl %%ebx, 28(%%edi) + + lea 32(%%esi), %%esi + lea 32(%%edi), %%edi + dec %%ecx + jne 1b + adcl $0, %%eax +2: movl %%edx, %%ecx + andl $28, %%edx + je 4f + shrl $2, %%edx + testl %%esi, %%esi +3: movl (%%esi), %%ebx + adcl %%ebx, %%eax + movl %%ebx, (%%edi) + lea 4(%%esi), %%esi + lea 4(%%edi), %%edi + dec %%edx + jne 3b + adcl $0, %%eax +4: andl $3, %%ecx + jz 7f + cmpl $2, %%ecx + jb 5f + movw (%%esi), %%cx + leal 2(%%esi), %%esi + movw %%cx, (%%edi) + leal 2(%%edi), %%edi + je 6f + shll $16,%%edx +5: movb (%%esi), %%cl + movb %%cl, (%%edi) +6: addl %%ecx, %%eax + adcl $0, %%eax +7: + " + : "=a" (sum) + : "0"(sum), "c"(len), "S"(src), "D" (dst) + : "bx", "cx", "dx", "si", "di" ); + return(sum); +} diff -u --recursive --new-file v1.3.6/linux/drivers/block/Makefile linux/drivers/block/Makefile --- v1.3.6/linux/drivers/block/Makefile Tue Jun 27 14:11:32 1995 +++ linux/drivers/block/Makefile Sat Jul 1 19:05:58 1995 @@ -35,19 +35,21 @@ ifdef CONFIG_CDU31A OBJS := $(OBJS) cdu31a.o SRCS := $(SRCS) cdu31a.c -endif +endif #CONFIG_CDU31A ifdef CONFIG_MCD OBJS := $(OBJS) mcd.o SRCS := $(SRCS) mcd.c -endif +else +BLOCK_MODULE_OBJS := $(BLOCK_MODULE_OBJS) mcd.o +endif #CONFIG_MCD -ifdef CONFIG_AZTCD -OBJS := $(OBJS) aztcd.o -SRCS := $(SRCS) aztcd.c +ifdef CONFIG_MCDX +OBJS := $(OBJS) mcdx.o +SRCS := $(SRCS) mcdx.c else -BLOCK_MODULE_OBJS := $(BLOCK_MODULE_OBJS) aztcd.o -endif +BLOCK_MODULE_OBJS := $(BLOCK_MODULE_OBJS) mcdx.o +endif #CONFIG_MCDX ifdef CONFIG_SBPCD OBJS := $(OBJS) sbpcd.o @@ -71,6 +73,48 @@ SRCS := $(SRCS) sbpcd4.c endif #CONFIG_SBPCD4 +ifdef CONFIG_AZTCD +OBJS := $(OBJS) aztcd.o +SRCS := $(SRCS) aztcd.c +else +BLOCK_MODULE_OBJS := $(BLOCK_MODULE_OBJS) aztcd.o +endif #CONFIG_AZTCD + +ifdef CONFIG_CDU535 +OBJS := $(OBJS) sonycd535.o +SRCS := $(SRCS) sonycd535.c +else +BLOCK_MODULE_OBJS := $(BLOCK_MODULE_OBJS) sonycd535.o +endif #CONFIG_CDU535 + +ifdef CONFIG_GSCD +OBJS := $(OBJS) gscd.o +SRCS := $(SRCS) gscd.c +else +BLOCK_MODULE_OBJS := $(BLOCK_MODULE_OBJS) gscd.o +endif #CONFIG_GSCD + +ifdef CONFIG_CM206 +OBJS := $(OBJS) cm206.o +SRCS := $(SRCS) cm206.c +else +BLOCK_MODULE_OBJS := $(BLOCK_MODULE_OBJS) cm206.o +endif #CONFIG_CM206 + +ifdef CONFIG_OPTCD +OBJS := $(OBJS) optcd.o +SRCS := $(SRCS) optcd.c +else +BLOCK_MODULE_OBJS := $(BLOCK_MODULE_OBJS) optcd.o +endif #CONFIG_OPTCD + +ifdef CONFIG_SJCD +OBJS := $(OBJS) sjcd.o +SRCS := $(SRCS) sjcd.c +#else +#BLOCK_MODULE_OBJS := $(BLOCK_MODULE_OBJS) sjcd.o +endif #CONFIG_SJCD + ifdef CONFIG_BLK_DEV_HD OBJS := $(OBJS) hd.o SRCS := $(SRCS) hd.c @@ -84,13 +128,6 @@ ifdef CONFIG_BLK_DEV_XD OBJS := $(OBJS) xd.o SRCS := $(SRCS) xd.c -endif - -ifdef CONFIG_CDU535 -OBJS := $(OBJS) sonycd535.o -SRCS := $(SRCS) sonycd535.c -else -BLOCK_MODULE_OBJS := $(BLOCK_MODULE_OBJS) sonycd535.o endif all: block.a diff -u --recursive --new-file v1.3.6/linux/drivers/block/README.cdu31a linux/drivers/block/README.cdu31a --- v1.3.6/linux/drivers/block/README.cdu31a Thu Jan 1 02:00:00 1970 +++ linux/drivers/block/README.cdu31a Sat Jul 1 19:05:58 1995 @@ -0,0 +1,160 @@ + Tips for using cdu31a.c, the driver for Sony CDU-31A and CDU-33A CDROM + drives. + + Corey Minyard (minyard@wf-rch.cirr.com) + + Colossians 3:17 + + The Sony interface device driver handles Sony interface CDROM + drives and provides a complete block-level interface as well as an + ioctl() interface compatible with the Sun (as specified in + include/linux/cdrom.h). With this interface, CDROMs can be + accessed and standard audio CDs can be played back normally. + + WARNING - All autoprobes have been removed from the driver. + You MUST configure the CDU31A via a LILO config + at boot time or in lilo.conf. I have the + following in my lilo.conf: + + append="cdu31a=0x1f88,0,PAS" + + The first number is the I/O base address of the + card. The second is the interrupt (0 means none). + The third should be "PAS" if on a Pro-Audio + spectrum, or nothing if on something else. + + This interface is (unfortunately) a polled interface. This is + because most Sony interfaces are set up with DMA and interrupts + disables. Some (like mine) do not even have the capability to + handle interrupts or DMA. For this reason you will see a lot of + the following: + + retry_count = jiffies+ SONY_JIFFIES_TIMEOUT; + while ((retry_count > jiffies) && (! ' +The driver should report his results now. + +That's it! Mount a disk, i.e. 'mount -rt iso9660 /dev/gscd0 /cdrom' + +Feel free to report errors and suggestions to the following address. +Be sure, I'm very happy to receive your comments! + + Oliver Raupach Hannover, Juni 1995 +(raupach@nwfs1.rz.fh-hannover.de) diff -u --recursive --new-file v1.3.6/linux/drivers/block/README.mcd linux/drivers/block/README.mcd --- v1.3.6/linux/drivers/block/README.mcd Thu Jan 1 02:00:00 1970 +++ linux/drivers/block/README.mcd Sat Jul 1 19:05:58 1995 @@ -0,0 +1,6 @@ +This driver does not support XA or MultiSession CDs (PhotoCDs). Use the +experimental driver mcdx.c for that. + +You can use mcd for one interface, and mcdx for another; this way, you +can use the audio functions with the "old" driver, and read XA CDs with +the "new" driver (if you have at least two drives). diff -u --recursive --new-file v1.3.6/linux/drivers/block/README.mcdx linux/drivers/block/README.mcdx --- v1.3.6/linux/drivers/block/README.mcdx Thu Jan 1 02:00:00 1970 +++ linux/drivers/block/README.mcdx Sat Jul 1 19:05:58 1995 @@ -0,0 +1,37 @@ +This is a first attempt to create an `improved' driver for the Mitsumi drives. +It is able to "live together" with mcd.c, if you have at least two Mitsumi +drives: each driver can use his own drive. + +To allow this "coexistence" as long as mcdx.c is not a superset of mcd.c, +this driver has to use its own device files. We use MAJOR 20 for it. So, +you have to do + # mknod /dev/mcdx0 b 20 0 + # mknod /dev/mcdx1 b 20 1 +and so on, one entry for each drive to support, once. + +If you are using the driver as a module, you can specify your ports and IRQs +like + # insmod mcdx.o mcdx=0x300,11,0x304,5 +and so on ("address,IRQ" pairs). +This will override the configuration in mcdx.h. + +This driver: + + o handles XA (and hopefully) multi session CDs as well as + ordinary CDs; + o supports up to 5 drives (of course, you'll need free + IRQs, i/o ports and slots); + o uses much less kernel memory than the standard mcd driver + (no extra driver internal buffers!). + +This version doesn't support yet: + + o audio functions; + o shared IRQs (but it seems to be possible - I've successfully + connected two drives to the same irq. So it's `only' a + problem of the driver.) + +This driver never will: + + o Read digital audio (i.e. copy directly), due to missing + hardware features. diff -u --recursive --new-file v1.3.6/linux/drivers/block/README.optcd linux/drivers/block/README.optcd --- v1.3.6/linux/drivers/block/README.optcd Thu Jan 1 02:00:00 1970 +++ linux/drivers/block/README.optcd Sat Jul 1 19:05:58 1995 @@ -0,0 +1,38 @@ +This is the README file for the Optics Storage 8000 AT CDROM device driver. + +The driver contains code to enable an ISP16 interface if it finds one, so if +you have that, you're lucky. + +My configuration code for the ISP-16 card can get found at + dutette.et.tudelft.nl:/pub/linux/ +and at Eberhard's mirror + ftp.gwdg.de:/pub/linux/cdrom/drivers/optics/ + +Much more elaborate information can be found at ftp:rbrf.msk.su, +where Vadim Model (vadim@rbrf.msk.su) has made available an ISP16 +device driver. +Vadim's directory is + rbrf.msk.su:/linux/mediamagic/ +and Eberhard is holding a mirror at + ftp.gwdg.de:/pub/linux/cdrom/drivers/sanyo/ + + +Before you can use the driver, you have to create the device file once: + # mknod /dev/optcd0 b 17 0 + +To specify the base address if the driver is "compiled-in" to your kernel, +you can use the kernel command line item (LILO option) + optcd=0x340 +with the right address. + +If you have compiled optcd as a module, you can load it with + # insmod /usr/src/linux/modules/optcd.o +or + # insmod /usr/src/linux/modules/optcd.o optcd=0x340 +with the matching address value of your interface card. + +I have tried the module with several 1.2.x kernel versions, and it seems to +work, as far as I tested. If you use it, I'd appreciate success/failure +reports. + +Leo Spiekman (spiekman@dutette.et.tudelft.nl) diff -u --recursive --new-file v1.3.6/linux/drivers/block/README.sjcd linux/drivers/block/README.sjcd --- v1.3.6/linux/drivers/block/README.sjcd Thu Jan 1 02:00:00 1970 +++ linux/drivers/block/README.sjcd Sat Jul 1 19:05:58 1995 @@ -0,0 +1,39 @@ + 80% of the work takes 20% of the time, + 20% of the work takes 80% of the time... + (Murphy law) + + Once started, training can not be stopped... + (StarWars) + +This file is meant as a tips & tricks edge for the usage of the SANYO CDR-H94A +cdrom drive. It will grow as the questions arise. ;-) + +The driver should work with any SoundBlaster/Panasonic style CDROM interface, +including the "soft configurable" MediaMagic sound card. +To make this sound card (and others like "Mozart") working, it has to get +"configured" by software. +So, you should boot DOS once (and by this, run the "configuration driver") +and then switch to Linux by use of CTL-ALT-DEL. Each use of the RESET +button or the power switch makes this procedure necessary again. + +Vadim has implemented a Linux "configuration driver" to set up the +registers of the MediaMagic (ISP-16) sound card. These routines have to get +integrated into the related CDROM and sound drivers directly at a later +time. Currently, they reside at Vadim's server + rbrf.msk.su:/linux/mediamagic/ +and at Eberhard's mirror + ftp.gwdg.de:/pub/linux/cdrom/drivers/sanyo/ + +Leo Spiekman's configuration routines for the ISP-16 card can get found at + dutette.et.tudelft.nl:/pub/linux/ +and at Eberhard's mirror + ftp.gwdg.de:/pub/linux/cdrom/drivers/optics/ + +If something is wrong, e-mail to vadim@rbrf.msk.su + or vadim@ipsun.ras.ru + or model@cecmow.enet.dec.com + +It happens sometimes that Vadim is not reachable by mail. For these +instances, Eric van der Maarel (maarel@marin.nl) will help, too. + + Vadim V. Model, Eric van der Maarel, Eberhard Moenkeberg diff -u --recursive --new-file v1.3.6/linux/drivers/block/README.sonycd535 linux/drivers/block/README.sonycd535 --- v1.3.6/linux/drivers/block/README.sonycd535 Mon Jun 12 12:06:02 1995 +++ linux/drivers/block/README.sonycd535 Sat Jul 1 19:05:58 1995 @@ -89,6 +89,8 @@ To install the module, simply type: insmod sony535.o + or +insmod sony535.o sonycd535=
And to remove it: diff -u --recursive --new-file v1.3.6/linux/drivers/block/blk.h linux/drivers/block/blk.h --- v1.3.6/linux/drivers/block/blk.h Tue Jun 27 14:11:33 1995 +++ linux/drivers/block/blk.h Sat Jul 1 19:05:58 1995 @@ -37,23 +37,42 @@ #define SUBSECTOR(block) (CURRENT->current_nr_sectors > 0) -extern unsigned long cdu31a_init(unsigned long mem_start, unsigned long mem_end); -extern unsigned long mcd_init(unsigned long mem_start, unsigned long mem_end); +#ifdef CONFIG_CDU31A +extern unsigned long cdu31a_init(unsigned long, unsigned long); +#endif CONFIG_CDU31A +#ifdef CONFIG_MCD +extern unsigned long mcd_init(unsigned long, unsigned long); +#endif CONFIG_MCD +#ifdef CONFIG_MCDX +extern unsigned long mcdx_init(unsigned long, unsigned long); +#endif CONFIG_MCDX +#ifdef CONFIG_SBPCD +extern unsigned long sbpcd_init(unsigned long, unsigned long); +#endif CONFIG_SBPCD #ifdef CONFIG_AZTCD -extern unsigned long aztcd_init(unsigned long mem_start, unsigned long mem_end); -#endif +extern unsigned long aztcd_init(unsigned long, unsigned long); +#endif CONFIG_AZTCD #ifdef CONFIG_CDU535 -extern unsigned long sony535_init(unsigned long mem_start, unsigned long mem_end); -#endif +extern unsigned long sony535_init(unsigned long, unsigned long); +#endif CONFIG_CDU535 +#ifdef CONFIG_GSCD +extern unsigned long gscd_init(unsigned long, unsigned long); +#endif CONFIG_GSCD +#ifdef CONFIG_CM206 +extern unsigned long cm206_init(unsigned long, unsigned long); +#endif CONFIG_CM206 +#ifdef CONFIG_OPTCD +extern unsigned long optcd_init(unsigned long, unsigned long); +#endif CONFIG_OPTCD +#ifdef CONFIG_SJCD +extern unsigned long sjcd_init(unsigned long, unsigned long); +#endif CONFIG_SJCD #ifdef CONFIG_BLK_DEV_HD extern unsigned long hd_init(unsigned long mem_start, unsigned long mem_end); #endif #ifdef CONFIG_BLK_DEV_IDE extern unsigned long ide_init(unsigned long mem_start, unsigned long mem_end); #endif -#ifdef CONFIG_SBPCD -extern unsigned long sbpcd_init(unsigned long, unsigned long); -#endif CONFIG_SBPCD extern void set_device_ro(int dev,int flag); extern int floppy_init(void); @@ -165,19 +184,11 @@ #define DEVICE_ON(device) #define DEVICE_OFF(device) -#elif (MAJOR_NR == AZTECH_CDROM_MAJOR) - -#define DEVICE_NAME "Aztech CD-ROM" -#define DEVICE_REQUEST do_aztcd_request -#define DEVICE_NR(device) (MINOR(device)) -#define DEVICE_ON(device) -#define DEVICE_OFF(device) +#elif (MAJOR_NR == MITSUMI_X_CDROM_MAJOR) -#elif (MAJOR_NR == CDU535_CDROM_MAJOR) - -#define DEVICE_NAME "SONY-CDU535" -#define DEVICE_INTR do_cdu535 -#define DEVICE_REQUEST do_cdu535_request +#define DEVICE_NAME "Mitsumi CD-ROM" +/* #define DEVICE_INTR do_mcdx */ +#define DEVICE_REQUEST do_mcdx_request #define DEVICE_NR(device) (MINOR(device)) #define DEVICE_ON(device) #define DEVICE_OFF(device) @@ -210,6 +221,54 @@ #define DEVICE_NAME "Matsushita CD-ROM controller #4" #define DEVICE_REQUEST do_sbpcd4_request +#define DEVICE_NR(device) (MINOR(device)) +#define DEVICE_ON(device) +#define DEVICE_OFF(device) + +#elif (MAJOR_NR == AZTECH_CDROM_MAJOR) + +#define DEVICE_NAME "Aztech CD-ROM" +#define DEVICE_REQUEST do_aztcd_request +#define DEVICE_NR(device) (MINOR(device)) +#define DEVICE_ON(device) +#define DEVICE_OFF(device) + +#elif (MAJOR_NR == CDU535_CDROM_MAJOR) + +#define DEVICE_NAME "SONY-CDU535" +#define DEVICE_INTR do_cdu535 +#define DEVICE_REQUEST do_cdu535_request +#define DEVICE_NR(device) (MINOR(device)) +#define DEVICE_ON(device) +#define DEVICE_OFF(device) + +#elif (MAJOR_NR == GOLDSTAR_CDROM_MAJOR) + +#define DEVICE_NAME "Goldstar R420" +#define DEVICE_REQUEST do_gscd_request +#define DEVICE_NR(device) (MINOR(device)) +#define DEVICE_ON(device) +#define DEVICE_OFF(device) + +#elif (MAJOR_NR == CM206_CDROM_MAJOR) +#define DEVICE_NAME "Philips/LMS cd-rom cm206" +#define DEVICE_REQUEST do_cm206_request +#define DEVICE_NR(device) (MINOR(device)) +#define DEVICE_ON(device) +#define DEVICE_OFF(device) + +#elif (MAJOR_NR == OPTICS_CDROM_MAJOR) + +#define DEVICE_NAME "DOLPHIN 8000AT CD-ROM" +#define DEVICE_REQUEST do_optcd_request +#define DEVICE_NR(device) (MINOR(device)) +#define DEVICE_ON(device) +#define DEVICE_OFF(device) + +#elif (MAJOR_NR == SANYO_CDROM_MAJOR) + +#define DEVICE_NAME "Sanyo H94A CD-ROM" +#define DEVICE_REQUEST do_sjcd_request #define DEVICE_NR(device) (MINOR(device)) #define DEVICE_ON(device) #define DEVICE_OFF(device) diff -u --recursive --new-file v1.3.6/linux/drivers/block/cm206.c linux/drivers/block/cm206.c --- v1.3.6/linux/drivers/block/cm206.c Thu Jan 1 02:00:00 1970 +++ linux/drivers/block/cm206.c Sat Jul 1 19:05:59 1995 @@ -0,0 +1,1198 @@ +/* cm206.c. A linux-driver for the cm206 cdrom player with cm260 adapter card. + Copyright (c) 1995 David van Leeuwen. + + 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. + +History: + Started 25 jan 1994. Waiting for documentation... + 22 feb 1995: 0.1a first reasonably safe polling driver. + Two major bugs, one in read_sector and one in + do_cm206_request, happened to cancel! + 25 feb 1995: 0.2a first reasonable interrupt driven version of above. + uart writes are still done in polling mode. + 25 feb 1995: 0.21a writes also in interrupt mode, still some + small bugs to be found... Larger buffer. + 2 mrt 1995: 0.22 Bug found (cd-> nowhere, interrupt was called in + initialization), read_ahead of 16. Timeouts implemented. + unclear if they do something... + 7 mrt 1995: 0.23 Start of background read-ahead. + 18 mrt 1995: 0.24 Working background read-ahead. (still problems) + 26 mrt 1995: 0.25 Multi-session ioctl added (kernel v1.2). + Statistics implemented, though separate stats206.h. + Accessible trough ioctl 0x1000 (just a number). + Hard to choose between v1.2 development and 1.1.75. + Bottom-half doesn't work with 1.2... + 0.25a: fixed... typo. Still problems... + 1 apr 1995: 0.26 Module support added. Most bugs found. Use kernel 1.2.n. + 5 apr 1995: 0.27 Auto-probe for the adapter card base address. + Auto-probe for the adaptor card irq line. + 7 apr 1995: 0.28 Added lilo setup support for base address and irq. + Use major number 32 (not in this source), officially + assigned to this driver. + 9 apr 1995: 0.29 Added very limited audio support. Toc_header, stop, pause, + resume, eject. Play_track ignores track info, because we can't + read a table-of-contents entry. Toc_entry is implemented + as a `placebo' function: always returns start of disc. + 3 may 1995: 0.30 Audio support completed. The get_toc_entry function + is implemented as a binary search. + 15 may 1995: 0.31 More work on audio stuff. Workman is not easy to + satisfy; changed binary search into linear search. + Auto-probe for base address somewhat relaxed. + 1 jun 1995: 0.32 Removed probe_irq_on/off for module version. + 10 jun 1995: 0.33 Workman still behaves funny, but you should be + able to eject and substitute another disc. + * + * Parts of the code are based upon lmscd.c written by Kai Petzke, + * sbpcd.c written by Eberhard Moenkeberg, and mcd.c by Martin + * Harriss, but any off-the-shelf dynamic programming algorithm won't + * be able to find them. + * + * The cm206 drive interface and the cm260 adapter card seem to be + * sufficiently different from their cm205/cm250 counterparts + * in order to write a complete new driver. + * + * I call all routines connected to the Linux kernel something + * with `cm206' in it, as this stuff is too series-dependent. + * + * Currently, my limited knowledge is based on: + * - The Linux Kernel Hacker's guide, v. 0.5 , by Michael J. Johnson + * - Linux Kernel Programmierung, by Michael Beck and others + * - Philips/LMS cm206 and cm226 product specification + * - Philips/LMS cm260 product specification + * + * David van Leeuwen, david@tm.tno.nl. */ +#define VERSION "0.33" + +#ifdef MODULE /* OK, so some of this is stolen */ +#include +#include +#include +#ifndef CONFIG_MODVERSIONS +char kernel_version[]=UTS_RELEASE; +#endif +#else +#define MOD_INC_USE_COUNT +#define MOD_DEC_USE_COUNT +#endif MODULE + +#include /* These include what we really need */ +#include +#include +#include +#include +#include +#include +#include + +#include + +#define MAJOR_NR CM206_CDROM_MAJOR +#include "blk.h" +#include + +/* This variable defines whether or not to probe for adapter base port + address and interrupt request. It can be overridden by the boot + parameter `auto'. +*/ +static int auto_probe=1; /* Yes, why not? */ + +#define cm206_base cm206 /* for compatible "insmod" parameter passing */ +static int cm206_base = CM206_BASE; +static int cm206_irq = CM206_IRQ; /* must directly follow cm206_base */ + +#undef DEBUG +#undef DEBUG_SECTORS +#define STATISTICS +#undef AUTO_PROBE_MODULE + +#define POLLOOP 10000 +#define READ_AHEAD 1 /* defines private buffer, waste! */ +#define BACK_AHEAD 1 /* defines adapter-read ahead */ +#define DATA_TIMEOUT 300 /* measured in jiffies (10 ms) */ +#define UART_TIMEOUT 5 +#define DSB_TIMEOUT 700 /* time for the slowest command to finish */ + +#define RAW_SECTOR_SIZE 2352 /* ok, is also defined in cdrom.h */ +#define ISO_SECTOR_SIZE 2048 + +#ifdef STATISTICS /* keep track of errors in counters */ +#include +#define stats(i) ++cd->stats[st_ ## i]; \ + cd->last_stat[st_ ## i] = cd->stat_counter++; +#else +#define stats(i) (void) 0 +#endif + +#ifdef DEBUG /* from lmscd.c */ +#define debug(a) printk a +#else +#define debug(a) (void) 0 +#endif + +typedef unsigned char uch; /* 8-bits */ +typedef unsigned short ush; /* 16-bits */ + +struct toc_struct{ + uch track, fsm[3], q0; +}; + +struct cm206_struct { + ush intr_ds; /* data status read on last interrupt */ + ush intr_ls; /* uart line status read on last interrupt*/ + uch intr_ur; /* uart receive buffer */ + uch dsb, cc; /* drive status byte and condition (error) code */ + uch fool; + int command; /* command to be written to te uart */ + int openfiles; + ush sector[READ_AHEAD*RAW_SECTOR_SIZE/2]; /* buffered cd-sector */ + int sector_first, sector_last; /* range of these sector */ + struct wait_queue * uart; /* wait for interrupt */ + struct wait_queue * data; + struct timer_list timer; /* time-out */ + char timed_out; + signed char max_sectors; + char wait_back; /* we're waiting for a background-read */ + char background; /* is a read going on in the background? */ + int adapter_first; /* if so, that's the starting sector */ + int adapter_last; + char fifo_overflowed; + uch disc_status[7]; /* result of get_disc_status command */ +#ifdef STATISTICS + int stats[NR_STATS]; + int last_stat[NR_STATS]; /* `time' at which stat was stat */ + int stat_counter; +#endif + struct toc_struct toc[101]; /* The whole table of contents + lead-out */ + uch q[10]; /* Last read q-channel info */ + uch audio_status[5]; /* last read position on pause */ +}; + +#define DISC_STATUS cd->disc_status[0] +#define FIRST_TRACK cd->disc_status[1] +#define LAST_TRACK cd->disc_status[2] +#define PAUSED cd->audio_status[0] /* misuse this memory byte! */ +#define PLAY_TO cd->toc[0] /* toc[0] records end-time in play */ + +static struct cm206_struct * cd; + +/* First, we define some polling functions. These are actually + only being used in the initialization. */ + +void send_command_polled(int command) +{ + int loop=POLLOOP; + while (!(inw(r_line_status) & ls_transmitter_buffer_empty) && loop>0) + --loop; + outw(command, r_uart_transmit); +} + +uch receive_echo_polled(void) +{ + int loop=POLLOOP; + while (!(inw(r_line_status) & ls_receive_buffer_full) && loop>0) --loop; + return ((uch) inw(r_uart_receive)); +} + +uch send_receive_polled(int command) +{ + send_command_polled(command); + return receive_echo_polled(); +} + +/* The interrupt handler. When the cm260 generates an interrupt, very + much care has to be taken in reading out the registers in the right + order; in case of a receive_buffer_full interrupt, first the + uart_receive must be read, and then the line status again to + de-assert the interrupt line. It took me a couple of hours to find + this out:-( + + The function reset_cm206 appears to cause an interrupt, because + pulling up the INIT line clears both the uart-write-buffer /and/ + the uart-write-buffer-empty mask. We call this a `lost interrupt,' + as there seems so reason for this to happen. +*/ + +static void cm206_interrupt(int sig, struct pt_regs * regs) /* you rang? */ +{ + volatile ush fool; + cd->intr_ds = inw(r_data_status); /* resets data_ready, data_error, + crc_error, sync_error, toc_ready + interrupts */ + cd->intr_ls = inw(r_line_status); /* resets overrun bit */ + /* receive buffer full? */ + if (cd->intr_ls & ls_receive_buffer_full) { + cd->intr_ur = inb(r_uart_receive); /* get order right! */ + cd->intr_ls = inw(r_line_status); /* resets rbf interrupt */ + if (!cd->background && cd->uart) wake_up_interruptible(&cd->uart); + } + /* data ready in fifo? */ + else if (cd->intr_ds & ds_data_ready) { + if (cd->background) ++cd->adapter_last; + if ((cd->wait_back || !cd->background) && cd->data) + wake_up_interruptible(&cd->data); + stats(data_ready); + } + /* ready to issue a write command? */ + else if (cd->command && cd->intr_ls & ls_transmitter_buffer_empty) { + outw(dc_normal | (inw(r_data_status) & 0x7f), r_data_control); + outw(cd->command, r_uart_transmit); + cd->command=0; + if (!cd->background) wake_up_interruptible(&cd->uart); + } + /* now treat errors (at least, identify them for debugging) */ + else if (cd->intr_ds & ds_fifo_overflow) { + debug(("Fifo overflow at sectors 0x%x\n", cd->sector_first)); + fool = inw(r_fifo_output_buffer); /* de-assert the interrupt */ + cd->fifo_overflowed=1; /* signal one word less should be read */ + stats(fifo_overflow); + } + else if (cd->intr_ds & ds_data_error) { + debug(("Data error at sector 0x%x\n", cd->sector_first)); + stats(data_error); + } + else if (cd->intr_ds & ds_crc_error) { + debug(("CRC error at sector 0x%x\n", cd->sector_first)); + stats(crc_error); + } + else if (cd->intr_ds & ds_sync_error) { + debug(("Sync at sector 0x%x\n", cd->sector_first)); + stats(sync_error); + } + else if (cd->intr_ds & ds_toc_ready) { + /* do something appropiate */ + } + /* couldn't see why this interrupt, maybe due to init */ + else { + outw(dc_normal | READ_AHEAD, r_data_control); + stats(lost_intr); + } + if (cd->background && (cd->adapter_last-cd->adapter_first == cd->max_sectors + || cd->fifo_overflowed)) + mark_bh(CM206_BH); /* issue a stop read command */ + stats(interrupt); +} + +/* we have put the address of the wait queue in who */ +void cm206_timeout(unsigned long who) +{ + cd->timed_out = 1; + wake_up_interruptible((struct wait_queue **) who); +} + +/* This function returns 1 if a timeout occurred, 0 if an interrupt + happened */ +int sleep_or_timeout(struct wait_queue ** wait, int timeout) +{ + cd->timer.data=(unsigned long) wait; + cd->timer.expires = timeout; + add_timer(&cd->timer); + interruptible_sleep_on(wait); + del_timer(&cd->timer); + if (cd->timed_out) { + cd->timed_out = 0; + return 1; + } + else return 0; +} + +void cm206_delay(int jiffies) +{ + struct wait_queue * wait = NULL; + sleep_or_timeout(&wait, jiffies); +} + +void send_command(int command) +{ + if (!(inw(r_line_status) & ls_transmitter_buffer_empty)) { + cd->command = command; + cli(); /* don't interrupt before sleep */ + outw(dc_mask_sync_error | dc_no_stop_on_error | + (inw(r_data_status) & 0x7f), r_data_control); + /* interrupt routine sends command */ + if (sleep_or_timeout(&cd->uart, UART_TIMEOUT)) { + debug(("Time out on write-buffer\n")); + stats(write_timeout); + outw(command, r_uart_transmit); + } + } + else outw(command, r_uart_transmit); +} + +uch receive_echo(void) +{ + if (!(inw(r_line_status) & ls_receive_buffer_full) && + sleep_or_timeout(&cd->uart, UART_TIMEOUT)) { + debug(("Time out on receive-buffer\n")); + stats(receive_timeout); + return ((uch) inw(r_uart_receive)); + } + return cd->intr_ur; +} + +inline uch send_receive(int command) +{ + send_command(command); + return receive_echo(); +} + +uch wait_dsb(void) +{ + if (!(inw(r_line_status) & ls_receive_buffer_full) && + sleep_or_timeout(&cd->uart, DSB_TIMEOUT)) { + debug(("Time out on Drive Status Byte\n")); + stats(dsb_timeout); + return ((uch) inw(r_uart_receive)); + } + return cd->intr_ur; +} + +int type_0_command(int command, int expect_dsb) +{ + int e; + if (command != (e=send_receive(command))) { + debug(("command 0x%x echoed as 0x%x\n", command, e)); + stats(echo); + return -1; + } + if (expect_dsb) { + cd->dsb = wait_dsb(); /* wait for command to finish */ + } + return 0; +} + +int type_1_command(int command, int bytes, uch * status) /* returns info */ +{ + int i; + if (type_0_command(command,0)) return -1; + for(i=0; ibackground) return -1; /* can't do twice */ + outw(dc_normal | BACK_AHEAD, r_data_control); + if (!reading && start_read(start)) return -2; + cd->adapter_first = cd->adapter_last = start; + cd->background = 1; /* flag a read is going on */ + return 0; +} + +int read_sector(int start) +{ + if (cd->background) { + cd->background=0; + cd->adapter_last = -1; /* invalidate adapter memory */ + stop_read(); + } + cd->fifo_overflowed=0; + reset_cm260(); /* empty fifo etc. */ + if (start_read(start)) return -1; + if (sleep_or_timeout(&cd->data, DATA_TIMEOUT)) { + debug(("Read timed out sector 0x%x\n", start)); + stats(read_timeout); + stop_read(); + return -3; + } + insw(r_fifo_output_buffer, cd->sector, READ_AHEAD*RAW_SECTOR_SIZE/2); + if (read_background(start+READ_AHEAD,1)) stats(read_background); + cd->sector_first = start; cd->sector_last = start+READ_AHEAD; + stats(read_restarted); + return 0; +} + +/* The function of bottom-half is to send a stop command to the drive + This isn't easy because the routine is not `owned' by any process; + we can't go to sleep! The variable cd->background gives the status: + 0 no read pending + 1 a read is pending + 2 c_stop waits for write_buffer_empty + 3 c_stop waits for receive_buffer_full: echo + 4 c_stop waits for receive_buffer_full: 0xff +*/ + +void cm206_bh(void * unused) +{ + debug(("bh: %d\n", cd->background)); + switch (cd->background) { + case 1: + stats(bh); + if (!(cd->intr_ls & ls_transmitter_buffer_empty)) { + cd->command = c_stop; + outw(dc_mask_sync_error | dc_no_stop_on_error | + (inw(r_data_status) & 0x7f), r_data_control); + cd->background=2; + break; /* we'd better not time-out here! */ + } + else outw(c_stop, r_uart_transmit); + /* fall into case 2: */ + case 2: + /* the write has been satisfied by interrupt routine */ + cd->background=3; + break; + case 3: + if (cd->intr_ur != c_stop) { + debug(("cm206_bh: c_stop echoed 0x%x\n", cd->intr_ur)); + stats(echo); + } + cd->background++; + break; + case 4: + if (cd->intr_ur != 0xff) { + debug(("cm206_bh: c_stop reacted with 0x%x\n", cd->intr_ur)); + stats(stop_0xff); + } + cd->background=0; + } +} + +void get_drive_status(void) +{ + uch status[2]; + type_1_command(c_drive_status, 2, status); /* this might be done faster */ + cd->dsb=status[0]; + cd->cc=status[1]; +} + +void get_disc_status(void) +{ + if (type_1_command(c_disc_status, 7, cd->disc_status)) { + debug(("get_disc_status: error\n")); + } +} + +static int cm206_open(struct inode *ip, struct file *fp) +{ + if (!cd->openfiles) { + cd->background=0; + reset_cm260(); + cd->adapter_last = -1; /* invalidate adapter memory */ + cd->sector_last = -1; + get_drive_status(); + if (cd->dsb & dsb_tray_not_closed) { + int i=0; + type_0_command(c_close_tray, 1); + while (i++<10 && cd->dsb & dsb_drive_not_ready) { + cm206_delay(100); + get_drive_status(); + } + } + if (cd->dsb & (dsb_not_useful)) return -EIO; + if (!(cd->dsb & dsb_disc_present)) return -ENODATA; + if (cd->dsb & dsb_possible_media_change) { + memset(cd->toc, 0, sizeof(cd->toc)); + memset(cd->audio_status, 0, sizeof(cd->audio_status)); + } + get_disc_status(); + type_0_command(c_lock_tray,1); + if (!(cd->dsb & dsb_tray_locked)) { + debug(("Couldn't lock tray\n")); + } +#if 0 + if (!(DISC_STATUS & cds_all_audio)) + read_background(16,0); /* do something useful */ +#endif + } + ++cd->openfiles; MOD_INC_USE_COUNT; + stats(open); + return 0; +} + +static void cm206_release(struct inode *ip, struct file *fp) +{ + if (cd->openfiles==1) { + if (cd->background) { + cd->background=0; + stop_read(); + } + type_0_command(c_unlock_tray,1); + cd->sector_last = -1; /* Make our internal buffer invalid */ + FIRST_TRACK = 0; /* No valid disc status */ + sync_dev(ip -> i_rdev); /* These two lines are stolen */ + invalidate_buffers(ip -> i_rdev); + } + --cd->openfiles; MOD_DEC_USE_COUNT; +} + +/* Empty buffer empties $sectors$ sectors of the adapter card buffer, + * and then reads a sector in kernel memory. */ +void empty_buffer(int sectors) +{ + while (sectors>=0) { + insw(r_fifo_output_buffer, cd->sector + cd->fifo_overflowed, + RAW_SECTOR_SIZE/2 - cd->fifo_overflowed); + --sectors; + ++cd->adapter_first; /* update the current adapter sector */ + cd->fifo_overflowed=0; /* reset overflow bit */ + stats(sector_transferred); + } + cd->sector_first=cd->adapter_first-1; + cd->sector_last=cd->adapter_first; /* update the buffer sector */ +} + +/* try_adapter. This function determines of the requested sector is is + in adapter memory, or will appear there soon. Returns 0 upon + success */ +int try_adapter(int sector) +{ + if (cd->adapter_first <= sector && sector < cd->adapter_last) { + /* sector is in adapter memory */ + empty_buffer(sector - cd->adapter_first); + return 0; + } + else if (cd->background==1 && cd->adapter_first <= sector + && sector < cd->adapter_first+cd->max_sectors) { + /* a read is going on, we can wait for it */ + cd->wait_back=1; + while (sector >= cd->adapter_last) { + if (sleep_or_timeout(&cd->data, DATA_TIMEOUT)) { + debug(("Timed out during background wait: %d %d %d %d\n", sector, + cd->adapter_last, cd->adapter_first, cd->background)); + stats(back_read_timeout); + cd->wait_back=0; + return -1; + } + } + cd->wait_back=0; + empty_buffer(sector - cd->adapter_first); + return 0; + } + else return -2; +} + +/* This is not a very smart implementation. We could optimize for + consecutive block numbers. I'm not conviced this would really + bring down the processor load. */ +static void do_cm206_request(void) +{ + long int i, cd_sec_no; + int quarter, error; + uch * source, * dest; + + while(1) { /* repeat until all requests have been satisfied */ + INIT_REQUEST; + if (CURRENT == NULL || CURRENT->dev == -1) return; + if (CURRENT->cmd != READ) { + debug(("Non-read command %d on cdrom\n", CURRENT->cmd)); + end_request(0); + continue; + } + error=0; + for (i=0; inr_sectors; i++) { + cd_sec_no = (CURRENT->sector+i)/4; /* 4 times 512 bytes */ + quarter = (CURRENT->sector+i) % 4; + dest = CURRENT->buffer + i*512; + /* is already in buffer memory? */ + if (cd->sector_first <= cd_sec_no && cd_sec_no < cd->sector_last) { + source = ((uch *) cd->sector) + 16 + + quarter*512 + (cd_sec_no-cd->sector_first)*RAW_SECTOR_SIZE; + memcpy(dest, source, 512); + } + else if (!try_adapter(cd_sec_no) || !read_sector(cd_sec_no)) { + source = ((uch *) cd->sector)+16+quarter*512; + memcpy(dest, source, 512); + } + else { + error=1; + } + } + end_request(!error); + } +} + +int get_multi_session_info(struct cdrom_multisession * mssp) +{ + if (!FIRST_TRACK) get_disc_status(); + if (mssp && DISC_STATUS & cds_multi_session) { /* multi-session */ + mssp->addr.lba = fsm2lba(&cd->disc_status[3]); + mssp->xa_flag = 1; /* don't know */ + mssp->addr_format = CDROM_LBA; /* too bad if fsm requested! */ + return 1; + } + return 0; +} + +/* Audio support. I've tried very hard, but the cm206 drive doesn't + seem to have a get_toc (table-of-contents) function, while i'm + pretty sure it must read the toc upon disc insertion. Therefore + this function has been implemented through a binary search + strategy. All track starts that happen to be found are stored in + cd->toc[], for future use. + + I've spent a whole day on a bug that only shows under Workman--- + I don't get it. Tried everything, nothing works. If workman asks + for track# 0xaa, it'll get the wrong time back. Any other program + receives the correct value. I'm stymied. +*/ + +/* seek seeks to address lba. It does wait to arrive there. */ +void seek(int lba) +{ + int i; + uch seek_command[4]={c_seek, }; + + fsm(lba, &seek_command[1]); + for (i=0; i<4; i++) type_0_command(seek_command[i], 0); + cd->dsb = wait_dsb(); +} + +uch bcdbin(unsigned char bcd) /* stolen from mcd.c! */ +{ + return (bcd >> 4)*10 + (bcd & 0xf); +} + +inline uch normalize_track(uch track) +{ + if (track<1) return 1; + if (track>LAST_TRACK) return LAST_TRACK+1; + return track; +} + +/* This function does a binary search for track start. It records all + * tracks seen in the process. Input $track$ must be between 1 and + * #-of-tracks+1 */ +int get_toc_lba(uch track) +{ + int max=74*60*75-150, min=0; + int i, lba, l, old_lba=0; + uch * q = cd->q; + uch ct; /* current track */ + int binary=0; + const skip = 3*60*75; + + for (i=track; i>0; i--) if (cd->toc[i].track) { + min = fsm2lba(cd->toc[i].fsm); + break; + } + lba = min + skip; /* 3 minutes */ + do { + seek(lba); + type_1_command(c_read_current_q, 10, q); + ct = normalize_track(q[1]); + if (!cd->toc[ct].track) { + l = q[9]-bcdbin(q[5]) + 75*(q[8]-bcdbin(q[4])-2 + + 60*(q[7]-bcdbin(q[3]))); + cd->toc[ct].track=q[1]; /* lead out still 0xaa */ + fsm(l, cd->toc[ct].fsm); + cd->toc[ct].q0 = q[0]; /* contains adr and ctrl info */ +/* + if (ct==LAST_TRACK+1) + printk("Leadout %x %x %x %x %d %d %d \n", q[1], q[3], q[4], q[5], + q[7], q[8], q[9]); +*/ + if (ct==track) return l; + } + old_lba=lba; + if (binary) { + if (ct < track) min = lba; else max = lba; + lba = (min+max)/2; + } else { + if(ct < track) lba += skip; + else { + binary=1; + max = lba; min = lba - skip; + lba = (min+max)/2; + } + } + } while (lba!=old_lba); + return lba; +} + +void update_toc_entry(uch track) +{ + track = normalize_track(track); + if (!cd->toc[track].track) get_toc_lba(track); +} + +int read_toc_header(struct cdrom_tochdr * hp) +{ + if (!FIRST_TRACK) get_disc_status(); + if (hp && DISC_STATUS & cds_all_audio) { /* all audio */ + int i; + hp->cdth_trk0 = FIRST_TRACK; + hp->cdth_trk1 = LAST_TRACK; + cd->toc[1].track=1; /* fill in first track position */ + for (i=0; i<3; i++) cd->toc[1].fsm[i] = cd->disc_status[3+i]; + update_toc_entry(LAST_TRACK+1); /* find most entries */ + return 1; + } + return 0; +} + +void play_from_to_msf(struct cdrom_msf* msfp) +{ + uch play_command[] = {c_play, + msfp->cdmsf_frame0, msfp->cdmsf_sec0, msfp->cdmsf_min0, + msfp->cdmsf_frame1, msfp->cdmsf_sec1, msfp->cdmsf_min1, 2, 2}; + int i; + for (i=0; i<9; i++) type_0_command(play_command[i], 0); + for (i=0; i<3; i++) + PLAY_TO.fsm[i] = play_command[i+4]; + PLAY_TO.track = 0; /* say no track end */ + cd->dsb = wait_dsb(); +} + +void play_from_to_track(int from, int to) +{ + uch play_command[8] = {c_play, }; + int i; + + if (from==0) { /* continue paused play */ + for (i=0; i<3; i++) { + play_command[i+1] = cd->audio_status[i+2]; + play_command[i+4] = PLAY_TO.fsm[i]; + } + } else { + update_toc_entry(from); update_toc_entry(to+1); + for (i=0; i<3; i++) { + play_command[i+1] = cd->toc[from].fsm[i]; + PLAY_TO.fsm[i] = play_command[i+4] = cd->toc[to+1].fsm[i]; + } + PLAY_TO.track = to; + } + for (i=0; i<7; i++) type_0_command(play_command[i],0); + for (i=0; i<2; i++) type_0_command(0x2, 0); /* volume */ + cd->dsb = wait_dsb(); +} + +int get_current_q(struct cdrom_subchnl * qp) +{ + int i; + uch * q = cd->q; + if (type_1_command(c_read_current_q, 10, q)) return 0; +/* q[0] = bcdbin(q[0]); Don't think so! */ + for (i=2; i<6; i++) q[i]=bcdbin(q[i]); + qp->cdsc_adr = q[0] & 0xf; qp->cdsc_ctrl = q[0] >> 4; /* from mcd.c */ + qp->cdsc_trk = q[1]; qp->cdsc_ind = q[2]; + if (qp->cdsc_format == CDROM_MSF) { + qp->cdsc_reladdr.msf.minute = q[3]; + qp->cdsc_reladdr.msf.second = q[4]; + qp->cdsc_reladdr.msf.frame = q[5]; + qp->cdsc_absaddr.msf.minute = q[7]; + qp->cdsc_absaddr.msf.second = q[8]; + qp->cdsc_absaddr.msf.frame = q[9]; + } else { + qp->cdsc_reladdr.lba = f_s_m2lba(q[5], q[4], q[3]); + qp->cdsc_absaddr.lba = f_s_m2lba(q[9], q[8], q[7]); + } + get_drive_status(); + if (cd->dsb & dsb_play_in_progress) + qp->cdsc_audiostatus = CDROM_AUDIO_PLAY ; + else if (PAUSED) + qp->cdsc_audiostatus = CDROM_AUDIO_PAUSED; + else qp->cdsc_audiostatus = CDROM_AUDIO_NO_STATUS; + return 1; +} + +void get_toc_entry(struct cdrom_tocentry * ep) +{ + uch track = normalize_track(ep->cdte_track); + update_toc_entry(track); + if (ep->cdte_format == CDROM_MSF) { + ep->cdte_addr.msf.frame = cd->toc[track].fsm[0]; + ep->cdte_addr.msf.second = cd->toc[track].fsm[1]; + ep->cdte_addr.msf.minute = cd->toc[track].fsm[2]; + } + else ep->cdte_addr.lba = fsm2lba(cd->toc[track].fsm); + ep->cdte_adr = cd->toc[track].q0 & 0xf; + ep->cdte_ctrl = cd->toc[track].q0 >> 4; + ep->cdte_datamode=0; +} + +/* Ioctl. I have made the statistics accessible through an ioctl + call. The constant is defined in cm206.h, it shouldn't clash with + the standard Linux ioctls. Multisession info is gathered at + run-time, this may turn out to be slow. */ + +static int cm206_ioctl(struct inode * inode, struct file * file, + unsigned int cmd, unsigned long arg) +{ + switch (cmd) { +#ifdef STATISTICS + case CM206CTL_GET_STAT: + if (arg >= NR_STATS) return -EINVAL; + else return cd->stats[arg]; + case CM206CTL_GET_LAST_STAT: + if (arg >= NR_STATS) return -EINVAL; + else return cd->last_stat[arg]; +#endif + case CDROMMULTISESSION: { + struct cdrom_multisession ms_info; + stats(ioctl_multisession); + if (get_multi_session_info(&ms_info)) { + memcpy_tofs((struct cdrom_multisession *) arg, &ms_info, + sizeof(struct cdrom_multisession)); + return 0; + } + else return -cmd; + } + case CM206_RESET_DRIVE: + stop_read(); + reset_cm260(); + outw(dc_normal | dc_break | READ_AHEAD, r_data_control); + udelay(1000); /* 750 musec minimum */ + outw(dc_normal | READ_AHEAD, r_data_control); + cd->sector_last = -1; /* flag no data buffered */ + cd->adapter_last = -1; + return 0; + } + get_drive_status(); + if (cd->dsb & (dsb_drive_not_ready | dsb_tray_not_closed) ) + return -EAGAIN; + switch (cmd) { + case CDROMREADTOCHDR: { + struct cdrom_tochdr header; + get_drive_status(); + if (cd->dsb & (dsb_drive_not_ready | dsb_tray_not_closed) ) + return -EAGAIN; + if (read_toc_header(&header)) { + memcpy_tofs((struct cdrom_tochdr *) arg, &header, sizeof(header)); + return 0; + } + else return -ENODATA; + } + case CDROMREADTOCENTRY: { + struct cdrom_tocentry entry; + memcpy_fromfs(&entry, (struct cdrom_tocentry *) arg, sizeof entry); + get_toc_entry(&entry); + memcpy_tofs((struct cdrom_tocentry *) arg, &entry, sizeof entry); + return 0; + } + case CDROMPLAYMSF: { + struct cdrom_msf msf; + memcpy_fromfs(&msf, (struct cdrom_mdf *) arg, sizeof msf); + play_from_to_msf(&msf); + return 0; + } + case CDROMPLAYTRKIND: { + struct cdrom_ti track_index; + memcpy_fromfs(&track_index, (struct cdrom_ti *) arg, sizeof(track_index)); + play_from_to_track(track_index.cdti_trk0, track_index.cdti_trk1); + return 0; + } + case CDROMSTOP: + PAUSED=0; + if (cd->dsb & dsb_play_in_progress) return type_0_command(c_stop, 1); + return 0; + case CDROMPAUSE: + if (cd->dsb & dsb_play_in_progress) { + type_0_command(c_stop, 1); + type_1_command(c_audio_status, 5, cd->audio_status); + PAUSED=1; /* say we're paused */ + } + return 0; + case CDROMRESUME: + if (PAUSED) play_from_to_track(0,0); + PAUSED=0; + return 0; + case CDROMEJECT: + PAUSED=0; + if (cd->openfiles == 1) { /* Must do an open before an eject! */ + type_0_command(c_open_tray,1); + memset(cd->toc, 0, sizeof(cd->toc)); + memset(cd->disc_status, 0, sizeof(cd->disc_status)); + return 0; + } + else return -EBUSY; + case CDROMSTART: + case CDROMVOLCTRL: + return 0; + case CDROMSUBCHNL: { + struct cdrom_subchnl q; + memcpy_fromfs(&q, (struct cdrom_subchnl *) arg, sizeof q); + if (get_current_q(&q)) { + memcpy_tofs((struct cdrom_subchnl *) arg, &q, sizeof q); + return 0; + } + else return -cmd; + } + case CDROM_GET_UPC: { + uch upc[10]; + if (type_1_command(c_read_upc, 10, upc)) return -EIO; + memcpy_tofs((uch *) arg, &upc[1], 8); + return 0; + } + default: + debug(("Unknown ioctl call 0x%x\n", cmd)); + return -EINVAL; + } +} + +/* from lmscd.c */ +static struct file_operations cm206_fops = { + NULL, /* lseek */ + block_read, /* read - general block-dev read */ + block_write, /* write - general block-dev write */ + NULL, /* readdir */ + NULL, /* select */ + cm206_ioctl, /* ioctl */ + NULL, /* mmap */ + cm206_open, /* open */ + cm206_release, /* release */ + NULL, /* fsync */ + NULL, /* fasync */ + NULL, /* media_change */ + NULL /* revalidate */ +}; + +/* This routine gets called during init if thing go wrong, can be used + * in cleanup_module as well. */ +void cleanup(int level) +{ + switch (level) { + case 4: + if (unregister_blkdev(MAJOR_NR, "cm206")) { + printk("Can't unregister cm206\n"); + return; + } + case 3: + free_irq(cm206_irq); + case 2: + case 1: +#ifdef MODULE + kfree(cd); +#endif + release_region(cm206_base, 16); + default: + } +} + +/* This function probes for the adapter card. It returns the base + address if it has found the adapter card. One can specify a base + port to probe specifically, or 0 which means span all possible + bases. + + Linus says it is too dangerous to use writes for probing, so we + stick with pure reads for a while. Hope that 8 possible ranges, + check_region, 15 bits of one port and 6 of another make things + likely enough to accept the region on the first hit... + */ +int probe_base_port(int base) +{ + int b=0x300, e=0x370; /* this is the range of start addresses */ + volatile int fool; +#if 0 + const pattern1=0x65, pattern2=0x1a; +#endif + + if (base) b=e=base; + for (base=b; base<=e; base += 0x10) { + if (check_region(base, 0x10)) continue; + fool = inw(base+2); /* empty possibly uart_receive_buffer */ + if((inw(base+6) & 0xffef) != 0x0001 || /* line_status */ + (inw(base) & 0xad00) != 0) /* data status */ + continue; +#if 0 /* writes... dangerous... */ + outw(dc_normal | pattern1, base+8); + if ((inw(base) & 0x7f) != pattern1) continue; + outw(dc_normal | pattern2, base+8); + if ((inw(base) & 0x7f) != pattern2) continue; + outw(dc_normal | READ_AHEAD, base+8); +#endif + return(base); + } + return 0; +} + +#if !defined(MODULE) || defined(AUTO_PROBE_MODULE) +/* Probe for irq# nr. If nr==0, probe for all possible irq's. */ +int probe_irq(int nr) { + int irqs, irq; + outw(dc_normal | READ_AHEAD, r_data_control); /* disable irq-generation */ + sti(); + irqs = probe_irq_on(); + reset_cm260(); /* causes interrupt */ + udelay(10); /* wait for it */ + irq = probe_irq_off(irqs); + outw(dc_normal | READ_AHEAD, r_data_control); /* services interrupt */ + if (nr && irq!=nr && irq>0) return 0; /* wrong interrupt happened */ + else return irq; +} +#endif + +/* Wow is this piece of #ifdeffing ugly! */ +#ifdef MODULE +#define OK 0 +#define ERROR -EIO +int init_module(void) +#else +#define OK mem_start+size +#define ERROR mem_start +unsigned long cm206_init(unsigned long mem_start, unsigned long mem_end) +#endif +{ + uch e=0; + long int size=sizeof(struct cm206_struct); + + printk("cm206: v" VERSION); +#if defined(MODULE) && !defined(AUTO_PROBE_MODULE) + auto_probe=0; +#endif + cm206_base = probe_base_port(auto_probe ? 0 : cm206_base); + if (!cm206_base) { + printk(" can't find adapter!\n"); + return ERROR; + } + printk(" adapter at 0x%x", cm206_base); + request_region(cm206_base, 16, "cm206"); +#ifdef MODULE + cd = (struct cm206_struct *) kmalloc(size, GFP_KERNEL); + if (!cd) return ERROR; +#else + cd = (struct cm206_struct *) mem_start; +#endif + /* Now we have found the adaptor card, try to reset it. As we have + * found out earlier, this process generates an interrupt as well, + * so we might just exploit that fact for irq probing! */ +#if !defined(MODULE) || defined(AUTO_PROBE_MODULE) + cm206_irq = probe_irq(auto_probe ? 0 : cm206_irq); + if (cm206_irq<=0) { + printk("can't find IRQ!\n"); + cleanup(1); + return ERROR; + } + else printk(" IRQ %d found\n", cm206_irq); +#else + reset_cm260(); + printk(" using IRQ %d\n", cm206_irq); +#endif + if (send_receive_polled(c_drive_configuration) != c_drive_configuration) + { + printk(" drive not there\n"); + cleanup(1); + return ERROR; + } + e = send_receive_polled(c_gimme); + printk("Firmware revision %d", e & dcf_revision_code); + if (e & dcf_transfer_rate) printk(" double"); + else printk(" single"); + printk(" speed drive"); + if (e & dcf_motorized_tray) printk(", motorized tray"); + if (request_irq(cm206_irq, cm206_interrupt, 0, "cm206")) { + printk("\nUnable to reserve IRQ---aborted\n"); + cleanup(2); + return ERROR; + } + printk(".\n"); + if (register_blkdev(MAJOR_NR, "cm206", &cm206_fops) != 0) { + printk("Cannot register for major %d!\n", MAJOR_NR); + cleanup(3); + return ERROR; + } + blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST; + read_ahead[MAJOR_NR] = 16; /* reads ahead what? */ + bh_base[CM206_BH].routine = cm206_bh; + enable_bh(CM206_BH); + + memset(cd, 0, sizeof(*cd)); /* give'm some reasonable value */ + cd->sector_last = -1; /* flag no data buffered */ + cd->adapter_last = -1; + cd->timer.function = cm206_timeout; + cd->max_sectors = (inw(r_data_status) & ds_ram_size) ? 24 : 97; + printk("%d kB adapter memory available, " + " %ld bytes kernel memory used.\n", cd->max_sectors*2, size); + return OK; +} +#undef OK +#undef ERROR + +#ifdef MODULE +void cleanup_module(void) +{ + cleanup(4); + printk("cm206 removed\n"); +} + +#else MODULE + +/* This setup function accepts either `auto' or numbers in the range + * 3--11 (for irq) or 0x300--0x370 (for base port) or both. */ +void cm206_setup(char *s, int *p) +{ + int i; +#ifdef AUTO_PROBE_MODULE + if (!strcmp(s, "auto")) auto_probe=1; +#endif + for(i=1; i<=p[0]; i++) { + if (0x300 <= p[i] && i<= 0x370 && p[i] % 0x10 == 0) { + cm206_base = p[i]; + auto_probe = 0; + } + else if (3 <= p[i] && p[i] <= 15) { + cm206_irq = p[i]; + auto_probe = 0; + } + } +} +#endif MODULE diff -u --recursive --new-file v1.3.6/linux/drivers/block/genhd.c linux/drivers/block/genhd.c --- v1.3.6/linux/drivers/block/genhd.c Fri May 26 08:23:33 1995 +++ linux/drivers/block/genhd.c Wed Jul 5 12:53:22 1995 @@ -35,6 +35,8 @@ printk(" %s%c%d", hd->major_name, minor_name(hd, minor), minor & ((1 << hd->minor_shift) - 1)); } + +#ifdef CONFIG_MSDOS_PARTITION /* * Create devices for each logical partition in an extended partition. * The logical partitions form a linked list, with each entry being @@ -101,15 +103,131 @@ brelse(bh); } -static void check_partition(struct gendisk *hd, unsigned int dev) +static int msdos_partition(struct gendisk *hd, unsigned int dev, unsigned long first_sector) { - static int first_time = 1; int i, minor = current_minor; struct buffer_head *bh; struct partition *p; - unsigned long first_sector; int mask = (1 << hd->minor_shift) - 1; + if (!(bh = bread(dev,0,1024))) { + printk("unable to read partition table\n"); + return -1; + } + if (*(unsigned short *) (bh->b_data+510) != 0xAA55) { + brelse(bh); + return 0; + } + current_minor += 4; /* first "extra" minor (for extended partitions) */ + p = (struct partition *) (0x1BE + bh->b_data); + for (i=1 ; i<=4 ; minor++,i++,p++) { + if (!p->nr_sects) + continue; + add_partition(hd, minor, first_sector+p->start_sect, p->nr_sects); + if ((current_minor & 0x3f) >= 60) + continue; + if (p->sys_ind == EXTENDED_PARTITION) { + printk(" <"); + extended_partition(hd, (hd->major << 8) | minor); + printk(" >"); + } + } + /* + * check for Disk Manager partition table + */ + if (*(unsigned short *) (bh->b_data+0xfc) == 0x55AA) { + p = (struct partition *) (0x1BE + bh->b_data); + for (i = 4 ; i < 16 ; i++, current_minor++) { + p--; + if ((current_minor & mask) >= mask-2) + break; + if (!(p->start_sect && p->nr_sects)) + continue; + add_partition(hd, current_minor, p->start_sect, p->nr_sects); + } + } + printk("\n"); + brelse(bh); + return 1; +} + +#endif /* CONFIG_MSDOS_PARTITION */ + +#ifdef CONFIG_OSF_PARTITION + +static int osf_partition(struct gendisk *hd, unsigned int dev, unsigned long first_sector) +{ + int i; + struct buffer_head *bh; + struct disklabel { + u32 d_magic; + u16 d_type,d_subtype; + u8 d_typename[16]; + u8 d_packname[16]; + u32 d_secsize; + u32 d_nsectors; + u32 d_ntracks; + u32 d_ncylinders; + u32 d_secpercyl; + u32 d_secprtunit; + u16 d_sparespertrack; + u16 d_sparespercyl; + u32 d_acylinders; + u16 d_rpm, d_interleave, d_trackskew, d_cylskew; + u32 d_headswitch, d_trkseek, d_flags; + u32 d_drivedata[5]; + u32 d_spare[5]; + u32 d_magic2; + u16 d_checksum; + u16 d_npartitions; + u32 d_bbsize, d_sbsize; + struct d_partition { + u32 p_size; + u32 p_offset; + u32 p_fsize; + u8 p_fstype; + u8 p_frag; + u16 p_cpg; + } d_partitions[8]; + } * label; + struct d_partition * partition; +#define DISKLABELMAGIC (0x82564557UL) + + if (!(bh = bread(dev,0,1024))) { + printk("unable to read partition table\n"); + return -1; + } + label = (struct disklabel *) (bh->b_data+64); + partition = label->d_partitions; + if (label->d_magic != DISKLABELMAGIC) { + printk("magic: %08x\n", label->d_magic); + brelse(bh); + return 0; + } + if (label->d_magic2 != DISKLABELMAGIC) { + printk("magic2: %08x\n", label->d_magic2); + brelse(bh); + return 0; + } + for (i = 0 ; i < label->d_npartitions; i++, partition++) { + if (partition->p_size) + add_partition(hd, current_minor, + first_sector+partition->p_offset, + partition->p_size); + current_minor++; + } + printk("\n"); + brelse(bh); + return 1; +} + +#endif /* CONFIG_OSF_PARTITION */ + +static void check_partition(struct gendisk *hd, unsigned int dev) +{ + static int first_time = 1; + unsigned long first_sector; + if (first_time) printk("Partition check:\n"); first_time = 0; @@ -124,44 +242,16 @@ return; } - if (!(bh = bread(dev,0,1024))) { - printk(" unable to read partition table of device %04x\n",dev); + printk(" %s%c:", hd->major_name, minor_name(hd, MINOR(dev))); +#ifdef CONFIG_MSDOS_PARTITION + if (msdos_partition(hd, dev, first_sector)) return; - } - printk(" %s%c:", hd->major_name, minor_name(hd, minor)); - current_minor += 4; /* first "extra" minor (for extended partitions) */ - if (*(unsigned short *) (bh->b_data+510) == 0xAA55) { - p = (struct partition *) (0x1BE + bh->b_data); - for (i=1 ; i<=4 ; minor++,i++,p++) { - if (!p->nr_sects) - continue; - add_partition(hd, minor, first_sector+p->start_sect, p->nr_sects); - if ((current_minor & 0x3f) >= 60) - continue; - if (p->sys_ind == EXTENDED_PARTITION) { - printk(" <"); - extended_partition(hd, (hd->major << 8) | minor); - printk(" >"); - } - } - /* - * check for Disk Manager partition table - */ - if (*(unsigned short *) (bh->b_data+0xfc) == 0x55AA) { - p = (struct partition *) (0x1BE + bh->b_data); - for (i = 4 ; i < 16 ; i++, current_minor++) { - p--; - if ((current_minor & mask) >= mask-2) - break; - if (!(p->start_sect && p->nr_sects)) - continue; - add_partition(hd, current_minor, p->start_sect, p->nr_sects); - } - } - } else - printk(" bad partition table"); - printk("\n"); - brelse(bh); +#endif +#ifdef CONFIG_OSF_PARTITION + if (osf_partition(hd, dev, first_sector)) + return; +#endif + printk("unknown partition table\n"); } /* This function is used to re-read partition tables for removable disks. diff -u --recursive --new-file v1.3.6/linux/drivers/block/gscd.c linux/drivers/block/gscd.c --- v1.3.6/linux/drivers/block/gscd.c Thu Jan 1 02:00:00 1970 +++ linux/drivers/block/gscd.c Sat Jul 1 19:05:59 1995 @@ -0,0 +1,1129 @@ +#define GSCD_VERSION "0.4a Oliver Raupach " + +/* + linux/drivers/block/gscd.c - GoldStar R420 CDROM driver + + Copyright (C) 1995 Oliver Raupach + based upon pre-works by Eberhard Moenkeberg + + + For all kind of other information about the GoldStar CDROM + and this Linux device driver I installed a WWW-URL: + http://linux.rz.fh-hannover.de/~raupach + + + If you are the editor of a Linux CD, you should + enable gscd.c within your boot floppy kernel and + send me one of your CDs for free. + + + -------------------------------------------------------------------- + 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. + +*/ + +/* These settings are for various debug-level. Leave they untouched ... */ +#define NO_GSCD_DEBUG +#define NO_IOCTL_DEBUG +#define NO_MODULE_DEBUG +#define NO_FUTURE_WORK +/*------------------------*/ + +#include + +#ifdef MODULE +#include +#include +#include +#ifndef CONFIG_MODVERSIONS +char kernel_version[] = UTS_RELEASE; +#endif +#endif MODULE + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#define MAJOR_NR GOLDSTAR_CDROM_MAJOR +#include "blk.h" +#define gscd_port gscd /* for compatible parameter passing with "insmod" */ +#include + + +static int gscdPresent = 0; + +static unsigned char gscd_buf[2048]; /* buffer for block size conversion */ +static int gscd_bn = -1; +static short gscd_port = GSCD_BASE_ADDR; + +/* Kommt spaeter vielleicht noch mal dran ... + * static struct wait_queue *gscd_waitq = NULL; + */ + +static void gscd_transfer (void); +static void gscd_read_cmd (void); +static void gscd_hsg2msf (long hsg, struct msf *msf); +static void gscd_bin2bcd (unsigned char *p); + +/* Schnittstellen zum Kern/FS */ + +static void do_gscd_request (void); +static int gscd_ioctl (struct inode *, struct file *, unsigned int, unsigned long); +static int gscd_open (struct inode *, struct file *); +static void gscd_release (struct inode *, struct file *); +static int check_gscd_med_chg (dev_t); + +/* GoldStar Funktionen */ + +static void cc_Reset (void); +static int wait_drv_ready (void); +static int find_drives (void); +static void cmd_out (int, char *, char *, int); +static void cmd_status (void); +static void cc_Ident (char *); +static void cc_SetSpeed (void); +static void init_cd_drive (int); + +static int get_status (void); +static void clear_Audio (void); +static void cc_invalidate (void); + +/* some things for the next version */ +#ifdef FUTURE_WORK +static void update_state (void); +static long gscd_msf2hsg (struct msf *mp); +static int gscd_bcd2bin (unsigned char bcd); +#endif + +/* common GoldStar Initialization */ + +static long my_gscd_init (unsigned long , unsigned long); + + +/* lo-level cmd-Funktionen */ + +static void cmd_info_in ( char *, int ); +static void cmd_end ( void ); +static void cmd_read_b ( char *, int, int ); +static void cmd_read_w ( char *, int, int ); +static int cmd_unit_alive ( void ); +static void cmd_write_cmd ( char * ); + + +/* GoldStar Variablen */ + +static int curr_drv_state; +static int drv_states[] = {0,0,0,0,0,0,0,0}; +static int drv_mode; +static int disk_state; +static int speed; +static int ndrives; + +static unsigned char drv_num_read; +static unsigned char f_dsk_valid; +static unsigned char current_drive; +static unsigned char f_drv_ok; + + +static char f_AudioPlay; +static char f_AudioPause; +static int AudioStart_m; +static int AudioStart_f; +static int AudioEnd_m; +static int AudioEnd_f; + + +static struct file_operations gscd_fops = { + NULL, /* lseek - default */ + block_read, /* read - general block-dev read */ + block_write, /* write - general block-dev write */ + NULL, /* readdir - bad */ + NULL, /* select */ + gscd_ioctl, /* ioctl */ + NULL, /* mmap */ + gscd_open, /* open */ + gscd_release, /* release */ + NULL, /* fsync */ + NULL, /* fasync*/ + check_gscd_med_chg, /* media change */ + NULL /* revalidate */ +}; + +/* + * Checking if the media has been changed + * (not yet implemented) + */ +static int check_gscd_med_chg (dev_t full_dev) +{ + int target; + + + target = MINOR(full_dev); + + if (target > 0) + { + printk("GSCD: GoldStar CD-ROM request error: invalid device.\n"); + return 0; + } + + #ifdef GSCD_DEBUG + printk ("gscd: check_med_change\n"); + #endif + + return 0; +} + + +void gscd_setup (char *str, int *ints) +{ + if (ints[0] > 0) + { + gscd_port = ints[1]; + } +} + + +static int gscd_ioctl (struct inode *ip, struct file *fp, unsigned int cmd, unsigned long arg) +{ +unsigned char to_do[10]; +unsigned char dummy; + + + switch (cmd) + { + case CDROMSTART: /* Spin up the drive */ + /* Don't think we can do this. Even if we could, + * I think the drive times out and stops after a while + * anyway. For now, ignore it. + */ + return 0; + + case CDROMRESUME: /* keine Ahnung was das ist */ + return 0; + + + case CDROMEJECT: + cmd_status (); + to_do[0] = CMD_TRAY_CTL; + cmd_out (TYPE_INFO, (char *)&to_do, (char *)&dummy, 0); + + return 0; + + default: + return -EINVAL; + } + +} + + +/* + * Take care of the different block sizes between cdrom and Linux. + * When Linux gets variable block sizes this will probably go away. + */ + +static void gscd_transfer (void) +{ +long offs; + + while (CURRENT -> nr_sectors > 0 && gscd_bn == CURRENT -> sector / 4) + { + offs = (CURRENT -> sector & 3) * 512; + memcpy(CURRENT -> buffer, gscd_buf + offs, 512); + CURRENT -> nr_sectors--; + CURRENT -> sector++; + CURRENT -> buffer += 512; + } +} + + +/* + * I/O request routine called from Linux kernel. + */ + +static void do_gscd_request (void) +{ +unsigned int block,dev; +unsigned int nsect; + +repeat: + if (!(CURRENT) || CURRENT->dev < 0) return; + INIT_REQUEST; + dev = MINOR(CURRENT->dev); + block = CURRENT->sector; + nsect = CURRENT->nr_sectors; + + if (CURRENT == NULL || CURRENT -> sector == -1) + return; + + if (CURRENT -> cmd != READ) + { + printk("GSCD: bad cmd %d\n", CURRENT -> cmd); + end_request(0); + goto repeat; + } + + if (MINOR(CURRENT -> dev) != 0) + { + printk("GSCD: this version supports only one device\n"); + end_request(0); + goto repeat; + } + + gscd_transfer(); + + /* if we satisfied the request from the buffer, we're done. */ + + if (CURRENT -> nr_sectors == 0) + { + end_request(1); + goto repeat; + } + +#ifdef GSCD_DEBUG + printk ("GSCD: dev %d, block %d, nsect %d\n", dev, block, nsect ); +#endif + + gscd_read_cmd (); +} + + + +/* + * Check the result of the set-mode command. On success, send the + * read-data command. + */ + +static void +gscd_read_cmd (void) +{ +long block; +struct gscd_Play_msf gscdcmd; +char cmd[] = { CMD_READ, 0x80, 0,0,0, 0,1 }; /* cmd mode M-S-F secth sectl */ + + + + cmd_status (); + if ( disk_state & (ST_NO_DISK | ST_DOOR_OPEN) ) + { + printk ( "GSCD: no disk or door open\n" ); + end_request (0); + } + else + { + if ( disk_state & ST_INVALID ) + { + printk ( "GSCD: disk invalid\n" ); + end_request (0); + } + else + { + gscd_bn = -1; /* purge our buffer */ + block = CURRENT -> sector / 4; + gscd_hsg2msf(block, &gscdcmd.start); /* cvt to msf format */ + + cmd[2] = gscdcmd.start.min; + cmd[3] = gscdcmd.start.sec; + cmd[4] = gscdcmd.start.frame; + +#ifdef GSCD_DEBUG + printk ("GSCD: read msf %d:%d:%d\n", cmd[2], cmd[3], cmd[4] ); +#endif + cmd_out ( TYPE_DATA, (char *)&cmd, (char *)&gscd_buf[0], 1 ); + + gscd_bn = CURRENT -> sector / 4; + gscd_transfer(); + end_request(1); + } + } + SET_TIMER(do_gscd_request, 1); +} + + +/* + * Open the device special file. Check that a disk is in. + */ + +static int gscd_open (struct inode *ip, struct file *fp) +{ +int st; + +#ifdef GSCD_DEBUG +printk ( "GSCD: open\n" ); +#endif + + if (gscdPresent == 0) + return -ENXIO; /* no hardware */ + + get_status (); + st = disk_state & (ST_NO_DISK | ST_DOOR_OPEN); + if ( st ) + { + printk ( "GSCD: no disk or door open\n" ); + return -ENXIO; + } + +/* if (updateToc() < 0) + return -EIO; +*/ + + #ifdef MODULE + MOD_INC_USE_COUNT; + #endif + + return 0; +} + + +/* + * On close, we flush all gscd blocks from the buffer cache. + */ + +static void gscd_release (struct inode * inode, struct file * file) +{ + +#ifdef GSCD_DEBUG +printk ( "GSCD: release\n" ); +#endif + + gscd_bn = -1; + sync_dev(inode->i_rdev); + invalidate_buffers(inode -> i_rdev); + + #ifdef MODULE + MOD_DEC_USE_COUNT; + #endif +} + + +int get_status (void) +{ +int status; + + cmd_status (); + status = disk_state & (ST_x08 | ST_x04 | ST_INVALID | ST_x01); + + if ( status == (ST_x08 | ST_x04 | ST_INVALID | ST_x01) ) + { + cc_invalidate (); + return 1; + } + else + { + return 0; + } +} + + +void cc_invalidate (void) +{ + drv_num_read = 0xFF; + f_dsk_valid = 0xFF; + current_drive = 0xFF; + f_drv_ok = 0xFF; + + clear_Audio (); + +} + +void clear_Audio (void) +{ + + f_AudioPlay = 0; + f_AudioPause = 0; + AudioStart_m = 0; + AudioStart_f = 0; + AudioEnd_m = 0; + AudioEnd_f = 0; + +} + +/* + * waiting ? + */ + +int wait_drv_ready (void) +{ +int found, read; + + do + { + found = inb ( GSCDPORT(0) ); + found &= 0x0f; + read = inb ( GSCDPORT(0) ); + read &= 0x0f; + } while ( read != found ); + +#ifdef GSCD_DEBUG +printk ( "Wait for: %d\n", read ); +#endif + + return read; +} + +void cc_Ident (char * respons) +{ +char to_do [] = {CMD_IDENT, 0, 0}; + + cmd_out (TYPE_INFO, (char *)&to_do, (char *)respons, (int)0x1E ); + +} + +void cc_SetSpeed (void) +{ +char to_do [] = {CMD_SETSPEED, 0, 0}; +char dummy; + + if ( speed > 0 ) + { + to_do[1] = speed & 0x0F; + cmd_out (TYPE_INFO, (char *)&to_do, (char *)&dummy, 0); + } +} + + +void cc_Reset (void) +{ +char to_do [] = {CMD_RESET, 0}; +char dummy; + + cmd_out (TYPE_INFO, (char *)&to_do, (char *)&dummy, 0); +} + + + +void cmd_status (void) +{ +char to_do [] = {CMD_STATUS, 0}; +char dummy; + + cmd_out (TYPE_INFO, (char *)&to_do, (char *)&dummy, 0); + +#ifdef GSCD_DEBUG +printk ("GSCD: Status: %d\n", disk_state ); +#endif + +} + +void cmd_out ( int cmd_type, char * cmd, char * respo_buf, int respo_count ) +{ +int result; + + + result = wait_drv_ready (); + if ( result != drv_mode ) + { + unsigned long test_loops = 0xFFFF; + int i,dummy; + + outb ( curr_drv_state, GSCDPORT(0)); + + /* LOCLOOP_170 */ + do + { + result = wait_drv_ready (); + test_loops--; + } while ( (result != drv_mode) && (test_loops > 0) ); + + if ( result != drv_mode ) + { + disk_state = ST_x08 | ST_x04 | ST_INVALID; + return; + } + + /* ...and waiting */ + for ( i=1,dummy=1 ; i<0xFFFF ; i++ ) + { + dummy *= i; + } + } + + /* LOC_172 */ + /* check the unit */ + /* and wake it up */ + if ( cmd_unit_alive () != 0x08 ) + { + /* LOC_174 */ + /* game over for this unit */ + disk_state = ST_x08 | ST_x04 | ST_INVALID; + return; + } + + /* LOC_176 */ + #ifdef GSCD_DEBUG + printk ("LOC_176 "); + #endif + if ( drv_mode == 0x09 ) + { + /* magic... */ + printk ("GSCD: magic ...\n"); + outb ( result, GSCDPORT(2)); + } + + /* write the command to the drive */ + cmd_write_cmd (cmd); + + /* LOC_178 */ + for (;;) + { + result = wait_drv_ready (); + if ( result != drv_mode ) + { + /* LOC_179 */ + if ( result == 0x04 ) /* Mode 4 */ + { + /* LOC_205 */ + #ifdef GSCD_DEBUG + printk ("LOC_205 "); + #endif + disk_state = inb ( GSCDPORT (2)); + + do + { + result = wait_drv_ready (); + } while ( result != drv_mode ); + return; + + } + else + { + if ( result == 0x06 ) /* Mode 6 */ + { + /* LOC_181 */ + #ifdef GSCD_DEBUG + printk ("LOC_181 "); + #endif + + if (cmd_type == TYPE_DATA) + { + /* read data */ + /* LOC_184 */ + if ( drv_mode == 9 ) + { + /* read the data to the buffer (word) */ + + /* (*(cmd+1))?(CD_FRAMESIZE/2):(CD_FRAMESIZE_RAW/2) */ + cmd_read_w ( respo_buf, respo_count, CD_FRAMESIZE/2 ); + return; + } + else + { + /* read the data to the buffer (byte) */ + + /* (*(cmd+1))?(CD_FRAMESIZE):(CD_FRAMESIZE_RAW) */ + cmd_read_b ( respo_buf, respo_count, CD_FRAMESIZE ); + return; + } + } + else + { + /* read the info to the buffer */ + cmd_info_in ( respo_buf, respo_count ); + return; + } + + return; + } + } + + } + else + { + disk_state = ST_x08 | ST_x04 | ST_INVALID; + return; + } + } /* for (;;) */ + + +#ifdef GSCD_DEBUG +printk ("\n"); +#endif +} + + +static void cmd_write_cmd ( char *pstr ) +{ +int i,j; + + /* LOC_177 */ + #ifdef GSCD_DEBUG + printk ("LOC_177 "); + #endif + + /* calculate the number of parameter */ + j = *pstr & 0x0F; + + /* shift it out */ + for ( i=0 ; i 0) ); + + return result; +} + + +static void cmd_info_in ( char *pb, int count ) +{ +int result; +char read; + + + /* read info */ + /* LOC_182 */ + #ifdef GSCD_DEBUG + printk ("LOC_182 "); + #endif + + do + { + read = inb (GSCDPORT(2)); + if ( count > 0 ) + { + *pb = read; + pb++; + count--; + } + + /* LOC_183 */ + do + { + result = wait_drv_ready (); + } while ( result == 0x0E ); + } while ( result == 6 ); + + cmd_end (); + return; +} + + +static void cmd_read_b ( char *pb, int count, int size ) +{ +int result; +int i; + + + /* LOC_188 */ + /* LOC_189 */ + #ifdef GSCD_DEBUG + printk ("LOC_189 "); + #endif + + do + { + do + { + result = wait_drv_ready (); + } while ( result != 6 || result == 0x0E ); + + if ( result != 6 ) + { + cmd_end (); + return; + } + + #ifdef GSCD_DEBUG + printk ("LOC_191 "); + #endif + + for ( i=0 ; i< size ; i++ ) + { + *pb = inb (GSCDPORT(2)); + pb++; + } + count--; + } while ( count > 0 ); + + cmd_end (); + return; +} + + +static void cmd_end (void) +{ +int result; + + + /* LOC_204 */ + #ifdef GSCD_DEBUG + printk ("LOC_204 "); + #endif + + do + { + result = wait_drv_ready (); + if ( result == drv_mode ) + { + return; + } + } while ( result != 4 ); + + /* LOC_205 */ + #ifdef GSCD_DEBUG + printk ("LOC_205 "); + #endif + + disk_state = inb ( GSCDPORT (2)); + + do + { + result = wait_drv_ready (); + } while ( result != drv_mode ); + return; + +} + + +static void cmd_read_w ( char *pb, int count, int size ) +{ +int result; +int i; + + + #ifdef GSCD_DEBUG + printk ("LOC_185 "); + #endif + + do + { + /* LOC_185 */ + do + { + result = wait_drv_ready (); + } while ( result != 6 || result == 0x0E ); + + if ( result != 6 ) + { + cmd_end (); + return; + } + + for ( i=0 ; i 0 ); + + cmd_end (); + return; +} + +int find_drives (void) +{ +int *pdrv; +int drvnum; +int subdrv; +int i; + + speed = 0; + pdrv = (int *)&drv_states; + curr_drv_state = 0xFE; + subdrv = 0; + drvnum = 0; + + for ( i=0 ; i<8 ; i++ ) + { + subdrv++; + cmd_status (); + disk_state &= ST_x08 | ST_x04 | ST_INVALID | ST_x01; + if ( disk_state != (ST_x08 | ST_x04 | ST_INVALID) ) + { + /* LOC_240 */ + *pdrv = curr_drv_state; + init_cd_drive (drvnum); + pdrv++; + drvnum++; + } + else + { + if ( subdrv < 2 ) + { + continue; + } + else + { + subdrv = 0; + } + } + +/* curr_drv_state<<1; <-- das geht irgendwie nicht */ +/* muss heissen: curr_drv_state <<= 1; (ist ja Wert-Zuweisung) */ + curr_drv_state *= 2; + curr_drv_state |= 1; +#ifdef GSCD_DEBUG + printk ("DriveState: %d\n", curr_drv_state ); +#endif + } + + ndrives = drvnum; + return drvnum; +} + +void init_cd_drive ( int num ) +{ +char resp [50]; +int i; + + printk ("GSCD: init unit %d\n", num ); + cc_Ident ((char *)&resp); + + printk ("GSCD: identification: "); + for ( i=0 ; i<0x1E; i++ ) + { + printk ( "%c", resp[i] ); + } + printk ("\n"); + + cc_SetSpeed (); + +} + +#ifdef FUTURE_WORK +/* return_done */ +static void update_state ( void ) +{ +unsigned int AX; + + + if ( (disk_state & (ST_x08 | ST_x04 | ST_INVALID | ST_x01)) == 0 ) + { + if ( disk_state == (ST_x08 | ST_x04 | ST_INVALID)) + { + AX = ST_INVALID; + } + + if ( (disk_state & (ST_x08 | ST_x04 | ST_INVALID | ST_x01)) == 0 ) + { + invalidate (); + f_drv_ok = 0; + } + + AX |= 0x8000; + } + + if ( disk_state & ST_PLAYING ) + { + AX |= 0x200; + } + + AX |= 0x100; + /* pkt_esbx = AX; */ + + disk_state = 0; + +} +#endif + +/* Init for the Module-Version */ +int init_module (void) +{ +long err; + + + /* call the GoldStar-init with dummys */ + err = my_gscd_init ( 10, 20 ); + + if ( err < 0 ) + { + return -EIO; + } + else + { + printk ( "Happy GoldStar !\n" ); + return 0; + } +} + +#ifdef MODULE +void cleanup_module (void) +{ + + if (MOD_IN_USE) + { + printk("GoldStar-module in use - can't remove it.\n" ); + return; + } + + if ((unregister_blkdev(MAJOR_NR, "gscd" ) == -EINVAL)) + { + printk("What's that: can't unregister GoldStar-module\n" ); + return; + } + + release_region (gscd_port,4); + printk( "GoldStar-module released.\n" ); +} +#endif + + +/* Test for presence of drive and initialize it. Called only at boot time. */ +unsigned long gscd_init (unsigned long mem_start, unsigned long mem_end) +{ +unsigned long err; + + err = my_gscd_init ( mem_start, mem_end ); + return ( labs(err)); +} + + +/* This is the common initalisation for the GoldStar drive. */ +/* It is called at boot time AND for module init. */ +long my_gscd_init (unsigned long mem_start, unsigned long mem_end) +{ +int i; +int result; + + printk ("GSCD: version %s\n", GSCD_VERSION); + printk ("GSCD: Trying to detect a Goldstar R420 CD-ROM drive at 0x%X.\n", gscd_port); + + if (check_region(gscd_port, 4)) + { + printk("GSCD: Init failed, I/O port (%X) already in use.\n", gscd_port); + return -mem_start; + } + + + /* check for card */ + result = wait_drv_ready (); + if ( result == 0x09 ) + { + printk ("GSCD: DMA kann ich noch nicht!\n" ); + return -mem_start; + } + + if ( result == 0x0b ) + { + drv_mode = result; + i = find_drives (); + if ( i == 0 ) + { + printk ( "GSCD: GoldStar CD-ROM Drive is not found.\n" ); + return -mem_start; + } + } + + if ( (result != 0x0b) && (result != 0x09) ) + { + printk ("GSCD: GoldStar Interface Adapter does not exist or H/W error\n" ); + return -mem_start; + } + + /* reset all drives */ + i = 0; + while ( drv_states[i] != 0 ) + { + curr_drv_state = drv_states[i]; + printk ( "GSCD: Reset unit %d ... ",i ); + cc_Reset (); + printk ( "done\n" ); + i++; + } + + if (register_blkdev(MAJOR_NR, "gscd", &gscd_fops) != 0) + { + printk("GSCD: Unable to get major %d for GoldStar CD-ROM\n", + MAJOR_NR); + return -mem_start; + } + + blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST; + read_ahead[MAJOR_NR] = 4; + + disk_state = 0; + gscdPresent = 1; + + request_region(gscd_port, 4, "gscd"); + + printk ( "GSCD: GoldStar CD-ROM Drive found.\n" ); + return mem_start; +} + +static void gscd_hsg2msf (long hsg, struct msf *msf) +{ + hsg += CD_BLOCK_OFFSET; + msf -> min = hsg / (CD_FRAMES*CD_SECS); + hsg %= CD_FRAMES*CD_SECS; + msf -> sec = hsg / CD_FRAMES; + msf -> frame = hsg % CD_FRAMES; + + gscd_bin2bcd(&msf -> min); /* convert to BCD */ + gscd_bin2bcd(&msf -> sec); + gscd_bin2bcd(&msf -> frame); +} + + +static void gscd_bin2bcd (unsigned char *p) +{ +int u, t; + + u = *p % 10; + t = *p / 10; + *p = u | (t << 4); +} + + +#ifdef FUTURE_WOTK +static long gscd_msf2hsg (struct msf *mp) +{ + return gscd_bcd2bin(mp -> frame) + + gscd_bcd2bin(mp -> sec) * CD_FRAMES + + gscd_bcd2bin(mp -> min) * CD_FRAMES * CD_SECS + - CD_BLOCK_OFFSET; +} + +static int gscd_bcd2bin (unsigned char bcd) +{ + return (bcd >> 4) * 10 + (bcd & 0xF); +} +#endif + + diff -u --recursive --new-file v1.3.6/linux/drivers/block/ll_rw_blk.c linux/drivers/block/ll_rw_blk.c --- v1.3.6/linux/drivers/block/ll_rw_blk.c Tue Jun 27 14:11:33 1995 +++ linux/drivers/block/ll_rw_blk.c Sat Jul 1 19:05:59 1995 @@ -592,26 +592,41 @@ #ifdef CONFIG_BLK_DEV_XD mem_start = xd_init(mem_start,mem_end); #endif -#ifdef CONFIG_CDU31A - mem_start = cdu31a_init(mem_start,mem_end); -#endif -#ifdef CONFIG_CDU535 - mem_start = sony535_init(mem_start,mem_end); -#endif -#ifdef CONFIG_MCD - mem_start = mcd_init(mem_start,mem_end); -#endif -#ifdef CONFIG_AZTCD - mem_start = aztcd_init(mem_start,mem_end); -#endif #ifdef CONFIG_BLK_DEV_FD floppy_init(); #else outb_p(0xc, 0x3f2); #endif +#ifdef CONFIG_CDU31A + mem_start = cdu31a_init(mem_start,mem_end); +#endif CONFIG_CDU31A +#ifdef CONFIG_MCD + mem_start = mcd_init(mem_start,mem_end); +#endif CONFIG_MCD +#ifdef CONFIG_MCDX + mem_start = mcdx_init(mem_start,mem_end); +#endif CONFIG_MCDX #ifdef CONFIG_SBPCD mem_start = sbpcd_init(mem_start, mem_end); #endif CONFIG_SBPCD +#ifdef CONFIG_AZTCD + mem_start = aztcd_init(mem_start,mem_end); +#endif CONFIG_AZTCD +#ifdef CONFIG_CDU535 + mem_start = sony535_init(mem_start,mem_end); +#endif CONFIG_CDU535 +#ifdef CONFIG_GSCD + mem_start = gscd_init(mem_start, mem_end); +#endif CONFIG_GSCD +#ifdef CONFIG_CM206 + mem_start = cm206_init(mem_start, mem_end); +#endif +#ifdef CONFIG_OPTCD + mem_start = optcd_init(mem_start,mem_end); +#endif CONFIG_OPTCD +#ifdef CONFIG_SJCD + mem_start = sjcd_init(mem_start,mem_end); +#endif CONFIG_SJCD if (ramdisk_size) mem_start += rd_init(mem_start, ramdisk_size*1024); return mem_start; diff -u --recursive --new-file v1.3.6/linux/drivers/block/mcd.c linux/drivers/block/mcd.c --- v1.3.6/linux/drivers/block/mcd.c Fri Feb 3 15:29:33 1995 +++ linux/drivers/block/mcd.c Sat Jul 1 19:05:59 1995 @@ -3,7 +3,7 @@ Copyright (C) 1992 Martin Harriss - martin@bdsi.com + martin@bdsi.com (no longer valid - where are you now, Martin?) 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,13 +32,29 @@ (Jon Tombs ) October 1993 Bernd Huebner and Ruediger Helsch, Unifix Software GmbH, - Braunschweig, Germany: Total rework to speed up data read operation. + Braunschweig, Germany: rework to speed up data read operation. Also enabled definition of irq and address from bootstrap, using the - environment. linux/init/main.c must be patched to export the env. + environment. November 93 added code for FX001 S,D (single & double speed). February 94 added code for broken M 5/6 series of 16-bit single speed. + + 0.4 Added support for loadable MODULEs, so mcd can now also be + loaded by insmod and removed by rmmod during runtime. + Werner Zimmermann (zimmerma@rz.fht-esslingen.de), Mar. 26, 95 */ +#include + +#ifdef MODULE +# include +# include +# ifndef CONFIG_MODVERSIONS + char kernel_version[]= UTS_RELEASE; +# endif +#else +# define MOD_INC_USE_COUNT +# define MOD_DEC_USE_COUNT +#endif #include #include @@ -59,6 +75,7 @@ #define MAJOR_NR MITSUMI_CDROM_MAJOR #include "blk.h" +#define mcd_port mcd /* for compatible parameter passing with "insmod" */ #include #if 0 @@ -114,8 +131,8 @@ int mitsumi_bug_93_wait = 0; #endif /* WORK_AROUND_MITSUMI_BUG_93 */ -static short mcd_port = MCD_BASE_ADDR; -static int mcd_irq = MCD_INTR_NR; +static short mcd_port = MCD_BASE_ADDR; /* used as "mcd" by "insmod" */ +static int mcd_irq = MCD_INTR_NR; /* must directly follow mcd_port */ static int McdTimeout, McdTries; static struct wait_queue *mcd_waitq = NULL; @@ -1039,7 +1056,7 @@ } ++mcd_open_count; - + MOD_INC_USE_COUNT; return 0; } @@ -1050,7 +1067,7 @@ static void mcd_release(struct inode * inode, struct file * file) -{ +{ MOD_DEC_USE_COUNT; if (!--mcd_open_count) { mcd_invalidate_buffers(); sync_dev(inode->i_rdev); @@ -1080,15 +1097,23 @@ * Test for presence of drive and initialize it. Called at boot time. */ +#ifndef MODULE unsigned long mcd_init(unsigned long mem_start, unsigned long mem_end) +#else +int init_module(void) +#endif { int count; unsigned char result[3]; if (mcd_port <= 0 || mcd_irq <= 0) { printk("skip mcd_init\n"); +#ifndef MODULE return mem_start; +#else + return -EIO; +#endif } printk("mcd=0x%x,%d: ", mcd_port, mcd_irq); @@ -1097,13 +1122,22 @@ { printk("Unable to get major %d for Mitsumi CD-ROM\n", MAJOR_NR); +#ifndef MODULE return mem_start; +#else + return -EIO; +#endif + } if (check_region(mcd_port, 4)) { printk("Init failed, I/O port (%X) already in use\n", mcd_port); +#ifndef MODULE return mem_start; +#else + return -EIO; +#endif } blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST; @@ -1123,7 +1157,11 @@ if (count >= 2000000) { printk("Init failed. No mcd device at 0x%x irq %d\n", mcd_port, mcd_irq); +#ifndef MODULE return mem_start; +#else + return -EIO; +#endif } count = inb(MCDPORT(0)); /* pick up the status */ @@ -1132,12 +1170,19 @@ if(getValue(result+count)) { printk("mitsumi get version failed at 0x%d\n", mcd_port); +#ifndef MODULE return mem_start; +#else + return -EIO; +#endif } if (result[0] == result[1] && result[1] == result[2]) +#ifndef MODULE return mem_start; - +#else + return -EIO; +#endif printk("Mitsumi status, type and version : %02X %c %x\n", result[0],result[1],result[2]); @@ -1153,7 +1198,11 @@ if (request_irq(mcd_irq, mcd_interrupt, SA_INTERRUPT, "Mitsumi CD")) { printk("Unable to get IRQ%d for Mitsumi CD-ROM\n", mcd_irq); +#ifndef MODULE return mem_start; +#else + return -EIO; +#endif } request_region(mcd_port, 4,"mcd"); @@ -1169,7 +1218,11 @@ mcd_invalidate_buffers(); mcdPresent = 1; +#ifndef MODULE return mem_start; +#else + return 0; +#endif } @@ -1520,3 +1573,17 @@ return limit > 0 ? 0 : -1; } +#ifdef MODULE +void cleanup_module(void) +{ if (MOD_IN_USE) + { printk("mcd module in use - can't remove it.\n"); + return; + } + if ((unregister_blkdev(MAJOR_NR, "mcd") == -EINVAL)) + { printk("What's that: can't unregister mcd\n"); + return; + } + release_region(mcd_port,4); + printk("mcd module released.\n"); +} +#endif MODULE diff -u --recursive --new-file v1.3.6/linux/drivers/block/mcdx.c linux/drivers/block/mcdx.c --- v1.3.6/linux/drivers/block/mcdx.c Thu Jan 1 02:00:00 1970 +++ linux/drivers/block/mcdx.c Sat Jul 1 19:05:59 1995 @@ -0,0 +1,1533 @@ +/* + * The Mitsumi CDROM interface + * Copyright (C) 1995 Heiko Schlittermann + * VERSION: @VERSION@ + * + * 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; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Thanks to + * The Linux Community at all and ... + * Martin Harriss (he wrote the first Mitsumi Driver) + * Eberhard Moenkeberg (he gave me much support and the initial kick) + * Bernd Huebner, Ruediger Helsch (Unifix-Software GmbH, they + * improved the original driver) + * John Tombs, Bjorn Ekwall (module support) + * Daniel v. Mosnenck (he sent me the Technical and Programming Reference) + * Gerd Knorr (he lent me his PhotoCD) + * Nils Faerber and Roger E. Wolff (extensivly tested the LU portion) + * ... somebody forgotten? + * + */ + + +#if RCS +static const char *mcdx_c_version + = "$Id: mcdx.c,v 1.2 1995/06/18 18:00:53 heiko Exp $"; +#endif + +#include +#ifdef MODULE +#include +#include +#ifndef CONFIG_MODVERSIONS +char kernel_version[]=UTS_RELEASE; +#endif +#else +#define MOD_INC_USE_COUNT +#define MOD_DEC_USE_COUNT +#define MOD_IN_USE 1 +#endif MODULE + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define MAJOR_NR MITSUMI_X_CDROM_MAJOR +#include "blk.h" +#define mcdx_drive_map mcdx /* for compatible parameter passing with "insmod" */ +#include + +/* CONSTANTS *******************************************************/ + +const int REQUEST_SIZE = 200; +const int DIRECT_SIZE = 200; + +enum drivemodes { TOC, DATA, RAW, COOKED }; +enum datamodes { MODE0, MODE1, MODE2 }; +enum resetmodes { SOFT, HARD }; + +const int SINGLE = 0x01; +const int DOUBLE = 0x02; +const int DOOR = 0x04; +const int MULTI = 0x08; + +const unsigned char READSSPEED = 0xc0; +const unsigned char READDSPEED = 0xc1; + + +/* DECLARATIONS ****************************************************/ +struct s_msf { + unsigned char minute; + unsigned char second; + unsigned char frame; +}; + +struct s_subqcode { + unsigned char control; + unsigned char tno; + unsigned char index; + struct s_msf tt; + struct s_msf dt; +}; + +struct s_diskinfo { + unsigned int n_first; + unsigned int n_last; + struct s_msf msf_leadout; + struct s_msf msf_first; +}; + +struct s_multi { + unsigned char multi; + struct s_msf msf_last; +}; + +struct s_version { + unsigned char code; + unsigned char ver; +}; + +/* Per drive/controller stuff **************************************/ + +struct s_drive_stuff { + /* waitquenes */ + struct wait_queue *busyq; + struct wait_queue *lockq; + struct wait_queue *sleepq; + + /* flags */ + volatile int introk; /* status of last irq operation */ + volatile int busy; /* drive performs an operation */ + volatile int lock; /* exclusive usage */ + + /* cd infos */ + struct s_diskinfo di; + struct s_multi multi; + struct s_subqcode* toc; /* first enty of the toc array */ + struct s_subqcode start; + struct s_subqcode stop; + int xa; /* 1 if xa disk */ + int audio; /* 1 if audio disk */ + int audiostatus; + + /* `buffer' control */ + volatile int valid; + volatile int pending; + volatile int off_direct; + volatile int off_requested; + + /* adds and odds */ + void* wreg_data; /* w data */ + void* wreg_reset; /* w hardware reset */ + void* wreg_hcon; /* w hardware conf */ + void* wreg_chn; /* w channel */ + void* rreg_data; /* r data */ + void* rreg_status; /* r status */ + + int irq; /* irq used by this drive */ + int minor; /* minor number of this drive */ + int present; /* drive present and its capabilities */ + char readcmd; /* read cmd depends on single/double speed */ + unsigned long changed; /* last jiff the media was changed */ + int users; /* keeps track of open/close */ + int lastsector; /* last block accessible */ + int errno; /* last operation's error */ + +}; + +/* Prototypes ******************************************************/ + +/* The following prototypes are already declared elsewhere. They are + repeated here to show what's going on. And to sense, if they're + changed elsewhere. */ + +/* declared in blk.h */ +unsigned long mcdx_init(unsigned long mem_start, unsigned long mem_end); +void do_mcdx_request(void); + +int check_mcdx_media_change(dev_t); + +/* already declared in init/main */ +void mcdx_setup(char *, int *); + +/* Indirect exported functions. These functions are exported by their + addresses, such as mcdx_open and mcdx_close in the + structure fops. */ + +/* ??? exported by the mcdx_sigaction struct */ +static void mcdx_intr(int, struct pt_regs*); + +/* exported by file_ops */ +static int mcdx_open(struct inode*, struct file*); +static void mcdx_close(struct inode*, struct file*); +static int mcdx_ioctl(struct inode*, struct file*, unsigned int, unsigned long); + +/* misc internal support functions */ +static void log2msf(unsigned int, struct s_msf*); +static unsigned int msf2log(const struct s_msf*); +static unsigned int uint2bcd(unsigned int); +static unsigned int bcd2uint(unsigned char); +#if MCDX_DEBUG +static void TRACE((int level, const char* fmt, ...)); +#endif +#ifndef NOWARN +static void WARN((const char* fmt, ...)); +#endif +static char *port(int*); +static int irq(int*); +static void mcdx_delay(struct s_drive_stuff*, long jifs); +static int mcdx_transfer(struct s_drive_stuff*, char* buf, int sector, int nr_sectors); + +static int mcdx_config(struct s_drive_stuff*, int); +static int mcdx_closedoor(struct s_drive_stuff*, int); +static int mcdx_requestversion(struct s_drive_stuff*, struct s_version*, int); +static int mcdx_lockdoor(struct s_drive_stuff*, int, int); +#if 0 +static int mcdx_getstatus(struct s_drive_stuff*, int); +#endif +static int mcdx_stop(struct s_drive_stuff*, int); +static int mcdx_reset(struct s_drive_stuff*, enum resetmodes, int); +static int mcdx_eject(struct s_drive_stuff*, int); +static int mcdx_setdrivemode(struct s_drive_stuff*, enum drivemodes, int); +static int mcdx_setdatamode(struct s_drive_stuff*, enum datamodes, int); +static int mcdx_requestsubqcode(struct s_drive_stuff*, struct s_subqcode*, int); +static int mcdx_requestmultidiskinfo(struct s_drive_stuff*, struct s_multi*, int); +static int mcdx_requesttocdata(struct s_drive_stuff*, struct s_diskinfo*, int); + +static int mcdx_talk(struct s_drive_stuff*, + const unsigned char* cmd, size_t, void *buffer, + size_t size, unsigned int timeout, int); +static int mcdx_readtoc(struct s_drive_stuff*); + +/* static variables ************************************************/ + +static int dummy0; +static int mcdx_drive_map[][2] = MCDX_DRIVEMAP; +static struct s_drive_stuff* mcdx_stuffp[MCDX_NDRIVES]; +static struct s_drive_stuff* mcdx_irq_map[16] = + {0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0}; + +static struct file_operations mcdx_fops = { + NULL, /* lseek - use kernel default */ + block_read, /* read - general block-dev read */ + block_write, /* write - general block-dev write */ + NULL, /* no readdir */ + NULL, /* no select */ + mcdx_ioctl, /* ioctl() */ + NULL, /* no mmap */ + mcdx_open, /* open() */ + mcdx_close, /* close() */ + NULL, /* fsync */ + NULL, /* fasync */ + check_mcdx_media_change, /* media_change */ + NULL /* revalidate */ +}; + +/* KERNEL INTERFACE FUNCTIONS **************************************/ + +static int +mcdx_ioctl( + struct inode* ip, struct file* fp, + unsigned int cmd, unsigned long arg) +{ + struct s_drive_stuff *stuffp = mcdx_stuffp[MINOR(ip->i_rdev)]; + + if (!stuffp->present) return -ENXIO; + if (!ip) return -EINVAL; + + switch (cmd) { + case CDROMSTART: { + TRACE((IOCTL, "ioctl() START\n")); + return 0; + } + case CDROMSTOP: { + TRACE((IOCTL, "ioctl() STOP\n")); + if (-1 == mcdx_stop(stuffp, 1)) + return -EIO; + return 0; + } + case CDROMPLAYTRKIND: { + return -EINVAL; + /* + int ans; + struct cdrom_ti ti; + TRACE((IOCTL, "ioctl() PLAYTRKIND\n")); + if (ans = verify_area(VERIFY_READ, (void*) arg, sizeof(ti)); + return ans; + memcpy_fromfs(&ti, (void*) arg, sizeof(ti)); + if ((ti.cdti_trk0 < stuffp->di.n_first) + || (ti.cdti_trk0 > stuffp->di.n_last) + || (ti.cdti_trk1 < stuffp->di.n_first)) + return -EINVAL; + if (ti.cdti_trk1 > stuffp->di.n_last) ti.cdti_trk1 = stuffp->di.n_last; + */ + } + + case CDROMREADTOCENTRY: { + struct cdrom_tocentry entry; + struct s_subqcode *tp = NULL; + int ans; + + TRACE((IOCTL, "ioctl() READTOCENTRY\n")); + + if ((stuffp->toc == NULL) && (0 != (ans = mcdx_readtoc(stuffp)))) return ans; + + if ((ans = verify_area(VERIFY_READ, (void *) arg, sizeof(entry)))) return ans; + memcpy_fromfs(&entry, (void *) arg, sizeof(entry)); + + if (entry.cdte_track == CDROM_LEADOUT) + tp = &stuffp->toc[stuffp->di.n_last - stuffp->di.n_first + 1]; + else if (entry.cdte_track > stuffp->di.n_last + || entry.cdte_track < stuffp->di.n_first) return -EINVAL; + else tp = &stuffp->toc[entry.cdte_track - stuffp->di.n_first]; + + if (NULL == tp) WARN(("FATAL.\n")); + + entry.cdte_adr = tp->control; + entry.cdte_ctrl = tp->control >> 4; + + if (entry.cdte_format == CDROM_MSF) { + entry.cdte_addr.msf.minute = bcd2uint(tp->dt.minute); + entry.cdte_addr.msf.second = bcd2uint(tp->dt.second); + entry.cdte_addr.msf.frame = bcd2uint(tp->dt.frame); + } else if (entry.cdte_format == CDROM_LBA) + entry.cdte_addr.lba = msf2log(&tp->dt); + else return -EINVAL; + + if ((ans = verify_area(VERIFY_WRITE, (void*) arg, sizeof(entry)))) return ans; + memcpy_tofs((void*) arg, &entry, sizeof(entry)); + + return 0; + } + + case CDROMSUBCHNL: { + int ans; + struct cdrom_subchnl sub; + struct s_subqcode q; + TRACE((IOCTL, "ioctl() SUBCHNL\n")); + + if ((ans = verify_area(VERIFY_READ, (void*) arg, sizeof(sub)))) return ans; + memcpy_fromfs(&sub, (void*) arg, sizeof(sub)); + + if (-1 == mcdx_requestsubqcode(stuffp, &q, 1)) return -EIO; + + TRACE((IOCTL, "audiostatus: %x\n", stuffp->audiostatus)); + sub.cdsc_audiostatus = stuffp->audiostatus; + sub.cdsc_adr = q.control; + sub.cdsc_ctrl = q.control >> 4; + sub.cdsc_trk = bcd2uint(q.tno); + sub.cdsc_ind = bcd2uint(q.index); + + if (sub.cdsc_format == CDROM_LBA) { + sub.cdsc_absaddr.lba = msf2log(&q.dt); + sub.cdsc_reladdr.lba = msf2log(&q.tt); + } else if (sub.cdsc_format == CDROM_MSF) { + sub.cdsc_absaddr.msf.minute = bcd2uint(q.dt.minute); + sub.cdsc_absaddr.msf.second = bcd2uint(q.dt.second); + sub.cdsc_absaddr.msf.frame = bcd2uint(q.dt.frame); + sub.cdsc_reladdr.msf.minute = bcd2uint(q.tt.minute); + sub.cdsc_reladdr.msf.second = bcd2uint(q.tt.second); + sub.cdsc_reladdr.msf.frame = bcd2uint(q.tt.frame); + } else return -EINVAL; + + if ((ans = verify_area(VERIFY_WRITE, (void*) arg, sizeof(sub)))) + return ans; + memcpy_tofs((void*) arg, &sub, sizeof(sub)); + + return 0; + } + + case CDROMREADTOCHDR: { + struct cdrom_tochdr toc; + int ans; + TRACE((IOCTL, "ioctl() READTOCHDR\n")); + if ((ans = verify_area(VERIFY_WRITE, (void*) arg, sizeof toc))) + return ans; + toc.cdth_trk0 = stuffp->di.n_first; + toc.cdth_trk1 = stuffp->di.n_last; + memcpy_tofs((void*) arg, &toc, sizeof toc); + TRACE((IOCTL, "ioctl() track0 = %d, track1 = %d\n", + stuffp->di.n_first, stuffp->di.n_last)); + return 0; + } + + case CDROMPAUSE: { + TRACE((IOCTL, "ioctl() PAUSE\n")); + if (stuffp->audiostatus != CDROM_AUDIO_PLAY) return -EINVAL; + if (-1 == mcdx_stop(stuffp, 1)) return -EIO; + if (-1 == mcdx_requestsubqcode(stuffp, &stuffp->start, 1)) + return -EIO; + return 0; + } + case CDROMMULTISESSION: { + int ans; + struct cdrom_multisession ms; + TRACE((IOCTL, "ioctl() MULTISESSION\n")); + if (0 != (ans = verify_area(VERIFY_READ, (void*) arg, + sizeof(struct cdrom_multisession)))) + return ans; + + memcpy_fromfs(&ms, (void*) arg, sizeof(struct cdrom_multisession)); + if (ms.addr_format == CDROM_MSF) { + ms.addr.msf.minute = bcd2uint(stuffp->multi.msf_last.minute); + ms.addr.msf.second = bcd2uint(stuffp->multi.msf_last.second); + ms.addr.msf.frame = bcd2uint(stuffp->multi.msf_last.frame); + } else if (ms.addr_format == CDROM_LBA) + ms.addr.lba = msf2log(&stuffp->multi.msf_last); + else + return -EINVAL; + ms.xa_flag = stuffp->xa; + + if (0 != (ans = verify_area(VERIFY_WRITE, (void*) arg, + sizeof(struct cdrom_multisession)))) + return ans; + + memcpy_tofs((void*) arg, &ms, sizeof(struct cdrom_multisession)); + if (ms.addr_format == CDROM_MSF) + TRACE((IOCTL, + "ioctl() (%d, %02x:%02x.%02x [%02x:%02x.%02x])\n", + ms.xa_flag, + ms.addr.msf.minute, + ms.addr.msf.second, + ms.addr.msf.frame, + stuffp->multi.msf_last.minute, + stuffp->multi.msf_last.second, + stuffp->multi.msf_last.frame)); + else + { + dummy0=0; + TRACE((IOCTL, + "ioctl() (%d, 0x%08x [%02x:%02x.%02x])\n", + ms.xa_flag, + ms.addr.lba, + stuffp->multi.msf_last.minute, + stuffp->multi.msf_last.second, + stuffp->multi.msf_last.frame)); + } + return 0; + } + + case CDROMEJECT: { + TRACE((IOCTL, "ioctl() EJECT\n")); + if (stuffp->users > 1) return -EBUSY; + if (-1 == mcdx_eject(stuffp, 1)) return -EIO; + return 0; + } + + default: + WARN(("ioctl(): unknown request 0x%04x\n", cmd)); + return -EINVAL; + } +} + +void do_mcdx_request() +{ + int dev; + struct s_drive_stuff *stuffp; + + again: + + TRACE((REQUEST, "do_request()\n")); + + if ((CURRENT == NULL) || (CURRENT->dev < 0)) { + TRACE((REQUEST, "do_request() done\n")); + return; + } + + stuffp = mcdx_stuffp[MINOR(CURRENT->dev)]; + TRACE((REQUEST, "do_request() stuffp = %p\n", stuffp)); + + INIT_REQUEST; + dev = MINOR(CURRENT->dev); + + if ((dev < 0) || (dev >= MCDX_NDRIVES) || (!stuffp->present)) { + printk(MCD "do_request(): bad device: 0x%04x\n", CURRENT->dev); + end_request(0); + goto again; + } + + if (stuffp->audio) { + WARN(("do_request() attempt to read from audio cd\n")); + end_request(0); + goto again; + } + + switch (CURRENT->cmd) { + case WRITE: + printk(MCD ": do_request(): attempt to write to cd!!\n"); + end_request(0); + break; + + case READ: + stuffp->errno = 0; + while (CURRENT->nr_sectors) { + int i; + + if (-1 == (i = mcdx_transfer( + stuffp, + CURRENT->buffer, + CURRENT->sector, + CURRENT->nr_sectors))) { + printk(MCD " read error\n"); + if (stuffp->errno == MCDX_EOM) { + CURRENT->sector += CURRENT->nr_sectors; + CURRENT->nr_sectors = 0; + } + end_request(0); + goto again; + } + CURRENT->sector += i; + CURRENT->nr_sectors -= i; + CURRENT->buffer += (i * 512); + + } + + end_request(1); + break; + + default: + panic(MCD "do_request: unknown command.\n"); + break; + } + + goto again; +} + +static int +mcdx_open(struct inode *ip, struct file *fp) +{ + struct s_drive_stuff *stuffp; + static unsigned long changed = 0; + + TRACE((OPENCLOSE, "open()\n")); + stuffp = mcdx_stuffp[MINOR(ip->i_rdev)]; + if (!stuffp->present) return -ENXIO; + + /* close the door, if necessary (get the door information + from the hardware status register) */ + if (inb((unsigned int) stuffp->rreg_status) & MCDX_RBIT_DOOR) + mcdx_closedoor(stuffp, 1); + + /* if the media changed we will have to little more */ + if (changed < stuffp->changed) { + + TRACE((OPENCLOSE, "open() media changed\n")); + /* but wait - the time of media change will be set at the + very last of this block - it seems, some of the following + talk() will detect a media change ... (I think, config() + is the reason. */ + + /* get the multisession information */ + { + TRACE((OPENCLOSE, "open() Request multisession info\n")); + if (-1 == mcdx_requestmultidiskinfo(stuffp, &stuffp->multi, 6)) + return -EIO; + + if (stuffp->multi.multi > 2) + WARN(("open() unknown multisession value (%d)\n", stuffp->multi.multi)); + + /* multisession ? */ + if (!stuffp->multi.multi) + stuffp->multi.msf_last.second = 2; + + TRACE((OPENCLOSE, "open() MS: %d, last @ %02x:%02x.%02x\n", + stuffp->multi.multi, + stuffp->multi.msf_last.minute, + stuffp->multi.msf_last.second, + stuffp->multi.msf_last.frame)); + } /* got multisession information */ + + + /* request the disks table of contents (aka diskinfo) */ + if (-1 == mcdx_requesttocdata(stuffp, &stuffp->di, 1)) return -EIO; + + stuffp->lastsector = (CD_FRAMESIZE / 512) * msf2log(&stuffp->di.msf_leadout) - 1; + + TRACE((OPENCLOSE, "open() start %d (%02x:%02x.%02x) %d\n", + stuffp->di.n_first, + stuffp->di.msf_first.minute, + stuffp->di.msf_first.second, + stuffp->di.msf_first.frame, + msf2log(&stuffp->di.msf_first))); + TRACE((OPENCLOSE, "open() last %d (%02x:%02x.%02x) %d\n", + stuffp->di.n_last, + stuffp->di.msf_leadout.minute, + stuffp->di.msf_leadout.second, + stuffp->di.msf_leadout.frame, + msf2log(&stuffp->di.msf_leadout))); + + if (stuffp->toc) { + TRACE((MALLOC, "open() free toc @ %p\n", stuffp->toc)); + kfree(stuffp->toc); + } + stuffp->toc = NULL; + + TRACE((OPENCLOSE, "open() init irq generation\n")); + if (-1 == mcdx_config(stuffp, 1)) return -EIO; + + /* try to get the first sector ... */ + { + char buf[512]; + int ans; + int tries; + + stuffp->xa = 0; + stuffp->audio = 0; + + for (tries = 6; tries; tries--) { + TRACE((OPENCLOSE, "open() try as %s\n", + stuffp->xa ? "XA" : "normal")); + + /* set data mode */ + if (-1 == (ans = mcdx_setdatamode(stuffp, + stuffp->xa ? MODE2 : MODE1, 1))) + return -EIO; + + if ((stuffp->audio = e_audio(ans))) break; + + while (0 == (ans = mcdx_transfer(stuffp, buf, 0, 1))) + ; + + if (ans == 1) break; + stuffp->xa = !stuffp->xa; + } + if (!tries) return -EIO; + } + + /* xa disks will be read in raw mode, others not */ + if (-1 == mcdx_setdrivemode(stuffp, + stuffp->xa ? RAW : COOKED, 1)) + return -EIO; + + if (stuffp->audio) { + WARN(("open() audio disk found\n")); + } else { + WARN(("open() %s%s disk found\n", + stuffp->xa ? "XA / " : "", + stuffp->multi.multi ? "Multi Session" : "Single Session")); + } + + changed = stuffp->changed; + } + + if (-1 == mcdx_lockdoor(stuffp, 1, 1)) return -EIO; + + stuffp->users++; + MOD_INC_USE_COUNT; + return 0; +} + +static void +mcdx_close(struct inode *ip, struct file *fp) +{ + struct s_drive_stuff *stuffp; + + TRACE((OPENCLOSE, "close()\n")); + + stuffp = mcdx_stuffp[MINOR(ip->i_rdev)]; + + if (0 == --stuffp->users) { + sync_dev(ip->i_rdev); /* needed for r/o device? */ + + /* invalidate_inodes(ip->i_rdev); */ + invalidate_buffers(ip->i_rdev); + + if (-1 == mcdx_lockdoor(stuffp, 0, 1)) + printk(MCD ": Cannot unlock the door\n"); + } + MOD_DEC_USE_COUNT; + + return; +} + +int check_mcdx_media_change(dev_t full_dev) +/* Return: 1 if media changed since last call to + this function + 0 else + Setting flag to 0 resets the changed state. */ + +{ + printk(MCD ":: check_mcdx_media_change(0x%x) called\n", full_dev); + return 0; +} + +void mcdx_setup(char *str, int *pi) +{ +#if MCDX_DEBUG + printk(MCD ":: setup(%s, %d) called\n", + str, pi[0]); +#endif +} + +/* DIRTY PART ******************************************************/ + +static void mcdx_delay(struct s_drive_stuff *stuff, long jifs) +/* This routine is used for sleeping while initialisation - it seems that + there are no other means available. May be we could use a simple count + loop w/ jumps to itself, but I wanna make this independend of cpu + speed. */ +{ + unsigned long tout = jiffies + jifs; + + if (jifs < 0) return; + +#ifdef MODULE + /* timer are available */ + current->timeout = tout; + while (current->timeout) + interruptible_sleep_on(&stuff->sleepq); +#else + /* timer are _not_ available at initialisation time */ + if (stuff->present) { + current->state = TASK_INTERRUPTIBLE; + current->timeout = tout; + interruptible_sleep_on(&stuff->sleepq); + } else + while (jiffies < tout) { + current->timeout = jiffies; + schedule(); + } +#endif MODULE +} + +static void +mcdx_intr(int irq, struct pt_regs* regs) +{ + struct s_drive_stuff *stuffp; + unsigned char x; + + stuffp = mcdx_irq_map[irq]; + + if (!stuffp->busy) { + WARN(("intr() unexpected interrupt @ irq %d\n", irq)); + return; + } + + /* if not ok read the next byte as the drives status */ + if (0 == (stuffp->introk = + (~(x = inb((unsigned int) stuffp->rreg_status)) & MCDX_RBIT_DTEN))) + TRACE((IRQ, "intr() irq %d failed, status %02x %02x\n", + irq, x, inb((unsigned int) stuffp->rreg_data))); + else + { + dummy0=0; + TRACE((IRQ, "irq() irq %d ok, status %02x\n", irq, x)); + } + stuffp->busy = 0; + wake_up_interruptible(&stuffp->busyq); +} + + +static int +mcdx_talk ( + struct s_drive_stuff *stuffp, + const unsigned char *cmd, size_t cmdlen, + void *buffer, size_t size, + unsigned int timeout, int tries) +/* Send a command to the drive, wait for the result. + * returns -1 on timeout, drive status otherwise + */ +{ + const DELAY = 1; /* minimum delay */ + char c; + int st; + + if (!buffer || size == 0) buffer = &c, size = 1; + + while (stuffp->lock) + interruptible_sleep_on(&stuffp->lockq); + + stuffp->lock = 1; + stuffp->valid = 0; + +#if MCDX_DEBUG & TALK + { + unsigned char i; + TRACE((TALK, "talk() res.size %d, command 0x%02x", + size, (unsigned char) cmd[0])); + for (i = 1; i < cmdlen; i++) printk(" 0x%02x", cmd[i]); + printk("\n"); + } +#endif + + for (st = -1; st == -1 && tries; tries--) { + + int sz = size; + unsigned char* bp = buffer; + + outsb((unsigned int) stuffp->wreg_data, cmd, cmdlen); + + while (sz--) { + int to = 0; + + /* wait for the status bit */ + { + unsigned long limit = jiffies + timeout; + while ((inb((unsigned int) stuffp->rreg_status)) & MCDX_RBIT_STEN) { + if ((to = (jiffies > limit))) break; + mcdx_delay(stuffp, DELAY); + } + } + + if (!to) { + + /* status read? */ + if (st == -1) { + + /* read the status byte */ + *bp++ = st = (unsigned char) inb((unsigned int) stuffp->rreg_data); + + TRACE((TALK, "talk() got status 0x%02x\n", st)); + + /* audio status is handled here */ + stuffp->audiostatus = e_audiobusy(st) ? + CDROM_AUDIO_PLAY : CDROM_AUDIO_NO_STATUS; + + /* media change is handled here ... */ + if (e_changed(st)) { + WARN(("talk() media changed\n")); + stuffp->changed = jiffies; + } + + /* command error is handled here ... */ + if (e_cmderr(st)) { + WARN(("command error\n")); + st = -1; + break; + } + } else { + /* read the answer */ + *bp++ = (unsigned char) inb((unsigned int) stuffp->rreg_data); + } + } else { + WARN(("talk() timed out, %1d %s left\n", + tries - 1, (tries -1 ) > 1 ? "tries" : "try")); + st = -1; + break; + } + } + } + + if (tries) WARN(("talk() giving up\n")); + + + stuffp->lock = 0; + wake_up_interruptible(&stuffp->lockq); + + TRACE((TALK, "talk() done with 0x%02x\n", st)); + return st; +} + +/* MODULE STUFF ***********************************************************/ +#ifdef MODULE + +int init_module(void) +{ + int i; + int drives = 0; + + mcdx_init(0, 0); + for (i = 0; i < MCDX_NDRIVES; i++) { + if (mcdx_stuffp[i]) { + TRACE((INIT, "init_module() drive %d stuff @ %p\n", + i, mcdx_stuffp[i])); + drives++; + } + } + + if (!drives) { + WARN(("init_module() cannot init any drive\n")); + return -EIO; + } + + return 0; +} + +void cleanup_module(void) +{ + int i; + + WARN(("cleanup_module called\n")); + + for (i = 0; i < MCDX_NDRIVES; i++) { + struct s_drive_stuff *stuffp; + stuffp = mcdx_stuffp[i]; + if (!stuffp) continue; + release_region((unsigned long) stuffp->wreg_data, MCDX_IO_SIZE); + free_irq(stuffp->irq); + if (stuffp->toc) { + TRACE((MALLOC, "cleanup_module() free toc @ %p\n", stuffp->toc)); + kfree(stuffp->toc); + } + TRACE((MALLOC, "cleanup_module() free stuffp @ %p\n", stuffp)); + mcdx_stuffp[i] = NULL; + kfree(stuffp); + } + + if (unregister_blkdev(MAJOR_NR, MCD) != 0) + printk(MCD ": cleanup_module failed.\n"); + else + printk(MCD ": cleanup_module succeeded.\n"); +} + +#endif MODULE + +/* Support functions ************************************************/ + +#if MCDX_DEBUG +void trace(int level, const char* fmt, ...) +{ + char s[255]; + va_list args; + if (level < 1) return; + va_start(args, fmt); + if (sizeof(s) < vsprintf(s, fmt, args)) + printk(MCD ":: dprintf exeeds limit!!\n"); + else printk(MCD ":: %s", s); + va_end(args); +} +#endif + +#ifndef NOWARN +void warn(const char* fmt, ...) +{ + char s[255]; + va_list args; + va_start(args, fmt); + if (sizeof(s) < vsprintf(s, fmt, args)) + printk(MCD ":: dprintf exeeds limit!!\n"); + else printk(MCD ": %s", s); + va_end(args); +} +#endif + + +unsigned long mcdx_init(unsigned long mem_start, unsigned long mem_end) +{ + int drive; + + printk(MCD + ": Version @VERSION@ " + "$Id: mcdx.c,v 1.2 1995/06/18 18:00:53 heiko Exp $ \n"); + + /* zero the pointer array */ + for (drive = 0; drive < MCDX_NDRIVES; drive++) + mcdx_stuffp[drive] = NULL; + + /* do the initialisation */ + for (drive = 0; drive < MCDX_NDRIVES; drive++) { + struct s_version version; + struct s_drive_stuff* stuffp; + + TRACE((INIT, "init() try drive %d\n", drive)); + TRACE((MALLOC, "init() malloc %d bytes\n", sizeof(*stuffp))); + + if (!(stuffp = kmalloc(sizeof(*stuffp), GFP_KERNEL))) { + WARN(("init() malloc failed\n")); + break; + } + + TRACE((INIT, "init() got %d bytes for drive stuff @ %p\n", sizeof(*stuffp), stuffp)); + + /* zero the stuff */ + memset(stuffp, 0, sizeof(*stuffp)); + + stuffp->present = 0; /* this should be 0 already */ + stuffp->toc = NULL; /* this should be NULL already */ + stuffp->changed = jiffies; + + /* setup our irq and i/o addresses */ + stuffp->irq = irq(mcdx_drive_map[drive]); + stuffp->wreg_data = stuffp->rreg_data = port(mcdx_drive_map[drive]); + stuffp->wreg_reset = stuffp->rreg_status = stuffp->wreg_data + 1; + stuffp->wreg_hcon = stuffp->wreg_reset + 1; + stuffp->wreg_chn = stuffp->wreg_hcon + 1; + + /* check if i/o addresses are available */ + if (0 != check_region((unsigned int) stuffp->wreg_data, MCDX_IO_SIZE)) { + WARN(("init() i/o ports at 0x%3p .. 0x%3p not available\n", + stuffp->wreg_data, stuffp->wreg_data + MCDX_IO_SIZE - 1)); + stuffp->wreg_data = 0; + TRACE((MALLOC, "init() free stuffp @ %p\n", stuffp)); + kfree(stuffp); + TRACE((INIT, "init() continue at next drive\n")); + continue; /* next drive */ + } + + TRACE((INIT, "init() i/o port is available at 0x%3p\n", stuffp->wreg_data)); + + TRACE((INIT, "init() hardware reset\n")); + mcdx_reset(stuffp, HARD, 1); + + TRACE((INIT, "init() get version\n")); + if (-1 == mcdx_requestversion(stuffp, &version, 2)) { + /* failed, next drive */ + TRACE((MALLOC, "init() free stuffp @ %p\n", stuffp)); + kfree(stuffp); + TRACE((INIT, "init() continue at next drive\n")); + continue; + } + switch (version.code) { + case 'D': + stuffp->readcmd = READDSPEED; + stuffp->present = DOUBLE | DOOR | MULTI; + break; + case 'F': + stuffp->readcmd = READSSPEED; + stuffp->present = SINGLE | DOOR | MULTI; + break; + case 'M': + stuffp->readcmd = READSSPEED; + stuffp->present = SINGLE; + break; + default: + stuffp->present = 0; break; + } + + + if (!stuffp->present) { + printk(MCD ": no drive found. continue at next drive\n"); + kfree(stuffp); + continue; /* next drive */ + } + + TRACE((INIT, "init() register blkdev\n")); + if (register_blkdev(MAJOR_NR, MCD, &mcdx_fops) != 0) { + printk(MCD ": unable to get major %d for " DEVICE_NAME "\n", + MAJOR_NR); + kfree(stuffp); + continue; /* next drive */ + } + + blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST; + read_ahead[MAJOR_NR] = READ_AHEAD; + +#if WE_KNOW_WHY + blksize_size[MAJOR_NR] = BLKSIZES; +#endif + + TRACE((INIT, "init() subscribe irq and i/o\n")); + mcdx_irq_map[stuffp->irq] = stuffp; + if (request_irq(stuffp->irq, mcdx_intr, SA_INTERRUPT, MCD)) { + printk(MCD ": init() unable to get IRQ %d for " + DEVICE_NAME "\n", stuffp->irq); + stuffp->irq = 0; + kfree(stuffp); + continue; + } + request_region((unsigned long) (unsigned int) stuffp->wreg_data, MCDX_IO_SIZE, MCD); + + TRACE((INIT, "init() get garbage\n")); + { + int i; + mcdx_delay(stuffp, 50); + for (i = 100; i; i--) (void) inb((unsigned int) stuffp->rreg_status); + } + + +#if WE_KNOW_WHY + outb(0x50, (unsigned int) stuffp->wreg_chn); /* irq 11 -> channel register */ +#endif + + TRACE((INIT, "init() set non dma but irq mode\n")); + mcdx_config(stuffp, 1); + + stuffp->minor = drive; + + printk(MCD ": " DEVICE_NAME " installed at 0x%3p, irq %d.\n" + MCD ": Firmware version %c %x\n", + stuffp->wreg_data, stuffp->irq, version.code, version.ver); + mcdx_stuffp[drive] = stuffp; + TRACE((INIT, "init() mcdx_stuffp[%d] = %p\n", drive, stuffp)); + } + + return mem_start; +} + + +static int mcdx_transfer(struct s_drive_stuff *stuffp, + char *p, int sector, int nr_sectors) +/* This does actually the transfer from the drive. + Return: -1 on timeout or other error + else status byte (as in stuff->st) */ +{ + int off; + int done = 0; + + TRACE((TRANSFER, "transfer() %d sectors at sector %d\n", + nr_sectors, sector)); + + if (stuffp->audio) { + printk(MCD ": attempt to read from audio disk\n"); + return -1; + } + + while (stuffp->lock) + interruptible_sleep_on(&stuffp->lockq); + + if (stuffp->valid + && (sector >= stuffp->pending) + && (sector < stuffp->off_direct)) { + + + off = stuffp->off_requested < (off = sector + nr_sectors) + ? stuffp->off_requested : off; + + stuffp->lock = current->pid; + + do { + int sig = 0; + int to = 0; + + /* wait for the drive become idle */ + current->timeout = jiffies + 500; + while (stuffp->busy) { + interruptible_sleep_on(&stuffp->busyq); + if ((sig = (current->signal && ~current->blocked)) + || (to = (current->timeout == 0))) { + break; + } + } + + current->timeout = 0; + + /* test for possible errors */ + if (((stuffp->busy == 0) && !stuffp->introk) + || sig + || to) { + if ((stuffp->busy == 0) && !stuffp->introk) + printk(MCD ": failure in data request\n"); + else if (to) + printk(MCD ": timeout\n"); + else if (sig) + printk(MCD ": got signal 0x%lx\n", current->signal); + + stuffp->lock = 0; + stuffp->busy = 0; + wake_up_interruptible(&stuffp->lockq); + wake_up_interruptible(&stuffp->busyq); + stuffp->errno = MCDX_E; + TRACE((TRANSFER, "transfer() done (-1)\n")); + return -1; + } + + /* test if it's the first sector of a block, + * there we have to skip some bytes as we read raw data */ + if (stuffp->xa && (0 == (stuffp->pending & 3))) { + const int HEAD = CD_FRAMESIZE_RAW - CD_XA_TAIL - CD_FRAMESIZE; + TRACE((TRANSFER, "transfer() sector %d, skip %d header bytes\n", + stuffp->pending, HEAD)); + insb((unsigned int) stuffp->rreg_data, p, HEAD); + } + + /* now actually read the data */ + + TRACE((TRANSFER, "transfer() read sector %d\n", stuffp->pending)); + insb((unsigned int) stuffp->rreg_data, p, 512); + + /* test if it's the last sector of a block, + * if so, we have to expect an interrupt and to skip some + * data too */ + if ((stuffp->busy = (3 == (stuffp->pending & 3))) && stuffp->xa) { + char dummy[CD_XA_TAIL]; + TRACE((TRANSFER, "transfer() sector %d, skip %d trailer bytes\n", + stuffp->pending, CD_XA_TAIL)); + insb((unsigned int) stuffp->rreg_data, &dummy[0], CD_XA_TAIL); + } + + if (stuffp->pending == sector) { + p += 512; + done++; + sector++; + } + } + while (++(stuffp->pending) < off); + + stuffp->lock = 0; + wake_up_interruptible(&stuffp->lockq); + + } else { + + static unsigned char cmd[] = { + 0, + 0, 0, 0, + 0, 0, 0 + }; + + cmd[0] = stuffp->readcmd; + + stuffp->valid = 1; + stuffp->pending = sector & ~3; + + /* do some sanity checks */ + TRACE((TRANSFER, "transfer() request sector %d\n", stuffp->pending)); + if (stuffp->pending > stuffp->lastsector) { + printk(MCD ": transfer() sector %d from nirvana requested.\n", + stuffp->pending); + stuffp->errno = MCDX_EOM; + TRACE((TRANSFER, "transfer() done (-1)\n")); + return -1; + } + + if ((stuffp->off_direct = stuffp->pending + DIRECT_SIZE) + > stuffp->lastsector + 1) + stuffp->off_direct = stuffp->lastsector + 1; + if ((stuffp->off_requested = stuffp->pending + REQUEST_SIZE) + > stuffp->lastsector + 1) + stuffp->off_requested = stuffp->lastsector + 1; + + TRACE((TRANSFER, "transfer() pending %d\n", stuffp->pending)); + TRACE((TRANSFER, "transfer() off_dir %d\n", stuffp->off_direct)); + TRACE((TRANSFER, "transfer() off_req %d\n", stuffp->off_requested)); + + { + struct s_msf pending; + log2msf(stuffp->pending / 4, &pending); + cmd[1] = pending.minute; + cmd[2] = pending.second; + cmd[3] = pending.frame; + } + + stuffp->busy = 1; + cmd[6] = (unsigned char) (stuffp->off_requested - stuffp->pending) / 4; + + outsb((unsigned int) stuffp->wreg_data, cmd, sizeof cmd); + + } + + stuffp->off_direct = (stuffp->off_direct += done) < stuffp->off_requested + ? stuffp->off_direct : stuffp->off_requested; + + TRACE((TRANSFER, "transfer() done (%d)\n", done)); + return done; +} + + +/* Access to elements of the mcdx_drive_map members */ + +static char* port(int *ip) { return (char*) ip[0]; } +static int irq(int *ip) { return ip[1]; } + +/* Misc number converters */ + +static unsigned int bcd2uint(unsigned char c) +{ return (c >> 4) * 10 + (c & 0x0f); } + +static unsigned int uint2bcd(unsigned int ival) +{ return ((ival / 10) << 4) | (ival % 10); } + +static void log2msf(unsigned int l, struct s_msf* pmsf) +{ + l += CD_BLOCK_OFFSET; + pmsf->minute = uint2bcd(l / 4500), l %= 4500; + pmsf->second = uint2bcd(l / 75); + pmsf->frame = uint2bcd(l % 75); +} + +static unsigned int msf2log(const struct s_msf* pmsf) +{ + return bcd2uint(pmsf->frame) + + bcd2uint(pmsf->second) * 75 + + bcd2uint(pmsf->minute) * 4500 + - CD_BLOCK_OFFSET; +} + +int mcdx_readtoc(struct s_drive_stuff* stuffp) +{ + + TRACE((IOCTL, "ioctl() readtoc for %d tracks\n", + stuffp->di.n_last - stuffp->di.n_first + 1)); + +#if MCDX_DEBUG && IOCTL + if (stuffp->toc) { + TRACE((IOCTL, "ioctl() toc already read\n")); + return 0; + } +#endif + + TRACE((IOCTL, "ioctl() tocmode\n")); + if (-1 == mcdx_setdrivemode(stuffp, TOC, 1)) return -EIO; + + /* all seems to be ok so far ... malloc */ + { + int size; + size = sizeof(struct s_subqcode) * (stuffp->di.n_last - stuffp->di.n_first + 2); + + TRACE((MALLOC, "ioctl() malloc %d bytes\n", size)); + stuffp->toc = kmalloc(size, GFP_KERNEL); + if (!stuffp->toc) { + WARN(("Cannot malloc %s bytes for toc\n", size)); + mcdx_setdrivemode(stuffp, DATA, 1); + return -EIO; + } + } + + /* now read actually the index */ + { + int trk; + int retries; + + for (trk = 0; + trk < (stuffp->di.n_last - stuffp->di.n_first + 1); + trk++) + stuffp->toc[trk].index = 0; + + for (retries = 300; retries; retries--) { /* why 300? */ + struct s_subqcode q; + unsigned int idx; + + if (-1 == mcdx_requestsubqcode(stuffp, &q, 1)) { + mcdx_setdrivemode(stuffp, DATA, 1); + return -EIO; + } + + idx = bcd2uint(q.index); + + if ((idx > 0) + && (idx <= stuffp->di.n_last) + && (q.tno == 0) + && (stuffp->toc[idx - stuffp->di.n_first].index == 0)) { + stuffp->toc[idx - stuffp->di.n_first] = q; + trk--; + } + if (trk == 0) break; + } + memset(&stuffp->toc[stuffp->di.n_last - stuffp->di.n_first + 1], + 0, sizeof(stuffp->toc[0])); + stuffp->toc[stuffp->di.n_last - stuffp->di.n_first + 1].dt + = stuffp->di.msf_leadout; + } + + /* unset toc mode */ + TRACE((IOCTL, "ioctl() undo toc mode\n")); + if (-1 == mcdx_setdrivemode(stuffp, DATA, 2)) + return -EIO; + +#if MCDX_DEBUG && IOCTL + { int trk; + for (trk = 0; + trk < (stuffp->di.n_last - stuffp->di.n_first + 2); + trk++) + TRACE((IOCTL, "ioctl() %d readtoc %02x %02x %02x" + " %02x:%02x.%02x %02x:%02x.%02x\n", + trk + stuffp->di.n_first, + stuffp->toc[trk].control, stuffp->toc[trk].tno, stuffp->toc[trk].index, + stuffp->toc[trk].tt.minute, stuffp->toc[trk].tt.second, stuffp->toc[trk].tt.frame, + stuffp->toc[trk].dt.minute, stuffp->toc[trk].dt.second, stuffp->toc[trk].dt.frame)); + } +#endif + + + return 0; +} + +/* Drive functions ************************************************/ + +static int +mcdx_closedoor(struct s_drive_stuff *stuffp, int tries) +{ + if (stuffp->present & DOOR) + return mcdx_talk(stuffp, "\xf8", 1, NULL, 0, 500, tries); + else + return 0; +} + +static int +mcdx_stop(struct s_drive_stuff *stuffp, int tries) +{ return mcdx_talk(stuffp, "\xf0", 1, NULL, 0, 200, tries); } + +static int +mcdx_eject(struct s_drive_stuff *stuffp, int tries) +{ + if (stuffp->present & DOOR) + return mcdx_talk(stuffp, "\xf6", 1, NULL, 0, 500, tries); + else + return 0; +} + +static int +mcdx_requestsubqcode(struct s_drive_stuff *stuffp, struct s_subqcode *sub, int tries) +{ + char buf[11]; + int ans; + ans = mcdx_talk(stuffp, "\x20", 1, buf, sizeof(buf), 200, tries); + sub->control = buf[1]; + sub->tno = buf[2]; + sub->index = buf[3]; + sub->tt.minute = buf[4]; + sub->tt.second = buf[5]; + sub->tt.frame = buf[6]; + sub->dt.minute = buf[8]; + sub->dt.second = buf[9]; + sub->dt.frame = buf[10]; + return ans; +} + +static int +mcdx_requestmultidiskinfo(struct s_drive_stuff *stuffp, struct s_multi *multi, int tries) +{ + char buf[5]; + int ans; + + if (stuffp->present & MULTI) { + ans = mcdx_talk(stuffp, "\x11", 1, buf, sizeof(buf), 200, tries); + multi->multi = buf[1]; + multi->msf_last.minute = buf[2]; + multi->msf_last.second = buf[3]; + multi->msf_last.frame = buf[4]; + return ans; + } else { + multi->multi = 0; + return 0; + } +} + +static int +mcdx_requesttocdata(struct s_drive_stuff *stuffp, struct s_diskinfo *info, int tries) +{ + char buf[9]; + int ans; + ans = mcdx_talk(stuffp, "\x10", 1, buf, sizeof(buf), 200, tries); + info->n_first = bcd2uint(buf[1]); + info->n_last = bcd2uint(buf[2]); + info->msf_leadout.minute = buf[3]; + info->msf_leadout.second = buf[4]; + info->msf_leadout.frame = buf[5]; + info->msf_first.minute = buf[6]; + info->msf_first.second = buf[7]; + info->msf_first.frame = buf[8]; + return ans; +} + +static int +mcdx_setdrivemode(struct s_drive_stuff *stuffp, enum drivemodes mode, int tries) +{ + char cmd[2]; + int ans; + + TRACE((HW, "setdrivemode() %d\n", mode)); + + if (-1 == (ans = mcdx_talk(stuffp, "\xc2", 1, cmd, sizeof(cmd), 500, tries))) + return ans; + + switch (mode) { + case TOC: cmd[1] |= 0x04; break; + case DATA: cmd[1] &= ~0x04; break; + case RAW: cmd[1] |= 0x40; break; + case COOKED: cmd[1] &= ~0x40; break; + default: break; + } + cmd[0] = 0x50; + return mcdx_talk(stuffp, cmd, 2, NULL, 0, 500, tries); +} + + +static int +mcdx_setdatamode(struct s_drive_stuff *stuffp, enum datamodes mode, int tries) +{ + unsigned char cmd[2] = { 0xa0 }; + TRACE((HW, "setdatamode() %d\n", mode)); + switch (mode) { + case MODE0: cmd[1] = 0x00; break; + case MODE1: cmd[1] = 0x01; break; + case MODE2: cmd[1] = 0x02; break; + default: return -EINVAL; + } + return mcdx_talk(stuffp, cmd, 2, NULL, 0, 500, tries); +} + +static int +mcdx_config(struct s_drive_stuff *stuffp, int tries) +{ + char cmd[4]; + + TRACE((HW, "config()\n")); + + cmd[0] = 0x90; + + cmd[1] = 0x10; /* irq enable */ + cmd[2] = 0x05; /* pre, err irq enable */ + + if (-1 == mcdx_talk(stuffp, cmd, 3, NULL, 0, 100, tries)) + return -1; + + cmd[1] = 0x02; /* dma select */ + cmd[2] = 0x00; /* no dma */ + + return mcdx_talk(stuffp, cmd, 3, NULL, 0, 100, tries); +} + +static int +mcdx_requestversion(struct s_drive_stuff *stuffp, struct s_version *ver, int tries) +{ + char buf[3]; + int ans; + + if (-1 == (ans = mcdx_talk(stuffp, "\xdc", 1, buf, sizeof(buf), 200, tries))) + return ans; + + ver->code = buf[1]; + ver->ver = buf[2]; + + return ans; +} + +static int +mcdx_reset(struct s_drive_stuff *stuffp, enum resetmodes mode, int tries) +{ + if (mode == HARD) { + outb(0, (unsigned int) stuffp->wreg_chn); /* no dma, no irq -> hardware */ + outb(0, (unsigned int) stuffp->wreg_reset); /* hw reset */ + return 0; + } else return mcdx_talk(stuffp, "\x60", 1, NULL, 0, 500, tries); +} + +static int +mcdx_lockdoor(struct s_drive_stuff *stuffp, int lock, int tries) +{ + char cmd[2] = { 0xfe }; + if (stuffp->present & DOOR) { + cmd[1] = lock ? 0x01 : 0x00; + return mcdx_talk(stuffp, cmd, sizeof(cmd), NULL, 0, 500, tries); + } else + return 0; +} + +#if 0 +static int +mcdx_getstatus(struct s_drive_stuff *stuffp, int tries) +{ return mcdx_talk(stuffp, "\x40", 1, NULL, 0, 500, tries); } +#endif diff -u --recursive --new-file v1.3.6/linux/drivers/block/optcd.c linux/drivers/block/optcd.c --- v1.3.6/linux/drivers/block/optcd.c Thu Jan 1 02:00:00 1970 +++ linux/drivers/block/optcd.c Sat Jul 1 19:05:59 1995 @@ -0,0 +1,1408 @@ +/* $Id: optcd.c,v 1.7 1995/06/28 20:20:13 root Exp $ + linux/drivers/block/optcd.c - Optics Storage 8000 AT CDROM driver + + Copyright (C) 1995 Leo Spiekman (spiekman@dutette.et.tudelft.nl) + + Based on Aztech CD268 CDROM driver by Werner Zimmermann and preworks + by Eberhard Moenkeberg. + + 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. + + History + 14-5-95 v0.0 Plays sound tracks. No reading of data CDs yet. + Detection of disk change doesn't work. + 21-5-95 v0.1 First ALPHA version. CD can be mounted. The + device major nr is borrowed from the Aztech + driver. Speed is around 240 kb/s, as measured + with "time dd if=/dev/cdrom of=/dev/null \ + bs=2048 count=4096". + 24-6-95 v0.2 Reworked the #defines for the command codes + and the like, as well as the structure of + the hardware communication protocol, to + reflect the "official" documentation, kindly + supplied by C.K. Tan, Optics Storage Pte. Ltd. + Also tidied up the state machine somewhat. + 28-6-95 v0.3 Removed the ISP-16 interface code, as this + should go into its own driver. The driver now + has its own major nr. + Disk change detection now seems to work, too. +*/ + +#include +#include + +#ifdef MODULE +# include +# include +# ifndef CONFIG_MODVERSIONS + char kernel_version[]= UTS_RELEASE; +# endif +#else +# define MOD_INC_USE_COUNT +# define MOD_DEC_USE_COUNT +#endif + +#include +#include +#include +#include +#include +#include +#include +#include + +#define MAJOR_NR OPTICS_CDROM_MAJOR + +# include "blk.h" +#define optcd_port optcd /* Needed for the modutils. */ +# include + +static short optcd_port = OPTCD_PORTBASE; + +/* Read current status/data availability flags */ +inline static int optFlags(void) { + return inb(STATUS_PORT) & FL_STDT; +} + +/* Wait for status available; return TRUE on timeout */ +static int sten_low(void) { + int no_status; + unsigned long count = 0; + while ((no_status = (optFlags() & FL_STEN))) + if (++count >= BUSY_TIMEOUT) + break; +#ifdef DEBUG_DRIVE_IF + if (no_status) + printk("optcd: timeout waiting for STEN low\n"); + else + printk("optcd: STEN low after %ld\n", count); +#endif + return no_status; +} + +/* Wait for data available; return TRUE on timeout */ +static int dten_low(void) { + int no_data; + unsigned long count = 0; + while ((no_data = (optFlags() & FL_DTEN))) + if (++count >= BUSY_TIMEOUT) + break; +#ifdef DEBUG_DRIVE_IF + if (no_data) + printk("optcd: timeout waiting for DTEN low\n"); + else + printk("optcd: DTEN low after %ld\n", count); +#endif + return no_data; +} + +/* Facilities for polled waiting for status or data */ +static int sleep_timeout; /* Max amount of time still to sleep */ +static unsigned char sleep_flags; /* Flags read last time around */ +static struct wait_queue *waitq = NULL; +static struct timer_list delay_timer = {NULL, NULL, 0, 0, NULL}; + +/* Timer routine: wake up when either of FL_STEN or FL_DTEN goes down, + * or when timeout expires. Otherwise wait some more. + */ +static void sleep_timer(void) { + if ((sleep_flags = optFlags()) != FL_STDT) { + wake_up(&waitq); + return; + } + if (--sleep_timeout <= 0) { + wake_up(&waitq); + return; + } + SET_TIMER(sleep_timer, 1); +} + +/* Sleep until any of FL_STEN or FL_DTEN go down, or until timeout. + * sleep_timeout must be set first. + */ +static int sleep_status(void) { +#ifdef DEBUG_DRIVE_IF + printk("optcd: sleeping %d on status\n", sleep_timeout); +#endif + if (sleep_timeout <= 0) /* timeout immediately */ + return FL_STDT; + if ((sleep_flags = optFlags()) == FL_STDT) { + SET_TIMER(sleep_timer, 1); + sleep_on(&waitq); + } +#ifdef DEBUG_DRIVE_IF + printk("optcd: woken up with %d to go, flags %d\n", + sleep_timeout, sleep_flags); +#endif + return sleep_flags; +} + +/* Sleep until status available; return TRUE on timeout */ +inline static int sleep_sten_low(void) { + int flags; + sleep_timeout = SLEEP_TIMEOUT; + flags = sleep_status(); +#ifdef DEBUG_DRIVE_IF + if (!(flags & FL_DTEN)) + printk("optcd: DTEN while waiting for STEN\n"); +#endif + return flags & FL_STEN; +} + +/* Sleep until data available; return TRUE on timeout */ +inline static int sleep_dten_low(void) { + int flags; + sleep_timeout = SLEEP_TIMEOUT; + flags = sleep_status(); +#ifdef DEBUG_DRIVE_IF + if (!(flags & FL_STEN)) + printk("optcd: STEN while waiting for DTEN\n"); +#endif + return flags & FL_DTEN; +} + +/* Send command code. Return <0 indicates error */ +static int optSendCmd(int cmd) { + unsigned char ack; +#if defined(DEBUG_DRIVE_IF)||defined(DEBUG_COMMANDS) + printk("optcd: executing command 0x%02x\n", cmd); +#endif + outb(HCON_DTS, HCON_PORT); /* Enable Suspend Data Transfer */ + outb(cmd, COMIN_PORT); /* Send command code */ + if (sten_low()) /* Wait for status available */ + return -ERR_IF_CMD_TIMEOUT; + ack = inb(DATA_PORT); /* read command acknowledge */ +#ifdef DEBUG_DRIVE_IF + printk("optcd: acknowledge code 0x%02x\n", ack); +#endif + outb(HCON_SDRQB, HCON_PORT); /* Disable Suspend Data Transfer */ + return ack==ST_OP_OK ? 0 : -ack; +} + +/* Send command parameters. Return <0 indicates error */ +static int optSendParams(struct opt_Play_msf *params) { + unsigned char ack; +#if defined(DEBUG_DRIVE_IF)||defined(DEBUG_COMMANDS) + printk("optcd: params %02x:%02x:%02x %02x:%02x:%02x\n", + params->start.min, params->start.sec, params->start.frame, + params->end.min, params->end.sec, params->end.frame); +#endif + outb(params -> start.min, COMIN_PORT); + outb(params -> start.sec, COMIN_PORT); + outb(params -> start.frame, COMIN_PORT); + outb(params -> end.min, COMIN_PORT); + outb(params -> end.sec, COMIN_PORT); + outb(params -> end.frame, COMIN_PORT); + if (sten_low()) /* Wait for status available */ + return -ERR_IF_CMD_TIMEOUT; + ack = inb(DATA_PORT); /* read command acknowledge */ +#ifdef DEBUG_DRIVE_IF + printk("optcd: acknowledge code 0x%02x\n", ack); +#endif + return ack==ST_PA_OK ? 0 : -ack; +} + +/* Return execution status for quick response commands, i.e. busy wait. + * Return value <0 indicates timeout. + */ +static int optGetExecStatus(void) { + unsigned char exec_status; + if (sten_low()) /* Wait for status available */ + return -ERR_IF_CMD_TIMEOUT; + exec_status = inb(DATA_PORT); /* read command execution status */ +#ifdef DEBUG_DRIVE_IF + printk("optcd: returned execution status: 0x%02x\n", exec_status); +#endif + return exec_status; +} + +/* Return execution status for slow commands. Only use when no data is + * expected. Return value <0 indicates timeout. + */ +static int optSleepTillExecStatus(void) { + unsigned char exec_status; + if (sleep_sten_low()) /* Wait for status available */ + return -ERR_IF_CMD_TIMEOUT; + exec_status = inb(DATA_PORT); /* read command execution status */ +#ifdef DEBUG_DRIVE_IF + printk("optcd: returned execution status: 0x%02x\n", exec_status); +#endif + return exec_status; +} + +/* Fetch status that has previously been waited for. <0 means not available */ +inline static int optStatus(void) { + unsigned char status; + if (optFlags() & FL_STEN) + return -ERR_IF_NOSTAT; + status = inb(DATA_PORT); +#ifdef DEBUG_DRIVE_IF + printk("optcd: read status: 0x%02x\n", status); +#endif + return status; +} + +/* Wait for extra byte of data that a command returns */ +static int optGetData(void) { + unsigned char data; + if (sten_low()) + return -ERR_IF_DATA_TIMEOUT; + data = inb(DATA_PORT); +#ifdef DEBUG_DRIVE_IF + printk("optcd: read data: 0x%02x\n", data); +#endif + return data; +} + +/* Read data that has previously been waited for. */ +inline static void optReadData(char *buf, int n) { + insb(DATA_PORT, buf, n); +} + +/* Flush status and data fifos */ +inline static void optFlushData(void) { + while (optFlags() != FL_STDT) + inb(DATA_PORT); +} + +/* Write something to RESET_PORT and wait. Return TRUE upon success. */ +static int optResetDrive(void) { + unsigned long count = 0; + int flags; +#ifdef DEBUG_DRIVE_IF + printk("optcd: reset drive\n"); +#endif + outb(0, RESET_PORT); + while (++count < RESET_WAIT) + inb(DATA_PORT); + count = 0; + while ((flags = (inb(STATUS_PORT) & FL_RESET)) != FL_RESET) + if (++count >= BUSY_TIMEOUT) + break; +#ifdef DEBUG_DRIVE_IF + if (flags == FL_RESET) + printk("optcd: drive reset\n"); + else + printk("optcd: reset failed\n"); +#endif + if (flags != FL_RESET) + return 0; /* Reset failed */ + outb(HCON_SDRQB, HCON_PORT); /* Disable Suspend Data Transfer */ + return 1; /* Reset succeeded */ +} + + +/* Command protocol */ + +/* Send a simple command and wait for response */ +inline static int optCmd(int cmd) { + int ack = optSendCmd(cmd); + if (ack < 0) + return ack; + if (cmd < COMFETCH) /* Quick response command */ + return optGetExecStatus(); + else /* Slow command */ + return optSleepTillExecStatus(); +} + +/* Send a command with parameters and wait for response */ +inline static int optPlayCmd(int cmd, struct opt_Play_msf *params) { + int ack = optSendCmd(cmd); + if (ack < 0) + return ack; + if ((ack = optSendParams(params)) < 0) + return ack; + return optSleepTillExecStatus(); +} + +/* Send a command with parameters. Don't wait for the response, + * which consists of the data blocks read. */ +inline static int optReadCmd(int cmd, struct opt_Play_msf *params) { + int ack = optSendCmd(cmd); + if (ack < 0) + return ack; + return optSendParams(params); +} + + +/* Address conversion routines */ + +/* Binary to BCD (2 digits) */ +inline static unsigned char bin2bcd(unsigned char p) { +#ifdef DEBUG_CONV + if (p > 99) + printk("optcd: error bin2bcd %d\n", p); +#endif + return (p % 10) | ((p / 10) << 4); +} + +/* Linear address to minute, second, frame form */ +static void hsg2msf(long hsg, struct msf *msf) { + hsg += 150; + msf -> min = hsg / 4500; + hsg %= 4500; + msf -> sec = hsg / 75; + msf -> frame = hsg % 75; +#ifdef DEBUG_CONV + if (msf -> min >= 70) + printk("optcd: Error hsg2msf address Minutes\n"); + if (msf -> sec >= 60) + printk("optcd: Error hsg2msf address Seconds\n"); + if (msf -> frame >= 75) + printk("optcd: Error hsg2msf address Frames\n"); +#endif + msf -> min = bin2bcd(msf -> min); /* convert to BCD */ + msf -> sec = bin2bcd(msf -> sec); + msf -> frame = bin2bcd(msf -> frame); +} + +/* Two BCD digits to binary */ +inline static int bcd2bin(unsigned char bcd) { + return (bcd >> 4) * 10 + (bcd & 0x0f); +} + +/* Minute, second, frame address to linear address */ +static long msf2hsg(struct msf *mp) { +#ifdef DEBUG_CONV + if (mp -> min >= 70) + printk("optcd: Error msf2hsg address Minutes\n"); + if (mp -> sec >= 60) + printk("optcd: Error msf2hsg address Seconds\n"); + if (mp -> frame >= 75) + printk("optcd: Error msf2hsg address Frames\n"); +#endif + return bcd2bin(mp -> frame) + + bcd2bin(mp -> sec) * 75 + + bcd2bin(mp -> min) * 4500 + - 150; +} + + +/* Drive status and table of contents */ + +static int optAudioStatus = CDROM_AUDIO_NO_STATUS; +static char optDiskChanged = 1; +static char optTocUpToDate = 0; +static struct opt_DiskInfo DiskInfo; +static struct opt_Toc Toc[MAX_TRACKS]; + +/* Get CDROM status, flagging completion of audio play and disk changes. */ +static int optGetStatus(void) { + int st; + if ((st = optCmd(COMIOCTLISTAT)) < 0) + return st; + if (st == 0xff) + return -ERR_IF_NOSTAT; + if (((st & ST_MODE_BITS) != ST_M_AUDIO) && + (optAudioStatus == CDROM_AUDIO_PLAY)) { + optAudioStatus = CDROM_AUDIO_COMPLETED; + } + if (st & ST_DSK_CHG) { + optDiskChanged = 1; + optTocUpToDate = 0; + optAudioStatus = CDROM_AUDIO_NO_STATUS; + } + return st; +} + +/* + * Read the current Q-channel info. Also used for reading the + * table of contents. + */ +static int optGetQChannelInfo(struct opt_Toc *qp) { + int st; +#ifdef DEBUG_TOC + printk("optcd: starting optGetQChannelInfo\n"); +#endif + if ((st = optGetStatus()) < 0) + return st; + if ((st = optCmd(COMSUBQ)) < 0) + return st; + if ((qp -> ctrl_addr = st = optGetData()), st < 0) return st; + if ((qp -> track = st = optGetData()), st < 0) return st; + if ((qp -> pointIndex = st = optGetData()), st < 0) return st; + if ((qp -> trackTime.min = st = optGetData()), st < 0) return st; + if ((qp -> trackTime.sec = st = optGetData()), st < 0) return st; + if ((qp -> trackTime.frame = st = optGetData()), st < 0) return st; + if ((st = optGetData()) < 0) return st; /* byte not used */ + if ((qp -> diskTime.min = st = optGetData()), st < 0) return st; + if ((qp -> diskTime.sec = st = optGetData()), st < 0) return st; + if ((qp -> diskTime.frame = st = optGetData()), st < 0) return st; +#ifdef DEBUG_TOC + printk("optcd: exiting optGetQChannelInfo\n"); +#endif + return 0; +} + +#define QINFO_FIRSTTRACK 0xa0 +#define QINFO_LASTTRACK 0xa1 +#define QINFO_DISKLENGTH 0xa2 + +static int optGetDiskInfo(void) { + int st, limit; + unsigned char test = 0; + struct opt_Toc qInfo; +#ifdef DEBUG_TOC + printk("optcd: starting optGetDiskInfo\n"); +#endif + optDiskChanged = 0; + if ((st = optCmd(COMLEADIN)) < 0) + return st; + for (limit = 300; (limit > 0) && (test != 0x0f); limit--) { + if ((st = optGetQChannelInfo(&qInfo)) < 0) + return st; + switch (qInfo.pointIndex) { + case QINFO_FIRSTTRACK: + DiskInfo.first = bcd2bin(qInfo.diskTime.min); +#ifdef DEBUG_TOC + printk("optcd: got first: %d\n", DiskInfo.first); +#endif + test |= 0x01; + break; + case QINFO_LASTTRACK: + DiskInfo.last = bcd2bin(qInfo.diskTime.min); +#ifdef DEBUG_TOC + printk("optcd: got last: %d\n", DiskInfo.last); +#endif + test |= 0x02; + break; + case QINFO_DISKLENGTH: + DiskInfo.diskLength.min = qInfo.diskTime.min; + DiskInfo.diskLength.sec = qInfo.diskTime.sec-2; + DiskInfo.diskLength.frame = qInfo.diskTime.frame; +#ifdef DEBUG_TOC + printk("optcd: got length: %x:%x.%x\n", + DiskInfo.diskLength.min, + DiskInfo.diskLength.sec, + DiskInfo.diskLength.frame); +#endif + test |= 0x04; + break; + default: + if ((test & 0x01) /* Got no of first track */ + && (qInfo.pointIndex == DiskInfo.first)) { + /* StartTime of First Track */ + DiskInfo.firstTrack.min = qInfo.diskTime.min; + DiskInfo.firstTrack.sec = qInfo.diskTime.sec; + DiskInfo.firstTrack.frame = qInfo.diskTime.frame; +#ifdef DEBUG_TOC + printk("optcd: got start: %x:%x.%x\n", + DiskInfo.firstTrack.min, + DiskInfo.firstTrack.sec, + DiskInfo.firstTrack.frame); +#endif + test |= 0x08; + } + } + } +#ifdef DEBUG_TOC + printk("optcd: exiting optGetDiskInfo\n"); +#endif + if (test != 0x0f) + return -ERR_TOC_MISSINGINFO; + return 0; +} + +static int optGetToc(void) { /* Presumes we have got DiskInfo */ + int st, count, px, limit; + struct opt_Toc qInfo; +#ifdef DEBUG_TOC + int i; + printk("optcd: starting optGetToc\n"); +#endif + for (count = 0; count < MAX_TRACKS; count++) + Toc[count].pointIndex = 0; + if ((st = optCmd(COMLEADIN)) < 0) + return st; + st = 0; + count = DiskInfo.last + 3; + for (limit = 300; (limit > 0) && (count > 0); limit--) { + if ((st = optGetQChannelInfo(&qInfo)) < 0) + break; + px = bcd2bin(qInfo.pointIndex); + if (px > 0 && px < MAX_TRACKS && qInfo.track == 0) + if (Toc[px].pointIndex == 0) { + Toc[px] = qInfo; + count--; + } + } + Toc[DiskInfo.last + 1].diskTime = DiskInfo.diskLength; +#ifdef DEBUG_TOC + printk("optcd: exiting optGetToc\n"); + for (i = 1; i <= DiskInfo.last + 1; i++) + printk("i = %3d ctl-adr = %02x track %2d px " + "%02x %02x:%02x.%02x %02x:%02x.%02x\n", + i, Toc[i].ctrl_addr, + Toc[i].track, + Toc[i].pointIndex, + Toc[i].trackTime.min, + Toc[i].trackTime.sec, + Toc[i].trackTime.frame, + Toc[i].diskTime.min, + Toc[i].diskTime.sec, + Toc[i].diskTime.frame); + for (i = 100; i < 103; i++) + printk("i = %3d ctl-adr = %02x track %2d px " + "%02x %02x:%02x.%02x %02x:%02x.%02x\n", + i, Toc[i].ctrl_addr, + Toc[i].track, + Toc[i].pointIndex, + Toc[i].trackTime.min, + Toc[i].trackTime.sec, + Toc[i].trackTime.frame, + Toc[i].diskTime.min, + Toc[i].diskTime.sec, + Toc[i].diskTime.frame); +#endif + return count ? -ERR_TOC_MISSINGENTRY : 0; +} + +static int optUpdateToc(void) { +#ifdef DEBUG_TOC + printk("optcd: starting optUpdateToc\n"); +#endif + if (optTocUpToDate) + return 0; + if (optGetDiskInfo() < 0) + return -EIO; + if (optGetToc() < 0) + return -EIO; + optTocUpToDate = 1; +#ifdef DEBUG_TOC + printk("optcd: exiting optUpdateToc\n"); +#endif + return 0; +} + + +/* Buffers */ + +#define OPT_BUF_SIZ 16 +#define OPT_BLOCKSIZE 2048 +#define OPT_BLOCKSIZE_RAW 2336 +#define OPT_BLOCKSIZE_ALL 2646 +#define OPT_NOBUF -1 + +/* Buffer for block size conversion. */ +static char opt_buf[OPT_BLOCKSIZE*OPT_BUF_SIZ]; +static volatile int opt_buf_bn[OPT_BUF_SIZ], opt_next_bn; +static volatile int opt_buf_in = 0, opt_buf_out = OPT_NOBUF; + +inline static void opt_invalidate_buffers(void) { + int i; +#ifdef DEBUG_BUFFERS + printk("optcd: executing opt_invalidate_buffers\n"); +#endif + for (i = 0; i < OPT_BUF_SIZ; i++) + opt_buf_bn[i] = OPT_NOBUF; + opt_buf_out = OPT_NOBUF; +} + +/* + * Take care of the different block sizes between cdrom and Linux. + * When Linux gets variable block sizes this will probably go away. + */ +static void opt_transfer(void) { +#if (defined DEBUG_BUFFERS) || (defined DEBUG_REQUEST) + printk("optcd: executing opt_transfer\n"); +#endif + if (!CURRENT_VALID) + return; + while (CURRENT -> nr_sectors) { + int bn = CURRENT -> sector / 4; + int i, offs, nr_sectors; + for (i = 0; i < OPT_BUF_SIZ && opt_buf_bn[i] != bn; ++i); +#ifdef DEBUG_REQUEST + printk("optcd: found %d\n", i); +#endif + if (i >= OPT_BUF_SIZ) { + opt_buf_out = OPT_NOBUF; + break; + } + offs = (i * 4 + (CURRENT -> sector & 3)) * 512; + nr_sectors = 4 - (CURRENT -> sector & 3); + if (opt_buf_out != i) { + opt_buf_out = i; + if (opt_buf_bn[i] != bn) { + opt_buf_out = OPT_NOBUF; + continue; + } + } + if (nr_sectors > CURRENT -> nr_sectors) + nr_sectors = CURRENT -> nr_sectors; + memcpy(CURRENT -> buffer, opt_buf + offs, nr_sectors * 512); + CURRENT -> nr_sectors -= nr_sectors; + CURRENT -> sector += nr_sectors; + CURRENT -> buffer += nr_sectors * 512; + } +} + + +/* State machine for reading disk blocks */ + +enum opt_state_e { + OPT_S_IDLE, /* 0 */ + OPT_S_START, /* 1 */ + OPT_S_READ, /* 2 */ + OPT_S_DATA, /* 3 */ + OPT_S_STOP, /* 4 */ + OPT_S_STOPPING /* 5 */ +}; + +static volatile enum opt_state_e opt_state = OPT_S_IDLE; +#ifdef DEBUG_STATE +static volatile enum opt_state_e opt_state_old = OPT_S_STOP; +static volatile int opt_st_old = 0; +static volatile long opt_state_n = 0; +#endif + +static volatile int opt_transfer_is_active = 0; +static volatile int opt_error = 0; /* do something with this?? */ +static int optTries; /* ibid?? */ + +static void opt_poll(void) { + static int optTimeout; + static volatile int opt_read_count = 1; + int st = 0; + int loop_ctl = 1; + int skip = 0; + + if (opt_error) { + printk("optcd: I/O error 0x%02x\n", opt_error); + opt_invalidate_buffers(); +#ifdef WARN_IF_READ_FAILURE + if (optTries == 5) + printk("optcd: read block %d failed; audio disk?\n", + opt_next_bn); +#endif + if (!optTries--) { + printk("optcd: read block %d failed; Giving up\n", + opt_next_bn); + if (opt_transfer_is_active) { + optTries = 0; + loop_ctl = 0; + } + if (CURRENT_VALID) + end_request(0); + optTries = 5; + } + opt_error = 0; + opt_state = OPT_S_STOP; + } + + while (loop_ctl) + { + loop_ctl = 0; /* each case must flip this back to 1 if we want + to come back up here */ +#ifdef DEBUG_STATE + if (opt_state == opt_state_old) + opt_state_n++; + else { + opt_state_old = opt_state; + if (++opt_state_n > 1) + printk("optcd: %ld times in previous state\n", + opt_state_n); + printk("optcd: state %d\n", opt_state); + opt_state_n = 0; + } +#endif + switch (opt_state) { + case OPT_S_IDLE: + return; + case OPT_S_START: + if (optSendCmd(COMDRVST)) + return; + opt_state = OPT_S_READ; + optTimeout = 3000; + break; + case OPT_S_READ: { + struct opt_Play_msf msf; + if (!skip) { + if ((st = optStatus()) < 0) + break; + if (st & ST_DSK_CHG) { + optDiskChanged = 1; + optTocUpToDate = 0; + opt_invalidate_buffers(); + } + } + skip = 0; + if ((st & ST_DOOR_OPEN) || (st & ST_DRVERR)) { + optDiskChanged = 1; + optTocUpToDate = 0; + printk((st & ST_DOOR_OPEN) + ? "optcd: door open\n" + : "optcd: disk removed\n"); + if (opt_transfer_is_active) { + opt_state = OPT_S_START; + loop_ctl = 1; + break; + } + opt_state = OPT_S_IDLE; + while (CURRENT_VALID) + end_request(0); + return; + } + if (!CURRENT_VALID) { + opt_state = OPT_S_STOP; + loop_ctl = 1; + break; + } + opt_next_bn = CURRENT -> sector / 4; + hsg2msf(opt_next_bn, &msf.start); + opt_read_count = OPT_BUF_SIZ; + msf.end.min = 0; + msf.end.sec = 0; + msf.end.frame = opt_read_count; +#ifdef DEBUG_REQUEST + printk("optcd: reading %x:%x.%x %x:%x.%x\n", + msf.start.min, + msf.start.sec, + msf.start.frame, + msf.end.min, + msf.end.sec, + msf.end.frame); + printk("optcd: opt_next_bn:%d opt_buf_in:%d opt_buf_out:%d opt_buf_bn:%d\n", + opt_next_bn, + opt_buf_in, + opt_buf_out, + opt_buf_bn[opt_buf_in]); +#endif + optReadCmd(COMREAD, &msf); + opt_state = OPT_S_DATA; + optTimeout = READ_TIMEOUT; + break; + } + case OPT_S_DATA: + st = optFlags() & (FL_STEN|FL_DTEN); +#ifdef DEBUG_STATE + if (st != opt_st_old) { + opt_st_old = st; + printk("optcd: st:%x\n", st); + } + if (st == FL_STEN) + printk("timeout cnt: %d\n", optTimeout); +#endif + switch (st) { + case FL_DTEN: +#ifdef WARN_IF_READ_FAILURE + if (optTries == 5) + printk("optcd: read block %d failed; audio disk?\n", + opt_next_bn); +#endif + if (!optTries--) { + printk("optcd: read block %d failed; Giving up\n", + opt_next_bn); + if (opt_transfer_is_active) { + optTries = 0; + break; + } + if (CURRENT_VALID) + end_request(0); + optTries = 5; + } + opt_state = OPT_S_START; + optTimeout = READ_TIMEOUT; + loop_ctl = 1; + case (FL_STEN|FL_DTEN): + break; + default: + optTries = 5; + if (!CURRENT_VALID && opt_buf_in == opt_buf_out) { + opt_state = OPT_S_STOP; + loop_ctl = 1; + break; + } + if (opt_read_count<=0) + printk("optcd: warning - try to read 0 frames\n"); + while (opt_read_count) { + opt_buf_bn[opt_buf_in] = OPT_NOBUF; + if (dten_low()) { /* should be no waiting here!?? */ + printk("read_count:%d CURRENT->nr_sectors:%ld opt_buf_in:%d\n", + opt_read_count, + CURRENT->nr_sectors, + opt_buf_in); + printk("opt_transfer_is_active:%x\n", + opt_transfer_is_active); + opt_read_count = 0; + opt_state = OPT_S_STOP; + loop_ctl = 1; + end_request(0); + break; + } + optReadData(opt_buf+OPT_BLOCKSIZE*opt_buf_in, OPT_BLOCKSIZE); + opt_read_count--; +#ifdef DEBUG_REQUEST + printk("OPT_S_DATA; ---I've read data- read_count: %d\n", + opt_read_count); + printk("opt_next_bn:%d opt_buf_in:%d opt_buf_out:%d opt_buf_bn:%d\n", + opt_next_bn, + opt_buf_in, + opt_buf_out, + opt_buf_bn[opt_buf_in]); +#endif + opt_buf_bn[opt_buf_in] = opt_next_bn++; + if (opt_buf_out == OPT_NOBUF) + opt_buf_out = opt_buf_in; + opt_buf_in = opt_buf_in + 1 == + OPT_BUF_SIZ ? 0 : opt_buf_in + 1; + } + if (!opt_transfer_is_active) { + while (CURRENT_VALID) { + opt_transfer(); + if (CURRENT -> nr_sectors == 0) + end_request(1); + else + break; + } + } + + if (CURRENT_VALID + && (CURRENT -> sector / 4 < opt_next_bn || + CURRENT -> sector / 4 > + opt_next_bn + OPT_BUF_SIZ)) { + opt_state = OPT_S_STOP; + loop_ctl = 1; + break; + } + optTimeout = READ_TIMEOUT; + if (opt_read_count == 0) { + opt_state = OPT_S_STOP; + loop_ctl = 1; + break; + } + } + break; + case OPT_S_STOP: + if (opt_read_count != 0) + printk("optcd: discard data=%x frames\n", + opt_read_count); + while (opt_read_count != 0) { + optFlushData(); + opt_read_count--; + } + if (optSendCmd(COMDRVST)) + return; + opt_state = OPT_S_STOPPING; + optTimeout = 1000; + break; + case OPT_S_STOPPING: + if ((st = optStatus()) < 0 && optTimeout) + break; + if ((st != -1) && (st & ST_DSK_CHG)) { + optDiskChanged = 1; + optTocUpToDate = 0; + opt_invalidate_buffers(); + } + if (CURRENT_VALID) { + if (st != -1) { + opt_state = OPT_S_READ; + loop_ctl = 1; + skip = 1; + break; + } else { + opt_state = OPT_S_START; + optTimeout = 1; + } + } else { + opt_state = OPT_S_IDLE; + return; + } + break; + default: + printk("optcd: invalid state %d\n", opt_state); + return; + } /* case */ + } /* while */ + + if (!optTimeout--) { + printk("optcd: timeout in state %d\n", opt_state); + opt_state = OPT_S_STOP; + if (optCmd(COMSTOP) < 0) + return; + } + + SET_TIMER(opt_poll, 1); +} + + +static void do_optcd_request(void) { +#ifdef DEBUG_REQUEST + printk("optcd: do_optcd_request(%ld+%ld)\n", + CURRENT -> sector, CURRENT -> nr_sectors); +#endif + opt_transfer_is_active = 1; + while (CURRENT_VALID) { + if (CURRENT->bh) { + if (!CURRENT->bh->b_lock) + panic(DEVICE_NAME ": block not locked"); + } + opt_transfer(); /* First try to transfer block from buffers */ + if (CURRENT -> nr_sectors == 0) { + end_request(1); + } else { /* Want to read a block not in buffer */ + opt_buf_out = OPT_NOBUF; + if (opt_state == OPT_S_IDLE) { + /* Should this block the request queue?? */ + if (optUpdateToc() < 0) { + while (CURRENT_VALID) + end_request(0); + break; + } + /* Start state machine */ + opt_state = OPT_S_START; + optTries = 5; + SET_TIMER(opt_poll, 1); /* why not start right away?? */ + } + break; + } + } + opt_transfer_is_active = 0; +#ifdef DEBUG_REQUEST + printk("opt_next_bn:%d opt_buf_in:%d opt_buf_out:%d opt_buf_bn:%d\n", + opt_next_bn, opt_buf_in, opt_buf_out, opt_buf_bn[opt_buf_in]); + printk("optcd: do_optcd_request ends\n"); +#endif +} + + +/* VFS calls */ + +static int opt_ioctl(struct inode *ip, struct file *fp, + unsigned int cmd, unsigned long arg) { + static struct opt_Play_msf opt_Play; /* pause position */ + int err; +#ifdef DEBUG_VFS + printk("optcd: starting opt_ioctl, command 0x%x\n", cmd); +#endif + if (!ip) + return -EINVAL; + if (optGetStatus() < 0) + return -EIO; + if ((err = optUpdateToc()) < 0) + return err; + + switch (cmd) { + case CDROMPAUSE: { + struct opt_Toc qInfo; + + if (optAudioStatus != CDROM_AUDIO_PLAY) + return -EINVAL; + if (optGetQChannelInfo(&qInfo) < 0) { + /* didn't get q channel info */ + optAudioStatus = CDROM_AUDIO_NO_STATUS; + return 0; + } + opt_Play.start = qInfo.diskTime; /* restart point */ + if (optCmd(COMPAUSEON) < 0) + return -EIO; + optAudioStatus = CDROM_AUDIO_PAUSED; + break; + } + case CDROMRESUME: + if (optAudioStatus != CDROM_AUDIO_PAUSED) + return -EINVAL; + if (optPlayCmd(COMPLAY, &opt_Play) < 0) { + optAudioStatus = CDROM_AUDIO_ERROR; + return -EIO; + } + optAudioStatus = CDROM_AUDIO_PLAY; + break; + case CDROMPLAYMSF: { + int st; + struct cdrom_msf msf; + + if ((st = verify_area(VERIFY_READ, (void *) arg, sizeof msf))) + return st; + memcpy_fromfs(&msf, (void *) arg, sizeof msf); + opt_Play.start.min = bin2bcd(msf.cdmsf_min0); + opt_Play.start.sec = bin2bcd(msf.cdmsf_sec0); + opt_Play.start.frame = bin2bcd(msf.cdmsf_frame0); + opt_Play.end.min = bin2bcd(msf.cdmsf_min1); + opt_Play.end.sec = bin2bcd(msf.cdmsf_sec1); + opt_Play.end.frame = bin2bcd(msf.cdmsf_frame1); + if (optPlayCmd(COMPLAY, &opt_Play) < 0) { + optAudioStatus = CDROM_AUDIO_ERROR; + return -EIO; + } + optAudioStatus = CDROM_AUDIO_PLAY; + break; + } + case CDROMPLAYTRKIND: { + int st; + struct cdrom_ti ti; + + if ((st = verify_area(VERIFY_READ, (void *) arg, sizeof ti))) + return st; + memcpy_fromfs(&ti, (void *) arg, sizeof ti); + if (ti.cdti_trk0 < DiskInfo.first + || ti.cdti_trk0 > DiskInfo.last + || ti.cdti_trk1 < ti.cdti_trk0) + return -EINVAL; + if (ti.cdti_trk1 > DiskInfo.last) + ti.cdti_trk1 = DiskInfo.last; + opt_Play.start = Toc[ti.cdti_trk0].diskTime; + opt_Play.end = Toc[ti.cdti_trk1 + 1].diskTime; +#ifdef DEBUG_VFS + printk("optcd: play %02x:%02x.%02x to %02x:%02x.%02x\n", + opt_Play.start.min, + opt_Play.start.sec, + opt_Play.start.frame, + opt_Play.end.min, + opt_Play.end.sec, + opt_Play.end.frame); +#endif + if (optPlayCmd(COMPLAY, &opt_Play) < 0) { + optAudioStatus = CDROM_AUDIO_ERROR; + return -EIO; + } + optAudioStatus = CDROM_AUDIO_PLAY; + break; + } + case CDROMREADTOCHDR: { /* Read the table of contents header. */ + int st; + struct cdrom_tochdr tocHdr; + + if ((st = verify_area(VERIFY_WRITE,(void *)arg,sizeof tocHdr))) + return st; + if (!optTocUpToDate) + optGetDiskInfo(); + tocHdr.cdth_trk0 = DiskInfo.first; + tocHdr.cdth_trk1 = DiskInfo.last; + memcpy_tofs((void *) arg, &tocHdr, sizeof tocHdr); + break; + } + case CDROMREADTOCENTRY: { /* Read a table of contents entry. */ + int st; + struct cdrom_tocentry entry; + struct opt_Toc *tocPtr; + + if ((st = verify_area(VERIFY_READ, (void *) arg, sizeof entry))) + return st; + if ((st = verify_area(VERIFY_WRITE, (void *) arg, sizeof entry))) + return st; + memcpy_fromfs(&entry, (void *) arg, sizeof entry); + if (!optTocUpToDate) + optGetDiskInfo(); + if (entry.cdte_track == CDROM_LEADOUT) + tocPtr = &Toc[DiskInfo.last + 1]; + else if (entry.cdte_track > DiskInfo.last + || entry.cdte_track < DiskInfo.first) + return -EINVAL; + else + tocPtr = &Toc[entry.cdte_track]; + entry.cdte_adr = tocPtr -> ctrl_addr; + entry.cdte_ctrl = tocPtr -> ctrl_addr >> 4; + switch (entry.cdte_format) { + case CDROM_LBA: + entry.cdte_addr.lba = msf2hsg(&tocPtr -> diskTime); + break; + case CDROM_MSF: + entry.cdte_addr.msf.minute = + bcd2bin(tocPtr -> diskTime.min); + entry.cdte_addr.msf.second = + bcd2bin(tocPtr -> diskTime.sec); + entry.cdte_addr.msf.frame = + bcd2bin(tocPtr -> diskTime.frame); + break; + default: + return -EINVAL; + } + memcpy_tofs((void *) arg, &entry, sizeof entry); + break; + } + case CDROMSTOP: + optCmd(COMSTOP); + optAudioStatus = CDROM_AUDIO_NO_STATUS; + break; + case CDROMSTART: + optCmd(COMCLOSE); /* What else can we do? */ + break; + case CDROMEJECT: + optCmd(COMUNLOCK); + optCmd(COMOPEN); + break; + case CDROMVOLCTRL: { + int st; + struct cdrom_volctrl volctrl; + + if ((st = verify_area(VERIFY_READ, (void *) arg, + sizeof(volctrl)))) + return st; + memcpy_fromfs(&volctrl, (char *) arg, sizeof(volctrl)); + opt_Play.start.min = 0x10; + opt_Play.start.sec = 0x32; + opt_Play.start.frame = volctrl.channel0; + opt_Play.end.min = volctrl.channel1; + opt_Play.end.sec = volctrl.channel2; + opt_Play.end.frame = volctrl.channel3; + if (optPlayCmd(COMCHCTRL, &opt_Play) < 0) + return -EIO; + break; + } + case CDROMSUBCHNL: { /* Get subchannel info */ + int st; + struct cdrom_subchnl subchnl; + struct opt_Toc qInfo; + + if ((st = verify_area(VERIFY_READ, + (void *) arg, sizeof subchnl))) + return st; + if ((st = verify_area(VERIFY_WRITE, + (void *) arg, sizeof subchnl))) + return st; + memcpy_fromfs(&subchnl, (void *) arg, sizeof subchnl); + if (optGetQChannelInfo(&qInfo) < 0) + return -EIO; + subchnl.cdsc_audiostatus = optAudioStatus; + subchnl.cdsc_adr = qInfo.ctrl_addr; + subchnl.cdsc_ctrl = qInfo.ctrl_addr >> 4; + subchnl.cdsc_trk = bcd2bin(qInfo.track); + subchnl.cdsc_ind = bcd2bin(qInfo.pointIndex); + switch (subchnl.cdsc_format) { + case CDROM_LBA: + subchnl.cdsc_absaddr.lba = msf2hsg(&qInfo.diskTime); + subchnl.cdsc_reladdr.lba = msf2hsg(&qInfo.trackTime); + break; + case CDROM_MSF: + subchnl.cdsc_absaddr.msf.minute = + bcd2bin(qInfo.diskTime.min); + subchnl.cdsc_absaddr.msf.second = + bcd2bin(qInfo.diskTime.sec); + subchnl.cdsc_absaddr.msf.frame = + bcd2bin(qInfo.diskTime.frame); + subchnl.cdsc_reladdr.msf.minute = + bcd2bin(qInfo.trackTime.min); + subchnl.cdsc_reladdr.msf.second = + bcd2bin(qInfo.trackTime.sec); + subchnl.cdsc_reladdr.msf.frame = + bcd2bin(qInfo.trackTime.frame); + break; + default: + return -EINVAL; + } + memcpy_tofs((void *) arg, &subchnl, sizeof subchnl); + break; + } + case CDROMREADMODE1: { + int st; + struct cdrom_msf msf; + char buf[OPT_BLOCKSIZE]; + + if ((st = verify_area(VERIFY_READ, (void *) arg, sizeof msf))) + return st; + if ((st = verify_area(VERIFY_WRITE,(void *)arg,OPT_BLOCKSIZE))) + return st; + memcpy_fromfs(&msf, (void *) arg, sizeof msf); + opt_Play.start.min = bin2bcd(msf.cdmsf_min0); + opt_Play.start.sec = bin2bcd(msf.cdmsf_sec0); + opt_Play.start.frame = bin2bcd(msf.cdmsf_frame0); + opt_Play.end.min = 0; + opt_Play.end.sec = 0; + opt_Play.end.frame = 1; /* read only one frame */ + st = optReadCmd(COMREAD, &opt_Play); +#ifdef DEBUG_VFS + printk("optcd: COMREAD status 0x%x\n", st); +#endif + sleep_dten_low(); /* error checking here?? */ + optReadData(buf, OPT_BLOCKSIZE); + memcpy_tofs((void *) arg, &buf, OPT_BLOCKSIZE); + break; + } + case CDROMMULTISESSION: + return -EINVAL; /* unluckily, not implemented yet */ + + default: + return -EINVAL; + } +#ifdef DEBUG_VFS + printk("optcd: exiting opt_ioctl\n"); +#endif + return 0; +} + +static int optPresent = 0; +static int opt_open_count = 0; + +/* Open device special file; check that a disk is in. */ +static int opt_open(struct inode *ip, struct file *fp) { +#ifdef DEBUG_VFS + printk("optcd: starting opt_open\n"); +#endif + if (!optPresent) + return -ENXIO; /* no hardware */ + if (!opt_open_count && opt_state == OPT_S_IDLE) { + int st; + opt_invalidate_buffers(); + if ((st = optGetStatus()) < 0) + return -EIO; + if (st & ST_DOOR_OPEN) { + optCmd(COMCLOSE); /* close door */ + if ((st = optGetStatus()) < 0) /* try again */ + return -EIO; + } + if (st & (ST_DOOR_OPEN|ST_DRVERR)) { + printk("optcd: no disk or door open\n"); + return -EIO; + } + if (optUpdateToc() < 0) + return -EIO; + } + opt_open_count++; + MOD_INC_USE_COUNT; + optCmd(COMLOCK); /* Lock door */ +#ifdef DEBUG_VFS + printk("optcd: exiting opt_open\n"); +#endif + return 0; +} + +/* Release device special file; flush all blocks from the buffer cache */ +static void opt_release(struct inode *ip, struct file *fp) { +#ifdef DEBUG_VFS + printk("optcd: executing opt_release\n"); + printk("inode: %p, inode -> i_rdev: 0x%x, file: %p\n", + ip, ip -> i_rdev, fp); +#endif + if (!--opt_open_count) { + opt_invalidate_buffers(); + sync_dev(ip -> i_rdev); + invalidate_buffers(ip -> i_rdev); + CLEAR_TIMER; + optCmd(COMUNLOCK); /* Unlock door */ + } + MOD_DEC_USE_COUNT; +} + + +/* Initialisation */ + +static int version_ok(void) { + char devname[100]; + int count, i, ch; + + if (optCmd(COMVERSION) < 0) + return 0; + if ((count = optGetData()) < 0) + return 0; + for (i = 0, ch = -1; count > 0; count--) { + if ((ch = optGetData()) < 0) + break; + if (i < 99) + devname[i++] = ch; + } + devname[i] = '\0'; + if (ch < 0) + return 0; + printk("optcd: Device %s detected\n", devname); + return ((devname[0] == 'D') + && (devname[1] == 'O') + && (devname[2] == 'L') + && (devname[3] == 'P') + && (devname[4] == 'H') + && (devname[5] == 'I') + && (devname[6] == 'N')); +} + + +static struct file_operations opt_fops = { + NULL, /* lseek - default */ + block_read, /* read - general block-dev read */ + block_write, /* write - general block-dev write */ + NULL, /* readdir - bad */ + NULL, /* select */ + opt_ioctl, /* ioctl */ + NULL, /* mmap */ + opt_open, /* open */ + opt_release, /* release */ + NULL, /* fsync */ + NULL, /* fasync */ + NULL, /* media change */ + NULL /* revalidate */ +}; + + +/* Get kernel parameter when used as a kernel driver */ +void optcd_setup(char *str, int *ints) { + if (ints[0] > 0) + optcd_port = ints[1]; +} + +#ifndef MODULE +#define RETURN_EIO return mem_start +#else +#define RETURN_EIO return -EIO +#endif + +/* + * Test for presence of drive and initialize it. Called at boot time. + */ +#ifndef MODULE +unsigned long optcd_init(unsigned long mem_start, unsigned long mem_end) { +#else +int init_module(void) { +#endif + if (optcd_port <= 0) { + printk("optcd: no Optics Storage CDROM Initialization\n"); + RETURN_EIO; + } + if (check_region(optcd_port, 4)) { + printk("optcd: conflict, I/O port 0x%x already used\n", + optcd_port); + RETURN_EIO; + } + if (!optResetDrive()) { + printk("optcd: drive at 0x%x not ready\n", optcd_port); + RETURN_EIO; + } + if (!version_ok()) { + printk("optcd: unknown drive detected; aborting\n"); + RETURN_EIO; + } + if (optCmd(COMINITDOUBLE) < 0) { + printk("optcd: cannot init double speed mode\n"); + RETURN_EIO; + } + if (register_blkdev(MAJOR_NR, "optcd", &opt_fops) != 0) + { + printk("optcd: unable to get major %d\n", MAJOR_NR); + RETURN_EIO; + } + blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST; + read_ahead[MAJOR_NR] = 4; + request_region(optcd_port, 4, "optcd"); + optPresent = 1; + printk("optcd: 8000 AT CDROM at 0x%x\n", optcd_port); +#ifndef MODULE + return mem_start; +#else + return 0; +#endif +} + +#ifdef MODULE +void cleanup_module(void) { + if (MOD_IN_USE) { + printk("optcd: module in use - can't remove it.\n"); + return; + } + if ((unregister_blkdev(MAJOR_NR, "optcd") == -EINVAL)) { + printk("optcd: what's that: can't unregister\n"); + return; + } + release_region(optcd_port, 4); + printk("optcd: module released.\n"); +} +#endif MODULE diff -u --recursive --new-file v1.3.6/linux/drivers/block/sbpcd.c linux/drivers/block/sbpcd.c --- v1.3.6/linux/drivers/block/sbpcd.c Mon Jun 12 09:51:18 1995 +++ linux/drivers/block/sbpcd.c Sat Jul 1 19:05:59 1995 @@ -9,9 +9,10 @@ * Also for the CreativeLabs CD200 drive (but I still need some * detailed bug reports). * Also for the TEAC CD-55A drive. - * Not for Funai or Sanyo drives. + * Not for Sanyo drives (but sjcd is there...). + * Not for Funai drives. * - * NOTE: This is release 3.7. + * NOTE: This is release 3.8. * * VERSION HISTORY * @@ -214,6 +215,8 @@ * a lot of sessions. * Bettered the sbpcd_open() behavior with TEAC drives. * + * 3.8 Elongated max_latency for CR-56x drives. + * * TODO * * disk change detection @@ -295,7 +298,7 @@ #include "blk.h" -#define VERSION "v3.7 Eberhard Moenkeberg " +#define VERSION "v3.8 Eberhard Moenkeberg " /*==========================================================================*/ /* @@ -3979,6 +3982,7 @@ case CDROMEJECT: msg(DBG_IOC,"ioctl: CDROMEJECT entered.\n"); if (fam0_drive) return (0); + if (D_S[d].open_count>1) return (-EBUSY); i=UnLockDoor(); D_S[d].open_count=-9; /* to get it locked next time again */ i=cc_SpinDown(); @@ -4028,6 +4032,8 @@ } st=verify_area(VERIFY_WRITE, (void *) arg, sizeof(struct cdrom_subchnl)); if (st) return (st); + st=verify_area(VERIFY_READ, (void *) arg, sizeof(struct cdrom_subchnl)); + if (st) return (st); memcpy_fromfs(&SC, (void *) arg, sizeof(struct cdrom_subchnl)); switch (D_S[d].audio_state) { @@ -4564,9 +4570,7 @@ max_latency=900; #else if (D_S[d].f_multisession) max_latency=900; - else if (fam0L_drive) max_latency=300; - else if (famT_drive) max_latency=300; - else max_latency=100; + else max_latency=300; #endif msg(DBG_TE2,"beginning to READ\n"); duration=jiffies; diff -u --recursive --new-file v1.3.6/linux/drivers/block/sjcd.c linux/drivers/block/sjcd.c --- v1.3.6/linux/drivers/block/sjcd.c Thu Jan 1 02:00:00 1970 +++ linux/drivers/block/sjcd.c Sat Jul 1 19:05:59 1995 @@ -0,0 +1,1358 @@ +/* + * Sanyo CD-ROM device driver implementation. + * + * Copyright (C) 1995 Vadim V. Model + * + * model@cecmow.enet.dec.com + * vadim@rbrf.msk.su + * vadim@ipsun.ras.ru + * + * This driver is based on pre-works by Eberhard Moenkeberg (emoenke@gwdg.de); + * it was developed under use of mcd.c from Martin Harriss, with help of + * E. van der Maarel (maarel@marin.nl). + * + * It is planned to include these routines into sbpcd.c later - to make + * a "mixed use" on one cable possible for all kinds of drives which use + * the SoundBlaster/Panasonic style CDROM interface. But today, the + * ability to install directly from CDROM is more important than flexibility. + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#define MAJOR_NR SANYO_CDROM_MAJOR +#include "blk.h" +#ifdef CONFIG_ISP_16 +#include +#endif +#include + +static int sjcd_present = 0; + +#define SJCD_BUF_SIZ 32 /* cdr-h94a has internal 64K buffer */ + +/* + * buffer for block size conversion + */ +static char sjcd_buf[ 2048 * SJCD_BUF_SIZ ]; +static volatile int sjcd_buf_bn[ SJCD_BUF_SIZ ], sjcd_next_bn; +static volatile int sjcd_buf_in, sjcd_buf_out = -1; + +/* + * Status. + */ +static unsigned short sjcd_status_valid = 0; +static unsigned short sjcd_door_closed; +static unsigned short sjcd_media_is_available; +static unsigned short sjcd_media_is_changed; +static unsigned short sjcd_toc_uptodate = 0; +static unsigned short sjcd_command_failed; +static volatile unsigned char sjcd_completion_status = 0; +static volatile unsigned char sjcd_completion_error = 0; +static unsigned short sjcd_command_is_in_progress = 0; +static unsigned short sjcd_error_reported = 0; + +static int sjcd_open_count; + +static int sjcd_audio_status; +static struct sjcd_play_msf sjcd_playing; + +static short sjcd_port = SJCD_BASE_ADDR; +static int sjcd_irq = SJCD_INTR_NR; + +static struct wait_queue *sjcd_waitq = NULL; + +/* + * Data transfer. + */ +static volatile unsigned short sjcd_transfer_is_active = 0; + +enum sjcd_transfer_state { + SJCD_S_IDLE = 0, + SJCD_S_START = 1, + SJCD_S_MODE = 2, + SJCD_S_READ = 3, + SJCD_S_DATA = 4, + SJCD_S_STOP = 5, + SJCD_S_STOPPING = 6 +}; +static enum sjcd_transfer_state sjcd_transfer_state = SJCD_S_IDLE; +static long sjcd_transfer_timeout = 0; +static int sjcd_read_count = 0; +#if 0 +static unsigned short sjcd_tries; +#endif +static unsigned char sjcd_mode = 0; + +#define SJCD_READ_TIMEOUT 5000 + +/* + * Statistic. + */ +static struct sjcd_stat statistic; + +/* + * Timer. + */ +static struct timer_list sjcd_delay_timer = { NULL, NULL, 0, 0, NULL }; + +#define SJCD_SET_TIMER( func, jiffies ) \ + ( sjcd_delay_timer.expires = jiffies, \ + sjcd_delay_timer.function = ( void * )func, \ + add_timer( &sjcd_delay_timer ) ) + +#define CLEAR_TIMER del_timer( &sjcd_delay_timer ) + +/* + * Set up device. Not yet implemented. + */ +void sjcd_setup( char *str, int *ints ){ + printk( "Sanyo CDR-H94A device driver setup is called (%s).\n", str ); +} + +/* + * Special converters. + */ +static unsigned char bin2bcd( int bin ){ + int u, v; + + u = bin % 10; v = bin / 10; + return( u | ( v << 4 ) ); +} + +static int bcd2bin( unsigned char bcd ){ + return( ( bcd >> 4 ) * 10 + ( bcd & 0x0F ) ); +} + +static long msf2hsg( struct msf *mp ){ + return( bcd2bin( mp->frame ) + bcd2bin( mp->sec ) * 75 + + bcd2bin( mp->min ) * 4500 - 150 ); +} + +static void hsg2msf( long hsg, struct msf *msf ){ + hsg += 150; msf->min = hsg / 4500; + hsg %= 4500; msf->sec = hsg / 75; msf->frame = hsg % 75; + msf->min = bin2bcd( msf->min ); /* convert to BCD */ + msf->sec = bin2bcd( msf->sec ); + msf->frame = bin2bcd( msf->frame ); +} + +/* + * Send a command to cdrom. Invalidate status. + */ +static void sjcd_send_cmd( unsigned char cmd ){ +#if 0 + printk( "sjcd: send_cmd( 0x%x )\n", cmd ); +#endif + outb( cmd, SJCDPORT( 0 ) ); + sjcd_command_is_in_progress = 1; + sjcd_status_valid = 0; + sjcd_command_failed = 0; +} + +/* + * Send a command with one arg to cdrom. Invalidate status. + */ +static void sjcd_send_1_cmd( unsigned char cmd, unsigned char a ){ +#if 0 + printk( "sjcd: send_1_cmd( 0x%x, 0x%x )\n", cmd, a ); +#endif + outb( cmd, SJCDPORT( 0 ) ); + outb( a, SJCDPORT( 0 ) ); + sjcd_command_is_in_progress = 1; + sjcd_status_valid = 0; + sjcd_command_failed = 0; +} + +/* + * Send a command with four args to cdrom. Invalidate status. + */ +static void sjcd_send_4_cmd( unsigned char cmd, unsigned char a, + unsigned char b, unsigned char c, unsigned char d ){ +#if 0 + printk( "sjcd: send_4_cmd( 0x%x )\n", cmd ); +#endif + outb( cmd, SJCDPORT( 0 ) ); + outb( a, SJCDPORT( 0 ) ); + outb( b, SJCDPORT( 0 ) ); + outb( c, SJCDPORT( 0 ) ); + outb( d, SJCDPORT( 0 ) ); + sjcd_command_is_in_progress = 1; + sjcd_status_valid = 0; + sjcd_command_failed = 0; +} + +/* + * Send a play or read command to cdrom. Invalidate Status. + */ +static void sjcd_send_6_cmd( unsigned char cmd, struct sjcd_play_msf *pms ){ +#if 0 + printk( "sjcd: send_long_cmd( 0x%x )\n", cmd ); +#endif + outb( cmd, SJCDPORT( 0 ) ); + outb( pms->start.min, SJCDPORT( 0 ) ); + outb( pms->start.sec, SJCDPORT( 0 ) ); + outb( pms->start.frame, SJCDPORT( 0 ) ); + outb( pms->end.min, SJCDPORT( 0 ) ); + outb( pms->end.sec, SJCDPORT( 0 ) ); + outb( pms->end.frame, SJCDPORT( 0 ) ); + sjcd_command_is_in_progress = 1; + sjcd_status_valid = 0; + sjcd_command_failed = 0; +} + +/* + * Get a value from the data port. Should not block, so we use a little + * wait for a while. Returns 0 if OK. + */ +static int sjcd_load_response( void *buf, int len ){ + unsigned char *resp = ( unsigned char * )buf; + + for( ; len; --len ){ + int i; + for( i = 200; i-- && inb( SJCDPORT( 1 ) ) != 0x09; ); + if( i > 0 ) *resp++ = ( unsigned char )inb( SJCDPORT( 0 ) ); + else break; + } + return( len ); +} + +/* + * Load and parse status. + */ +static void sjcd_load_status( void ){ + sjcd_media_is_changed = 0; + sjcd_completion_error = 0; + sjcd_completion_status = inb( SJCDPORT( 0 ) ); + if( sjcd_completion_status & SST_DOOR_OPENED ){ + sjcd_door_closed = sjcd_media_is_available = 0; + } else { + sjcd_door_closed = 1; + if( sjcd_completion_status & SST_MEDIA_CHANGED ) + sjcd_media_is_available = sjcd_media_is_changed = 1; + else if( sjcd_completion_status & 0x0F ){ + while( ( inb( SJCDPORT( 1 ) ) & 0x0B ) != 0x09 ); + sjcd_completion_error = inb( SJCDPORT( 0 ) ); + if( ( sjcd_completion_status & 0x08 ) && + ( sjcd_completion_error & 0x40 ) ) + sjcd_media_is_available = 0; + else sjcd_command_failed = 1; + } else sjcd_media_is_available = 1; + } + /* + * Ok, status loaded successfully. + */ + sjcd_status_valid = 1, sjcd_error_reported = 0; + sjcd_command_is_in_progress = 0; + if( sjcd_media_is_changed ) sjcd_toc_uptodate = 0; +#if 0 + printk( "sjcd: status %02x.%02x loaded.\n", + ( int )sjcd_completion_status, ( int )sjcd_completion_error ); +#endif +} + +/* + * Read status from cdrom. Check to see if the status is available. + */ +static int sjcd_check_status( void ){ + /* + * Try to load the response from cdrom into buffer. + */ + if( ( inb( SJCDPORT( 1 ) ) & 0x0B ) == 0x09 ){ + sjcd_load_status(); + return( 1 ); + } else { + /* + * No status is available. + */ + return( 0 ); + } +} + +static volatile long sjcd_status_timeout; +#define SJCD_WAIT_FOR_STATUS_TIMEOUT 1000 + +static void sjcd_status_timer( void ){ + if( sjcd_check_status() ){ + wake_up( &sjcd_waitq ); + } else if( --sjcd_status_timeout <= 0 ){ + wake_up( &sjcd_waitq ); + } else { + SJCD_SET_TIMER( sjcd_status_timer, 1 ); + } +} + +static int sjcd_wait_for_status( void ){ + sjcd_status_timeout = SJCD_WAIT_FOR_STATUS_TIMEOUT; + SJCD_SET_TIMER( sjcd_status_timer, 1 ); + sleep_on( &sjcd_waitq ); + if( sjcd_status_timeout <= 0 ) + printk( "sjcd: Error Wait For Status.\n" ); + return( sjcd_status_timeout ); +} + +static int sjcd_receive_status( void ){ + int i; +#if 0 + printk( "sjcd: receive_status\n" ); +#endif + /* + * Wait a bit for status available. + */ + for( i = 200; i-- && ( sjcd_check_status() == 0 ); ); + if( i < 0 ){ +#if 0 + printk( "sjcd: long wait for status\n" ); +#endif + if( sjcd_wait_for_status() <= 0 ) + printk( "sjcd: Timeout when read status.\n" ); + else i = 0; + } + return( i ); +} + +/* + * Load the status. + */ +static void sjcd_get_status( void ){ +#if 0 + printk( "sjcd: get_status\n" ); +#endif + sjcd_send_cmd( SCMD_GET_STATUS ); + sjcd_receive_status(); +} + +/* + * Check the drive if the disk is changed. + */ +static int sjcd_disk_change( dev_t full_dev ){ +#if 0 + printk( "sjcd_disk_change( 0x%x )\n", full_dev ); +#endif + if( MINOR( full_dev ) > 0 ){ + printk( "sjcd: request error: invalid device minor.\n" ); + return 0; + } + if( !sjcd_command_is_in_progress ) + sjcd_get_status(); + return( sjcd_status_valid ? sjcd_media_is_changed : 0 ); +} + +/* + * Read the table of contents (TOC) and TOC header if necessary. + * We assume that the drive contains no more than 99 toc entries. + */ +static struct sjcd_hw_disk_info sjcd_table_of_contents[ 100 ]; +static unsigned char sjcd_first_track_no, sjcd_last_track_no; +#define sjcd_disk_length sjcd_table_of_contents[0].un.track_msf + +static int sjcd_update_toc( void ){ + struct sjcd_hw_disk_info info; + int i; +#if 0 + printk( "sjcd: update toc:\n" ); +#endif + /* + * check to see if we need to do anything + */ + if( sjcd_toc_uptodate ) return( 0 ); + + /* + * Get the TOC start information. + */ + sjcd_send_1_cmd( SCMD_GET_DISK_INFO, SCMD_GET_1_TRACK ); + sjcd_receive_status(); + + if( !sjcd_status_valid ){ + printk( "cannot load status.\n" ); + return( -1 ); + } + + if( !sjcd_media_is_available ){ + printk( "no disk in drive\n" ); + return( -1 ); + } + + if( !sjcd_command_failed ){ + if( sjcd_load_response( &info, sizeof( info ) ) != 0 ){ + printk( "cannot load response about TOC start.\n" ); + return( -1 ); + } + sjcd_first_track_no = bcd2bin( info.un.track_no ); + } else { + printk( "get first failed\n" ); + return( -1 ); + } +#if 0 + printk( "TOC start 0x%02x ", sjcd_first_track_no ); +#endif + /* + * Get the TOC finish information. + */ + sjcd_send_1_cmd( SCMD_GET_DISK_INFO, SCMD_GET_L_TRACK ); + sjcd_receive_status(); + + if( !sjcd_status_valid ){ + printk( "cannot load status.\n" ); + return( -1 ); + } + + if( !sjcd_media_is_available ){ + printk( "no disk in drive\n" ); + return( -1 ); + } + + if( !sjcd_command_failed ){ + if( sjcd_load_response( &info, sizeof( info ) ) != 0 ){ + printk( "cannot load response about TOC finish.\n" ); + return( -1 ); + } + sjcd_last_track_no = bcd2bin( info.un.track_no ); + } else { + printk( "get last failed\n" ); + return( -1 ); + } +#if 0 + printk( "TOC finish 0x%02x ", sjcd_last_track_no ); +#endif + for( i = sjcd_first_track_no; i <= sjcd_last_track_no; i++ ){ + /* + * Get the first track information. + */ + sjcd_send_1_cmd( SCMD_GET_DISK_INFO, bin2bcd( i ) ); + sjcd_receive_status(); + + if( !sjcd_status_valid ){ + printk( "cannot load status.\n" ); + return( -1 ); + } + + if( !sjcd_media_is_available ){ + printk( "no disk in drive\n" ); + return( -1 ); + } + + if( !sjcd_command_failed ){ + if( sjcd_load_response( &sjcd_table_of_contents[ i ], + sizeof( struct sjcd_hw_disk_info ) ) != 0 ){ + printk( "cannot load info for %d track\n", i ); + return( -1 ); + } + } else { + printk( "get info %d failed\n", i ); + return( -1 ); + } + } + + /* + * Get the disk lenght info. + */ + sjcd_send_1_cmd( SCMD_GET_DISK_INFO, SCMD_GET_D_SIZE ); + sjcd_receive_status(); + + if( !sjcd_status_valid ){ + printk( "cannot load status.\n" ); + return( -1 ); + } + + if( !sjcd_media_is_available ){ + printk( "no disk in drive\n" ); + return( -1 ); + } + + if( !sjcd_command_failed ){ + if( sjcd_load_response( &info, sizeof( info ) ) != 0 ){ + printk( "cannot load response about disk size.\n" ); + return( -1 ); + } + sjcd_disk_length.min = info.un.track_msf.min; + sjcd_disk_length.sec = info.un.track_msf.sec; + sjcd_disk_length.frame = info.un.track_msf.frame; + } else { + printk( "get size failed\n" ); + return( 1 ); + } +#if 0 + printk( "(%02x:%02x.%02x)\n", sjcd_disk_length.min, + sjcd_disk_length.sec, sjcd_disk_length.frame ); +#endif + return( 0 ); +} + +/* + * Load subchannel information. + */ +static int sjcd_get_q_info( struct sjcd_hw_qinfo *qp ){ + int s; +#if 0 + printk( "sjcd: load sub q\n" ); +#endif + sjcd_send_cmd( SCMD_GET_QINFO ); + s = sjcd_receive_status(); + if( s < 0 || sjcd_command_failed || !sjcd_status_valid ){ + sjcd_send_cmd( 0xF2 ); + s = sjcd_receive_status(); + if( s < 0 || sjcd_command_failed || !sjcd_status_valid ) return( -1 ); + sjcd_send_cmd( SCMD_GET_QINFO ); + s = sjcd_receive_status(); + if( s < 0 || sjcd_command_failed || !sjcd_status_valid ) return( -1 ); + } + if( sjcd_media_is_available ) + if( sjcd_load_response( qp, sizeof( *qp ) ) == 0 ) return( 0 ); + return( -1 ); +} + +/* + * Start playing from the specified position. + */ +static int sjcd_play( struct sjcd_play_msf *mp ){ + struct sjcd_play_msf msf; + + /* + * Turn the device to play mode. + */ + sjcd_send_1_cmd( SCMD_SET_MODE, SCMD_MODE_PLAY ); + if( sjcd_receive_status() < 0 ) return( -1 ); + + /* + * Seek to the starting point. + */ + msf.start = mp->start; + msf.end.min = msf.end.sec = msf.end.frame = 0x00; + sjcd_send_6_cmd( SCMD_SEEK, &msf ); + if( sjcd_receive_status() < 0 ) return( -1 ); + + /* + * Start playing. + */ + sjcd_send_6_cmd( SCMD_PLAY, mp ); + return( sjcd_receive_status() ); +} + +/* + * Do some user commands. + */ +static int sjcd_ioctl( struct inode *ip, struct file *fp, + unsigned int cmd, unsigned long arg ){ +#if 0 + printk( "sjcd:ioctl\n" ); +#endif + + if( ip == NULL ) return( -EINVAL ); + + sjcd_get_status(); + if( !sjcd_status_valid ) return( -EIO ); + if( sjcd_update_toc() < 0 ) return( -EIO ); + + switch( cmd ){ + case CDROMSTART:{ +#if 0 + printk( "sjcd: ioctl: start\n" ); +#endif + return( 0 ); + } + + case CDROMSTOP:{ +#if 0 + printk( "sjcd: ioctl: stop\n" ); +#endif + sjcd_send_cmd( SCMD_PAUSE ); + ( void )sjcd_receive_status(); + sjcd_audio_status = CDROM_AUDIO_NO_STATUS; + return( 0 ); + } + + case CDROMPAUSE:{ + struct sjcd_hw_qinfo q_info; +#if 0 + printk( "sjcd: ioctl: pause\n" ); +#endif + if( sjcd_audio_status == CDROM_AUDIO_PLAY ){ + sjcd_send_cmd( SCMD_PAUSE ); + ( void )sjcd_receive_status(); + if( sjcd_get_q_info( &q_info ) < 0 ){ + sjcd_audio_status = CDROM_AUDIO_NO_STATUS; + } else { + sjcd_audio_status = CDROM_AUDIO_PAUSED; + sjcd_playing.start = q_info.abs; + } + return( 0 ); + } else return( -EINVAL ); + } + + case CDROMRESUME:{ +#if 0 + printk( "sjcd: ioctl: resume\n" ); +#endif + if( sjcd_audio_status == CDROM_AUDIO_PAUSED ){ + /* + * continue play starting at saved location + */ + if( sjcd_play( &sjcd_playing ) < 0 ){ + sjcd_audio_status = CDROM_AUDIO_ERROR; + return( -EIO ); + } else { + sjcd_audio_status = CDROM_AUDIO_PLAY; + return( 0 ); + } + } else return( -EINVAL ); + } + + case CDROMPLAYTRKIND:{ + struct cdrom_ti ti; int s; +#if 0 + printk( "sjcd: ioctl: playtrkind\n" ); +#endif + if( ( s = verify_area( VERIFY_READ, (void *) arg, sizeof( ti ) ) ) == 0 ){ + memcpy_fromfs( &ti, (void *) arg, sizeof( ti ) ); + + if( ti.cdti_trk0 < sjcd_first_track_no ) return( -EINVAL ); + if( ti.cdti_trk1 > sjcd_last_track_no ) + ti.cdti_trk1 = sjcd_last_track_no; + if( ti.cdti_trk0 > ti.cdti_trk1 ) return( -EINVAL ); + + sjcd_playing.start = sjcd_table_of_contents[ ti.cdti_trk0 ].un.track_msf; + sjcd_playing.end = ( ti.cdti_trk1 < sjcd_last_track_no ) ? + sjcd_table_of_contents[ ti.cdti_trk1 + 1 ].un.track_msf : + sjcd_table_of_contents[ 0 ].un.track_msf; + + if( sjcd_play( &sjcd_playing ) < 0 ){ + sjcd_audio_status = CDROM_AUDIO_ERROR; + return( -EIO ); + } else sjcd_audio_status = CDROM_AUDIO_PLAY; + } + return( s ); + } + + case CDROMPLAYMSF:{ + struct cdrom_msf sjcd_msf; int s; +#if 0 + printk( "sjcd: ioctl: playmsf\n" ); +#endif + if( ( s = verify_area( VERIFY_READ, (void *) arg, sizeof( sjcd_msf ) ) ) == 0 ){ + if( sjcd_audio_status == CDROM_AUDIO_PLAY ){ + sjcd_send_cmd( SCMD_PAUSE ); + ( void )sjcd_receive_status(); + sjcd_audio_status = CDROM_AUDIO_NO_STATUS; + } + + memcpy_fromfs( &sjcd_msf, ( void * )arg, sizeof( sjcd_msf ) ); + + sjcd_playing.start.min = bin2bcd( sjcd_msf.cdmsf_min0 ); + sjcd_playing.start.sec = bin2bcd( sjcd_msf.cdmsf_sec0 ); + sjcd_playing.start.frame = bin2bcd( sjcd_msf.cdmsf_frame0 ); + sjcd_playing.end.min = bin2bcd( sjcd_msf.cdmsf_min1 ); + sjcd_playing.end.sec = bin2bcd( sjcd_msf.cdmsf_sec1 ); + sjcd_playing.end.frame = bin2bcd( sjcd_msf.cdmsf_frame1 ); + + if( sjcd_play( &sjcd_playing ) < 0 ){ + sjcd_audio_status = CDROM_AUDIO_ERROR; + return( -EIO ); + } else sjcd_audio_status = CDROM_AUDIO_PLAY; + } + return( s ); + } + + case CDROMREADTOCHDR:{ + struct cdrom_tochdr toc_header; int s; +#if 0 + printk( "sjcd: ioctl: readtocheader\n" ); +#endif + if( ( s = verify_area( VERIFY_WRITE, (void *) arg, sizeof( toc_header ) ) ) == 0 ){ + toc_header.cdth_trk0 = sjcd_first_track_no; + toc_header.cdth_trk1 = sjcd_last_track_no; + memcpy_tofs( ( void * )arg, &toc_header, sizeof( toc_header ) ); + } + return( s ); + } + + case CDROMREADTOCENTRY:{ + struct cdrom_tocentry toc_entry; int s; +#if 0 + printk( "sjcd: ioctl: readtocentry\n" ); +#endif + if( ( s = verify_area( VERIFY_WRITE, (void *) arg, sizeof( toc_entry ) ) ) == 0 ){ + struct sjcd_hw_disk_info *tp; + + memcpy_fromfs( &toc_entry, ( void * )arg, sizeof( toc_entry ) ); + + if( toc_entry.cdte_track == CDROM_LEADOUT ) + tp = &sjcd_table_of_contents[ 0 ]; + else if( toc_entry.cdte_track < sjcd_first_track_no ) return( -EINVAL ); + else if( toc_entry.cdte_track > sjcd_last_track_no ) return( -EINVAL ); + else tp = &sjcd_table_of_contents[ toc_entry.cdte_track ]; + + toc_entry.cdte_adr = tp->track_control & 0x0F; + toc_entry.cdte_ctrl = tp->track_control >> 4; + + switch( toc_entry.cdte_format ){ + case CDROM_LBA: + toc_entry.cdte_addr.lba = msf2hsg( &( tp->un.track_msf ) ); + break; + case CDROM_MSF: + toc_entry.cdte_addr.msf.minute = bcd2bin( tp->un.track_msf.min ); + toc_entry.cdte_addr.msf.second = bcd2bin( tp->un.track_msf.sec ); + toc_entry.cdte_addr.msf.frame = bcd2bin( tp->un.track_msf.frame ); + break; + default: return( -EINVAL ); + } + memcpy_tofs( ( void * )arg, &toc_entry, sizeof( toc_entry ) ); + } + return( s ); + } + + case CDROMSUBCHNL:{ + struct cdrom_subchnl subchnl; int s; +#if 0 + printk( "sjcd: ioctl: subchnl\n" ); +#endif + if( ( s = verify_area( VERIFY_WRITE, (void *) arg, sizeof( subchnl ) ) ) == 0 ){ + struct sjcd_hw_qinfo q_info; + + memcpy_fromfs( &subchnl, ( void * )arg, sizeof( subchnl ) ); + if( sjcd_get_q_info( &q_info ) < 0 ) return( -EIO ); + + subchnl.cdsc_audiostatus = sjcd_audio_status; + subchnl.cdsc_adr = q_info.track_control & 0x0F; + subchnl.cdsc_ctrl = q_info.track_control >> 4; + subchnl.cdsc_trk = bcd2bin( q_info.track_no ); + subchnl.cdsc_ind = bcd2bin( q_info.x ); + + switch( subchnl.cdsc_format ){ + case CDROM_LBA: + subchnl.cdsc_absaddr.lba = msf2hsg( &( q_info.abs ) ); + subchnl.cdsc_reladdr.lba = msf2hsg( &( q_info.rel ) ); + break; + case CDROM_MSF: + subchnl.cdsc_absaddr.msf.minute = bcd2bin( q_info.abs.min ); + subchnl.cdsc_absaddr.msf.second = bcd2bin( q_info.abs.sec ); + subchnl.cdsc_absaddr.msf.frame = bcd2bin( q_info.abs.frame ); + subchnl.cdsc_reladdr.msf.minute = bcd2bin( q_info.rel.min ); + subchnl.cdsc_reladdr.msf.second = bcd2bin( q_info.rel.sec ); + subchnl.cdsc_reladdr.msf.frame = bcd2bin( q_info.rel.frame ); + break; + default: return( -EINVAL ); + } + memcpy_tofs( ( void * )arg, &subchnl, sizeof( subchnl ) ); + } + return( s ); + } + + case CDROMVOLCTRL:{ + struct cdrom_volctrl vol_ctrl; int s; +#if 0 + printk( "sjcd: ioctl: volctrl\n" ); +#endif + if( ( s = verify_area( VERIFY_READ, (void *) arg, sizeof( vol_ctrl ) ) ) == 0 ){ + unsigned char dummy[ 4 ]; + + memcpy_fromfs( &vol_ctrl, ( void * )arg, sizeof( vol_ctrl ) ); + sjcd_send_4_cmd( SCMD_SET_VOLUME, vol_ctrl.channel0, 0xFF, + vol_ctrl.channel1, 0xFF ); + if( sjcd_receive_status() < 0 ) return( -EIO ); + ( void )sjcd_load_response( dummy, 4 ); + } + return( s ); + } + + case CDROMEJECT:{ +#if 0 + printk( "sjcd: ioctl: eject\n" ); +#endif + if( !sjcd_command_is_in_progress ){ + sjcd_send_cmd( SCMD_EJECT_TRAY ); + ( void )sjcd_receive_status(); + } + return( 0 ); + } + + case 0xABCD:{ + int s; +#if 0 + printk( "sjcd: ioctl: statistic\n" ); +#endif + if( ( s = verify_area( VERIFY_WRITE, (void *) arg, sizeof( statistic ) ) ) == 0 ) + memcpy_tofs( ( void * )arg, &statistic, sizeof( statistic ) ); + return( s ); + } + + default: + return( -EINVAL ); + } +} + +#if 0 +/* + * We only seem to get interrupts after an error. + * Just take the interrupt and clear out the status reg. + */ +static void sjcd_interrupt( int irq, struct pt_regs *regs ){ + printk( "sjcd: interrupt is cought\n" ); +} +#endif + +/* + * Invalidate internal buffers of the driver. + */ +static void sjcd_invalidate_buffers( void ){ + int i; + for( i = 0; i < SJCD_BUF_SIZ; sjcd_buf_bn[ i++ ] = -1 ); + sjcd_buf_out = -1; +} + +/* + * Take care of the different block sizes between cdrom and Linux. + * When Linux gets variable block sizes this will probably go away. + */ + +#define CURRENT_IS_VALID \ + ( CURRENT != NULL && MAJOR( CURRENT->dev ) == MAJOR_NR && \ + CURRENT->cmd == READ && CURRENT->sector != -1 ) + +static void sjcd_transfer( void ){ +#if 0 + printk( "sjcd: transfer:\n" ); +#endif + if( CURRENT_IS_VALID ){ + while( CURRENT->nr_sectors ){ + int i, bn = CURRENT->sector / 4; + for( i = 0; i < SJCD_BUF_SIZ && sjcd_buf_bn[ i ] != bn; i++ ); + if( i < SJCD_BUF_SIZ ){ + int offs = ( i * 4 + ( CURRENT->sector & 3 ) ) * 512; + int nr_sectors = 4 - ( CURRENT->sector & 3 ); + if( sjcd_buf_out != i ){ + sjcd_buf_out = i; + if( sjcd_buf_bn[ i ] != bn ){ + sjcd_buf_out = -1; + continue; + } + } + if( nr_sectors > CURRENT->nr_sectors ) + nr_sectors = CURRENT->nr_sectors; +#if 0 + printk( "copy out\n" ); +#endif + memcpy( CURRENT->buffer, sjcd_buf + offs, nr_sectors * 512 ); + CURRENT->nr_sectors -= nr_sectors; + CURRENT->sector += nr_sectors; + CURRENT->buffer += nr_sectors * 512; + } else { + sjcd_buf_out = -1; + break; + } + } + } +#if 0 + printk( "sjcd: transfer: done\n" ); +#endif +} + +static void sjcd_poll( void ){ + /* + * Update total number of ticks. + */ + statistic.ticks++; + statistic.tticks[ sjcd_transfer_state ]++; + + ReSwitch: switch( sjcd_transfer_state ){ + + case SJCD_S_IDLE:{ + statistic.idle_ticks++; +#if 0 + printk( "SJCD_S_IDLE\n" ); +#endif + return; + } + + case SJCD_S_START:{ + statistic.start_ticks++; + sjcd_send_cmd( SCMD_GET_STATUS ); + sjcd_transfer_state = + sjcd_mode == SCMD_MODE_COOKED ? SJCD_S_READ : SJCD_S_MODE; + sjcd_transfer_timeout = 500; +#if 0 + printk( "SJCD_S_START: goto SJCD_S_%s mode\n", + sjcd_transfer_state == SJCD_S_READ ? "READ" : "MODE" ); +#endif + break; + } + + case SJCD_S_MODE:{ + if( sjcd_check_status() ){ + /* + * Previos command is completed. + */ + if( !sjcd_status_valid || sjcd_command_failed ){ +#if 0 + printk( "SJCD_S_MODE: pre-cmd failed: goto to SJCD_S_STOP mode\n" ); +#endif + sjcd_transfer_state = SJCD_S_STOP; + goto ReSwitch; + } + + sjcd_mode = 0; /* unknown mode; should not be valid when failed */ + sjcd_send_1_cmd( SCMD_SET_MODE, SCMD_MODE_COOKED ); + sjcd_transfer_state = SJCD_S_READ; sjcd_transfer_timeout = 1000; +#if 0 + printk( "SJCD_S_MODE: goto SJCD_S_READ mode\n" ); +#endif + } else statistic.mode_ticks++; + break; + } + + case SJCD_S_READ:{ + if( sjcd_status_valid ? 1 : sjcd_check_status() ){ + /* + * Previos command is completed. + */ + if( !sjcd_status_valid || sjcd_command_failed ){ +#if 0 + printk( "SJCD_S_READ: pre-cmd failed: goto to SJCD_S_STOP mode\n" ); +#endif + sjcd_transfer_state = SJCD_S_STOP; + goto ReSwitch; + } + if( !sjcd_media_is_available ){ +#if 0 + printk( "SJCD_S_READ: no disk: goto to SJCD_S_STOP mode\n" ); +#endif + sjcd_transfer_state = SJCD_S_STOP; + goto ReSwitch; + } + if( sjcd_mode != SCMD_MODE_COOKED ){ + /* + * We seem to come from set mode. So discard one byte of result. + */ + if( sjcd_load_response( &sjcd_mode, 1 ) != 0 ){ +#if 0 + printk( "SJCD_S_READ: load failed: goto to SJCD_S_STOP mode\n" ); +#endif + sjcd_transfer_state = SJCD_S_STOP; + goto ReSwitch; + } + if( sjcd_mode != SCMD_MODE_COOKED ){ +#if 0 + printk( "SJCD_S_READ: mode failed: goto to SJCD_S_STOP mode\n" ); +#endif + sjcd_transfer_state = SJCD_S_STOP; + goto ReSwitch; + } + } + + if( CURRENT_IS_VALID ){ + struct sjcd_play_msf msf; + + sjcd_next_bn = CURRENT->sector / 4; + hsg2msf( sjcd_next_bn, &msf.start ); + msf.end.min = 0; msf.end.sec = 0; + msf.end.frame = sjcd_read_count = SJCD_BUF_SIZ; +#if 0 + printk( "---reading msf-address %x:%x:%x %x:%x:%x\n", + msf.start.min, msf.start.sec, msf.start.frame, + msf.end.min, msf.end.sec, msf.end.frame ); + printk( "sjcd_next_bn:%x buf_in:%x buf_out:%x buf_bn:%x\n", \ + sjcd_next_bn, sjcd_buf_in, sjcd_buf_out, + sjcd_buf_bn[ sjcd_buf_in ] ); +#endif + sjcd_send_6_cmd( SCMD_DATA_READ, &msf ); + sjcd_transfer_state = SJCD_S_DATA; + sjcd_transfer_timeout = 500; +#if 0 + printk( "SJCD_S_READ: go to SJCD_S_DATA mode\n" ); +#endif + } else { +#if 0 + printk( "SJCD_S_READ: nothing to read: go to SJCD_S_STOP mode\n" ); +#endif + sjcd_transfer_state = SJCD_S_STOP; + goto ReSwitch; + } + } else statistic.read_ticks++; + break; + } + + case SJCD_S_DATA:{ + unsigned char stat; + + sjcd_s_data: stat = inb( SJCDPORT( 1 ) ) & 0x0B; +#if 0 + printk( "SJCD_S_DATA: status = 0x%02x\n", stat ); +#endif + if( stat == 0x09 ){ + /* + * No data is waiting for us in the drive buffer. Status of operation + * completion is available. Read and parse it. + */ + sjcd_load_status(); + + if( !sjcd_status_valid || sjcd_command_failed ){ + printk( "sjcd: read block %d failed, maybe audio disk? Giving up\n", + sjcd_next_bn ); + if( CURRENT_IS_VALID ) end_request( 0 ); + printk( "SJCD_S_DATA: pre-cmd failed: go to SJCD_S_STOP mode\n" ); + sjcd_transfer_state = SJCD_S_STOP; + goto ReSwitch; + } + + if( !sjcd_media_is_available ){ + printk( "SJCD_S_DATA: no disk: go to SJCD_S_STOP mode\n" ); + sjcd_transfer_state = SJCD_S_STOP; + goto ReSwitch; + } + + sjcd_transfer_state = SJCD_S_START; + goto ReSwitch; + } else if( stat == 0x0A ){ + /* + * One frame is read into device buffer. We must copy it to our memory. + * Otherwise cdrom hangs up. Check to see if we have something to read + * to. + */ + if( !CURRENT_IS_VALID && sjcd_buf_in == sjcd_buf_out ){ + printk( "SJCD_S_DATA: nothing to read: go to SJCD_S_STOP mode\n" ); + printk( " ... all the date would be discarded\n" ); + sjcd_transfer_state = SJCD_S_STOP; + goto ReSwitch; + } + + /* + * Everything seems to be OK. Just read the frame and recalculate + * indecis. + */ + sjcd_buf_bn[ sjcd_buf_in ] = -1; /* ??? */ + insb( SJCDPORT( 2 ), sjcd_buf + 2048 * sjcd_buf_in, 2048 ); +#if 0 + printk( "SJCD_S_DATA: next_bn=%d, buf_in=%d, buf_out=%d, buf_bn=%d\n", + sjcd_next_bn, sjcd_buf_in, sjcd_buf_out, + sjcd_buf_bn[ sjcd_buf_in ] ); +#endif + sjcd_buf_bn[ sjcd_buf_in ] = sjcd_next_bn++; + if( sjcd_buf_out == -1 ) sjcd_buf_out = sjcd_buf_in; + if( ++sjcd_buf_in == SJCD_BUF_SIZ ) sjcd_buf_in = 0; + + /* + * Only one frame is ready at time. So we should turn over to wait for + * another frame. If we need that, of course. + */ + if( --sjcd_read_count == 0 ){ + /* + * OK, request seems to be precessed. Continue transferring... + */ + if( !sjcd_transfer_is_active ){ + while( CURRENT_IS_VALID ){ + /* + * Continue transferring. + */ + sjcd_transfer(); + if( CURRENT->nr_sectors == 0 ) end_request( 1 ); + else break; + } + } + if( CURRENT_IS_VALID && + ( CURRENT->sector / 4 < sjcd_next_bn || + CURRENT->sector / 4 > sjcd_next_bn + SJCD_BUF_SIZ ) ){ +#if 0 + printk( "SJCD_S_DATA: can't read: go to SJCD_S_STOP mode\n" ); +#endif + sjcd_transfer_state = SJCD_S_STOP; + goto ReSwitch; + } + } + goto sjcd_s_data; + /* sjcd_transfer_timeout = 500; */ + } else statistic.data_ticks++; + break; + } + + case SJCD_S_STOP:{ + sjcd_read_count = 0; + sjcd_send_cmd( SCMD_STOP ); + sjcd_transfer_state = SJCD_S_STOPPING; + sjcd_transfer_timeout = 500; + statistic.stop_ticks++; + break; + } + + case SJCD_S_STOPPING:{ + unsigned char stat; + + stat = inb( SJCDPORT( 1 ) ) & 0x0B; +#if 0 + printk( "SJCD_S_STOP: status = 0x%02x\n", stat ); +#endif + if( stat == 0x0A ){ + int i; +#if 0 + printk( "SJCD_S_STOP: discard data\n" ); +#endif + /* + * Discard all the data from the pipe. Foolish method. + */ + for( i = 2048; i--; ( void )inb( SJCDPORT( 2 ) ) ); + sjcd_transfer_timeout = 500; + } else if( stat == 0x09 ){ + sjcd_load_status(); + if( sjcd_status_valid && sjcd_media_is_changed ) { + sjcd_toc_uptodate = 0; + sjcd_invalidate_buffers(); + } + if( CURRENT_IS_VALID ){ + if( sjcd_status_valid ) sjcd_transfer_state = SJCD_S_READ; + else sjcd_transfer_state = SJCD_S_START; + } else sjcd_transfer_state = SJCD_S_IDLE; + goto ReSwitch; + } else statistic.stopping_ticks++; + break; + } + + default: + printk( "sjcd_poll: invalid state %d\n", sjcd_transfer_state ); + return; + } + + if( --sjcd_transfer_timeout == 0 ){ + printk( "sjcd: timeout in state %d\n", sjcd_transfer_state ); + while( CURRENT_IS_VALID ) end_request( 0 ); + sjcd_send_cmd( SCMD_STOP ); + sjcd_transfer_state = SJCD_S_IDLE; + goto ReSwitch; + } + + /* + * Get back in some time. + */ + SJCD_SET_TIMER( sjcd_poll, 1 ); +} + +static void do_sjcd_request( void ){ +#if 0 + printk( "sjcd: do_sjcd_request(%ld+%ld)\n", + CURRENT->sector, CURRENT->nr_sectors ); +#endif + sjcd_transfer_is_active = 1; + while( CURRENT_IS_VALID ){ + /* + * Who of us are paranoic? + */ + if( CURRENT->bh && !( CURRENT->bh->b_lock ) ) + panic( DEVICE_NAME ": block not locked" ); + + sjcd_transfer(); + if( CURRENT->nr_sectors == 0 ) end_request( 1 ); + else { + sjcd_buf_out = -1; /* Want to read a block not in buffer */ + if( sjcd_transfer_state == SJCD_S_IDLE ){ + if( !sjcd_toc_uptodate ){ + if( sjcd_update_toc() < 0 ){ + printk( "sjcd: transfer: discard\n" ); + while( CURRENT_IS_VALID ) end_request( 0 ); + break; + } + } + sjcd_transfer_state = SJCD_S_START; + SJCD_SET_TIMER( sjcd_poll, 1 ); + } + break; + } + } + sjcd_transfer_is_active = 0; +#if 0 + printk( "sjcd_next_bn:%x sjcd_buf_in:%x sjcd_buf_out:%x sjcd_buf_bn:%x\n", + sjcd_next_bn, sjcd_buf_in, sjcd_buf_out, sjcd_buf_bn[ sjcd_buf_in ] ); + printk( "do_sjcd_request ends\n" ); +#endif +} + +/* + * Open the device special file. Check that a disk is in. + */ +int sjcd_open( struct inode *ip, struct file *fp ){ + /* + * Check the presence of device. + */ + if( !sjcd_present ) return( -ENXIO ); + + /* + * Only read operations are allowed. Really? (:-) + */ + if( fp->f_mode & 2 ) return( -EROFS ); + + if( sjcd_open_count == 0 ){ + sjcd_audio_status = CDROM_AUDIO_NO_STATUS; + sjcd_mode = 0; + sjcd_transfer_state = SJCD_S_IDLE; + sjcd_invalidate_buffers(); + + /* + * Strict status checking. + */ + sjcd_get_status(); + if( !sjcd_status_valid ){ +#if 0 + printk( "sjcd: open: timed out when check status.\n" ); +#endif + return( -EIO ); + } else if( !sjcd_media_is_available ){ +#if 0 + printk("sjcd: open: no disk in drive\n"); +#endif + return( -EIO ); + } +#if 0 + printk( "sjcd: open: done\n" ); +#endif + } + return( ++sjcd_open_count, 0 ); +} + +/* + * On close, we flush all sjcd blocks from the buffer cache. + */ +static void sjcd_release( struct inode *inode, struct file *file ){ +#if 0 + printk( "sjcd: release\n" ); +#endif + if( --sjcd_open_count == 0 ){ + sjcd_invalidate_buffers(); + sync_dev( inode->i_rdev ); + invalidate_buffers( inode->i_rdev ); + } +} + +/* + * A list of file operations allowed for this cdrom. + */ +static struct file_operations sjcd_fops = { + NULL, /* lseek - default */ + block_read, /* read - general block-dev read */ + block_write, /* write - general block-dev write */ + NULL, /* readdir - bad */ + NULL, /* select */ + sjcd_ioctl, /* ioctl */ + NULL, /* mmap */ + sjcd_open, /* open */ + sjcd_release, /* release */ + NULL, /* fsync */ + NULL, /* fasync */ + sjcd_disk_change, /* media change */ + NULL /* revalidate */ +}; + +/* + * Following staff is intended for initialization of the cdrom. It + * first looks for presence of device. If the device is present, it + * will be reset. Then read the version of the drive and load status. + */ +static struct { + unsigned char major, minor; +} sjcd_version; + +/* + * Test for presence of drive and initialize it. Called at boot time. + * Probe cdrom, find out version and status. + */ +unsigned long sjcd_init( unsigned long mem_start, unsigned long mem_end ){ + int i; + + if( sjcd_port != 0x340 || sjcd_irq != 0x0A /* 10 */ ){ + printk( "skip sjcd_init\n" ); + return( mem_start ); + } + +#ifdef CONFIG_ISP_16 + /* + * Initialize the CDROM interface of the card. + */ + isp16_cdi_setup( ISP_CDROM_SANYO, ISP_CDROM_IRQ_10, + ISP_CDROM_DMA_DISABLED, ISP_CDROM_PORT_340 ); +#endif + +#if 0 + printk( "sjcd=0x%x,%d: ", sjcd_port, sjcd_irq ); +#endif + + if( register_blkdev( MAJOR_NR, "sjcd", &sjcd_fops ) != 0 ){ + printk( "Unable to get major %d for Sanyo CD-ROM\n", MAJOR_NR ); + return( mem_start ); + } + + blk_dev[ MAJOR_NR ].request_fn = DEVICE_REQUEST; + read_ahead[ MAJOR_NR ] = 4; + + if( check_region( sjcd_port, 4 ) ){ + printk( "Init failed, I/O port (%X) is already in use\n", + sjcd_port ); + return( mem_start ); + } + + printk( "Sanyo CDR-H94A:" ); + + /* + * Check for card. + */ + for( i = 100; i > 0; --i ) + if( !( inb( SJCDPORT( 1 ) ) & 0x04 ) ) break; + if( i == 0 ){ + printk( " No device at 0x%x found.\n", sjcd_port ); + return( mem_start ); + } + + sjcd_send_cmd( SCMD_RESET ); + while( !sjcd_status_valid ) ( void )sjcd_check_status(); + + /* + * Get and print out cdrom version. + */ + sjcd_send_cmd( SCMD_GET_VERSION ); + while( !sjcd_status_valid ) ( void )sjcd_check_status(); + + if( sjcd_load_response( &sjcd_version, sizeof( sjcd_version ) ) == 0 ){ + printk( " Version %1x.%02x.", ( int )sjcd_version.major, + ( int )sjcd_version.minor ); + } else { + printk( " Read version failed.\n" ); + return( mem_start ); + } + + /* + * Check and print out the tray state. (if it is needed?). + */ + if( !sjcd_status_valid ){ + sjcd_send_cmd( SCMD_GET_STATUS ); + while( !sjcd_status_valid ) ( void )sjcd_check_status(); + } + + printk( " Status: port=0x%x, irq=%d\n", + sjcd_port, sjcd_irq ); + + sjcd_present++; + return( mem_start ); +} + diff -u --recursive --new-file v1.3.6/linux/drivers/block/sonycd535.c linux/drivers/block/sonycd535.c --- v1.3.6/linux/drivers/block/sonycd535.c Mon Jun 12 12:06:03 1995 +++ linux/drivers/block/sonycd535.c Sat Jul 1 19:05:59 1995 @@ -28,7 +28,7 @@ * (Heiko Eissfeldt ) * * 1995-06-01 - * More chages to support CDU-510/515 series + * More changes to support CDU-510/515 series * (Claudio Porfiri) * * Things to do: @@ -108,7 +108,6 @@ #include -#if defined(CONFIG_CDU535) || defined(MODULE) #ifdef MODULE # include @@ -117,6 +116,9 @@ # ifndef CONFIG_MODVERSIONS char kernel_version[]= UTS_RELEASE; # endif +#else +# define MOD_INC_USE_COUNT +# define MOD_DEC_USE_COUNT #endif #include @@ -136,17 +138,11 @@ #include #include -#include #define MAJOR_NR CDU535_CDROM_MAJOR - -#ifdef MODULE # include "blk.h" -#else -# include "blk.h" -# define MOD_INC_USE_COUNT -# define MOD_DEC_USE_COUNT -#endif +#define sony535_cd_base_io sonycd535 /* for compatible parameter passing with "insmod" */ +#include /* * this is the base address of the interface card for the Sony CDU-535 @@ -1541,8 +1537,8 @@ int i; #endif - /* Setting the base I/O address to 0xffff will disable it. */ - if (sony535_cd_base_io == 0xffff) + /* Setting the base I/O address to 0 will disable it. */ + if ((sony535_cd_base_io == 0xffff)||(sony535_cd_base_io == 0)) goto bail; /* Set up all the register locations */ @@ -1739,5 +1735,3 @@ printk(CDU535_HANDLE " module released\n"); } #endif /* MODULE */ - -#endif /* CONFIG_CDU535 */ diff -u --recursive --new-file v1.3.6/linux/drivers/net/3c501.c linux/drivers/net/3c501.c --- v1.3.6/linux/drivers/net/3c501.c Fri Jun 30 16:22:26 1995 +++ linux/drivers/net/3c501.c Wed Jul 5 13:06:26 1995 @@ -572,7 +572,7 @@ outb(AX_SYS, AX_CMD); - skb = dev_alloc_skb(pkt_len); + skb = dev_alloc_skb(pkt_len+2); /* * Start of frame */ @@ -582,6 +582,7 @@ lp->stats.rx_dropped++; return; } else { + skb_reserve(skb,2); /* Force 16 byte alignment */ skb->dev = dev; /* diff -u --recursive --new-file v1.3.6/linux/drivers/net/3c505.c linux/drivers/net/3c505.c --- v1.3.6/linux/drivers/net/3c505.c Fri Jun 30 16:22:26 1995 +++ linux/drivers/net/3c505.c Wed Jul 5 13:06:26 1995 @@ -560,7 +560,7 @@ rlen = (len+1) & ~1; - skb = dev_alloc_skb(rlen); + skb = dev_alloc_skb(rlen+2); /* * make sure the data register is going the right way @@ -587,6 +587,7 @@ adapter->stats.rx_dropped++; } else { + skb_reserve(skb,2); /* 16 byte alignment */ skb->dev = dev; /* diff -u --recursive --new-file v1.3.6/linux/drivers/net/3c507.c linux/drivers/net/3c507.c --- v1.3.6/linux/drivers/net/3c507.c Fri Jun 30 16:22:26 1995 +++ linux/drivers/net/3c507.c Wed Jul 5 13:06:26 1995 @@ -835,13 +835,14 @@ struct sk_buff *skb; pkt_len &= 0x3fff; - skb = dev_alloc_skb(pkt_len); + skb = dev_alloc_skb(pkt_len+2); if (skb == NULL) { printk("%s: Memory squeeze, dropping packet.\n", dev->name); lp->stats.rx_dropped++; break; } - skb->len = pkt_len; + + skb_reserve(skb,2); skb->dev = dev; /* 'skb->data' points to the start of sk_buff data area. */ diff -u --recursive --new-file v1.3.6/linux/drivers/net/3c509.c linux/drivers/net/3c509.c --- v1.3.6/linux/drivers/net/3c509.c Fri Jun 30 16:22:26 1995 +++ linux/drivers/net/3c509.c Wed Jul 5 13:06:26 1995 @@ -591,12 +591,13 @@ short pkt_len = rx_status & 0x7ff; struct sk_buff *skb; - skb = dev_alloc_skb(pkt_len+3); + skb = dev_alloc_skb(pkt_len+5); if (el3_debug > 4) printk("Receiving packet size %d status %4.4x.\n", pkt_len, rx_status); if (skb != NULL) { skb->dev = dev; + skb_reserve(skb,2); /* Align IP on 16 byte boundaries */ /* 'skb->data' points to the start of sk_buff data area. */ insl(ioaddr+RX_FIFO, skb_put(skb,pkt_len), diff -u --recursive --new-file v1.3.6/linux/drivers/net/8390.c linux/drivers/net/8390.c --- v1.3.6/linux/drivers/net/8390.c Fri Jun 30 16:22:26 1995 +++ linux/drivers/net/8390.c Wed Jul 5 13:06:26 1995 @@ -455,7 +455,7 @@ } else if ((rx_frame.status & 0x0F) == ENRSR_RXOK) { struct sk_buff *skb; - skb = dev_alloc_skb(pkt_len); + skb = dev_alloc_skb(pkt_len+2); if (skb == NULL) { if (ei_debug > 1) printk("%s: Couldn't allocate a sk_buff of size %d.\n", @@ -463,6 +463,7 @@ ei_local->stat.rx_dropped++; break; } else { + skb_reserve(skb,2); /* IP headers on 16 byte boundaries */ skb->dev = dev; ei_block_input(dev, pkt_len, skb_put(skb,pkt_len), diff -u --recursive --new-file v1.3.6/linux/drivers/net/README.wavelan linux/drivers/net/README.wavelan --- v1.3.6/linux/drivers/net/README.wavelan Wed Feb 22 16:25:04 1995 +++ linux/drivers/net/README.wavelan Sun Jul 2 10:30:37 1995 @@ -1,6 +1,4 @@ -#if defined(CONFIG_WAVELAN) - -Thu Feb 23 00:10:31 EST 1995 +Sun Jul 2 01:38:33 EST 1995 1. At present the driver autoprobes for a WaveLAN card only at I/O address 0x390. The version of the card that I use (NCR) supports four I/O addresses (selectable @@ -23,9 +21,13 @@ append ="ether=0,0x390,0x4321,eth0" .. -3. If you encounter any problems send me some email. +3. The driver uses the IRQ stored in the card's PSA. + To change this you will need to use the configuration/setup software that + accompanies each WaveLAN device. Yes, the driver should use the value passed + in via LILO and it will, just as soon as I can work out why that part of the + code doesn't work :-(. + +4. If you encounter any problems send me some email. Good luck, Bruce Janson (bruce@cs.usyd.edu.au) - -#endif /* defined(CONFIG_WAVELAN) */ diff -u --recursive --new-file v1.3.6/linux/drivers/net/arcnet.c linux/drivers/net/arcnet.c --- v1.3.6/linux/drivers/net/arcnet.c Fri Jun 30 16:22:26 1995 +++ linux/drivers/net/arcnet.c Wed Jul 5 13:06:26 1995 @@ -2084,6 +2084,13 @@ unsigned short arc_type_trans(struct sk_buff *skb,struct device *dev) { struct ClientData *head = (struct ClientData *) skb->data; + + /* + * Pull off the arcnet header. + */ + + skb->mac.raw=skb->data; + skb_pull(skb,dev->hard_header_len); if (head->daddr==0) skb->pkt_type=PACKET_BROADCAST; diff -u --recursive --new-file v1.3.6/linux/drivers/net/at1700.c linux/drivers/net/at1700.c --- v1.3.6/linux/drivers/net/at1700.c Fri Jun 30 16:22:26 1995 +++ linux/drivers/net/at1700.c Wed Jul 5 13:06:26 1995 @@ -527,7 +527,7 @@ lp->stats.rx_errors++; break; } - skb = dev_alloc_skb(pkt_len+1); + skb = dev_alloc_skb(pkt_len+3); if (skb == NULL) { printk("%s: Memory squeeze, dropping packet (len %d).\n", dev->name, pkt_len); @@ -537,8 +537,8 @@ lp->stats.rx_dropped++; break; } - skb->len = pkt_len; skb->dev = dev; + skb_reserve(skb,2); insw(ioaddr + DATAPORT, skb_put(skb,pkt_len), (pkt_len + 1) >> 1); skb->protocol=eth_type_trans(skb, dev); diff -u --recursive --new-file v1.3.6/linux/drivers/net/de4x5.c linux/drivers/net/de4x5.c --- v1.3.6/linux/drivers/net/de4x5.c Fri Jun 30 16:22:27 1995 +++ linux/drivers/net/de4x5.c Thu Jul 6 13:22:04 1995 @@ -1153,9 +1153,10 @@ struct sk_buff *skb; short pkt_len = (short)(lp->rx_ring[entry].status >> 16) - 4; - if ((skb = dev_alloc_skb(pkt_len)) != NULL) { + if ((skb = dev_alloc_skb(pkt_len+2)) != NULL) { skb->dev = dev; + skb_reserve(skb,2); /* Align */ if (entry < lp->rx_old) { /* Wrapped buffer */ short len = (lp->rxRingSize - lp->rx_old) * RX_BUFF_SZ; memcpy(skb_put(skb,len), bus_to_virt(lp->rx_ring[lp->rx_old].buf), len); @@ -2663,21 +2664,21 @@ tmp.addr[j++] = dev->dev_addr[i]; } tmp.addr[j++] = lp->rxRingSize; - tmp.lval[j>>2] = (s32)lp->rx_ring; j+=4; - tmp.lval[j>>2] = (s32)lp->tx_ring; j+=4; + tmp.lval[j>>2] = (long)lp->rx_ring; j+=4; + tmp.lval[j>>2] = (long)lp->tx_ring; j+=4; for (i=0;irxRingSize-1;i++){ if (i < 3) { - tmp.lval[j>>2] = (s32)&lp->rx_ring[i].status; j+=4; + tmp.lval[j>>2] = (long)&lp->rx_ring[i].status; j+=4; } } - tmp.lval[j>>2] = (s32)&lp->rx_ring[i].status; j+=4; + tmp.lval[j>>2] = (long)&lp->rx_ring[i].status; j+=4; for (i=0;itxRingSize-1;i++){ if (i < 3) { - tmp.lval[j>>2] = (s32)&lp->tx_ring[i].status; j+=4; + tmp.lval[j>>2] = (long)&lp->tx_ring[i].status; j+=4; } } - tmp.lval[j>>2] = (s32)&lp->tx_ring[i].status; j+=4; + tmp.lval[j>>2] = (long)&lp->tx_ring[i].status; j+=4; for (i=0;irxRingSize-1;i++){ if (i < 3) { diff -u --recursive --new-file v1.3.6/linux/drivers/net/de600.c linux/drivers/net/de600.c --- v1.3.6/linux/drivers/net/de600.c Fri Jun 30 16:22:27 1995 +++ linux/drivers/net/de600.c Wed Jul 5 13:06:26 1995 @@ -609,7 +609,7 @@ return; } - skb = dev_alloc_skb(size); + skb = dev_alloc_skb(size+2); sti(); if (skb == NULL) { printk("%s: Couldn't allocate a sk_buff of size %d.\n", @@ -619,6 +619,7 @@ /* else */ skb->dev = dev; + skb_reserve(skb,2); /* Align */ /* 'skb->data' points to the start of sk_buff data area. */ buffer = skb_put(skb,size); diff -u --recursive --new-file v1.3.6/linux/drivers/net/de620.c linux/drivers/net/de620.c --- v1.3.6/linux/drivers/net/de620.c Fri Jun 30 16:22:27 1995 +++ linux/drivers/net/de620.c Wed Jul 5 13:06:26 1995 @@ -678,13 +678,14 @@ printk("%s: Illegal packet size: %d!\n", dev->name, size); } else { /* Good packet? */ - skb = dev_alloc_skb(size); + skb = dev_alloc_skb(size+2); if (skb == NULL) { /* Yeah, but no place to put it... */ printk("%s: Couldn't allocate a sk_buff of size %d.\n", dev->name, size); ((struct netstats *)(dev->priv))->rx_dropped++; } else { /* Yep! Go get it! */ + skb_reserve(skb,2); /* Align */ skb->dev = dev; skb->free = 1; /* skb->data points to the start of sk_buff data area */ diff -u --recursive --new-file v1.3.6/linux/drivers/net/depca.c linux/drivers/net/depca.c --- v1.3.6/linux/drivers/net/depca.c Fri Jun 30 16:22:27 1995 +++ linux/drivers/net/depca.c Thu Jul 6 13:22:04 1995 @@ -943,9 +943,11 @@ short len, pkt_len = readw(&lp->rx_ring[entry].msg_length); struct sk_buff *skb; - skb = dev_alloc_skb(pkt_len); + skb = dev_alloc_skb(pkt_len+2); if (skb != NULL) { - unsigned char * buf = skb_put(skb,pkt_len); + unsigned char * buf; + skb_reserve(skb,2); /* 16 byte align the IP header */ + buf = skb_put(skb,pkt_len); skb->dev = dev; if (entry < lp->rx_old) { /* Wrapped buffer */ len = (lp->rxRingMask - lp->rx_old + 1) * RX_BUFF_SZ; @@ -973,13 +975,13 @@ } } if (buf[0] & 0x01) { /* Multicast/Broadcast */ - if ((*(s32 *)&buf[0] == -1) && (*(s16 *)&buf[4] == -1)) { + if ((*(s16 *)&buf[0] == -1) && (*(s32 *)&buf[2] == -1)) { lp->pktStats.broadcast++; } else { lp->pktStats.multicast++; } - } else if ((*(s32 *)&buf[0] == *(s32 *)&dev->dev_addr[0]) && - (*(s16 *)&buf[4] == *(s16 *)&dev->dev_addr[4])) { + } else if ((*(s16 *)&buf[0] == *(s16 *)&dev->dev_addr[0]) && + (*(s32 *)&buf[2] == *(s32 *)&dev->dev_addr[2])) { lp->pktStats.unicast++; } diff -u --recursive --new-file v1.3.6/linux/drivers/net/eepro.c linux/drivers/net/eepro.c --- v1.3.6/linux/drivers/net/eepro.c Fri Jun 30 16:22:27 1995 +++ linux/drivers/net/eepro.c Wed Jul 5 13:06:26 1995 @@ -1046,13 +1046,14 @@ struct sk_buff *skb; rcv_size &= 0x3fff; - skb = dev_alloc_skb(rcv_size); + skb = dev_alloc_skb(rcv_size+2); if (skb == NULL) { printk("%s: Memory squeeze, dropping packet.\n", dev->name); lp->stats.rx_dropped++; break; } skb->dev = dev; + skb_reserve(skb,2); insw(ioaddr+IO_PORT, skb_put(skb,rcv_size), (rcv_size + 1) >> 1); diff -u --recursive --new-file v1.3.6/linux/drivers/net/eexpress.c linux/drivers/net/eexpress.c --- v1.3.6/linux/drivers/net/eexpress.c Fri Jun 30 16:22:27 1995 +++ linux/drivers/net/eexpress.c Wed Jul 5 13:06:26 1995 @@ -941,13 +941,14 @@ struct sk_buff *skb; pkt_len &= 0x3fff; - skb = dev_alloc_skb(pkt_len); + skb = dev_alloc_skb(pkt_len+2); if (skb == NULL) { printk("%s: Memory squeeze, dropping packet.\n", dev->name); lp->stats.rx_dropped++; break; } skb->dev = dev; + skb_reserve(skb,2); outw(data_buffer_addr + 10, ioaddr + READ_PTR); diff -u --recursive --new-file v1.3.6/linux/drivers/net/ewrk3.c linux/drivers/net/ewrk3.c --- v1.3.6/linux/drivers/net/ewrk3.c Fri Jun 30 16:22:27 1995 +++ linux/drivers/net/ewrk3.c Thu Jul 6 13:29:59 1995 @@ -1035,18 +1035,19 @@ } else { struct sk_buff *skb; - if ((skb = dev_alloc_skb(pkt_len)) != NULL) { + if ((skb = dev_alloc_skb(pkt_len+2)) != NULL) { + unsigned char *p; skb->dev = dev; + skb_reserve(skb,2); /* Align to 16 bytes */ + p = skb_put(skb,pkt_len); if (lp->shmem_length == IO_ONLY) { - unsigned char *p = skb_put(skb,pkt_len); - *p = inb(EWRK3_DATA); /* dummy read */ - for (i=0; ilen; i++) { + for (i=0; idata, buf, pkt_len); + memcpy(p, buf, pkt_len); } /* @@ -1731,7 +1732,7 @@ break; case EWRK3_GET_STATS: /* Get the driver statistics */ - err = verify_area(VERIFY_WRITE, (void *)ioc->data, sizeof(lp->pktStats))); + err = verify_area(VERIFY_WRITE, (void *)ioc->data, sizeof(lp->pktStats)); if (err) return err; cli(); @@ -1879,6 +1880,7 @@ if (MOD_IN_USE) { printk("%s: device busy, remove delayed\n",thisEthwrk.name); } else { + release_region(thisEthwrk.base_addr, EWRK3_TOTAL_SIZE); unregister_netdev(&thisEthwrk); } } diff -u --recursive --new-file v1.3.6/linux/drivers/net/hp100.c linux/drivers/net/hp100.c --- v1.3.6/linux/drivers/net/hp100.c Fri Jun 30 16:22:28 1995 +++ linux/drivers/net/hp100.c Sat Jul 1 19:58:50 1995 @@ -601,7 +601,7 @@ else { skb -> dev = dev; - insl( ioaddr + HP100_REG_DATA32, skb_put(pkt_len), ( pkt_len + 3 ) >> 2 ); + insl( ioaddr + HP100_REG_DATA32, skb_put(skb, pkt_len), ( pkt_len + 3 ) >> 2 ); skb->protocol=eth_type_trans(skb,dev); netif_rx( skb ); lp -> stats.rx_packets++; diff -u --recursive --new-file v1.3.6/linux/drivers/net/i82586.h linux/drivers/net/i82586.h --- v1.3.6/linux/drivers/net/i82586.h Tue Jan 31 14:36:24 1995 +++ linux/drivers/net/i82586.h Sun Jul 2 10:30:37 1995 @@ -1,4 +1,3 @@ -#if defined(CONFIG_WAVELAN) /* * Intel 82586 IEEE 802.3 Ethernet LAN Coprocessor. * @@ -407,4 +406,3 @@ * * For more details, see wavelan.c. */ -#endif /* defined(CONFIG_WAVELAN) */ diff -u --recursive --new-file v1.3.6/linux/drivers/net/lance.c linux/drivers/net/lance.c --- v1.3.6/linux/drivers/net/lance.c Fri Jun 30 16:22:28 1995 +++ linux/drivers/net/lance.c Wed Jul 5 13:06:26 1995 @@ -984,7 +984,7 @@ short pkt_len = (lp->rx_ring[entry].msg_length & 0xfff)-4; struct sk_buff *skb; - skb = dev_alloc_skb(pkt_len); + skb = dev_alloc_skb(pkt_len+2); if (skb == NULL) { printk("%s: Memory squeeze, deferring packet.\n", dev->name); for (i=0; i < RX_RING_SIZE; i++) @@ -999,9 +999,11 @@ break; } skb->dev = dev; - memcpy(skb_put(skb,pkt_len), + skb_reserve(skb,2); /* 16 byte align */ + skb_put(skb,pkt_len); /* Make room */ + eth_copy_and_sum(skb_put(skb,pkt_len), (unsigned char *)(lp->rx_ring[entry].base & 0x00ffffff), - pkt_len); + pkt_len,0); skb->protocol=eth_type_trans(skb,dev); netif_rx(skb); lp->stats.rx_packets++; diff -u --recursive --new-file v1.3.6/linux/drivers/net/ne.c linux/drivers/net/ne.c --- v1.3.6/linux/drivers/net/ne.c Tue Jun 27 14:11:36 1995 +++ linux/drivers/net/ne.c Sun Jul 2 21:23:28 1995 @@ -20,6 +20,7 @@ Paul Gortmaker : use ENISR_RDC to monitor Tx PIO uploads, made sanity checks and bad clone support optional. + Paul Gortmaker : new reset code, reset card after probe at boot. */ @@ -84,8 +85,6 @@ #define NESM_START_PG 0x40 /* First page of TX buffer */ #define NESM_STOP_PG 0x80 /* Last page +1 of RX ring */ -#define NE_RDC_TIMEOUT 0x02 /* Max wait in jiffies for Tx RDC */ - int ne_probe(struct device *dev); static int ne_probe1(struct device *dev, int ioaddr); @@ -173,6 +172,23 @@ printk("NE*000 ethercard probe at %#3x:", ioaddr); + /* Reset card. Who knows what dain-bramaged state it was left in. */ + { unsigned long reset_start_time = jiffies; + + /* DON'T change these to inb_p/outb_p or reset will fail on clones. */ + outb(inb(ioaddr + NE_RESET), ioaddr + NE_RESET); + + /* wait 20 ms for the dust to settle. */ + while (jiffies - reset_start_time < 2*HZ/100) + barrier(); + + if ((inb_p(ioaddr+EN0_ISR) & ENISR_RESET) == 0) { + printk(" not found (no reset ack).\n"); + return ENODEV; + } + outb_p(0xff, ioaddr + EN0_ISR); /* Ack all intr. */ + } + /* Read the 16 bytes of station address PROM. We must first initialize registers, similar to NS8390_init(eifdev, 0). We can't reliably read the SAPROM address without this. @@ -328,17 +344,19 @@ static void ne_reset_8390(struct device *dev) { - int tmp = inb_p(NE_BASE + NE_RESET); - int reset_start_time = jiffies; + unsigned long reset_start_time = jiffies; if (ei_debug > 1) printk("resetting the 8390 t=%ld...", jiffies); + + /* DON'T change these to inb_p/outb_p or reset will fail on clones. */ + outb(inb(NE_BASE + NE_RESET), NE_BASE + NE_RESET); + ei_status.txing = 0; ei_status.dmaing = 0; - outb_p(tmp, NE_BASE + NE_RESET); /* This check _should_not_ be necessary, omit eventually. */ while ((inb_p(NE_BASE+EN0_ISR) & ENISR_RESET) == 0) - if (jiffies - reset_start_time > 2) { + if (jiffies - reset_start_time > 2*HZ/100) { printk("%s: ne_reset_8390() did not complete.\n", dev->name); break; } @@ -502,7 +520,7 @@ #endif while ((inb_p(nic_base + EN0_ISR) & ENISR_RDC) == 0) - if (jiffies - dma_start > NE_RDC_TIMEOUT) { + if (jiffies - dma_start > 2*HZ/100) { /* 20ms */ printk("%s: timeout waiting for Tx RDC.\n", dev->name); ne_reset_8390(dev); NS8390_init(dev,1); diff -u --recursive --new-file v1.3.6/linux/drivers/net/ni52.c linux/drivers/net/ni52.c --- v1.3.6/linux/drivers/net/ni52.c Fri Jun 30 16:22:28 1995 +++ linux/drivers/net/ni52.c Wed Jul 5 13:06:26 1995 @@ -803,10 +803,11 @@ { totlen &= RBD_MASK; /* length of this frame */ rbd->status = 0; - skb = (struct sk_buff *) dev_alloc_skb(totlen); + skb = (struct sk_buff *) dev_alloc_skb(totlen+2); if(skb != NULL) { skb->dev = dev; + skb_reserve(skb,2); /* 16 byte alignment */ memcpy(skb_put(skb,totlen),(char *) p->base+(unsigned long) rbd->buffer, totlen); skb->protocol=eth_type_trans(skb,dev); netif_rx(skb); diff -u --recursive --new-file v1.3.6/linux/drivers/net/pi2.c linux/drivers/net/pi2.c --- v1.3.6/linux/drivers/net/pi2.c Fri Jun 30 16:22:28 1995 +++ linux/drivers/net/pi2.c Wed Jul 5 13:06:26 1995 @@ -567,6 +567,7 @@ memcpy(cfix, (char *) cur_buf->data, pkt_len - 1); skb->protocol=htons(ETH_P_AX25); + skb->mac.raw=skb->data; IS_SKB(skb); netif_rx(skb); lp->stats.rx_packets++; diff -u --recursive --new-file v1.3.6/linux/drivers/net/ppp.c linux/drivers/net/ppp.c --- v1.3.6/linux/drivers/net/ppp.c Fri Jun 30 16:22:28 1995 +++ linux/drivers/net/ppp.c Wed Jul 5 13:06:26 1995 @@ -1153,10 +1153,10 @@ skb=dev_alloc_skb(count); if(skb) { + skb->mac.raw=skb->data; memcpy(skb_put(skb,count), c,count); skb->protocol=htons(ETH_P_IP); skb->dev=ppp->dev; - skb->len=count; netif_rx(skb); } return 1; @@ -1717,7 +1717,7 @@ /* Get pointers to the various components */ ppp = &ppp_ctrl[dev->base_addr]; tty = ppp->tty; - p = (unsigned char *) (skb + 1); + p = skb->data; len = skb->len; proto = PROTO_IP; @@ -1791,7 +1791,7 @@ ++ppp->stats.suncomp; if (ppp_debug_netpackets) { - struct iphdr *iph = (struct iphdr *) (skb + 1); + struct iphdr *iph = (struct iphdr *)skb->data; PRINTK ((KERN_DEBUG "%s ==> proto %x len %d src %x dst %x proto %d\n", dev->name, (int) proto, (int) len, (int) iph->saddr, (int) iph->daddr, (int) iph->protocol)) diff -u --recursive --new-file v1.3.6/linux/drivers/net/sk_g16.c linux/drivers/net/sk_g16.c --- v1.3.6/linux/drivers/net/sk_g16.c Fri Jun 30 16:22:28 1995 +++ linux/drivers/net/sk_g16.c Wed Jul 5 13:06:27 1995 @@ -1570,7 +1570,7 @@ int len = (rmdp->mlen & 0x0fff); /* extract message length from receive buffer */ struct sk_buff *skb; - skb = dev_alloc_skb(len); /* allocate socket buffer */ + skb = dev_alloc_skb(len+2); /* allocate socket buffer */ if (skb == NULL) /* Could not get mem ? */ { @@ -1591,6 +1591,7 @@ /* Prepare sk_buff to queue for upper layers */ skb->dev = dev; + skb_reserve(skb,2); /* Align IP header on 16 byte boundary */ /* * Copy data out of our receive descriptor into sk_buff. diff -u --recursive --new-file v1.3.6/linux/drivers/net/slip.c linux/drivers/net/slip.c --- v1.3.6/linux/drivers/net/slip.c Fri Jun 30 16:22:29 1995 +++ linux/drivers/net/slip.c Wed Jul 5 13:06:27 1995 @@ -1,7 +1,7 @@ /* * slip.c This module implements the SLIP protocol for kernel-based * devices like TTY. It interfaces between a raw TTY, and the - * kernel's INET protocol layers (via DDI). + * kernel's INET protocol layers. * * Version: @(#)slip.c 0.8.3 12/24/94 * @@ -321,6 +321,7 @@ } skb->dev = sl->dev; memcpy(skb_put(skb,count), sl->rbuff, count); + skb->mac.raw=skb->data; if(sl->mode&(SL_MODE_AX25|SL_MODE_AX25VC)) skb->protocol=htons(ETH_P_AX25); else @@ -452,32 +453,6 @@ #endif } -#ifdef CONFIG_AX25 -#ifdef CONFIG_INET - /* - * This code is not very intelligent. Fix me. - */ - if (skb->data[15] == LAPB_UI && skb->data[16] == AX25_P_IP) { - struct sk_buff *skbn; - char mode; - - mode = ax25_ip_mode_get((ax25_address *)(skb->data + 1), dev); - - if (mode == 'V' || mode == 'v' || (mode == ' ' && sl->mode & SL_MODE_AX25VC)) { - if ((skbn = skb_clone(skb, GFP_ATOMIC)) == NULL) { - sl->tx_errors++; - return 1; - } - - ax25_send_frame(skbn, (ax25_address *)dev->dev_addr, (ax25_address *)(skbn->data + 1), dev); - dev_kfree_skb(skb, FREE_WRITE); - mark_bh(NET_BH); - return 0; - } - } -#endif -#endif - /* We were not busy, so we are now... :-) */ if (skb != NULL) { sl_lock(sl); @@ -953,12 +928,12 @@ { int err; - err = verify_area(VERIFY_READ, addr, 7); + err = verify_area(VERIFY_READ, addr, AX25_ADDR_LEN); if (err) { return err; } - memcpy_fromfs(dev->dev_addr, addr, 7); /* addr is an AX.25 shifted ASCII mac address */ + memcpy_fromfs(dev->dev_addr, addr, AX25_ADDR_LEN); /* addr is an AX.25 shifted ASCII mac address */ return 0; } @@ -966,9 +941,17 @@ static int sl_set_dev_mac_address(struct device *dev, void *addr) { - memcpy(dev->dev_addr, addr, 7); + memcpy(dev->dev_addr, addr, AX25_ADDR_LEN); return 0; } + +int sl_get_ax25_mode(struct device *dev) +{ + struct slip *sl = &sl_ctrl[dev->base_addr]; + + return sl->mode & SL_MODE_AX25VC; +} + #endif /* CONFIG_AX25 */ @@ -1030,8 +1013,8 @@ } #else if ((tmp & SL_MODE_AX25) || (tmp & SL_MODE_AX25VC)) { - sl->dev->addr_len=7; /* sizeof an AX.25 addr */ - sl->dev->hard_header_len=17; /* We don't do digipeaters */ + sl->dev->addr_len=AX25_ADDR_LEN; /* sizeof an AX.25 addr */ + sl->dev->hard_header_len=AX25_HEADER_LEN; /* We don't do digipeaters */ } else { sl->dev->addr_len=0; /* No mac addr in slip mode */ sl->dev->hard_header_len=0; @@ -1078,9 +1061,9 @@ struct slip *sl = &sl_ctrl[dev->base_addr]; int i; #ifdef CONFIG_AX25 - static char ax25_bcast[7] = + static char ax25_bcast[AX25_ADDR_LEN] = {'Q'<<1,'S'<<1,'T'<<1,' '<<1,' '<<1,' '<<1,'0'<<1}; - static char ax25_test[7] = + static char ax25_test[AX25_ADDR_LEN] = {'L'<<1,'I'<<1,'N'<<1,'U'<<1,'X'<<1,' '<<1,'1'<<1}; #endif @@ -1143,8 +1126,8 @@ if (sl->dev->type == 260 || sl->dev->type == 272) { sl->dev->type = ARPHRD_AX25; } - memcpy(dev->broadcast, ax25_bcast, 7); /* Only activated in AX.25 mode */ - memcpy(dev->dev_addr, ax25_test, 7); /* "" "" "" "" */ + memcpy(dev->broadcast, ax25_bcast, AX25_ADDR_LEN); /* Only activated in AX.25 mode */ + memcpy(dev->dev_addr, ax25_test, AX25_ADDR_LEN); /* "" "" "" "" */ #endif dev->rebuild_header = sl_rebuild_header; diff -u --recursive --new-file v1.3.6/linux/drivers/net/tulip.c linux/drivers/net/tulip.c --- v1.3.6/linux/drivers/net/tulip.c Fri Jun 30 16:22:29 1995 +++ linux/drivers/net/tulip.c Wed Jul 5 13:06:27 1995 @@ -600,7 +600,7 @@ short pkt_len = lp->rx_ring[entry].status >> 16; struct sk_buff *skb; - skb = dev_alloc_skb(pkt_len); + skb = dev_alloc_skb(pkt_len+2); if (skb == NULL) { printk("%s: Memory squeeze, deferring packet.\n", dev->name); /* Check that at least two ring entries are free. @@ -617,6 +617,7 @@ break; } skb->dev = dev; + skb_reserve(skb,2); /* 16 byte align the data fields */ memcpy(skb_put(skb,pkt_len), lp->rx_ring[entry].buffer1, pkt_len); skb->protocol=eth_type_trans(skb,dev); netif_rx(skb); diff -u --recursive --new-file v1.3.6/linux/drivers/net/wavelan.c linux/drivers/net/wavelan.c --- v1.3.6/linux/drivers/net/wavelan.c Fri Jun 30 16:22:29 1995 +++ linux/drivers/net/wavelan.c Wed Jul 5 12:53:22 1995 @@ -6,7 +6,6 @@ #include -#if defined(CONFIG_WAVELAN) #if defined(MODULE) #include #include @@ -26,7 +25,7 @@ #include #include #include -#include +#include #include #include #include @@ -40,9 +39,10 @@ #define WAVELAN_DEBUG 0 #endif /* WAVELAN_DEBUG */ -#define nels(a) (sizeof(a) / sizeof(a[0])) - #define WATCHDOG_JIFFIES 512 /* TODO: express in HZ. */ +#define ENABLE_FULL_PROMISCUOUS 0x10000 + +#define nels(a) (sizeof(a) / sizeof(a[0])) typedef struct device device; typedef struct enet_statistics en_stats; @@ -63,6 +63,7 @@ unsigned int correct_nwid; unsigned int wrong_nwid; unsigned int promiscuous; + unsigned int full_promiscuous; timer_list watchdog; device *dev; net_local *prev; @@ -242,6 +243,28 @@ wavelan_16_on(ioaddr, hacr); } +#if defined(IRQ_SET_WORKS) +/* + * Write bytes to the PSA. + */ +static +void +psa_write(unsigned short ioaddr, unsigned short hacr, int o, unsigned char *b, int n) +{ + wavelan_16_off(ioaddr, hacr); + + while (n-- > 0) + { + outw(o, PIOR2(ioaddr)); + o++; + outb(*b, PIOP2(ioaddr)); + b++; + } + + wavelan_16_on(ioaddr, hacr); +} +#endif /* defined(IRQ_SET_WORKS) */ + /* * Read bytes from the on-board RAM. */ @@ -310,21 +333,36 @@ } } +static int irqvals[] = +{ + 0, 0, 0, 0x01, + 0x02, 0x04, 0, 0x08, + 0, 0, 0x10, 0x20, + 0x40, 0, 0, 0x80, +}; + +#if defined(IRQ_SET_WORKS) +static +int +wavelan_unmap_irq(int irq, unsigned char *irqval) +{ + if (irq < 0 || irq >= nels(irqvals) || irqvals[irq] == 0) + return -1; + + *irqval = (unsigned char)irqvals[irq]; + + return 0; +} +#endif /* defined(IRQ_SET_WORKS) */ + /* * Map values from the irq parameter register to irq numbers. */ static int -wavelan_map_irq(unsigned short ioaddr, unsigned char irqval) +wavelan_map_irq(unsigned char irqval) { - int irq; - static int irqvals[] = - { - 0, 0, 0, 0x01, - 0x02, 0x04, 0, 0x08, - 0, 0, 0x10, 0x20, - 0x40, 0, 0, 0x80, - }; + int irq; for (irq = 0; irq < nels(irqvals); irq++) { @@ -392,7 +430,7 @@ } else { - if (lp->promiscuous) + if (lp->promiscuous && lp->full_promiscuous) m.mmw_loopt_sel = MMW_LOOPT_SEL_UNDEFINED; else m.mmw_loopt_sel = 0x00; @@ -816,6 +854,7 @@ int irq; int i; net_local *lp; + int enable_full_promiscuous; if (wavelan_debug > 0) printk("%s: ->wavelan_probe1(dev=0x%x, ioaddr=0x%x)\n", dev->name, (unsigned int)dev, ioaddr); @@ -844,9 +883,27 @@ printk("%s: WaveLAN at %#x,", dev->name, ioaddr); - if ((irq = wavelan_map_irq(ioaddr, psa.psa_int_req_no)) == -1) + if (dev->irq != 0) { - printk(" could not wavelan_map_irq(0x%x, %d).\n", ioaddr, psa.psa_int_req_no); + printk("[WARNING: explicit IRQ value %d ignored: using PSA value instead]", dev->irq); +#if defined(IRQ_SET_WORKS) +Leave this out until I can get it to work -- BJ. + if (wavelan_unmap_irq(dev->irq, &psa.psa_int_req_no) == -1) + { + printk(" could not wavelan_unmap_irq(%d, ..) -- ignored.\n", dev->irq); + dev->irq = 0; + } + else + { + psa_write(ioaddr, HACR_DEFAULT, (char *)&psa.psa_int_req_no - (char *)&psa, (unsigned char *)&psa.psa_int_req_no, sizeof(psa.psa_int_req_no)); + wavelan_reset(ioaddr); + } +#endif /* defined(IRQ_SET_WORKS) */ + } + + if ((irq = wavelan_map_irq(psa.psa_int_req_no)) == -1) + { + printk(" could not wavelan_map_irq(%d).\n", psa.psa_int_req_no); if (wavelan_debug > 0) printk("%s: <-wavelan_probe1(): EAGAIN\n", dev->name); return EAGAIN; @@ -858,10 +915,19 @@ dev->base_addr = ioaddr; /* - * Apparently the third numeric argument to LILO's + * The third numeric argument to LILO's * `ether=' control line arrives here as `dev->mem_start'. - * If it is non-zero we use it instead of the PSA NWID. + * + * If bit 16 of dev->mem_start is non-zero we enable + * full promiscuity. + * + * If either of the least significant two bytes of + * dev->mem_start are non-zero we use them instead + * of the PSA NWID. */ + enable_full_promiscuous = (dev->mem_start & ENABLE_FULL_PROMISCUOUS) == ENABLE_FULL_PROMISCUOUS; + dev->mem_start &= ~ENABLE_FULL_PROMISCUOUS; + if (dev->mem_start != 0) { psa.psa_nwid[0] = (dev->mem_start >> 8) & 0xFF; @@ -878,6 +944,8 @@ printk("%s%02x", (i == 0) ? " " : ":", dev->dev_addr[i]); printk(", IRQ %d", dev->irq); + if (enable_full_promiscuous) + printk(", promisc"); printk(", nwid 0x%02x%02x", psa.psa_nwid[0], psa.psa_nwid[1]); printk(", PC"); @@ -957,6 +1025,7 @@ lp->hacr = HACR_DEFAULT; + lp->full_promiscuous = enable_full_promiscuous; lp->nwid[0] = psa.psa_nwid[0]; lp->nwid[1] = psa.psa_nwid[1]; @@ -2444,4 +2513,3 @@ * Basser Department of Computer Science Phone: +61-2-351-3423 * University of Sydney, N.S.W., 2006, AUSTRALIA Fax: +61-2-351-3838 */ -#endif /* defined(CONFIG_WAVELAN) */ diff -u --recursive --new-file v1.3.6/linux/drivers/net/wavelan.h linux/drivers/net/wavelan.h --- v1.3.6/linux/drivers/net/wavelan.h Wed Feb 1 09:19:36 1995 +++ linux/drivers/net/wavelan.h Sun Jul 2 10:30:38 1995 @@ -1,4 +1,3 @@ -#if defined(CONFIG_WAVELAN) #define WAVELAN_ADDR_SIZE 6 /* Size of a MAC address */ #define SA_ADDR0 0x08 /* First octet of WaveLAN MAC addresses */ #define SA_ADDR1 0x00 /* Second octet of WaveLAN MAC addresses */ @@ -251,4 +250,3 @@ * * For more details, see wavelan.c. */ -#endif /* defined(CONFIG_WAVELAN) */ diff -u --recursive --new-file v1.3.6/linux/drivers/net/znet.c linux/drivers/net/znet.c --- v1.3.6/linux/drivers/net/znet.c Fri Jun 30 16:22:29 1995 +++ linux/drivers/net/znet.c Tue Jul 4 11:43:15 1995 @@ -358,7 +358,7 @@ printk(KERN_WARNING "%s: Transmitter access conflict.\n", dev->name); else { short length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN; - unsigned char *buf = (void *)(skb+1); + unsigned char *buf = (void *)skb->data; ushort *tx_link = zn.tx_cur - 1; ushort rnd_len = (length + 1)>>1; @@ -565,7 +565,7 @@ } else { memcpy(skb_put(skb,pkt_len), zn.rx_cur, pkt_len); if (znet_debug > 6) { - unsigned int *packet = (unsigned int *) (skb + 1); + unsigned int *packet = (unsigned int *) skb->data; printk(KERN_DEBUG "Packet data is %08x %08x %08x %08x.\n", packet[0], packet[1], packet[2], packet[3]); } diff -u --recursive --new-file v1.3.6/linux/drivers/scsi/53c7,8xx.h linux/drivers/scsi/53c7,8xx.h --- v1.3.6/linux/drivers/scsi/53c7,8xx.h Thu Jun 29 19:02:42 1995 +++ linux/drivers/scsi/53c7,8xx.h Tue Jul 4 07:59:53 1995 @@ -78,9 +78,7 @@ #define NCR53c7xx_release NULL #endif -extern int generic_proc_info(char *, char **, off_t, int, int, int); - -#define NCR53c7xx {NULL, NULL, generic_proc_info, "NCR53c7xx", \ +#define NCR53c7xx {NULL, NULL, NULL, "NCR53c7xx", \ PROC_SCSI_NCR53C7xx, "NCR53c{7,8}xx (rel 4)", NCR53c7xx_detect, \ NULL, /* info */ NULL, /* command, deprecated */ NULL, \ NCR53c7xx_queue_command, NCR53c7xx_abort, NCR53c7xx_reset, \ diff -u --recursive --new-file v1.3.6/linux/drivers/scsi/Makefile linux/drivers/scsi/Makefile --- v1.3.6/linux/drivers/scsi/Makefile Thu Jun 29 19:02:45 1995 +++ linux/drivers/scsi/Makefile Tue Jul 4 07:59:53 1995 @@ -24,6 +24,14 @@ -O2 -fomit-frame-pointer -m486 include ../../.config + +.EXPORT_ALL_VARIABLES: + +SYMTAB_OBJS = scsi_syms.o + +TOPDIR = ../.. +include ../../versions.mk + endif SCSI_OBJS = @@ -36,6 +44,10 @@ ifdef CONFIG_SCSI SCSI_OBJS := hosts.o scsi.o scsi_ioctl.o constants.o scsicam.o scsi_proc.o else +ifdef CONFIG_MODVERSIONS +# Create this before we build anything else. +SCSI_MODULE_VER := scsi_syms.ver +endif SCSI_MODULE_OBJS := $(SCSI_MODULE_OBJS) scsi_mod.o endif @@ -235,17 +247,19 @@ mv scriptu.h 53c8xx_u.h rm fake.c -scsi_mod.o: hosts.o scsi.o scsi_ioctl.o constants.o scsicam.o scsi_proc.o - $(LD) $(LD_RFLAG) -r -o $@ hosts.o scsi.o scsi_ioctl.o constants.o scsicam.o scsi_proc.o +scsi_mod.o: $(SCSI_MODULE_VER) hosts.o scsi.o scsi_ioctl.o constants.o \ + scsicam.o scsi_proc.o $(SYMTAB_OBJS) + $(LD) $(LD_RFLAG) -r -o $@ hosts.o scsi.o scsi_ioctl.o constants.o scsicam.o scsi_proc.o $(SYMTAB_OBJS) -sr_mod.o: sr.o sr_ioctl.o +sr_mod.o: $(SCSI_MODULE_VER) sr.o sr_ioctl.o $(LD) $(LD_RFLAG) -r -o $@ sr.o sr_ioctl.o -sd_mod.o: sd.o sd_ioctl.o +sd_mod.o: $(SCSI_MODULE_VER) sd.o sd_ioctl.o $(LD) $(LD_RFLAG) -r -o $@ sd.o sd_ioctl.o +$(SYMTAB_OBJS): $(SYMTAB_OBJS:.o=.c) -modules: $(SCSI_MODULE_OBJS) +modules: $(SCSI_MODULE_VER) $(SCSI_MODULE_OBJS) echo $(SCSI_MODULE_OBJS) > ../../modules/SCSI_MODULES (cd ../../modules;for i in $(SCSI_MODULE_OBJS); do ln -sf ../drivers/scsi/$$i .; done) diff -u --recursive --new-file v1.3.6/linux/drivers/scsi/aha152x.h linux/drivers/scsi/aha152x.h --- v1.3.6/linux/drivers/scsi/aha152x.h Thu Jun 29 19:02:47 1995 +++ linux/drivers/scsi/aha152x.h Tue Jul 4 07:59:53 1995 @@ -18,8 +18,6 @@ int aha152x_reset(Scsi_Cmnd *); int aha152x_biosparam(Disk *, int, int*); -extern int generic_proc_info(char *, char **, off_t, int, int, int); - /* number of queueable commands (unless we support more than 1 cmd_per_lun this should do) */ #define AHA152X_MAXQUEUE 7 @@ -29,7 +27,7 @@ /* Initial value of Scsi_Host entry */ #define AHA152X { /* next */ NULL, \ /* usage_count */ NULL, \ - generic_proc_info, \ + NULL, \ "aha152x", \ PROC_SCSI_AHA152X, \ /* name */ AHA152X_REVID, \ diff -u --recursive --new-file v1.3.6/linux/drivers/scsi/aha1542.c linux/drivers/scsi/aha1542.c --- v1.3.6/linux/drivers/scsi/aha1542.c Thu Jun 29 19:02:47 1995 +++ linux/drivers/scsi/aha1542.c Tue Jul 4 07:59:53 1995 @@ -15,6 +15,7 @@ */ #ifdef MODULE +#include #include #endif diff -u --recursive --new-file v1.3.6/linux/drivers/scsi/aha1542.h linux/drivers/scsi/aha1542.h --- v1.3.6/linux/drivers/scsi/aha1542.h Thu Jun 29 19:02:47 1995 +++ linux/drivers/scsi/aha1542.h Tue Jul 4 07:59:53 1995 @@ -136,8 +136,6 @@ int aha1542_reset(Scsi_Cmnd *); int aha1542_biosparam(Disk *, int, int*); -extern int generic_proc_info(char *, char **, off_t, int, int, int); - #define AHA1542_MAILBOXES 8 #define AHA1542_SCATTER 16 #define AHA1542_CMDLUN 1 @@ -147,7 +145,7 @@ #endif #define AHA1542 { NULL, NULL, \ - generic_proc_info, \ + NULL, \ "aha1542", \ PROC_SCSI_AHA1542, \ "Adaptec 1542", \ diff -u --recursive --new-file v1.3.6/linux/drivers/scsi/aha1740.h linux/drivers/scsi/aha1740.h --- v1.3.6/linux/drivers/scsi/aha1740.h Thu Jun 29 19:02:47 1995 +++ linux/drivers/scsi/aha1740.h Tue Jul 4 07:59:53 1995 @@ -159,8 +159,6 @@ int aha1740_reset(Scsi_Cmnd *); int aha1740_biosparam(Disk *, int, int*); -extern int generic_proc_info(char *, char **, off_t, int, int, int); - #define AHA1740_ECBS 32 #define AHA1740_SCATTER 16 @@ -169,7 +167,7 @@ #endif #define AHA1740 {NULL, NULL, \ - generic_proc_info, \ + NULL, \ "aha1740", \ PROC_SCSI_AHA1740, \ "Adaptec 174x (EISA)", \ Binary files v1.3.6/linux/drivers/scsi/aic7770 and linux/drivers/scsi/aic7770 differ diff -u --recursive --new-file v1.3.6/linux/drivers/scsi/aic7xxx.h linux/drivers/scsi/aic7xxx.h --- v1.3.6/linux/drivers/scsi/aic7xxx.h Thu Jun 29 19:02:48 1995 +++ linux/drivers/scsi/aic7xxx.h Tue Jul 4 07:59:53 1995 @@ -47,7 +47,7 @@ #define AIC7XXX { \ NULL, \ NULL, \ - generic_proc_info, \ + NULL, \ "aic7xxx", \ PROC_SCSI_AIC7XXX, \ NULL, \ @@ -77,7 +77,5 @@ extern int aic7xxx_reset(Scsi_Cmnd *); extern const char *aic7xxx_info(struct Scsi_Host *); - -extern int generic_proc_info(char *, char **, off_t, int, int, int); #endif /* _aic7xxx_h */ diff -u --recursive --new-file v1.3.6/linux/drivers/scsi/buslogic.c linux/drivers/scsi/buslogic.c --- v1.3.6/linux/drivers/scsi/buslogic.c Thu Jun 29 19:02:48 1995 +++ linux/drivers/scsi/buslogic.c Tue Jul 4 07:52:51 1995 @@ -1515,8 +1515,8 @@ ip[1] = 32; } #else - ip[0] = 256; - ip[1] = 64; + ip[0] = 255; + ip[1] = 63; #endif } else { ip[0] = 128; diff -u --recursive --new-file v1.3.6/linux/drivers/scsi/buslogic.h linux/drivers/scsi/buslogic.h --- v1.3.6/linux/drivers/scsi/buslogic.h Thu Jun 29 19:02:49 1995 +++ linux/drivers/scsi/buslogic.h Tue Jul 4 07:59:53 1995 @@ -12,10 +12,8 @@ int buslogic_reset(Scsi_Cmnd *); int buslogic_biosparam(Disk *, int, int *); -extern int generic_proc_info(char *, char **, off_t, int, int, int); - #define BUSLOGIC { NULL, NULL, \ - generic_proc_info, \ + NULL, \ "buslogic", \ PROC_SCSI_BUSLOGIC, \ "BusLogic", \ diff -u --recursive --new-file v1.3.6/linux/drivers/scsi/constants.c linux/drivers/scsi/constants.c --- v1.3.6/linux/drivers/scsi/constants.c Thu Jun 29 19:02:49 1995 +++ linux/drivers/scsi/constants.c Tue Jul 4 07:59:53 1995 @@ -3,6 +3,20 @@ * etc. */ +#ifdef MODULE +/* + * Don't import our own symbols, as this would severely mess up our + * symbol tables. + */ +#define _SCSI_SYMS_VER_ +#include +#include +#include +#else +#define MOD_INC_USE_COUNT +#define MOD_DEC_USE_COUNT +#endif + #include #include "../block/blk.h" #include diff -u --recursive --new-file v1.3.6/linux/drivers/scsi/eata_pio.h linux/drivers/scsi/eata_pio.h --- v1.3.6/linux/drivers/scsi/eata_pio.h Fri Jun 30 16:22:29 1995 +++ linux/drivers/scsi/eata_pio.h Tue Jul 4 07:59:53 1995 @@ -73,8 +73,6 @@ #define eata_pio_release NULL #endif -extern int generic_proc_info(char *, char **, off_t, int, int, int); - #define EATA_PIO { \ NULL, NULL, \ diff -u --recursive --new-file v1.3.6/linux/drivers/scsi/fdomain.c linux/drivers/scsi/fdomain.c --- v1.3.6/linux/drivers/scsi/fdomain.c Thu Jun 29 19:02:50 1995 +++ linux/drivers/scsi/fdomain.c Wed Jul 5 11:21:10 1995 @@ -1,10 +1,10 @@ /* fdomain.c -- Future Domain TMC-16x0 SCSI driver * Created: Sun May 3 18:53:19 1992 by faith@cs.unc.edu - * Revised: Fri Jun 23 17:07:09 1995 by r.faith@ieee.org + * Revised: Tue Jul 4 13:58:47 1995 by r.faith@ieee.org * Author: Rickard E. Faith, faith@cs.unc.edu * Copyright 1992, 1993, 1994, 1995 Rickard E. Faith * - * $Id: fdomain.c,v 5.31 1995/06/23 21:07:16 faith Exp $ + * $Id: fdomain.c,v 5.33 1995/07/04 18:59:49 faith Exp $ * 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 @@ -206,7 +206,7 @@ #include #include -#define VERSION "$Revision: 5.31 $" +#define VERSION "$Revision: 5.33 $" /* START OF USER DEFINABLE OPTIONS */ @@ -679,12 +679,12 @@ return 1; /* success */ } -/* PCI detection function: int fdomain_36c70_detect(int* irq, int* iobase) - This function gets the Interrupt Level and I/O base address from the PCI - configuration registers. The I/O base address is masked with 0xfff8 - since on my card the address read from the PCI config registers is off - by one from the actual I/O base address necessary for accessing the - status and control registers on the card (PCI config register gives +/* 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. The I/O base address is masked with + 0xfff8 since on my card the address read from the PCI config registers + is off by one from the actual I/O base address necessary for accessing + the status and control registers on the card (PCI config register gives 0xf801, actual address is 0xf800). This is likely a bug in the FD config code that writes to the PCI registers, however using a mask should be safe since I think the scan done by the card to determine the @@ -696,20 +696,20 @@ detection function. Comments, bug reports, etc... on this function should be sent to mckinley@msupa.pa.msu.edu - James T. McKinley. */ -#ifdef PCI_CONFIG -static int fdomain_36c70_detect( int *irq, int *iobase ) +#ifdef CONFIG_PCI +static int fdomain_pci_bios_detect( int *irq, int *iobase ) { int error; unsigned char pci_bus, pci_dev_fn; /* PCI bus & device function */ unsigned char pci_irq; /* PCI interrupt line */ - unsigned long pci_base; /* PCI I/O base address */ + unsigned int pci_base; /* PCI I/O base address */ unsigned short pci_vendor, pci_device; /* PCI vendor & device IDs */ /* If the PCI BIOS doesn't exist, use the old-style detection routines. Otherwise, get the I/O base address and interrupt from the PCI config registers. */ - if (!pcibios_present()) return fdomain_pci_detect( irq, iobase ); + if (!pcibios_present()) return fdomain_pci_nobios_detect( irq, iobase ); #if DEBUG_DETECT /* Tell how to print a list of the known PCI devices from bios32 and @@ -857,7 +857,7 @@ if (!PCI_bus) { flag = fdomain_isa_detect( &interrupt_level, &port_base ); } else { -#ifdef PCI_CONFIG +#ifdef CONFIG_PCI flag = fdomain_pci_bios_detect( &interrupt_level, &port_base ); #else flag = fdomain_pci_nobios_detect( &interrupt_level, &port_base ); @@ -868,7 +868,7 @@ #if DEBUG_DETECT printk( " FAILED: NO PORT\n" ); #endif -#ifdef PCI_CONFIG +#ifdef CONFIG_PCI printk( "\nTMC-3260 36C70 PCI scsi chip detection failed.\n" ); printk( "Send mail to mckinley@msupa.pa.msu.edu.\n" ); #endif diff -u --recursive --new-file v1.3.6/linux/drivers/scsi/fdomain.h linux/drivers/scsi/fdomain.h --- v1.3.6/linux/drivers/scsi/fdomain.h Thu Jun 29 19:02:50 1995 +++ linux/drivers/scsi/fdomain.h Tue Jul 4 07:59:53 1995 @@ -33,11 +33,9 @@ int fdomain_16x0_queue( Scsi_Cmnd *, void (*done)(Scsi_Cmnd *) ); int fdomain_16x0_biosparam( Disk *, int, int * ); -extern int generic_proc_info(char *, char **, off_t, int, int, int); - #define FDOMAIN_16X0 { NULL, \ NULL, \ - generic_proc_info, \ + NULL, \ "fdomain", \ PROC_SCSI_FUTURE_DOMAIN, \ NULL, \ diff -u --recursive --new-file v1.3.6/linux/drivers/scsi/g_NCR5380.h linux/drivers/scsi/g_NCR5380.h --- v1.3.6/linux/drivers/scsi/g_NCR5380.h Thu Jun 29 19:02:50 1995 +++ linux/drivers/scsi/g_NCR5380.h Tue Jul 4 07:59:53 1995 @@ -53,7 +53,7 @@ #ifdef HOSTS_C -#define GENERIC_NCR5380 {NULL, NULL, generic_proc_info, "g_NCR5380", \ +#define GENERIC_NCR5380 {NULL, NULL, NULL, "g_NCR5380", \ PROC_SCSI_GENERIC_NCR5380, "Trantor T128/T128F/T228", \ generic_NCR5380_detect, NULL, NULL, NULL, \ generic_NCR5380_queue_command, generic_NCR5380_abort, \ diff -u --recursive --new-file v1.3.6/linux/drivers/scsi/hosts.c linux/drivers/scsi/hosts.c --- v1.3.6/linux/drivers/scsi/hosts.c Thu Jun 29 19:02:50 1995 +++ linux/drivers/scsi/hosts.c Tue Jul 4 07:59:53 1995 @@ -16,6 +16,20 @@ * hosts currently present in the system. */ +#ifdef MODULE +/* + * Don't import our own symbols, as this would severely mess up our + * symbol tables. + */ +#define _SCSI_SYMS_VER_ +#include +#include +#include +#else +#define MOD_INC_USE_COUNT +#define MOD_DEC_USE_COUNT +#endif + #include #include "../block/blk.h" #include diff -u --recursive --new-file v1.3.6/linux/drivers/scsi/in2000.h linux/drivers/scsi/in2000.h --- v1.3.6/linux/drivers/scsi/in2000.h Thu Jun 29 19:02:50 1995 +++ linux/drivers/scsi/in2000.h Tue Jul 4 07:59:53 1995 @@ -101,15 +101,13 @@ int in2000_reset(Scsi_Cmnd *); int in2000_biosparam(Disk *, int, int*); -extern int generic_proc_info(char *, char **, off_t, int, int, int); - #ifndef NULL #define NULL 0 #endif /* next may be "SG_NONE" or "SG_ALL" or nr. of (1k) blocks per R/W Cmd. */ #define IN2000_SG SG_ALL -#define IN2000 {NULL, NULL, generic_proc_info, \ +#define IN2000 {NULL, NULL, NULL, \ "in2000", PROC_SCSI_IN2000, \ "Always IN2000", in2000_detect, NULL, \ NULL, in2000_command, \ diff -u --recursive --new-file v1.3.6/linux/drivers/scsi/pas16.h linux/drivers/scsi/pas16.h --- v1.3.6/linux/drivers/scsi/pas16.h Thu Jun 29 19:02:50 1995 +++ linux/drivers/scsi/pas16.h Tue Jul 4 07:59:53 1995 @@ -120,8 +120,6 @@ int pas16_queue_command(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *)); int pas16_reset(Scsi_Cmnd *); -extern int generic_proc_info(char *, char **, off_t, int, int, int); - #ifndef NULL #define NULL 0 #endif @@ -142,7 +140,7 @@ #ifdef HOSTS_C -#define MV_PAS16 {NULL, NULL, generic_proc_info, "pas16", PROC_SCSI_PAS16, \ +#define MV_PAS16 {NULL, NULL, NULL, "pas16", PROC_SCSI_PAS16, \ "Pro Audio Spectrum-16 SCSI", \ pas16_detect, NULL, NULL, \ NULL, pas16_queue_command, pas16_abort, pas16_reset, NULL, \ diff -u --recursive --new-file v1.3.6/linux/drivers/scsi/qlogic.h linux/drivers/scsi/qlogic.h --- v1.3.6/linux/drivers/scsi/qlogic.h Thu Jun 29 19:02:50 1995 +++ linux/drivers/scsi/qlogic.h Tue Jul 4 07:59:53 1995 @@ -9,8 +9,6 @@ int qlogic_reset(Scsi_Cmnd *); int qlogic_biosparam(Disk *,int,int[]); -extern int generic_proc_info(char *, char **, off_t, int, int, int); - #ifndef NULL #define NULL (0) #endif @@ -18,7 +16,7 @@ #define QLOGIC { \ NULL, \ NULL, \ - generic_proc_info, \ + NULL, \ "qlogic", \ PROC_SCSI_QLOGIC, \ NULL, \ diff -u --recursive --new-file v1.3.6/linux/drivers/scsi/scsi.c linux/drivers/scsi/scsi.c --- v1.3.6/linux/drivers/scsi/scsi.c Thu Jun 29 19:02:51 1995 +++ linux/drivers/scsi/scsi.c Tue Jul 4 07:59:54 1995 @@ -20,6 +20,19 @@ * Native multichannel and wide scsi support added * by Michael Neuffer neuffer@goofy.zdv.uni-mainz.de */ +#ifdef MODULE +/* + * Don't import our own symbols, as this would severely mess up our + * symbol tables. + */ +#define _SCSI_SYMS_VER_ +#include +#include +#include +#else +#define MOD_INC_USE_COUNT +#define MOD_DEC_USE_COUNT +#endif #include #include @@ -36,16 +49,9 @@ #include "hosts.h" #include "constants.h" -#ifdef MODULE -#include -#include -#else -#define MOD_INC_USE_COUNT -#define MOD_DEC_USE_COUNT -#endif - #undef USE_STATIC_SCSI_MEMORY + /* static const char RCSid[] = "$Header: /usr/src/linux/kernel/blk_drv/scsi/RCS/scsi.c,v 1.5 1993/09/24 12:45:18 drew Exp drew $"; */ @@ -511,6 +517,8 @@ SDpnt->manufacturer = SCSI_MAN_NEC; } else if (!strncmp(scsi_result+8,"TOSHIBA",7)) SDpnt->manufacturer = SCSI_MAN_TOSHIBA; + else if (!strncmp(scsi_result+8,"SONY",4)) + SDpnt->manufacturer = SCSI_MAN_SONY; else SDpnt->manufacturer = SCSI_MAN_UNKNOWN; @@ -2865,55 +2873,28 @@ } #endif - #ifdef MODULE -/* -extern int kernel_scsi_ioctl (Scsi_Device *dev, int cmd, void *arg); -extern int scsi_ioctl (Scsi_Device *dev, int cmd, void *arg); -*/ -struct symbol_table scsi_symbol_table = { -#include -#ifdef CONFIG_MODVERSIONS - { (void *)1 /* Version version :-) */, "_Using_Versions" }, -#endif - X(scsi_register_module), - X(scsi_unregister_module), - X(scsi_free), - X(scsi_malloc), - X(scsi_register), - X(scsi_unregister), - X(scsicam_bios_param), - X(allocate_device), - X(scsi_do_cmd), - X(scsi_command_size), - X(scsi_init_malloc), - X(scsi_init_free), - X(scsi_ioctl), - X(print_command), - X(print_sense), - X(dma_free_sectors), - X(kernel_scsi_ioctl), - X(need_isa_buffer), - X(request_queueable), -/* - * These are here only while I debug the rest of the scsi stuff. - */ - X(scsi_hostlist), - X(scsi_hosts), - X(scsi_devicelist), - X(scsi_devices), - - /******************************************************** - * Do not add anything below this line, - * as the stacked modules depend on this! - */ -#include -}; char kernel_version[] = UTS_RELEASE; +extern struct symbol_table scsi_symbol_table; + int init_module(void) { + +#if CONFIG_PROC_FS + /* + * This will initialize the directory so that we do not have + * random crap in there. + */ + build_proc_dir_entries(); +#endif + + /* + * This makes the real /proc/scsi visible. + */ + dispatch_scsi_info_ptr = dispatch_scsi_info; + timer_table[SCSI_TIMER].fn = scsi_main_timeout; timer_table[SCSI_TIMER].expires = 0; register_symtab(&scsi_symbol_table); diff -u --recursive --new-file v1.3.6/linux/drivers/scsi/scsi.h linux/drivers/scsi/scsi.h --- v1.3.6/linux/drivers/scsi/scsi.h Fri Jun 30 16:22:29 1995 +++ linux/drivers/scsi/scsi.h Sat Jul 1 19:05:59 1995 @@ -261,6 +261,7 @@ #define SCSI_MAN_NEC 1 #define SCSI_MAN_TOSHIBA 2 #define SCSI_MAN_NEC_OLDCDR 3 +#define SCSI_MAN_SONY 4 /* * As the scsi do command functions are intelligent, and may need to diff -u --recursive --new-file v1.3.6/linux/drivers/scsi/scsi_debug.c linux/drivers/scsi/scsi_debug.c --- v1.3.6/linux/drivers/scsi/scsi_debug.c Thu Jun 29 19:02:52 1995 +++ linux/drivers/scsi/scsi_debug.c Tue Jul 4 07:59:54 1995 @@ -8,11 +8,13 @@ */ #ifdef MODULE +#include #include #endif #include #include +#include #include #include #include @@ -598,6 +600,36 @@ { static char buffer[] = " "; /* looks nicer without anything here */ return buffer; +} + +/* generic_proc_info + * Used if the driver currently has no own support for /proc/scsi + */ +int scsi_debug_proc_info(char *buffer, char **start, off_t offset, + int length, int inode, int inout) +{ + int len, pos, begin; + + if(inout == 1) + return(-ENOSYS); /* This is a no-op */ + + begin = 0; + pos = len = sprintf(buffer, + "This driver is not a real scsi driver, but it plays one on TV.\n" + "It is very handy for debugging specific problems because you\n" + "can simulate a variety of error conditions\n"); + 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); } #ifdef MODULE diff -u --recursive --new-file v1.3.6/linux/drivers/scsi/scsi_debug.h linux/drivers/scsi/scsi_debug.h --- v1.3.6/linux/drivers/scsi/scsi_debug.h Thu Jun 29 19:02:52 1995 +++ linux/drivers/scsi/scsi_debug.h Tue Jul 4 07:59:54 1995 @@ -8,16 +8,15 @@ int scsi_debug_abort(Scsi_Cmnd *); int scsi_debug_biosparam(Disk *, int, int[]); int scsi_debug_reset(Scsi_Cmnd *); - -extern int generic_proc_info(char *, char **, off_t, int, int, int); - +int scsi_debug_proc_info(char *, char **, off_t, int, int, int); + #ifndef NULL #define NULL 0 #endif #define SCSI_DEBUG_MAILBOXES 8 -#define SCSI_DEBUG {NULL, NULL, generic_proc_info, "scsi_debug", \ +#define SCSI_DEBUG {NULL, NULL, scsi_debug_proc_info, "scsi_debug", \ PROC_SCSI_SCSI_DEBUG, "SCSI DEBUG", scsi_debug_detect, NULL, \ NULL, scsi_debug_command, \ scsi_debug_queuecommand, \ diff -u --recursive --new-file v1.3.6/linux/drivers/scsi/scsi_ioctl.c linux/drivers/scsi/scsi_ioctl.c --- v1.3.6/linux/drivers/scsi/scsi_ioctl.c Thu Jun 29 19:02:52 1995 +++ linux/drivers/scsi/scsi_ioctl.c Tue Jul 4 07:59:54 1995 @@ -1,3 +1,17 @@ +#ifdef MODULE +/* + * Don't import our own symbols, as this would severely mess up our + * symbol tables. + */ +#define _SCSI_SYMS_VER_ +#include +#include +#include +#else +#define MOD_INC_USE_COUNT +#define MOD_DEC_USE_COUNT +#endif + #include #include #include diff -u --recursive --new-file v1.3.6/linux/drivers/scsi/scsi_proc.c linux/drivers/scsi/scsi_proc.c --- v1.3.6/linux/drivers/scsi/scsi_proc.c Thu Jun 29 19:02:52 1995 +++ linux/drivers/scsi/scsi_proc.c Tue Jul 4 07:59:54 1995 @@ -13,6 +13,19 @@ * Andreas Heilwagen */ +#ifdef MODULE +/* + * Don't import our own symbols, as this would severely mess up our + * symbol tables. + */ +#define _SCSI_SYMS_VER_ +#include +#include +#include +#else +#define MOD_INC_USE_COUNT +#define MOD_DEC_USE_COUNT +#endif #include #include @@ -39,13 +52,20 @@ struct Scsi_Host *hpnt = scsi_hostlist; uint x = 0; + /* + * Danger - this has massive race conditions in it. + * If the someone adds/removes entries from the scsi chain + * while someone else is looking at /proc/scsi, unpredictable + * results will be obtained. + */ while (tpnt) { if (ino == tpnt->low_ino) return(x); x += 3; while (hpnt) { + if(hpnt->hostt == tpnt) /* This gives us the correct index */ + x++; hpnt = hpnt->next; - x++; } tpnt = tpnt->next; } @@ -86,16 +106,31 @@ extern int dispatch_scsi_info(int ino, char *buffer, char **start, off_t offset, int length, int func) { + int retval; struct Scsi_Host *hpnt = scsi_hostlist; if(func != 2) { - if(ino == PROC_SCSI_SCSI) - return(scsi_proc_info(buffer, start, offset, length, - hpnt->host_no, func)); + if(ino == PROC_SCSI_SCSI) { + /* + * If there are no hosts, tell the user to go away. + */ + if( hpnt == NULL ) { + return (-ENOSYS); + } + + retval = scsi_proc_info(buffer, start, offset, length, + hpnt->host_no, func); + return(retval); + } + while(hpnt) { if (ino == (hpnt->host_no + PROC_SCSI_FILE)) - return(hpnt->hostt->proc_info(buffer, start, offset, length, - hpnt->host_no, func)); + if(hpnt->hostt->proc_info == NULL) + return generic_proc_info(buffer, start, offset, length, + hpnt->host_no, func); + else + return(hpnt->hostt->proc_info(buffer, start, offset, length, + hpnt->host_no, func)); hpnt = hpnt->next; } return(-EBADF); @@ -118,7 +153,7 @@ void build_proc_dir_hba_entries(void) { Scsi_Host_Template *tpnt = scsi_hosts; - struct Scsi_Host *hpnt = scsi_hostlist; + struct Scsi_Host *hpnt; static char names[PROC_SCSI_LAST - PROC_SCSI_FILE][3]; uint x, y; @@ -131,8 +166,9 @@ scsi_hba_dir[x].low_ino = PROC_SCSI; scsi_hba_dir[x].namelen = 2; scsi_hba_dir[x++].name = ".."; - - while (hpnt) { + + hpnt = scsi_hostlist; + while (hpnt) { if (tpnt == hpnt->hostt) { scsi_hba_dir[x].low_ino = PROC_SCSI_FILE + hpnt->host_no; scsi_hba_dir[x].namelen = sprintf(names[y],"%d",hpnt->host_no); @@ -142,8 +178,8 @@ } hpnt = hpnt->next; } - - scsi_hba_dir[x].low_ino = 0; + + scsi_hba_dir[x].low_ino = 0; scsi_hba_dir[x].namelen = 0; scsi_hba_dir[x++].name = NULL; tpnt = tpnt->next; @@ -168,11 +204,13 @@ scsi_dir[2].low_ino = PROC_SCSI_SCSI; scsi_dir[2].namelen = 4; scsi_dir[2].name = "scsi"; - for(x = 3; x < newnum + 3; x++, tpnt = tpnt->next) { + + for(x = 3; x < newnum + 3; x++, tpnt = tpnt->next) { scsi_dir[x].low_ino = tpnt->low_ino; scsi_dir[x].namelen = strlen(tpnt->procname); scsi_dir[x].name = tpnt->procname; } + scsi_dir[x].low_ino = 0; scsi_dir[x].namelen = 0; scsi_dir[x].name = NULL; diff -u --recursive --new-file v1.3.6/linux/drivers/scsi/scsi_syms.c linux/drivers/scsi/scsi_syms.c --- v1.3.6/linux/drivers/scsi/scsi_syms.c Thu Jan 1 02:00:00 1970 +++ linux/drivers/scsi/scsi_syms.c Tue Jul 4 07:59:54 1995 @@ -0,0 +1,84 @@ + +#include + +/* + * We should not even be trying to compile this if we are not doing + * a module. + */ +#ifndef MODULE +#error Go away. +#endif + +/* + * Even though we are building a module, we need to undef this, since + * we are building a symbol table to be used by other modules. For + * the symbol table to build properly, we need to undefine this. + */ +#undef MODULE + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../block/blk.h" +#include "scsi.h" +#include "hosts.h" +#include "constants.h" + +#include "sd.h" +/* + * This source file contains the symbol table used by scsi loadable + * modules. + */ + +extern void print_command (unsigned char *command); +extern void print_sense(char * devclass, Scsi_Cmnd * SCpnt); + +struct symbol_table scsi_symbol_table = { +#include +#ifdef CONFIG_MODVERSIONS + { (void *)1 /* Version version :-) */, + SYMBOL_NAME_STR("Using_Versions") }, +#endif + X(scsi_register_module), + X(scsi_unregister_module), + X(scsi_free), + X(scsi_malloc), + X(scsi_register), + X(scsi_unregister), + X(scsicam_bios_param), + X(allocate_device), + X(scsi_do_cmd), + X(scsi_command_size), + X(scsi_init_malloc), + X(scsi_init_free), + X(scsi_ioctl), + X(print_command), + X(print_sense), + X(dma_free_sectors), + X(kernel_scsi_ioctl), + X(need_isa_buffer), + X(request_queueable), +/* + * These are here only while I debug the rest of the scsi stuff. + */ + X(scsi_hostlist), + X(scsi_hosts), + X(scsi_devicelist), + X(scsi_devices), + + /******************************************************** + * Do not add anything below this line, + * as the stacked modules depend on this! + */ +#include +}; diff -u --recursive --new-file v1.3.6/linux/drivers/scsi/scsicam.c linux/drivers/scsi/scsicam.c --- v1.3.6/linux/drivers/scsi/scsicam.c Thu Jun 29 19:02:52 1995 +++ linux/drivers/scsi/scsicam.c Tue Jul 4 07:59:54 1995 @@ -10,6 +10,20 @@ * For more information, please consult the SCSI-CAM draft. */ +#ifdef MODULE +/* + * Don't import our own symbols, as this would severely mess up our + * symbol tables. + */ +#define _SCSI_SYMS_VER_ +#include +#include +#include +#else +#define MOD_INC_USE_COUNT +#define MOD_DEC_USE_COUNT +#endif + #include #include #include diff -u --recursive --new-file v1.3.6/linux/drivers/scsi/sd.c linux/drivers/scsi/sd.c --- v1.3.6/linux/drivers/scsi/sd.c Thu Jun 29 19:02:52 1995 +++ linux/drivers/scsi/sd.c Tue Jul 4 07:59:54 1995 @@ -16,6 +16,20 @@ * low-level scsi drivers. */ +#ifdef MODULE +#include +#include +#include +/* + * This is a variable in scsi.c that is set when we are processing something + * after boot time. By definition, this is true when we are a loadable module + * ourselves. + */ +#define MODULE_FLAG 1 +#else +#define MODULE_FLAG scsi_loadable_module_flag +#endif /* MODULE */ + #include #include #include @@ -1174,7 +1188,7 @@ rscsi_disks[i].device) { i = sd_init_onedisk(i); - if (scsi_loadable_module_flag + if (MODULE_FLAG && !rscsi_disks[i].has_part_table) { sd_sizes[i << 4] = rscsi_disks[i].capacity; revalidate_scsidisk(i << 4, 0); diff -u --recursive --new-file v1.3.6/linux/drivers/scsi/sd_ioctl.c linux/drivers/scsi/sd_ioctl.c --- v1.3.6/linux/drivers/scsi/sd_ioctl.c Thu Jun 29 19:02:53 1995 +++ linux/drivers/scsi/sd_ioctl.c Tue Jul 4 07:59:54 1995 @@ -1,3 +1,9 @@ +#ifdef MODULE +#include +#include +#include +#endif /* MODULE */ + #include #include #include diff -u --recursive --new-file v1.3.6/linux/drivers/scsi/seagate.h linux/drivers/scsi/seagate.h --- v1.3.6/linux/drivers/scsi/seagate.h Thu Jun 29 19:02:53 1995 +++ linux/drivers/scsi/seagate.h Tue Jul 4 07:59:54 1995 @@ -26,9 +26,7 @@ int seagate_st0x_biosparam(Disk *, int, int*); -extern int generic_proc_info(char *, char **, off_t, int, int, int); - -#define SEAGATE_ST0X { NULL, NULL, generic_proc_info, "seagate", \ +#define SEAGATE_ST0X { NULL, NULL, NULL, "seagate", \ PROC_SCSI_SEAGATE, NULL, seagate_st0x_detect, \ NULL, \ seagate_st0x_info, seagate_st0x_command, \ diff -u --recursive --new-file v1.3.6/linux/drivers/scsi/sg.c linux/drivers/scsi/sg.c --- v1.3.6/linux/drivers/scsi/sg.c Thu Jun 29 19:02:53 1995 +++ linux/drivers/scsi/sg.c Tue Jul 4 07:59:54 1995 @@ -7,6 +7,7 @@ * Borrows code from st driver. */ #ifdef MODULE +#include #include #include #endif /* MODULE */ diff -u --recursive --new-file v1.3.6/linux/drivers/scsi/sr.c linux/drivers/scsi/sr.c --- v1.3.6/linux/drivers/scsi/sr.c Thu Jun 29 19:02:53 1995 +++ linux/drivers/scsi/sr.c Tue Jul 4 07:59:54 1995 @@ -15,6 +15,12 @@ * low-level scsi drivers. */ +#ifdef MODULE +#include +#include +#include +#endif /* MODULE */ + #include #include #include @@ -450,7 +456,32 @@ scsi_CDs[MINOR(inode->i_rdev)].needs_sector_size = 1; } break; - + + case SCSI_MAN_SONY: /* Thomas QUINOT */ +#ifdef DEBUG + printk("sr_photocd: use SONY code\n"); +#endif + memset(buf,0,40); + *((unsigned long*)buf) = 0x0; /* we send nothing... */ + *((unsigned long*)buf+1) = 0x0c; /* and receive 0x0c bytes */ + cmd[0] = 0x43; /* Read TOC */ + cmd[8] = 0x0c; + cmd[9] = 0x40; + rc = kernel_scsi_ioctl(scsi_CDs[MINOR(inode->i_rdev)].device, + SCSI_IOCTL_SEND_COMMAND, buf); + + if ((rc != 0) || ((rec[0] << 8) + rec[1] != 0x0a)) { + printk("sr_photocd: ioctl error (SONY): 0x%x\n",rc); + break; + } + sector = rec[11] + (rec[10] << 8) + (rec[9] << 16) + (rec[8] << 24); + is_xa = !!sector; +#ifdef DEBUG + if (sector) + printk ("sr_photocd: multisession CD detected. start: %lu\n",sector); +#endif + break; + case SCSI_MAN_NEC_OLDCDR: case SCSI_MAN_UNKNOWN: default: diff -u --recursive --new-file v1.3.6/linux/drivers/scsi/sr_ioctl.c linux/drivers/scsi/sr_ioctl.c --- v1.3.6/linux/drivers/scsi/sr_ioctl.c Thu Jun 29 19:02:53 1995 +++ linux/drivers/scsi/sr_ioctl.c Tue Jul 4 07:59:54 1995 @@ -1,3 +1,9 @@ +#ifdef MODULE +#include +#include +#include +#endif /* MODULE */ + #include #include #include diff -u --recursive --new-file v1.3.6/linux/drivers/scsi/st.c linux/drivers/scsi/st.c --- v1.3.6/linux/drivers/scsi/st.c Thu Jun 29 19:02:53 1995 +++ linux/drivers/scsi/st.c Tue Jul 4 07:59:54 1995 @@ -14,6 +14,7 @@ Last modified: Sat Feb 18 10:51:25 1995 by root@kai.home */ #ifdef MODULE +#include #include #include #endif /* MODULE */ diff -u --recursive --new-file v1.3.6/linux/drivers/scsi/t128.h linux/drivers/scsi/t128.h --- v1.3.6/linux/drivers/scsi/t128.h Thu Jun 29 19:02:53 1995 +++ linux/drivers/scsi/t128.h Tue Jul 4 07:59:54 1995 @@ -117,7 +117,7 @@ #ifdef HOSTS_C -#define TRANTOR_T128 {NULL, NULL, generic_proc_info, "t128", PROC_SCSI_T128, \ +#define TRANTOR_T128 {NULL, NULL, NULL, "t128", PROC_SCSI_T128, \ "Trantor T128/T128F/T228", t128_detect, NULL, \ NULL, \ NULL, t128_queue_command, t128_abort, t128_reset, NULL, \ diff -u --recursive --new-file v1.3.6/linux/drivers/scsi/u14-34f.h linux/drivers/scsi/u14-34f.h --- v1.3.6/linux/drivers/scsi/u14-34f.h Thu Jun 29 19:02:54 1995 +++ linux/drivers/scsi/u14-34f.h Tue Jul 4 07:59:54 1995 @@ -10,14 +10,12 @@ int u14_34f_reset(Scsi_Cmnd *); int u14_34f_biosparam(Disk *, int, int *); -extern int generic_proc_info(char *, char **, off_t, int, int, int); - #define U14_34F_VERSION "2.01.00" #define ULTRASTOR_14_34F { \ NULL, /* Ptr for modules */ \ NULL, /* usage count for modules */ \ - generic_proc_info, \ + NULL, \ "u14_34f", \ PROC_SCSI_U14_34F, \ "UltraStor 14F/34F rev. " U14_34F_VERSION " ", \ diff -u --recursive --new-file v1.3.6/linux/drivers/scsi/ultrastor.h linux/drivers/scsi/ultrastor.h --- v1.3.6/linux/drivers/scsi/ultrastor.h Thu Jun 29 19:02:54 1995 +++ linux/drivers/scsi/ultrastor.h Tue Jul 4 07:59:54 1995 @@ -20,7 +20,6 @@ int ultrastor_reset(Scsi_Cmnd *); int ultrastor_biosparam(Disk *, int, int *); -extern int generic_proc_info(char *, char **, off_t, int, int, int); #define ULTRASTOR_14F_MAX_SG 16 #define ULTRASTOR_24F_MAX_SG 33 @@ -32,7 +31,7 @@ #define ULTRASTOR_14F { NULL, NULL, /* Ptr for modules*/ \ - generic_proc_info, \ + NULL, \ "ultrastor", \ PROC_SCSI_ULTRASTOR, \ "UltraStor 14F/24F/34F", \ diff -u --recursive --new-file v1.3.6/linux/drivers/scsi/wd7000.h linux/drivers/scsi/wd7000.h --- v1.3.6/linux/drivers/scsi/wd7000.h Thu Jun 29 19:02:54 1995 +++ linux/drivers/scsi/wd7000.h Tue Jul 4 07:59:54 1995 @@ -19,8 +19,6 @@ int wd7000_reset(Scsi_Cmnd *); int wd7000_biosparam(Disk *, int, int*); -extern int generic_proc_info(char *, char **, off_t, int, int, int); - #ifndef NULL #define NULL 0L #endif @@ -40,7 +38,7 @@ #define WD7000_SG 16 #define WD7000 { NULL, NULL, \ - generic_proc_info, \ + NULL, \ "wd7000", \ PROC_SCSI_7000FASST, \ "Western Digital WD-7000", \ diff -u --recursive --new-file v1.3.6/linux/fs/Makefile linux/fs/Makefile --- v1.3.6/linux/fs/Makefile Mon Jun 5 12:29:08 1995 +++ linux/fs/Makefile Sat Jul 1 19:00:18 1995 @@ -7,7 +7,7 @@ # # Note 2! The CFLAGS definitions are now in the main makefile... -SUBDIRS = minix ext ext2 msdos proc isofs nfs xiafs umsdos hpfs sysv +SUBDIRS = minix ext ext2 msdos proc isofs nfs xiafs umsdos hpfs sysv smbfs ifdef CONFIG_MINIX_FS FS_SUBDIRS := $(FS_SUBDIRS) minix @@ -61,6 +61,12 @@ FS_SUBDIRS := $(FS_SUBDIRS) sysv else MODULE_FS_SUBDIRS := $(MODULE_FS_SUBDIRS) sysv +endif + +ifdef CONFIG_SMB_FS +FS_SUBDIRS := $(FS_SUBDIRS) smbfs +else +MODULE_FS_SUBDIRS := $(MODULE_FS_SUBDIRS) smbfs endif ifdef CONFIG_HPFS_FS diff -u --recursive --new-file v1.3.6/linux/fs/exec.c linux/fs/exec.c --- v1.3.6/linux/fs/exec.c Tue Jun 27 14:11:39 1995 +++ linux/fs/exec.c Thu Jul 6 13:24:46 1995 @@ -515,7 +515,8 @@ int ch; char * name; - current->dumpable = 1; + if (current->euid == current->uid && current->egid == current->gid) + current->dumpable = 1; name = bprm->filename; for (i=0; (ch = *(name++)) != '\0';) { if (ch == '/') diff -u --recursive --new-file v1.3.6/linux/fs/filesystems.c linux/fs/filesystems.c --- v1.3.6/linux/fs/filesystems.c Sun Jul 24 17:39:44 1994 +++ linux/fs/filesystems.c Sat Jul 1 19:00:18 1995 @@ -20,6 +20,7 @@ #include #include #include +#include extern void device_setup(void); @@ -71,6 +72,11 @@ #ifdef CONFIG_NFS_FS register_filesystem(&(struct file_system_type) {nfs_read_super, "nfs", 0, NULL}); +#endif + +#ifdef CONFIG_SMB_FS + register_filesystem(&(struct file_system_type) + {smb_read_super, "smbfs", 0, NULL}); #endif #ifdef CONFIG_ISO9660_FS diff -u --recursive --new-file v1.3.6/linux/fs/isofs/dir.c linux/fs/isofs/dir.c --- v1.3.6/linux/fs/isofs/dir.c Fri Jun 9 12:08:41 1995 +++ linux/fs/isofs/dir.c Wed Jul 5 11:27:08 1995 @@ -137,6 +137,19 @@ printk("Block, offset, f_pos: %x %x %x\n", block, offset, filp->f_pos); #endif + /* Next directory_record on next CDROM sector */ + if (offset >= bufsize) { + brelse(bh); + offset = 0; + block = isofs_bmap(inode, (filp->f_pos) >> bufbits); + if (!block) + return 0; + bh = breada(inode->i_dev, block, bufsize, filp->f_pos, inode->i_size); + if (!bh) + return 0; + continue; + } + de = (struct iso_directory_record *) (bh->b_data + offset); inode_number = (block << bufbits) + (offset & (bufsize - 1)); diff -u --recursive --new-file v1.3.6/linux/fs/proc/inode.c linux/fs/proc/inode.c --- v1.3.6/linux/fs/proc/inode.c Thu Jun 29 19:02:54 1995 +++ linux/fs/proc/inode.c Thu Jul 6 13:24:46 1995 @@ -170,6 +170,15 @@ inode->i_op = &proc_scsi_inode_operations; return; } + /* + * Special hook used when scsi is not present. + */ + if (ino == PROC_SCSI_NOT_PRESENT) { + inode->i_mode = S_IFREG | S_IRUGO | S_IXUGO; + inode->i_op = &proc_scsi_inode_operations; + return; + } + /* files within /proc/scsi */ if ((ino > PROC_SCSI_SCSI) && (ino < PROC_SCSI_FILE)) { inode->i_nlink = 2; @@ -221,7 +230,8 @@ return; } ino &= 0x0000ffff; - if (p->dumpable && p->uid == p->euid && p->gid == p->egid) { + if (ino == PROC_PID_INO || + (p->dumpable && p->uid == p->euid && p->gid == p->egid)) { inode->i_uid = p->uid; inode->i_gid = p->gid; } diff -u --recursive --new-file v1.3.6/linux/fs/proc/scsi.c linux/fs/proc/scsi.c --- v1.3.6/linux/fs/proc/scsi.c Fri Jun 30 16:22:30 1995 +++ linux/fs/proc/scsi.c Tue Jul 4 07:59:54 1995 @@ -89,30 +89,50 @@ { 0, 0, NULL } }; -inline static uint count_dir_entries(uint inode) +inline static uint count_dir_entries(uint inode, uint *num) { struct proc_dir_entry *dir; - uint i = 0; - + uint index, flag; + + (uint) *num = flag = index = 0; if(dispatch_scsi_info_ptr) - if (inode <= PROC_SCSI_SCSI_DEBUG) + { + if (inode == PROC_SCSI) { dir = scsi_dir; - else + while(dir[(uint)*num].low_ino) + (*num)++; + } else { dir = scsi_hba_dir; - else dir = scsi_dir2; - - while(dir[i].low_ino) - i++; - - return(i); + while(dir[index].low_ino || dir[index].low_ino <= PROC_SCSI_LAST) { + if(dir[index].low_ino == inode) + flag = 1; + if(dir[index].low_ino == 0) { + if(flag == 1) + break; + else + *num = 0; + } else { + (*num)++; + } + index++; + } + return(index - (*num)); + } + } + else { + dir = scsi_dir2; + while(dir[(uint)*num].low_ino) + (*num)++; + } + return(0); } static int proc_lookupscsi(struct inode * dir, const char * name, int len, struct inode ** result) { struct proc_dir_entry *de = NULL; - + *result = NULL; if (!dir) return(-ENOENT); @@ -121,11 +141,13 @@ return(-ENOENT); } if (dispatch_scsi_info_ptr != NULL) + { if (dir->i_ino <= PROC_SCSI_SCSI) de = scsi_dir; else { de = &scsi_hba_dir[dispatch_scsi_info_ptr(dir->i_ino, 0, 0, 0, 0, 2)]; } + } else de = scsi_dir2; @@ -146,19 +168,25 @@ void * dirent, filldir_t filldir) { struct proc_dir_entry * de; - unsigned int ino; - + uint index, num; + + index = num = 0; + if (!inode || !S_ISDIR(inode->i_mode)) return(-EBADF); - ino = inode->i_ino; - while (((unsigned) filp->f_pos) < count_dir_entries(ino)) { - if (dispatch_scsi_info_ptr) - if (ino <= PROC_SCSI_SCSI) + + index = count_dir_entries(inode->i_ino, &num); + + while (((unsigned) filp->f_pos + index) < index + num) { + if (dispatch_scsi_info_ptr) { + if (inode->i_ino <= PROC_SCSI_SCSI) de = scsi_dir + filp->f_pos; else - de = scsi_hba_dir + filp->f_pos; - else + de = scsi_hba_dir + filp->f_pos + index; + } + else { de = scsi_dir2 + filp->f_pos; + } if (filldir(dirent, de->name, de->namelen, filp->f_pos, de->low_ino)<0) break; filp->f_pos++; @@ -172,7 +200,7 @@ begin = 0; pos = len = sprintf(buffer, - "The scsi core module is currently not present\n"); + "No low-level scsi modules are currently present\n"); if(pos < offset) { len = 0; begin = pos; @@ -257,7 +285,6 @@ static int proc_writescsi(struct inode * inode, struct file * file, char * buf, int count) { - uint ino; int ret = 0; char * page; @@ -268,11 +295,9 @@ return(-EOVERFLOW); } - ino = inode->i_ino; - if(dispatch_scsi_info_ptr != NULL) { memcpy_fromfs(page, buf, count); - ret = dispatch_scsi_info_ptr(ino, page, 0, 0, count, 1); + ret = dispatch_scsi_info_ptr(inode->i_ino, page, 0, 0, count, 1); } else { free_page((ulong) page); return(-ENOPKG); /* Nothing here */ diff -u --recursive --new-file v1.3.6/linux/fs/smbfs/Makefile linux/fs/smbfs/Makefile --- v1.3.6/linux/fs/smbfs/Makefile Thu Jan 1 02:00:00 1970 +++ linux/fs/smbfs/Makefile Sat Jul 1 19:00:18 1995 @@ -0,0 +1,33 @@ +# +# Makefile for the linux smb-filesystem routines. +# +# 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... + +.c.s: + $(CC) $(CFLAGS) -S $< +.c.o: + $(CC) $(CFLAGS) -c $< +.s.o: + $(AS) -o $*.o $< + +OBJS= proc.o sock.o inode.o file.o dir.o \ + ioctl.o mmap.o + +smbfs.o: $(OBJS) + $(LD) -r -o smbfs.o $(OBJS) + +dep: + $(CPP) -M *.c > .depend + +modules: smbfs.o + +# +# include a dependency file if one exists +# +ifeq (.depend,$(wildcard .depend)) +include .depend +endif diff -u --recursive --new-file v1.3.6/linux/fs/smbfs/README linux/fs/smbfs/README --- v1.3.6/linux/fs/smbfs/README Thu Jan 1 02:00:00 1970 +++ linux/fs/smbfs/README Sat Jul 1 19:00:18 1995 @@ -0,0 +1,12 @@ +smbfs is a filesystem which understands the SMB protocol. This is the +protocol Windows for Workgroups, Windows NT or Lan Manager use to talk +to each other. It was inspired by samba, the program by Andrew +Tridgell that turns any unix site into a file server for DOS or +Windows clients. See ftp://nimbus.anu.edu.au/pub/tridge/samba/ for +this interesting program suite and lots of more information on SMB and +NetBIOS over TCP/IP. There you also find explanation for conceps like +netbios name or share. + +To use smbfs, you need a special mount program, which can be found in +the ksmbfs package, found on sunsite.unc.edu:/pub/Linux/ALPHA/smbfs. + diff -u --recursive --new-file v1.3.6/linux/fs/smbfs/dir.c linux/fs/smbfs/dir.c --- v1.3.6/linux/fs/smbfs/dir.c Thu Jan 1 02:00:00 1970 +++ linux/fs/smbfs/dir.c Sat Jul 1 19:00:18 1995 @@ -0,0 +1,940 @@ +/* + * dir.c + * + * Copyright (C) 1995 by Paal-Kr. Engstad and Volker Lendecke + * + */ + +#include +#ifdef MODULE +#include +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define NAME_OFFSET(de) ((int) ((de)->d_name - (char *) (de))) +#define ROUND_UP(x) (((x)+3) & ~3) + +static int +smb_dir_read(struct inode *inode, struct file *filp, char *buf, int count); + +static int +smb_readdir(struct inode *inode, struct file *filp, + void *dirent, filldir_t filldir); + +static int +get_pname(struct inode *dir, const char *name, int len, + char **res_path, int *res_len); + +static int +get_pname_static(struct inode *dir, const char *name, int len, + char *path, int *res_len); + +static struct inode * +smb_iget(struct inode *dir, char *path, struct smb_dirent *finfo); + +static void +put_pname(char *path); + +static struct smb_inode_info * +smb_find_inode(struct smb_server *server, const char *path); + +static int +smb_lookup(struct inode *dir, const char *__name, + int len, struct inode **result); + +static int +smb_create(struct inode *dir, const char *name, int len, int mode, + struct inode **result); + +static int +smb_mkdir(struct inode *dir, const char *name, int len, int mode); + +static int +smb_rmdir(struct inode *dir, const char *name, int len); + +static int +smb_unlink(struct inode *dir, const char *name, int len); + +static int +smb_rename(struct inode *old_dir, const char *old_name, int old_len, + struct inode *new_dir, const char *new_name, int new_len); + +static inline void str_upper(char *name) +{ + while (*name) { + if (*name >= 'a' && *name <= 'z') + *name -= ('a' - 'A'); + name++; + } +} + +static inline void str_lower(char *name) +{ + while (*name) { + if (*name >= 'A' && *name <= 'Z') + *name += ('a' - 'A'); + name ++; + } +} + +static struct file_operations smb_dir_operations = { + NULL, /* lseek - default */ + smb_dir_read, /* read - bad */ + NULL, /* write - bad */ + smb_readdir, /* readdir */ + NULL, /* select - default */ + smb_ioctl, /* ioctl - default */ + NULL, /* mmap */ + NULL, /* no special open code */ + NULL, /* no special release code */ + NULL /* fsync */ +}; + +struct inode_operations smb_dir_inode_operations = +{ + &smb_dir_operations, /* default directory file ops */ + smb_create, /* create */ + smb_lookup, /* lookup */ + NULL, /* link */ + smb_unlink, /* unlink */ + NULL, /* symlink */ + smb_mkdir, /* mkdir */ + smb_rmdir, /* rmdir */ + NULL, /* mknod */ + smb_rename, /* rename */ + NULL, /* readlink */ + NULL, /* follow_link */ + NULL, /* bmap */ + NULL, /* truncate */ + NULL, /* permission */ + NULL /* smap */ +}; + + +static int +smb_dir_read(struct inode *inode, struct file *filp, char *buf, int count) +{ + return -EISDIR; +} + +/* + * Description: + * smb_readdir provides a listing in the form of filling the dirent structure. + * Note that dirent resides in the user space. This is to support reading of a + * directory "stream". + * Arguments: + * inode --- Pointer to to the directory. + * filp --- The directory stream. (filp->f_pos indicates + * position in the stream.) + * dirent --- Will hold count directory entries. (Is in user space.) + * count --- Number of entries to be read. Should indicate the total + * buffer space available for filling with dirents. + * Return values: + * < 0 --- An error occured (linux/errno.h). + * = 0 --- + * > 0 --- Success, amount of bytes written to dirent. + * Notes: + * Since we want to reduce directory lookups we revert into a + * dircache. It is taken rather directly out of the nfs_readdir. + */ + +/* In smbfs, we have unique inodes across all mounted filesystems, for + all inodes that are in memory. That's why it's enough to index the + directory cache by the inode number. */ + +static unsigned long c_ino = 0; +static int c_size; +static int c_seen_eof; +static int c_last_returned_index; +static struct smb_dirent* c_entry = NULL; + +static int +smb_readdir1(struct inode *inode, const struct file *filp, + struct smb_dirent *ret,ino_t *ino) +{ + int result, i = 0; + struct smb_dirent *entry = NULL; + struct smb_server *server = SMB_SERVER(inode); + + DDPRINTK("smb_readdir: filp->f_pos = %d\n", (int)filp->f_pos); + DDPRINTK("smb_readdir: inode->i_ino = %ld, c_ino = %ld\n", + inode->i_ino, c_ino); + + if (!inode || !S_ISDIR(inode->i_mode)) { + printk("smb_readdir: inode is NULL or not a directory\n"); + return -EBADF; + } + + if (c_entry == NULL) + { + i = sizeof (struct smb_dirent) * SMB_READDIR_CACHE_SIZE; + c_entry = (struct smb_dirent *) smb_kmalloc(i, GFP_KERNEL); + for (i = 0; i < SMB_READDIR_CACHE_SIZE; i++) { + c_entry[i].path = + (char *) smb_kmalloc(SMB_MAXNAMELEN + 1, + GFP_KERNEL); + if (c_entry[i].path == NULL) { + DPRINTK("smb_readdir: could not alloc path\n"); + } + } + } + + if (filp->f_pos == 0) { + smb_invalid_dir_cache(inode->i_ino); + } + + if (inode->i_ino == c_ino) { + for (i = 0; i < c_size; i++) { + if (filp->f_pos == c_entry[i].f_pos) { + entry = &c_entry[i]; + c_last_returned_index = i; + break; + } + } + if ((entry == NULL) && c_seen_eof) + return 0; + } + + if (entry == NULL) { + DPRINTK("smb_readdir: Not found in cache.\n"); + result = smb_proc_readdir(server, inode, + filp->f_pos, SMB_READDIR_CACHE_SIZE, + c_entry); + + if (result < 0) { + c_ino = 0; + return result; + } + + if (result > 0) { + c_seen_eof = (result < SMB_READDIR_CACHE_SIZE); + c_ino = inode->i_ino; + c_size = result; + entry = c_entry; + c_last_returned_index = 0; + for (i = 0; i < c_size; i++) { + + switch (server->case_handling) + { + case CASE_UPPER: + str_upper(c_entry[i].path); break; + case CASE_LOWER: + str_lower(c_entry[i].path); break; + case CASE_DEFAULT: + break; + } + } + } + } + + if (entry) { + + /* We found it. For getwd(), we have to return the + correct inode in d_ino if the inode is currently in + use. Otherwise the inode number does not + matter. */ + + int path_len; + struct smb_inode_info *ino_info; + char complete_path[SMB_MAXPATHLEN]; + + + + i = strlen(entry->path); + if ((result = get_pname_static(inode, entry->path, i, + complete_path, + &path_len)) < 0) + return result; + + ino_info = smb_find_inode(server, complete_path); + + /* Some programs seem to be confused about a zero + inode number, so we set it to one. Thanks to + Gordon Chaffee for this one. */ + if (ino_info == NULL) { + ino_info = (struct smb_inode_info *) 1; + } + + DDPRINTK("smb_readdir: entry->path = %s\n", entry->path); + DDPRINTK("smb_readdir: entry->f_pos = %ld\n", entry->f_pos); + + *ino = (ino_t)ino_info; /* use the pointer as the + inode - dangerous if we have + 64 bit pointers! FIXME */ + + *ret = *entry; + return 1; + } + + return 0; +} + +static int +smb_readdir(struct inode *inode, struct file *filp, + void *dirent, filldir_t filldir) +{ + struct smb_dirent d; + ino_t ino; + + while (smb_readdir1(inode,filp,&d,&ino) == 1) { + if (filldir(dirent,d.path,strlen(d.path)+1, + filp->f_pos,ino) < 0) { + return 0; + } + filp->f_pos++; + } + return 0; +} + +void +smb_init_dir_cache(void) +{ + c_ino = 0; + c_entry = NULL; +} + +void +smb_invalid_dir_cache(unsigned long ino) +{ + if (ino == c_ino) { + c_ino = 0; + c_seen_eof = 0; + } +} + +void +smb_free_dir_cache(void) +{ + int i; + + DPRINTK("smb_free_dir_cache: enter\n"); + + if (c_entry == NULL) + return; + + for (i = 0; i < SMB_READDIR_CACHE_SIZE; i++) { + smb_kfree_s(c_entry[i].path, NAME_MAX + 1); + } + + smb_kfree_s(c_entry, + sizeof(struct smb_dirent) * SMB_READDIR_CACHE_SIZE); + c_entry = NULL; + + DPRINTK("smb_free_dir_cache: exit\n"); +} + + +/* get_pname_static: it expects the res_path to be a preallocated + string of len SMB_MAXPATHLEN. */ + +static int +get_pname_static(struct inode *dir, const char *name, int len, + char *path, int *res_len) +{ + char *parentname = SMB_INOP(dir)->finfo.path; + int parentlen = SMB_INOP(dir)->finfo.len; + +#if 1 + if (parentlen != strlen(parentname)) { + printk("get_pname: parent->finfo.len = %d instead of %d\n", + parentlen, strlen(parentname)); + parentlen = strlen(parentname); + } + +#endif + DDPRINTK("get_pname_static: parentname = %s, len = %d\n", + parentname, parentlen); + + if (len > SMB_MAXNAMELEN) { + return -ENAMETOOLONG; + } + + /* Fast cheat for . */ + if (len == 0 || (len == 1 && name[0] == '.')) { + + memcpy(path, parentname, parentlen + 1); + *res_len = parentlen; + return 0; + } + + /* Hmm, what about .. ? */ + if (len == 2 && name[0] == '.' && name[1] == '.') { + + char *pos = strrchr(parentname, '\\'); + + if ( (pos == NULL) + && (parentlen == 0)) { + + /* We're at the top */ + + path[0] = '\\'; + path[1] = '\0'; + *res_len = 2; + return 0; + } + + + if (pos == NULL) { + printk("smb_make_name: Bad parent SMB-name: %s", + parentname); + return -ENODATA; + } + + len = pos - parentname; + + memcpy(path, parentname, len); + path[len] = '\0'; + } + else + { + if (len + parentlen + 2 > SMB_MAXPATHLEN) + return -ENAMETOOLONG; + + memcpy(path, parentname, parentlen); + path[parentlen] = '\\'; + memcpy(path + parentlen + 1, name, len); + path[parentlen + 1 + len] = '\0'; + len = parentlen + len + 1; + } + + switch (SMB_SERVER(dir)->case_handling) + { + case CASE_UPPER: + str_upper(path); + break; + case CASE_LOWER: + str_lower(path); + break; + case CASE_DEFAULT: + break; + } + + *res_len = len; + + DDPRINTK("get_pname: path = %s, *pathlen = %d\n", + path, *res_len); + return 0; +} + +static int +get_pname(struct inode *dir, const char *name, int len, + char **res_path, int *res_len) +{ + char result[SMB_MAXPATHLEN]; + int result_len; + int res; + + if ((res = get_pname_static(dir,name,len,result,&result_len) != 0)) { + return res; + } + + if ((*res_path = smb_kmalloc(result_len+1, GFP_KERNEL)) == NULL) { + printk("get_pname: Out of memory while allocating name."); + return -ENOMEM; + } + + strcpy(*res_path, result); + *res_len = result_len; + return 0; +} + +static void +put_pname(char *path) +{ + smb_kfree_s(path, 0); +} + +/* Insert a NEW smb_inode_info into the inode tree of our filesystem, + under dir. The caller must assure that it's not already there. We + assume that path is allocated for us. */ + +static struct inode * +smb_iget(struct inode *dir, char *path, struct smb_dirent *finfo) +{ + struct smb_dirent newent = { 0 }; + struct inode *inode; + int error, len; + struct smb_inode_info *new_inode_info; + struct smb_inode_info *root; + + if (!dir) { + printk("smb_iget: dir is NULL\n"); + return NULL; + } + + if (!path) { + printk("smb_iget: path is NULL\n"); + return NULL; + } + + len = strlen(path); + + if (!finfo) { + error = smb_proc_getattr(&(SMB_SBP(dir->i_sb)->s_server), + path, len, &newent); + if (error) { + printk("smb_iget: getattr error = %d\n", -error); + return NULL; + } + finfo = &newent; + DPRINTK("smb_iget: Read finfo:\n"); + DPRINTK("smb_iget: finfo->attr = 0x%X\n", finfo->attr); + } + + new_inode_info = smb_kmalloc(sizeof(struct smb_inode_info), + GFP_KERNEL); + + if (new_inode_info == NULL) { + printk("smb_iget: could not alloc mem for %s\n", path); + return NULL; + } + + new_inode_info->state = INODE_LOOKED_UP; + new_inode_info->nused = 0; + new_inode_info->dir = SMB_INOP(dir); + + new_inode_info->finfo = *finfo; + new_inode_info->finfo.opened = 0; + new_inode_info->finfo.path = path; + new_inode_info->finfo.len = len; + + SMB_INOP(dir)->nused += 1; + + /* We have to link the new inode_info into the doubly linked + list of inode_infos to make a complete linear search + possible. */ + + root = &(SMB_SERVER(dir)->root); + + new_inode_info->prev = root; + new_inode_info->next = root->next; + root->next->prev = new_inode_info; + root->next = new_inode_info; + + if (!(inode = iget(dir->i_sb, (int)new_inode_info))) { + printk("smb_iget: iget failed!"); + return NULL; + } + + return inode; +} + +void +smb_free_inode_info(struct smb_inode_info *i) +{ + if (i == NULL) { + printk("smb_free_inode: i == NULL\n"); + return; + } + + i->state = INODE_CACHED; + while ((i->nused == 0) && (i->state == INODE_CACHED)) { + struct smb_inode_info *dir = i->dir; + + i->next->prev = i->prev; + i->prev->next = i->next; + + smb_kfree_s(i->finfo.path, i->finfo.len+1); + smb_kfree_s(i, sizeof(struct smb_inode_info)); + + if (dir == NULL) return; + + (dir->nused)--; + i = dir; + } +} + +int +smb_init_root(struct smb_server *server) +{ + struct smb_inode_info *root = &(server->root); + int result; + + root->finfo.path = server->m.root_path; + root->finfo.len = strlen(root->finfo.path); + root->finfo.opened = 0; + + root->state = INODE_LOOKED_UP; + root->nused = 1; + root->dir = NULL; + root->next = root->prev = root; + + if (root->finfo.len == 0) { + result = smb_proc_getattr(server, "\\", 1, &(root->finfo)); + } + else + { + result = smb_proc_getattr(server, + root->finfo.path, root->finfo.len, + &(root->finfo)); + } + return result; +} + +void +smb_free_all_inodes(struct smb_server *server) +{ + /* Here nothing should be to do. I do not know whether it's + better to leave some memory allocated or be stuck in an + endless loop */ +#if 1 + struct smb_inode_info *root = &(server->root); + + if (root->next != root) { + printk("smb_free_all_inodes: INODES LEFT!!!\n"); + } + + while (root->next != root) { + printk("smb_free_all_inodes: freeing inode\n"); + smb_free_inode_info(root->next); + /* In case we have an endless loop.. */ + schedule(); + } +#endif + + return; +} + +/* This has to be called when a connection has gone down, so that all + file-handles we got from the server are invalid */ + +void +smb_invalidate_all_inodes(struct smb_server *server) +{ + struct smb_inode_info *ino = &(server->root); + + do { + ino->finfo.opened = 0; + ino = ino->next; + } while (ino != &(server->root)); + + return; +} + + +/* We will search the inode that belongs to this name, currently by a + complete linear search through the inodes belonging to this + filesystem. This has to be fixed. */ + +static struct smb_inode_info * +smb_find_inode(struct smb_server *server, const char *path) +{ + struct smb_inode_info *result = &(server->root); + + if (path == NULL) + return NULL; + + do { + if (strcmp(result->finfo.path, path) == 0) + return result; + result = result->next; + + } while (result != &(server->root)); + + return NULL; +} + + +static int +smb_lookup(struct inode *dir, const char *__name, int len, + struct inode **result) +{ + char *name = NULL; + struct smb_dirent finfo; + struct smb_inode_info *result_info; + int error; + int found_in_cache; + + *result = NULL; + + if (!dir || !S_ISDIR(dir->i_mode)) { + printk("smb_lookup: inode is NULL or not a directory.\n"); + iput(dir); + return -ENOENT; + } + + DDPRINTK("smb_lookup: %s\n", __name); + + /* Fast cheat for . */ + if (len == 0 || (len == 1 && __name[0] == '.')) { + *result = dir; + return 0; + } + + /* Now we will have to build up an SMB filename. */ + if ((error = get_pname(dir, __name, len, &name, &len)) < 0) { + iput(dir); + return error; + } + + result_info = smb_find_inode(SMB_SERVER(dir), name); + + if (result_info != 0) { + + if (result_info->state == INODE_CACHED) + result_info->state = INODE_LOOKED_UP; + + put_pname(name); + + /* Here we convert the inode_info address into an + inode number */ + + *result = iget(dir->i_sb, (int)result_info); + iput(dir); + + if (*result == NULL) { + return -EACCES; + } else { + return 0; + } + } + + /* Ok, now we have made our name. We have to build a new + smb_inode_info struct and insert it into the tree, if it is + a name that exists on the server */ + + /* If the file is in the dir cache, we do not have to ask the + server. */ + + found_in_cache = 0; + + if (dir->i_ino == c_ino) { + int first = c_last_returned_index - 1; + int i; + + if (first < 0) { + first = c_size - 1; + } + + i = first; + do { + DDPRINTK("smb_lookup: trying index: %d, name: %s\n", + i, c_entry[i].path); + if (strcmp(c_entry[i].path, __name) == 0) { + DPRINTK("smb_lookup: found in cache!\n"); + finfo = c_entry[i]; + finfo.path = NULL; /* It's not ours! */ + found_in_cache = 1; + break; + } + i = (i + 1) % c_size; + + } while (i != first); + } + + if (found_in_cache == 0) { + error = smb_proc_getattr(SMB_SERVER(dir), name, len, &finfo); + if (error < 0) { + put_pname(name); + iput(dir); + return error; + } + } + + if (!(*result = smb_iget(dir, name, &finfo))) { + put_pname(name); + iput(dir); + return -EACCES; + } + + DDPRINTK("smb_lookup: %s => %lu\n", name, (unsigned long)result_info); + iput(dir); + return 0; +} + +static int +smb_create(struct inode *dir, const char *name, int len, int mode, + struct inode **result) +{ + int error; + char *path = NULL; + struct smb_dirent entry; + + *result = NULL; + + if (!dir || !S_ISDIR(dir->i_mode)) { + printk("smb_create: inode is NULL or not a directory\n"); + iput(dir); + return -ENOENT; + } + + /* Now we will have to build up an SMB filename. */ + if ((error = get_pname(dir, name, len, &path, &len)) < 0) { + iput(dir); + return error; + } + + entry.attr = 0; + entry.ctime = CURRENT_TIME; + entry.size = 0; + + error = smb_proc_create(SMB_SERVER(dir), path, len, &entry); + if (error < 0) { + put_pname(path); + iput(dir); + return error; + } + + smb_invalid_dir_cache(dir->i_ino); + + if (!(*result = smb_iget(dir, path, &entry)) < 0) { + put_pname(path); + iput(dir); + return error; + } + iput(dir); + return 0; +} + +static int +smb_mkdir(struct inode *dir, const char *name, int len, int mode) +{ + int error; + char path[SMB_MAXPATHLEN]; + + if (!dir || !S_ISDIR(dir->i_mode)) { + printk("smb_mkdir: inode is NULL or not a directory\n"); + iput(dir); + return -ENOENT; + } + + /* Now we will have to build up an SMB filename. */ + if ((error = get_pname_static(dir, name, len, path, &len)) < 0) { + iput(dir); + return error; + } + + if ((error = smb_proc_mkdir(SMB_SERVER(dir), path, len)) == 0) { + smb_invalid_dir_cache(dir->i_ino); + } + + iput(dir); + return error; +} + +static int +smb_rmdir(struct inode *dir, const char *name, int len) +{ + int error; + char path[SMB_MAXPATHLEN]; + + if (!dir || !S_ISDIR(dir->i_mode)) { + printk("smb_rmdir: inode is NULL or not a directory\n"); + iput(dir); + return -ENOENT; + } + if ((error = get_pname_static(dir, name, len, path, &len)) < 0) { + iput(dir); + return error; + } + if (smb_find_inode(SMB_SERVER(dir), path) != NULL) { + error = -EBUSY; + } else { + if ((error = smb_proc_rmdir(SMB_SERVER(dir), path, len)) == 0) + smb_invalid_dir_cache(dir->i_ino); + } + iput(dir); + return error; +} + +static int +smb_unlink(struct inode *dir, const char *name, int len) +{ + int error; + char path[SMB_MAXPATHLEN]; + + if (!dir || !S_ISDIR(dir->i_mode)) { + printk("smb_unlink: inode is NULL or not a directory\n"); + iput(dir); + return -ENOENT; + } + if ((error = get_pname_static(dir, name, len, path, &len)) < 0) { + iput(dir); + return error; + } + if (smb_find_inode(SMB_SERVER(dir), path) != NULL) { + error = -EBUSY; + } else { + if ((error = smb_proc_unlink(SMB_SERVER(dir), path, len)) == 0) + smb_invalid_dir_cache(dir->i_ino); + } + + iput(dir); + return error; +} + +static int +smb_rename(struct inode *old_dir, const char *old_name, int old_len, + struct inode *new_dir, const char *new_name, int new_len) +{ + int res; + char old_path[SMB_MAXPATHLEN], new_path[SMB_MAXPATHLEN]; + + if (!old_dir || !S_ISDIR(old_dir->i_mode)) { + printk("smb_rename: old inode is NULL or not a directory\n"); + res = -ENOENT; + goto finished; + } + + if (!new_dir || !S_ISDIR(new_dir->i_mode)) { + printk("smb_rename: new inode is NULL or not a directory\n"); + res = -ENOENT; + goto finished; + } + + res = get_pname_static(old_dir, old_name, old_len, old_path, &old_len); + if (res < 0) { + goto finished; + } + + res = get_pname_static(new_dir, new_name, new_len, new_path, &new_len); + if (res < 0) { + goto finished; + } + + if ( (smb_find_inode(SMB_SERVER(old_dir), old_path) != NULL) + || (smb_find_inode(SMB_SERVER(new_dir), new_path) != NULL)) { + res = -EBUSY; + goto finished; + } + + res = smb_proc_mv(SMB_SERVER(old_dir), old_path, old_len, + new_path, new_len); + + if (res == 0) { + smb_invalid_dir_cache(old_dir->i_ino); + smb_invalid_dir_cache(new_dir->i_ino); + } + + finished: + iput(old_dir); + iput(new_dir); + return res; +} + +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * Emacs will notice this stuff at the end of the file and automatically + * adjust the settings for this buffer only. This must remain at the end + * of the file. + * --------------------------------------------------------------------------- + * Local variables: + * c-indent-level: 8 + * c-brace-imaginary-offset: 0 + * c-brace-offset: -8 + * c-argdecl-indent: 8 + * c-label-offset: -8 + * c-continued-statement-offset: 8 + * c-continued-brace-offset: 0 + * End: + */ diff -u --recursive --new-file v1.3.6/linux/fs/smbfs/file.c linux/fs/smbfs/file.c --- v1.3.6/linux/fs/smbfs/file.c Thu Jan 1 02:00:00 1970 +++ linux/fs/smbfs/file.c Sat Jul 1 19:00:18 1995 @@ -0,0 +1,237 @@ +/* + * file.c + * + * Copyright (C) 1995 by Paal-Kr. Engstad and Volker Lendecke + * + */ + +#include +#ifdef MODULE +#include +#include +#endif + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +static int +smb_fsync(struct inode *inode, struct file *file) +{ + return 0; +} + +int +smb_make_open(struct inode *i, int right) +{ + struct smb_dirent *dirent; + int open_result; + + if (i == NULL) { + printk("smb_make_open: got NULL inode\n"); + return -EINVAL; + } + + dirent = &(SMB_INOP(i)->finfo); + + DDPRINTK("smb_make_open: dirent->opened = %d\n", dirent->opened); + + if ((dirent->opened) == 0) { + /* tries max. rights */ + open_result = smb_proc_open(SMB_SERVER(i), + dirent->path, dirent->len, + dirent); + if (open_result) + return open_result; + + dirent->opened = 1; + } + + if ( ((right == O_RDONLY) && ( (dirent->access == O_RDONLY) + || (dirent->access == O_RDWR))) + || ((right == O_WRONLY) && ( (dirent->access == O_WRONLY) + || (dirent->access == O_RDWR))) + || ((right == O_RDWR) && (dirent->access == O_RDWR))) + return 0; + + return -EACCES; +} + +static int +smb_file_read(struct inode *inode, struct file *file, char *buf, int count) +{ + int result, bufsize, to_read, already_read; + off_t pos; + int errno; + + DPRINTK("smb_file_read: enter %s\n", SMB_FINFO(inode)->path); + + if (!inode) { + DPRINTK("smb_file_read: inode = NULL\n"); + return -EINVAL; + } + + if (!S_ISREG(inode->i_mode)) { + DPRINTK("smb_file_read: read from non-file, mode %07o\n", + inode->i_mode); + return -EINVAL; + } + + if ((errno = smb_make_open(inode, O_RDONLY)) != 0) + return errno; + + pos = file->f_pos; + + if (pos + count > inode->i_size) + count = inode->i_size - pos; + + if (count <= 0) + return 0; + bufsize = SMB_SERVER(inode)->max_xmit - SMB_HEADER_LEN - 5 * 2 - 5; + + already_read = 0; + + /* First read in as much as possible for each bufsize. */ + while (already_read < count) { + + to_read = min(bufsize, count - already_read); + + result = smb_proc_read(SMB_SERVER(inode), SMB_FINFO(inode), + pos, to_read, buf, 1); + if (result < 0) + return result; + pos += result; + buf += result; + already_read += result; + + if (result < to_read) { + break; + } + } + + file->f_pos = pos; + + DPRINTK("smb_file_read: exit %s\n", SMB_FINFO(inode)->path); + + return already_read; +} + +static int +smb_file_write(struct inode *inode, struct file *file, char *buf, int count) +{ + int result, bufsize, to_write, already_written; + off_t pos; + int errno; + + if (!inode) { + DPRINTK("smb_file_write: inode = NULL\n"); + return -EINVAL; + } + + if (!S_ISREG(inode->i_mode)) { + DPRINTK("smb_file_write: write to non-file, mode %07o\n", + inode->i_mode); + return -EINVAL; + } + + DPRINTK("smb_file_write: enter %s\n", SMB_FINFO(inode)->path); + + if (count <= 0) + return 0; + + if ((errno = smb_make_open(inode, O_RDWR)) != 0) + return errno; + + pos = file->f_pos; + + if (file->f_flags & O_APPEND) + pos = inode->i_size; + + bufsize = SMB_SERVER(inode)->max_xmit - SMB_HEADER_LEN - 5 * 2 - 5; + + already_written = 0; + + while (already_written < count) { + + to_write = min(bufsize, count - already_written); + + result = smb_proc_write(SMB_SERVER(inode), SMB_FINFO(inode), + pos, to_write, buf); + + if (result < 0) + return result; + + pos += result; + buf += result; + already_written += result; + + if (result < to_write) { + break; + } + } + + file->f_pos = pos; + + if (pos > inode->i_size) { + inode->i_size = pos; + } + + DPRINTK("smb_file_write: exit %s\n", SMB_FINFO(inode)->path); + + return already_written; +} + +static struct file_operations smb_file_operations = { + NULL, /* lseek - default */ + smb_file_read, /* read */ + smb_file_write, /* write */ + NULL, /* readdir - bad */ + NULL, /* select - default */ + smb_ioctl, /* ioctl */ + smb_mmap, /* mmap */ + NULL, /* open */ + NULL, /* release */ + smb_fsync, /* fsync */ +}; + +struct inode_operations smb_file_inode_operations = { + &smb_file_operations, /* default file operations */ + NULL, /* create */ + NULL, /* lookup */ + NULL, /* link */ + NULL, /* unlink */ + NULL, /* symlink */ + NULL, /* mkdir */ + NULL, /* rmdir */ + NULL, /* mknod */ + NULL, /* rename */ + NULL, /* readlink */ + NULL, /* follow_link */ + NULL, /* bmap */ + NULL /* truncate */ +}; + +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * Emacs will notice this stuff at the end of the file and automatically + * adjust the settings for this buffer only. This must remain at the end + * of the file. + * --------------------------------------------------------------------------- + * Local variables: + * c-indent-level: 8 + * c-brace-imaginary-offset: 0 + * c-brace-offset: -8 + * c-argdecl-indent: 8 + * c-label-offset: -8 + * c-continued-statement-offset: 8 + * c-continued-brace-offset: 0 + * End: + */ diff -u --recursive --new-file v1.3.6/linux/fs/smbfs/inode.c linux/fs/smbfs/inode.c --- v1.3.6/linux/fs/smbfs/inode.c Thu Jan 1 02:00:00 1970 +++ linux/fs/smbfs/inode.c Sat Jul 1 19:00:18 1995 @@ -0,0 +1,462 @@ +/* + * inode.c + * + * Copyright (C) 1995 by Paal-Kr. Engstad and Volker Lendecke + * + */ + +#include +#ifdef MODULE +#include +#include +#else +#define MOD_INC_USE_COUNT +#define MOD_DEC_USE_COUNT +#endif + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +extern int close_fp(struct file *filp); + +int smb_notify_change(struct inode *, struct iattr *); +static void smb_put_inode(struct inode *); +static void smb_read_inode(struct inode *); +static void smb_put_super(struct super_block *); +static void smb_statfs(struct super_block *, struct statfs *, int bufsiz); + +static struct super_operations smb_sops = { + smb_read_inode, /* read inode */ + smb_notify_change, /* notify change */ + NULL, /* write inode */ + smb_put_inode, /* put inode */ + smb_put_super, /* put superblock */ + NULL, /* write superblock */ + smb_statfs, /* stat filesystem */ + NULL + }; + +/* smb_read_inode: Called from iget, it only traverses the allocated + smb_inode_info's and initializes the inode from the data found + there. It does not allocate or deallocate anything. */ + +static void +smb_read_inode(struct inode *inode) +{ + /* Our task should be extremely simple here. We only have to + look up the infomation somebody else (smb_iget) put into + the inode tree. The address of this information is the + inode->i_ino. Just to make sure everything went well, we + check it's there. */ + + struct smb_inode_info *inode_info + = (struct smb_inode_info *)(inode->i_ino); + +#if 1 + struct smb_inode_info *root = &(SMB_SERVER(inode)->root); + struct smb_inode_info *check_info = root; + + do { + if (inode_info == check_info) { + if (check_info->state == INODE_LOOKED_UP) { + DDPRINTK("smb_read_inode: found it!\n"); + goto good; + } + else { + printk("smb_read_inode: " + "state != INODE_LOOKED_UP\n"); + return; + } + } + check_info = check_info->next; + } while (check_info != root); + + /* Ok, now we're in trouble. The inode info is not there. What + should we do now??? */ + printk("smb_read_inode: inode info not found\n"); + return; + + good: +#endif + inode_info->state = INODE_VALID; + + SMB_INOP(inode) = inode_info; + + if (SMB_INOP(inode)->finfo.attr & aDIR) + inode->i_mode = SMB_SERVER(inode)->m.dir_mode; + else + inode->i_mode = SMB_SERVER(inode)->m.file_mode; + + DDPRINTK("smb_read_inode: inode->i_mode = %u\n", inode->i_mode); + + inode->i_nlink = 1; + inode->i_uid = SMB_SERVER(inode)->m.uid; + inode->i_gid = SMB_SERVER(inode)->m.gid; + inode->i_size = SMB_INOP(inode)->finfo.size; + inode->i_blksize = 1024; + inode->i_rdev = 0; + if ((inode->i_blksize != 0) && (inode->i_size != 0)) + inode->i_blocks = + (inode->i_size - 1) / inode->i_blksize + 1; + else + inode->i_blocks = 0; + + inode->i_mtime = SMB_INOP(inode)->finfo.mtime; + inode->i_ctime = SMB_INOP(inode)->finfo.ctime; + inode->i_atime = SMB_INOP(inode)->finfo.atime; + + if (S_ISREG(inode->i_mode)) + inode->i_op = &smb_file_inode_operations; + else if (S_ISDIR(inode->i_mode)) + inode->i_op = &smb_dir_inode_operations; + else + inode->i_op = NULL; + +} + +static void +smb_put_inode(struct inode *inode) +{ + struct smb_dirent *finfo = SMB_FINFO(inode); + + if (finfo->opened != 0) { + + /* smb_proc_close wants mtime in finfo */ + finfo->mtime = inode->i_mtime; + + if (smb_proc_close(SMB_SERVER(inode), finfo)) { + /* We can't do anything but complain. */ + printk("smb_put_inode: could not close\n"); + } + } + + smb_free_inode_info(SMB_INOP(inode)); + + if (S_ISDIR(inode->i_mode)) { + DDPRINTK("smb_put_inode: put directory %ld\n", + inode->i_ino); + smb_invalid_dir_cache(inode->i_ino); + } + + clear_inode(inode); +} + +static void +smb_put_super(struct super_block *sb) +{ + struct smb_server *server = &(SMB_SBP(sb)->s_server); + + smb_proc_disconnect(server); + close_fp(server->sock_file); + + lock_super(sb); + + smb_free_all_inodes(server); + + smb_kfree_s(server->packet, server->max_xmit); + + sb->s_dev = 0; + smb_kfree_s(SMB_SBP(sb), sizeof(struct smb_sb_info)); + + unlock_super(sb); + + MOD_DEC_USE_COUNT; +} + + +/* Hmm, should we do this like the NFS mount command does? Guess so.. */ +struct super_block * +smb_read_super(struct super_block *sb, void *raw_data, int silent) +{ + struct smb_mount_data *data = (struct smb_mount_data *) raw_data; + struct smb_server *server; + struct smb_sb_info *smb_sb; + unsigned int fd; + struct file *filp; + dev_t dev = sb->s_dev; + int error; + + if (!data) { + printk("smb_read_super: missing data argument\n"); + sb->s_dev = 0; + return NULL; + } + fd = data->fd; + if (data->version != SMB_MOUNT_VERSION) { + printk("smb warning: mount version %s than kernel\n", + (data->version < SMB_MOUNT_VERSION) ? + "older" : "newer"); + } + if (fd >= NR_OPEN || !(filp = current->files->fd[fd])) { + printk("smb_read_super: invalid file descriptor\n"); + sb->s_dev = 0; + return NULL; + } + if (!S_ISSOCK(filp->f_inode->i_mode)) { + printk("smb_read_super: not a socket!\n"); + sb->s_dev = 0; + return NULL; + } + + /* We must malloc our own super-block info */ + smb_sb = (struct smb_sb_info *)smb_kmalloc(sizeof(struct smb_sb_info), + GFP_KERNEL); + + if (smb_sb == NULL) { + printk("smb_read_super: could not alloc smb_sb_info\n"); + return NULL; + } + + filp->f_count += 1; + + lock_super(sb); + + SMB_SBP(sb) = smb_sb; + + sb->s_blocksize = 1024; /* Eh... Is this correct? */ + sb->s_blocksize_bits = 10; + sb->s_magic = SMB_SUPER_MAGIC; + sb->s_dev = dev; + sb->s_op = &smb_sops; + + server = &(SMB_SBP(sb)->s_server); + server->sock_file = filp; + server->lock = 0; + server->wait = NULL; + server->packet = NULL; + server->max_xmit = data->max_xmit; + if (server->max_xmit <= 0) + server->max_xmit = SMB_DEF_MAX_XMIT; + + server->tid = 0; + server->pid = current->pid; + server->mid = current->pid + 20; + + server->m = *data; + server->m.file_mode = (server->m.file_mode & + (S_IRWXU|S_IRWXG|S_IRWXO)) | S_IFREG; + server->m.dir_mode = (server->m.dir_mode & + (S_IRWXU|S_IRWXG|S_IRWXO)) | S_IFDIR; + + /* + * Make the connection to the server + */ + + error = smb_proc_connect(server); + + unlock_super(sb); + + if (error < 0) { + sb->s_dev = 0; + printk("smb_read_super: Failed connection, bailing out " + "(error = %d).\n", -error); + goto fail; + } + + if (server->protocol >= PROTOCOL_LANMAN2) + server->case_handling = CASE_DEFAULT; + else + server->case_handling = CASE_LOWER; + + if ((error = smb_proc_dskattr(sb, &(SMB_SBP(sb)->s_attr))) < 0) { + sb->s_dev = 0; + printk("smb_read_super: could not get super block " + "attributes\n"); + smb_kfree_s(server->packet, server->max_xmit); + goto fail; + } + + DPRINTK("smb_read_super : %u %u %u %u\n", + SMB_SBP(sb)->s_attr.total, + SMB_SBP(sb)->s_attr.blocksize, + SMB_SBP(sb)->s_attr.allocblocks, + SMB_SBP(sb)->s_attr.free); + + if (smb_init_root(server) != 0) { + sb->s_dev = 0; + printk("smb_read_super: invalid root directory\n"); + smb_kfree_s(server->packet, server->max_xmit); + goto fail; + } + + DPRINTK("smb_read_super: SMB_SBP(sb) = %x\n", (int)SMB_SBP(sb)); + + if (!(sb->s_mounted = iget(sb, (int)&(server->root)))) { + sb->s_dev = 0; + printk("smb_read_super: get root inode failed\n"); + smb_kfree_s(server->packet, server->max_xmit); + goto fail; + } + + MOD_INC_USE_COUNT; + return sb; + + fail: + filp->f_count -= 1; + smb_kfree_s(SMB_SBP(sb), sizeof(struct smb_sb_info)); + return NULL; +} + +static void +smb_statfs(struct super_block *sb, struct statfs *buf, int bufsiz) +{ + int error; + struct smb_dskattr attr; + struct statfs tmp; + + error = smb_proc_dskattr(sb, &attr); + + if (error) { + printk("smb_statfs: dskattr error = %d\n", -error); + attr.total = attr.allocblocks = attr.blocksize = + attr.free = 0; + } + + tmp.f_type = SMB_SUPER_MAGIC; + tmp.f_bsize = attr.blocksize*attr.allocblocks; + tmp.f_blocks = attr.total; + tmp.f_bfree = attr.free; + tmp.f_bavail = attr.free; + tmp.f_files = -1; + tmp.f_ffree = -1; + tmp.f_namelen = SMB_MAXPATHLEN; + memcpy_tofs(buf, &tmp, bufsiz); +} + +/* DO MORE */ +int +smb_notify_change(struct inode *inode, struct iattr *attr) +{ + int error = 0; + + if ((error = inode_change_ok(inode, attr)) < 0) + return error; + + if (!S_ISREG(inode->i_mode)) + return -EPERM; + + if ((attr->ia_valid & (ATTR_MODE | ATTR_UID | ATTR_GID)) != 0) { + return -EPERM; + } + + if ((attr->ia_valid & ATTR_SIZE) != 0) { + + if ((error = smb_make_open(inode, O_WRONLY)) < 0) + goto fail; + + if ((error = smb_proc_trunc(SMB_SERVER(inode), + SMB_FINFO(inode)->fileid, + attr->ia_size)) < 0) + goto fail; + + } + + if ((attr->ia_valid & (ATTR_CTIME | ATTR_MTIME | ATTR_ATIME)) != 0) { + + struct smb_dirent finfo; + + finfo.attr = 0; + + if ((attr->ia_valid & ATTR_CTIME) != 0) + finfo.ctime = attr->ia_ctime; + else + finfo.ctime = inode->i_ctime; + + if ((attr->ia_valid & ATTR_MTIME) != 0) + finfo.mtime = attr->ia_mtime; + else + finfo.mtime = inode->i_mtime; + + if ((attr->ia_valid & ATTR_ATIME) != 0) + finfo.atime = attr->ia_atime; + else + finfo.atime = inode->i_atime; + + if ((error = smb_proc_setattr(SMB_SERVER(inode), + inode, &finfo)) >= 0) { + inode->i_ctime = finfo.ctime; + inode->i_mtime = finfo.mtime; + inode->i_atime = finfo.atime; + } + } + + fail: + smb_invalid_dir_cache((unsigned long)(SMB_INOP(inode)->dir)); + + return error; +} + + +#ifdef DEBUG_SMB_MALLOC +int smb_malloced; +int smb_current_malloced; +#endif + +#ifdef MODULE + +static char kernel_version[] = UTS_RELEASE; + +/* looks ugly, taken from gcc-info */ +static void *shut_up_gcc = (&shut_up_gcc, kernel_version); + +static struct file_system_type smb_fs_type = { + smb_read_super, "smbfs", 0, NULL + }; + +int +init_module( void) +{ + DPRINTK("smbfs: init_module called\n"); + +#ifdef DEBUG_SMB_MALLOC + smb_malloced = 0; + smb_current_malloced = 0; +#endif + + smb_init_dir_cache(); + register_filesystem(&smb_fs_type); + return 0; +} + +void +cleanup_module(void) +{ + DPRINTK("smbfs: cleanup_module called\n"); + smb_free_dir_cache(); + unregister_filesystem(&smb_fs_type); +#ifdef DEBUG_SMB_MALLOC + printk("smb_malloced: %d\n", smb_malloced); + printk("smb_current_malloced: %d\n", smb_current_malloced); +#endif +} + +#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-indent-level: 8 + * c-brace-imaginary-offset: 0 + * c-brace-offset: -8 + * c-argdecl-indent: 8 + * c-label-offset: -8 + * c-continued-statement-offset: 8 + * c-continued-brace-offset: 0 + * End: + */ diff -u --recursive --new-file v1.3.6/linux/fs/smbfs/ioctl.c linux/fs/smbfs/ioctl.c --- v1.3.6/linux/fs/smbfs/ioctl.c Thu Jan 1 02:00:00 1970 +++ linux/fs/smbfs/ioctl.c Sat Jul 1 19:00:18 1995 @@ -0,0 +1,59 @@ +/* + * ioctl.c + * + * Copyright (C) 1995 by Volker Lendecke + * + */ +#include +#ifdef MODULE +#include +#include +#else +#define MOD_INC_USE_COUNT +#define MOD_DEC_USE_COUNT +#endif + +#include +#include +#include +#include +#include +#include +#include + +int +smb_ioctl (struct inode * inode, struct file * filp, + unsigned int cmd, unsigned long arg) +{ + int result; + + switch (cmd) { + case SMB_IOC_GETMOUNTUID: + if ((result = verify_area(VERIFY_WRITE, (uid_t*) arg, + sizeof(uid_t))) != 0) { + return result; + } + put_fs_word(SMB_SERVER(inode)->m.mounted_uid, (uid_t*) arg); + return 0; + default: + return -EINVAL; + } +} + + +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * Emacs will notice this stuff at the end of the file and automatically + * adjust the settings for this buffer only. This must remain at the end + * of the file. + * --------------------------------------------------------------------------- + * Local variables: + * c-indent-level: 8 + * c-brace-imaginary-offset: 0 + * c-brace-offset: -8 + * c-argdecl-indent: 8 + * c-label-offset: -8 + * c-continued-statement-offset: 8 + * c-continued-brace-offset: 0 + * End: + */ diff -u --recursive --new-file v1.3.6/linux/fs/smbfs/mmap.c linux/fs/smbfs/mmap.c --- v1.3.6/linux/fs/smbfs/mmap.c Thu Jan 1 02:00:00 1970 +++ linux/fs/smbfs/mmap.c Sat Jul 1 19:00:18 1995 @@ -0,0 +1,141 @@ +/* + * mmap.c + * + * Copyright (C) 1995 by Paal-Kr. Engstad and Volker Lendecke + * + */ + +#include +#ifdef MODULE +#include +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +/* + * Fill in the supplied page for mmap + */ +static unsigned long +smb_file_mmap_nopage(struct vm_area_struct * area, + unsigned long address, unsigned long page, int no_share) +{ + struct inode * inode = area->vm_inode; + unsigned int clear; + unsigned long tmp; + int n; + int i; + int pos; + + address &= PAGE_MASK; + pos = address - area->vm_start + area->vm_offset; + + clear = 0; + if (address + PAGE_SIZE > area->vm_end) { + clear = address + PAGE_SIZE - area->vm_end; + } + + /* what we can read in one go */ + n = SMB_SERVER(inode)->max_xmit - SMB_HEADER_LEN - 5 * 2 - 3 - 10; + + if (smb_make_open(inode, O_RDONLY) < 0) { + clear = PAGE_SIZE; + } + else + { + + for (i = 0; i < (PAGE_SIZE - clear); i += n) { + int hunk, result; + + hunk = PAGE_SIZE - i; + if (hunk > n) + hunk = n; + + DDPRINTK("smb_file_mmap_nopage: reading\n"); + DDPRINTK("smb_file_mmap_nopage: pos = %d\n", pos); + result = smb_proc_read(SMB_SERVER(inode), + SMB_FINFO(inode), pos, hunk, + (char *) (page + i), 0); + DDPRINTK("smb_file_mmap_nopage: result= %d\n", result); + if (result < 0) + break; + pos += result; + if (result < n) { + i += result; + break; + } + } + } + + tmp = page + PAGE_SIZE; + while (clear--) { + *(char *)--tmp = 0; + } + return page; +} + +struct vm_operations_struct smb_file_mmap = { + NULL, /* open */ + NULL, /* close */ + NULL, /* unmap */ + NULL, /* protect */ + NULL, /* sync */ + NULL, /* advise */ + smb_file_mmap_nopage, /* nopage */ + NULL, /* wppage */ + NULL, /* swapout */ + NULL, /* swapin */ +}; + + +/* This is used for a general mmap of a smb file */ +int +smb_mmap(struct inode * inode, struct file * file, struct vm_area_struct * vma) +{ + DPRINTK("smb_mmap: called\n"); + + /* only PAGE_COW or read-only supported now */ + if (vma->vm_flags & VM_SHARED) + return -EINVAL; + if (!inode->i_sb || !S_ISREG(inode->i_mode)) + return -EACCES; + if (!IS_RDONLY(inode)) { + inode->i_atime = CURRENT_TIME; + inode->i_dirt = 1; + } + + vma->vm_inode = inode; + inode->i_count++; + vma->vm_ops = &smb_file_mmap; + return 0; +} + +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * Emacs will notice this stuff at the end of the file and automatically + * adjust the settings for this buffer only. This must remain at the end + * of the file. + * --------------------------------------------------------------------------- + * Local variables: + * c-indent-level: 8 + * c-brace-imaginary-offset: 0 + * c-brace-offset: -8 + * c-argdecl-indent: 8 + * c-label-offset: -8 + * c-continued-statement-offset: 8 + * c-continued-brace-offset: 0 + * End: + */ diff -u --recursive --new-file v1.3.6/linux/fs/smbfs/proc.c linux/fs/smbfs/proc.c --- v1.3.6/linux/fs/smbfs/proc.c Thu Jan 1 02:00:00 1970 +++ linux/fs/smbfs/proc.c Sat Jul 1 19:00:18 1995 @@ -0,0 +1,1917 @@ +/* + * proc.c + * + * Copyright (C) 1995 by Paal-Kr. Engstad and Volker Lendecke + * + */ + +#include +#ifdef MODULE +#include +#include +#endif + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define ARCH i386 +#define SMB_VWV(packet) ((packet) + SMB_HEADER_LEN) +#define SMB_CMD(packet) ((packet)[8]) +#define SMB_WCT(packet) ((packet)[SMB_HEADER_LEN - 1]) +#define SMB_BCC(packet) smb_bcc(packet) +#define SMB_BUF(packet) ((packet) + SMB_HEADER_LEN + SMB_WCT(packet) * 2 + 2) + +#define SMB_DIRINFO_SIZE 43 +#define SMB_STATUS_SIZE 21 + +#define HI_WORD(l) ((word)(l >> 16)) +#define LO_WORD(l) ((word)(l % 0xFFFF)) + +void smb_printerr(int class, int num); +int smb_request(struct smb_server *); +static int smb_request_ok(struct smb_server *s, int command, int wct, int bcc); + +/*****************************************************************************/ +/* */ +/* Encoding/Decoding section */ +/* */ +/*****************************************************************************/ + +static byte * +smb_encode_word(byte *p, word data) +{ +#if (ARCH == i386) + *((word *)p) = data; +#else + p[0] = data & 0x00ffU; + p[1] = (data & 0xff00U) >> 8; +#error "Non-Intel" +#endif + return &p[2]; +} + +static byte * +smb_decode_word(byte *p, word *data) +{ +#if (ARCH == i386) + *data = *(word *)p; +#else + *data = (word) p[0] | p[1] << 8; +#endif + return &p[2]; +} + +static byte * +smb_decode_dword(byte *p, dword *data) +{ +#if (ARCH == i386) + *data = *((dword *)p); +#else + *data = (dword)p[0] | p[1] << 8 | p[2] << 16 | p[3] << 24; +#endif + return &p[4]; +} + +static byte * +smb_encode_smb_length(byte *p, dword len) +{ + p[0] = p[1] = 0; + p[2] = (len & 0xFF00) >> 8; + p[3] = (len & 0xFF); + if (len > 0xFFFF) + p[1] |= 0x01; + return &p[4]; +} + +static byte * +smb_encode_dialect(byte *p, const byte *name, int len) +{ + *p ++ = 2; + strcpy(p, name); + return p + len + 1; +} + +static byte * +smb_encode_ascii(byte *p, const byte *name, int len) +{ + *p ++ = 4; + strcpy(p, name); + return p + len + 1; +} + +static byte * +smb_encode_vblock(byte *p, const byte *data, word len, int fs) +{ + *p ++ = 5; + p = smb_encode_word(p, len); + if (fs) + memcpy_fromfs(p, data, len); + else + memcpy(p, data, len); + return p + len; +} + +static byte * +smb_decode_data(byte *p, byte *data, word *data_len, int fs) +{ + word len; + + if (!(*p == 1 || *p == 5)) { + printk("smb_decode_data: Warning! Data block not starting " + "with 1 or 5\n"); + } + + len = WVAL(p, 1); + p += 3; + + if (fs) + memcpy_tofs(data, p, len); + else + memcpy(data, p, len); + + *data_len = len; + + return p + len; +} + +static byte * +smb_name_mangle(byte *p, const byte *name) +{ + int len, pad = 0; + + len = strlen(name); + + if (len < 16) + pad = 16 - len; + + *p ++ = 2 * (len + pad); + + while (*name) { + *p ++ = (*name >> 4) + 'A'; + *p ++ = (*name & 0x0F) + 'A'; + name ++; + } + while (pad --) { + *p ++ = 'C'; + *p ++ = 'A'; + } + *p++ = '\0'; + + return p; +} + +/* The following are taken directly from msdos-fs */ + +/* Linear day numbers of the respective 1sts in non-leap years. */ + +static int day_n[] = { 0,31,59,90,120,151,181,212,243,273,304,334,0,0,0,0 }; + /* JanFebMarApr May Jun Jul Aug Sep Oct Nov Dec */ + + +extern struct timezone sys_tz; + +static int +utc2local(int time) +{ + return time - sys_tz.tz_minuteswest*60; +} + +static int +local2utc(int time) +{ + return time + sys_tz.tz_minuteswest*60; +} + +/* Convert a MS-DOS time/date pair to a UNIX date (seconds since 1 1 70). */ + +static int +date_dos2unix(unsigned short time,unsigned short date) +{ + int month,year,secs; + + month = ((date >> 5) & 15)-1; + year = date >> 9; + secs = (time & 31)*2+60*((time >> 5) & 63)+(time >> 11)*3600+86400* + ((date & 31)-1+day_n[month]+(year/4)+year*365-((year & 3) == 0 && + month < 2 ? 1 : 0)+3653); + /* days since 1.1.70 plus 80's leap day */ + return local2utc(secs); +} + + +/* Convert linear UNIX date to a MS-DOS time/date pair. */ + +static void +date_unix2dos(int unix_date,unsigned short *time, unsigned short *date) +{ + int day,year,nl_day,month; + + unix_date = utc2local(unix_date); + *time = (unix_date % 60)/2+(((unix_date/60) % 60) << 5)+ + (((unix_date/3600) % 24) << 11); + day = unix_date/86400-3652; + year = day/365; + if ((year+3)/4+365*year > day) year--; + day -= (year+3)/4+365*year; + if (day == 59 && !(year & 3)) { + nl_day = day; + month = 2; + } + else { + nl_day = (year & 3) || day <= 59 ? day : day-1; + for (month = 0; month < 12; month++) + if (day_n[month] > nl_day) break; + } + *date = nl_day-day_n[month-1]+1+(month << 5)+(year << 9); +} + + + +/*****************************************************************************/ +/* */ +/* Support section. */ +/* */ +/*****************************************************************************/ + +dword +smb_len(byte *packet) +{ + return ((packet[1] & 0x1) << 16L) | (packet[2] << 8L) | (packet[3]); +} + +static word +smb_bcc(byte *packet) +{ + int pos = SMB_HEADER_LEN + SMB_WCT(packet) * sizeof(word); +#if (ARCH == i386) + return *((word *)((byte *)packet + pos)); +#else + return packet[pos] | packet[pos+1] << 8; +#endif +} + +/* smb_valid_packet: We check if packet fulfills the basic + requirements of a smb packet */ + +static int +smb_valid_packet(byte *packet) +{ + DDPRINTK("len: %ld, wct: %d, bcc: %d\n", + smb_len(packet), SMB_WCT(packet), SMB_BCC(packet)); + return ( packet[4] == 0xff + && packet[5] == 'S' + && packet[6] == 'M' + && packet[7] == 'B' + && (smb_len(packet) + 4 == SMB_HEADER_LEN + + SMB_WCT(packet) * 2 + SMB_BCC(packet))); +} + +/* smb_verify: We check if we got the answer we expected, and if we + got enough data. If bcc == -1, we don't care. */ + +static int +smb_verify(byte *packet, int command, int wct, int bcc) +{ + return (SMB_CMD(packet) == command && + SMB_WCT(packet) >= wct && + (bcc == -1 || SMB_BCC(packet) == bcc)) ? 0 : -EIO; +} + +static int +smb_errno(int errcls, int error) +{ + +#if DEBUG_SMB > 1 + if (errcls) { + printk("smb_errno: "); + smb_printerr(errcls, error); + printk("\n"); + } +#endif + + if (errcls == ERRDOS) + switch (error) { + case ERRbadfunc: return EINVAL; + case ERRbadfile: return ENOENT; + case ERRbadpath: return ENOENT; + case ERRnofids: return EMFILE; + case ERRnoaccess: return EACCES; + case ERRbadfid: return EBADF; + case ERRbadmcb: return EREMOTEIO; + case ERRnomem: return ENOMEM; + case ERRbadmem: return EFAULT; + case ERRbadenv: return EREMOTEIO; + case ERRbadformat: return EREMOTEIO; + case ERRbadaccess: return EACCES; + case ERRbaddata: return E2BIG; + case ERRbaddrive: return ENXIO; + case ERRremcd: return EREMOTEIO; + case ERRdiffdevice: return EXDEV; + case ERRnofiles: return 0; + case ERRbadshare: return ETXTBSY; + case ERRlock: return EDEADLOCK; + case ERRfilexists: return EEXIST; + case 87: return 0; /* Unknown error!! */ + default: return EIO; + } + else if (errcls == ERRSRV) + switch (error) { + case ERRerror: return ENFILE; + case ERRbadpw: return EINVAL; + case ERRbadtype: return EIO; + case ERRaccess: return EACCES; + default: return EIO; + } + else if (errcls == ERRHRD) + switch (error) { + case ERRnowrite: return EROFS; + case ERRbadunit: return ENODEV; + case ERRnotready: return EUCLEAN; + case ERRbadcmd: return EIO; + case ERRdata: return EIO; + case ERRbadreq: return ERANGE; + case ERRbadshare: return ETXTBSY; + case ERRlock: return EDEADLOCK; + default: return EIO; + } + else if (errcls == ERRCMD) + return EIO; + return 0; +} + +#if DEBUG_SMB > 0 +static char +print_char(char c) +{ + if ((c < ' ') || (c > '~')) + return '.'; + return c; +} + +static void +smb_dump_packet(byte *packet) { + int i, j, len; + int errcls, error; + + errcls = (int)packet[9]; + error = (int)(int)(packet[11]|packet[12]<<8); + + printk("smb_len = %d valid = %d \n", + len = smb_len(packet), smb_valid_packet(packet)); + printk("smb_cmd = %d smb_wct = %d smb_bcc = %d\n", + packet[8], SMB_WCT(packet), SMB_BCC(packet)); + printk("smb_rcls = %d smb_err = %d\n", errcls, error); + + if (errcls) { + smb_printerr(errcls, error); + printk("\n"); + } + + if (len > 100) + len = 100; + + for (i = 0; i < len; i += 10) { + printk("%03d:", i); + for (j = i; j < i+10; j++) + if (j < len) + printk("%02x ", packet[j]); + else + printk(" "); + printk(": "); + for (j = i; j < i+10; j++) + if (j < len) + printk("%c", print_char(packet[j])); + printk("\n"); + } +} +#endif + +static void +smb_lock_server(struct smb_server *server) +{ + while (server->lock) + sleep_on(&server->wait); + server->lock = 1; +} + +static void +smb_unlock_server(struct smb_server *server) +{ + if (server->lock != 1) { + printk("smb_unlock_server: was not locked!\n"); + } + + server->lock = 0; + wake_up(&server->wait); +} + +/* smb_request_ok: We expect the server to be locked. Then we do the + request and check the answer completely. When smb_request_ok + returns 0, you can be quite sure that everything went well. When + the answer is <=0, the returned number is a valid unix errno. */ + +static int +smb_request_ok(struct smb_server *s, int command, int wct, int bcc) +{ + int result = 0; + s->rcls = 0; + s->err = 0; + + if (smb_request(s) < 0) { + DPRINTK("smb_request failed\n"); + result = -EIO; + } + else if (smb_valid_packet(s->packet) != 0) { + DPRINTK("not a valid packet!\n"); + result = -EIO; + } + else if (s->rcls != 0) { + result = -smb_errno(s->rcls, s->err); + } + else if (smb_verify(s->packet, command, wct, bcc) != 0) { + DPRINTK("smb_verify failed\n"); + result = -EIO; + } + + return result; +} + +/* smb_retry: This function should be called when smb_request_ok has + indicated an error. If the error was indicated because the + connection was killed, we try to reconnect. If smb_retry returns 0, + the error was indicated for another reason, so a retry would not be + of any use. */ + +static int +smb_retry(struct smb_server *server) +{ + if (server->state != CONN_INVALID) { + return 0; + } + + if (smb_release(server) < 0) { + DPRINTK("smb_retry: smb_release failed\n"); + server->state = CONN_RETRIED; + return 0; + } + if(smb_proc_reconnect(server) < 0) { + DPRINTK("smb_proc_reconnect failed\n"); + server->state = CONN_RETRIED; + return 0; + } + + server->state = CONN_VALID; + return 1; +} + +static int +smb_request_ok_unlock(struct smb_server *s, int command, int wct, int bcc) +{ + int result = smb_request_ok(s, command, wct, bcc); + + smb_unlock_server(s); + + return result; +} + +/* smb_setup_header: We completely set up the packet. You only have to + insert the command-specific fields */ + +static byte * +smb_setup_header(struct smb_server *server, byte command, word wct, word bcc) +{ + dword xmit_len = SMB_HEADER_LEN + wct * sizeof(word) + bcc + 2; + byte *p = server->packet; + byte *buf = server->packet; + + p = smb_encode_smb_length(p, xmit_len); + + BSET(p,0,0xff); + BSET(p,1,'S'); + BSET(p,2,'M'); + BSET(p,3,'B'); + BSET(p,4,command); + + p += 5; + memset(p, '\0', 19); + p += 19; + p += 8; + + WSET(buf, smb_tid, server->tid); + WSET(buf, smb_pid, server->pid); + WSET(buf, smb_uid, server->server_uid); + WSET(buf, smb_mid, server->mid); + + if (server->protocol > PROTOCOL_CORE) { + BSET(buf, smb_flg, 0x8); + WSET(buf, smb_flg2, 0x3); + } + + *p++ = wct; /* wct */ + p += 2*wct; + WSET(p, 0, bcc); + return p+2; +} + +/* smb_setup_header_exclusive waits on server->lock and locks the + server, when it's free. You have to unlock it manually when you're + finished with server->packet! */ + +static byte * +smb_setup_header_exclusive(struct smb_server *server, + byte command, word wct, word bcc) +{ + smb_lock_server(server); + return smb_setup_header(server, command, wct, bcc); +} + + +/*****************************************************************************/ +/* */ +/* File operation section. */ +/* */ +/*****************************************************************************/ + +int +smb_proc_open(struct smb_server *server, const char *pathname, int len, + struct smb_dirent *entry) +{ + int error; + char* p; + char* buf = server->packet; + const word o_attr = aSYSTEM | aHIDDEN | aDIR; + + DPRINTK("smb_proc_open: path=%s\n", pathname); + + smb_lock_server(server); + + retry: + p = smb_setup_header(server, SMBopen, 2, 2 + len); + WSET(buf, smb_vwv0, 0x42); /* read/write */ + WSET(buf, smb_vwv1, o_attr); + smb_encode_ascii(p, pathname, len); + + if ((error = smb_request_ok(server, SMBopen, 7, 0)) != 0) { + + if (smb_retry(server)) { + goto retry; + } + + if (error != -EACCES) { + smb_unlock_server(server); + return error; + } + + p = smb_setup_header(server, SMBopen, 2, 2 + len); + WSET(buf, smb_vwv0, 0x40); /* read only */ + WSET(buf, smb_vwv1, o_attr); + smb_encode_ascii(p, pathname, len); + + if ((error = smb_request_ok(server, SMBopen, 7, 0)) != 0) { + if (smb_retry(server)) { + goto retry; + } + smb_unlock_server(server); + return error; + } + } + + /* We should now have data in vwv[0..6]. */ + + entry->fileid = WVAL(buf, smb_vwv0); + entry->attr = WVAL(buf, smb_vwv1); + entry->ctime = entry->atime = + entry->mtime = local2utc(DVAL(buf, smb_vwv2)); + entry->size = DVAL(buf, smb_vwv4); + entry->access = WVAL(buf, smb_vwv6); + + smb_unlock_server(server); + + entry->access &= 3; + DPRINTK("smb_proc_open: entry->access = %d\n", entry->access); + return 0; +} + +/* smb_proc_close: in finfo->mtime we can send a modification time to + the server */ +int +smb_proc_close(struct smb_server *server, struct smb_dirent *finfo) +{ + char *buf = server->packet; + + smb_setup_header_exclusive(server, SMBclose, 3, 0); + WSET(buf, smb_vwv0, finfo->fileid); + DSET(buf, smb_vwv1, utc2local(finfo->mtime)); + + return smb_request_ok_unlock(server, SMBclose, 0, 0); +} + +/* In smb_proc_read and smb_proc_write we do not retry, because the + file-id would not be valid after a reconnection. */ + +/* smb_proc_read: fs indicates if it should be copied with + memcpy_tofs. */ + +int +smb_proc_read(struct smb_server *server, struct smb_dirent *finfo, + off_t offset, long count, char *data, int fs) +{ + word returned_count, data_len; + char *buf = server->packet; + int error; + + smb_setup_header_exclusive(server, SMBread, 5, 0); + + WSET(buf, smb_vwv0, finfo->fileid); + WSET(buf, smb_vwv1, count); + DSET(buf, smb_vwv2, offset); + WSET(buf, smb_vwv4, 0); + + if ((error = smb_request_ok(server, SMBread, 5, -1)) < 0) { + smb_unlock_server(server); + return error; + } + + returned_count = WVAL(buf, smb_vwv0); + + smb_decode_data(SMB_BUF(server->packet), data, &data_len, fs); + + smb_unlock_server(server); + + if (returned_count != data_len) { + printk("smb_proc_read: Warning, returned_count != data_len\n"); + printk("smb_proc_read: ret_c=%d, data_len=%d\n", + returned_count, data_len); + } + + return data_len; +} + +int +smb_proc_write(struct smb_server *server, struct smb_dirent *finfo, + off_t offset, int count, char *data) +{ + int res = 0; + char *buf = server->packet; + byte *p; + + p = smb_setup_header_exclusive(server, SMBwrite, 5, count + 3); + WSET(buf, smb_vwv0, finfo->fileid); + WSET(buf, smb_vwv1, count); + DSET(buf, smb_vwv2, offset); + WSET(buf, smb_vwv4, 0); + + *p++ = 1; + WSET(p, 0, count); + memcpy_fromfs(p+2, data, count); + + if ((res = smb_request_ok(server, SMBwrite, 1, 0)) >= 0) { + res = WVAL(buf, smb_vwv0); + } + + smb_unlock_server(server); + + return res; +} + +/* smb_proc_do_create: We expect entry->attry & entry->ctime to be set. */ + +static int +smb_proc_do_create(struct smb_server *server, const char *path, int len, + struct smb_dirent *entry, word command) +{ + int error; + char *p; + char *buf = server->packet; + + smb_lock_server(server); + retry: + p = smb_setup_header(server, command, 3, len + 2); + WSET(buf, smb_vwv0, entry->attr); + DSET(buf, smb_vwv1, utc2local(entry->ctime)); + smb_encode_ascii(p, path, len); + + if ((error = smb_request_ok(server, command, 1, 0)) < 0) { + if (smb_retry(server)) { + goto retry; + } + smb_unlock_server(server); + return error; + } + + entry->opened = 1; + entry->fileid = WVAL(buf, smb_vwv0); + smb_unlock_server(server); + + smb_proc_close(server, entry); + + return 0; +} + +int +smb_proc_create(struct smb_server *server, const char *path, int len, + struct smb_dirent *entry) +{ + return smb_proc_do_create(server, path, len, entry, SMBcreate); +} + +int +smb_proc_mknew(struct smb_server *server, const char *path, int len, + struct smb_dirent *entry) +{ + return smb_proc_do_create(server, path, len, entry, SMBmknew); +} + +int +smb_proc_mv(struct smb_server *server, + const char *opath, const int olen, + const char *npath, const int nlen) +{ + char *p; + char *buf = server->packet; + int result; + + smb_lock_server(server); + + retry: + p = smb_setup_header(server, SMBmv, 1, olen + nlen + 4); + WSET(buf, smb_vwv0, 0); + p = smb_encode_ascii(p, opath, olen); + smb_encode_ascii(p, npath, olen); + + if ((result = smb_request_ok(server, SMBmv, 0, 0)) < 0) { + if (smb_retry(server)) { + goto retry; + } + } + smb_unlock_server(server); + return result; +} + +int +smb_proc_mkdir(struct smb_server *server, const char *path, const int len) +{ + char *p; + int result; + + smb_lock_server(server); + + retry: + p = smb_setup_header(server, SMBmkdir, 0, 2 + len); + smb_encode_ascii(p, path, len); + + if ((result = smb_request_ok(server, SMBmkdir, 0, 0)) < 0) { + if (smb_retry(server)) { + goto retry; + } + } + smb_unlock_server(server); + return result; +} + +int +smb_proc_rmdir(struct smb_server *server, const char *path, const int len) +{ + char *p; + int result; + + smb_lock_server(server); + + retry: + p = smb_setup_header(server, SMBrmdir, 0, 2 + len); + smb_encode_ascii(p, path, len); + + if ((result = smb_request_ok(server, SMBrmdir, 0, 0)) < 0) { + if (smb_retry(server)) { + goto retry; + } + } + smb_unlock_server(server); + return result; +} + +int +smb_proc_unlink(struct smb_server *server, const char *path, const int len) +{ + char *p; + char *buf = server->packet; + int result; + + smb_lock_server(server); + + retry: + p = smb_setup_header(server, SMBunlink, 1, 2 + len); + WSET(buf, smb_vwv0, 0); + smb_encode_ascii(p, path, len); + + if ((result = smb_request_ok(server, SMBunlink, 0, 0)) < 0) { + if (smb_retry(server)) { + goto retry; + } + } + smb_unlock_server(server); + return result; +} + +int +smb_proc_trunc(struct smb_server *server, word fid, dword length) +{ + char *p; + char *buf = server->packet; + int result; + + smb_lock_server(server); + + retry: + p = smb_setup_header(server, SMBwrite, 5, 3); + WSET(buf, smb_vwv0, fid); + WSET(buf, smb_vwv1, 0); + DSET(buf, smb_vwv2, length); + WSET(buf, smb_vwv4, 0); + smb_encode_ascii(p, "", 0); + + if ((result = smb_request_ok(server, SMBwrite, 1, 0)) < 0) { + if (smb_retry(server)) { + goto retry; + } + } + smb_unlock_server(server); + return result; +} + +static char * +smb_decode_dirent(char *p, struct smb_dirent *entry) +{ + p += SMB_STATUS_SIZE; /* reserved (search_status) */ + entry->attr = BVAL(p, 0); + entry->mtime = entry->atime = entry->ctime = + date_dos2unix(WVAL(p, 1), WVAL(p, 3)); + entry->size = DVAL(p, 5); + memcpy(entry->path, p+9, 13); + DDPRINTK("smb_decode_dirent: path = %s\n", entry->path); + return p + 22; +} + +/* This routine is used to read in directory entries from the network. + Note that it is for short directory name seeks, i.e.: protocol < + PROTOCOL_LANMAN2 */ + +static int +smb_proc_readdir_short(struct smb_server *server, struct inode *dir, int fpos, + int cache_size, struct smb_dirent *entry) +{ + char *p; + char *buf; + int error; + int result; + int i; + int first, total_count; + struct smb_dirent *current_entry; + word bcc; + word count; + char status[SMB_STATUS_SIZE]; + int entries_asked = (server->max_xmit - 100) / SMB_DIRINFO_SIZE; + int dirlen = strlen(SMB_FINFO(dir)->path); + char mask[dirlen + 5]; + + strcpy(mask, SMB_FINFO(dir)->path); + strcat(mask, "\\*.*"); + + DPRINTK("SMB call readdir %d @ %d\n", cache_size, fpos); + DPRINTK(" mask = %s\n", mask); + + buf = server->packet; + + smb_lock_server(server); + + retry: + first = 1; + total_count = 0; + current_entry = entry; + + while (1) { + if (first == 1) { + p = smb_setup_header(server, SMBsearch, 2, + 5 + strlen(mask)); + WSET(buf, smb_vwv0, entries_asked); + WSET(buf, smb_vwv1, aDIR); + p = smb_encode_ascii(p, mask, strlen(mask)); + *p ++ = 5; + p = smb_encode_word(p, 0); + } else { + p = smb_setup_header(server, SMBsearch, 2, + 5 + SMB_STATUS_SIZE); + WSET(buf, smb_vwv0, entries_asked); + WSET(buf, smb_vwv1, aDIR); + p = smb_encode_ascii(p, "", 0); + p = smb_encode_vblock(p, status, SMB_STATUS_SIZE, 0); + } + + if ((error = smb_request_ok(server, SMBsearch, 1, -1)) < 0) { + if ( (server->rcls == ERRDOS) + && (server->err == ERRnofiles)) { + result = total_count - fpos; + goto unlock_return; + } + else + { + if (smb_retry(server)) { + goto retry; + } + result = error; + goto unlock_return; + } + } + + p = SMB_VWV(server->packet); + p = smb_decode_word(p, &count); /* vwv[0] = count-returned */ + p = smb_decode_word(p, &bcc); + + first = 0; + + if (count <= 0) { + result = total_count - fpos; + goto unlock_return; + } + if (bcc != count * SMB_DIRINFO_SIZE + 3) { + result = -EIO; + goto unlock_return; + } + + p += 3; /* Skipping VBLOCK header (5, length lo, length hi). */ + + /* Read the last entry into the status field. */ + memcpy(status, + SMB_BUF(server->packet) + 3 + + (count - 1) * SMB_DIRINFO_SIZE, + SMB_STATUS_SIZE); + + /* Now we are ready to parse smb directory entries. */ + + for (i = 0; i < count; i ++) { + if (total_count < fpos) { + p += SMB_DIRINFO_SIZE; + DDPRINTK("smb_proc_readdir: skipped entry.\n"); + DDPRINTK(" total_count = %d\n" + " i = %d, fpos = %d\n", + total_count, i, fpos); + } + else if (total_count >= fpos + cache_size) { + result = total_count - fpos; + goto unlock_return; + } + else { + p = smb_decode_dirent(p, current_entry); + current_entry->f_pos = total_count; + DDPRINTK("smb_proc_readdir: entry->f_pos = " + "%lu\n", entry->f_pos); + current_entry += 1; + } + total_count += 1; + } + } + unlock_return: + smb_unlock_server(server); + return result; +} + +/* interpret a long filename structure - this is mostly guesses at the + moment. The length of the structure is returned. The structure of + a long filename depends on the info level. 260 is used by NT and 2 + is used by OS/2. */ + +static char * +smb_decode_long_dirent(char *p, struct smb_dirent *finfo, int level) +{ + char *result; + + if (finfo) { + /* I have to set times to 0 here, because I do not + have specs about this for all info levels. */ + finfo->ctime = finfo->mtime = finfo->atime = 0; + } + + switch (level) + { + case 1: /* OS/2 understands this */ + if (finfo) + { + DPRINTK("received entry\n"); + strcpy(finfo->path,p+27); + finfo->len = strlen(finfo->path); + finfo->size = DVAL(p,16); + finfo->attr = BVAL(p,24); + + finfo->ctime = date_dos2unix(WVAL(p, 6), WVAL(p, 4)); + finfo->atime = date_dos2unix(WVAL(p, 10), WVAL(p, 8)); + finfo->mtime = date_dos2unix(WVAL(p, 14), WVAL(p, 12)); + } + result = p + 28 + BVAL(p,26); + break; + + case 2: /* this is what OS/2 uses */ + if (finfo) + { + strcpy(finfo->path,p+31); + finfo->len = strlen(finfo->path); + finfo->size = DVAL(p,16); + finfo->attr = BVAL(p,24); +#if 0 + finfo->atime = make_unix_date2(p+8); + finfo->mtime = make_unix_date2(p+12); +#endif + } + result = p + 32 + BVAL(p,30); + break; + + case 260: /* NT uses this, but also accepts 2 */ + result = p + WVAL(p,0); + if (finfo) + { + int namelen; + p += 4; /* next entry offset */ + p += 4; /* fileindex */ + /* finfo->ctime = interpret_filetime(p);*/ + p += 8; + /* finfo->atime = interpret_filetime(p);*/ + p += 8; + p += 8; /* write time */ + /* finfo->mtime = interpret_filetime(p);*/ + p += 8; + finfo->size = DVAL(p,0); + p += 8; + p += 8; /* alloc size */ + finfo->attr = BVAL(p,0); + p += 4; + namelen = min(DVAL(p,0), SMB_MAXNAMELEN); + p += 4; + p += 4; /* EA size */ + p += 2; /* short name len? */ + p += 24; /* short name? */ + strncpy(finfo->path,p,namelen); + finfo->len = namelen; + } + break; + + default: + DPRINTK("Unknown long filename format %d\n",level); + result = p + WVAL(p,0); + } + return result; +} + +int +smb_proc_readdir_long(struct smb_server *server, struct inode *dir, int fpos, + int cache_size, struct smb_dirent *entry) +{ + int max_matches = 512; + + /* NT uses 260, OS/2 uses 2. Both accept 1. */ + int info_level = 1; + + char *p; + int i; + int first, total_count; + struct smb_dirent *current_entry; + + char *resp_data; + char *resp_param; + int resp_data_len = 0; + int resp_param_len=0; + + int attribute = aSYSTEM | aHIDDEN | aDIR; + int result; + + int ff_resume_key = 0; + int ff_searchcount=0; + int ff_eos=0; + int ff_lastname=0; + int ff_dir_handle=0; + int loop_count = 0; + + int dirlen = strlen(SMB_FINFO(dir)->path); + char mask[dirlen + 5]; + + strcpy(mask, SMB_FINFO(dir)->path); + strcat(mask, "\\*"); + + DPRINTK("SMB call lreaddir %d @ %d\n", cache_size, fpos); + DPRINTK(" mask = %s\n", mask); + + resp_param = NULL; + resp_data = NULL; + + smb_lock_server(server); + + retry: + + first = 1; + total_count = 0; + current_entry = entry; + + while (ff_eos == 0) + { + int masklen = strlen(mask); + unsigned char *outbuf = server->packet; + + loop_count += 1; + if (loop_count > 200) + { + printk("smb_proc_readdir_long: " + "Looping in FIND_NEXT??\n"); + break; + } + + smb_setup_header(server, SMBtrans2, 15, + 5 + 12 + masklen + 1); + + WSET(outbuf,smb_tpscnt,12 + masklen +1); + WSET(outbuf,smb_tdscnt,0); + WSET(outbuf,smb_mprcnt,10); + WSET(outbuf,smb_mdrcnt,TRANS2_MAX_TRANSFER); + WSET(outbuf,smb_msrcnt,0); + WSET(outbuf,smb_flags,0); + DSET(outbuf,smb_timeout,0); + WSET(outbuf,smb_pscnt,WVAL(outbuf,smb_tpscnt)); + WSET(outbuf,smb_psoff,((SMB_BUF(outbuf)+3) - outbuf)-4); + WSET(outbuf,smb_dscnt,0); + WSET(outbuf,smb_dsoff,0); + WSET(outbuf,smb_suwcnt,1); + WSET(outbuf,smb_setup0, + first == 1 ? TRANSACT2_FINDFIRST : TRANSACT2_FINDNEXT); + + p = SMB_BUF(outbuf); + *p++=0; /* put in a null smb_name */ + *p++='D'; *p++ = ' '; /* this was added because OS/2 does it */ + + if (first != 0) + { + WSET(p,0,attribute); /* attribute */ + WSET(p,2,max_matches); /* max count */ + WSET(p,4,8+4+2); /* resume required + close on end + + continue */ + WSET(p,6,info_level); + DSET(p,8,0); + p += 12; + strncpy(p, mask, masklen); + p += masklen; + *p++ = 0; *p++ = 0; + } + else + { + DPRINTK("hand=0x%X resume=%d ff_lastname=%d mask=%s\n", + ff_dir_handle,ff_resume_key,ff_lastname,mask); + WSET(p,0,ff_dir_handle); + WSET(p,2,max_matches); /* max count */ + WSET(p,4,info_level); + DSET(p,6,ff_resume_key); /* ff_resume_key */ + WSET(p,10,8+4+2); /* resume required + close on end + + continue */ + p += 12; + strncpy(p, mask, masklen); + p += masklen; + *p++ = 0; *p++ = 0; + } + + result = smb_trans2_request(server, + &resp_data_len,&resp_param_len, + &resp_data,&resp_param); + + if (result < 0) { + if (smb_retry(server)) { + goto retry; + } + DPRINTK("smb_proc_readdir_long: " + "got error from trans2_request\n"); + break; + } + + if (server->rcls != 0) + { + result = -EIO; + break; + } + + /* parse out some important return info */ + p = resp_param; + if (first != 0) + { + ff_dir_handle = WVAL(p,0); + ff_searchcount = WVAL(p,2); + ff_eos = WVAL(p,4); + ff_lastname = WVAL(p,8); + } + else + { + ff_searchcount = WVAL(p,0); + ff_eos = WVAL(p,2); + ff_lastname = WVAL(p,6); + } + + if (ff_searchcount == 0) + break; + + /* point to the data bytes */ + p = resp_data; + + /* we might need the lastname for continuations */ + if (ff_lastname > 0) + { + switch(info_level) + { + case 260: + ff_resume_key =0; + strcpy(mask,p+ff_lastname+94); + break; + case 1: + strcpy(mask,p + ff_lastname + 1); + ff_resume_key = 0; + break; + } + } + else + strcpy(mask,""); + + /* Now we are ready to parse smb directory entries. */ + + for (i = 0; i < ff_searchcount; i ++) { + if (total_count < fpos) { + p = smb_decode_long_dirent(p, NULL, + info_level); + DPRINTK("smb_proc_readdir: skipped entry.\n"); + DDPRINTK(" total_count = %d\n" + " i = %d, fpos = %d\n", + total_count, i, fpos); + } + else if (total_count >= fpos + cache_size) { + goto finished; + } + else { + p = smb_decode_long_dirent(p, current_entry, + info_level); + current_entry->f_pos = total_count; + DDPRINTK("smb_proc_readdir: entry->f_pos = " + "%lu\n", entry->f_pos); + current_entry += 1; + } + total_count += 1; + } + + if (resp_data != NULL) { + smb_kfree_s(resp_data, 0); + resp_data = NULL; + } + if (resp_param != NULL) { + smb_kfree_s(resp_param, 0); + resp_param = NULL; + } + + DPRINTK("received %d entries (eos=%d resume=%d)\n", + ff_searchcount,ff_eos,ff_resume_key); + + first = 0; + } + + finished: + if (resp_data != NULL) { + smb_kfree_s(resp_data, 0); + resp_data = NULL; + } + if (resp_param != NULL) { + smb_kfree_s(resp_param, 0); + resp_param = NULL; + } + + smb_unlock_server(server); + + return total_count - fpos; +} + +int +smb_proc_readdir(struct smb_server *server, struct inode *dir, int fpos, + int cache_size, struct smb_dirent *entry) +{ + if (server->protocol >= PROTOCOL_LANMAN2) + return smb_proc_readdir_long(server, dir, fpos, cache_size, + entry); + else + return smb_proc_readdir_short(server, dir, fpos, cache_size, + entry); +} + +static int +smb_proc_getattr_core(struct smb_server *server, const char *path, int len, + struct smb_dirent *entry) +{ + int result; + char *p; + char *buf = server->packet; + + smb_lock_server(server); + + DDPRINTK("smb_proc_getattr: %s\n", path); + + retry: + p = smb_setup_header(server, SMBgetatr, 0, 2 + len); + smb_encode_ascii(p, path, len); + + if ((result = smb_request_ok(server, SMBgetatr, 10, 0)) < 0) { + if (smb_retry(server)) { + goto retry; + } + smb_unlock_server(server); + return result; + } + + entry->attr = WVAL(buf, smb_vwv0); + entry->ctime = entry->atime = /* The server only tells us 1 time */ + entry->mtime = local2utc(DVAL(buf, smb_vwv1)); + + entry->size = DVAL(buf, smb_vwv3); + smb_unlock_server(server); + return 0; +} + +/* smb_proc_getattrE: entry->fid must be valid */ + +static int +smb_proc_getattrE(struct smb_server *server, struct smb_dirent *entry) +{ + char* buf = server->packet; + int result; + + smb_setup_header_exclusive(server, SMBgetattrE, 1, 0); + WSET(buf, smb_vwv0, entry->fileid); + + if ((result = smb_request_ok(server, SMBgetattrE, 11, 0)) != 0) { + smb_unlock_server(server); + return result; + } + + entry->ctime = date_dos2unix(WVAL(buf, smb_vwv1), WVAL(buf, smb_vwv0)); + entry->atime = date_dos2unix(WVAL(buf, smb_vwv3), WVAL(buf, smb_vwv2)); + entry->mtime = date_dos2unix(WVAL(buf, smb_vwv5), WVAL(buf, smb_vwv4)); + entry->size = DVAL(buf, smb_vwv6); + entry->attr = WVAL(buf, smb_vwv10); + + smb_unlock_server(server); + return 0; +} + +int +smb_proc_getattr(struct smb_server *server, const char *path, int len, + struct smb_dirent *entry) +{ + if (server->protocol >= PROTOCOL_LANMAN1) { + + int result = 0; + struct smb_dirent temp_entry; + + if ((result=smb_proc_open(server,path,len, + &temp_entry)) < 0) { + /* We cannot open directories, so we try to use the + core variant */ + return smb_proc_getattr_core(server,path,len,entry); + } + + if ((result=smb_proc_getattrE(server, &temp_entry)) >= 0) { + entry->attr = temp_entry.attr; + entry->atime = temp_entry.atime; + entry->mtime = temp_entry.mtime; + entry->ctime = temp_entry.ctime; + entry->size = temp_entry.size; + } + + smb_proc_close(server, &temp_entry); + return result; + + } else { + return smb_proc_getattr_core(server, path, len, entry); + } +} + + +/* In core protocol, there is only 1 time to be set, we use + entry->mtime, to make touch work. */ +static int +smb_proc_setattr_core(struct smb_server *server, + const char *path, int len, + struct smb_dirent *new_finfo) +{ + char *p; + char *buf = server->packet; + int result; + + smb_lock_server(server); + + retry: + p = smb_setup_header(server, SMBsetatr, 8, 4 + len); + WSET(buf, smb_vwv0, new_finfo->attr); + DSET(buf, smb_vwv1, utc2local(new_finfo->mtime)); + p = smb_encode_ascii(p, path, len); + p = smb_encode_ascii(p, "", 0); + + if ((result = smb_request_ok(server, SMBsetatr, 0, 0)) < 0) { + if (smb_retry(server)) { + goto retry; + } + } + smb_unlock_server(server); + return result; +} + +/* smb_proc_setattrE: we do not retry here, because we rely on fid, + which would not be valid after a retry. */ +static int +smb_proc_setattrE(struct smb_server *server, word fid, + struct smb_dirent *new_entry) +{ + char *buf = server->packet; + word date, time; + + smb_setup_header_exclusive(server, SMBsetattrE, 7, 0); + + WSET(buf, smb_vwv0, fid); + + date_unix2dos(new_entry->ctime, &time, &date); + WSET(buf, smb_vwv1, date); + WSET(buf, smb_vwv2, time); + + date_unix2dos(new_entry->atime, &time, &date); + WSET(buf, smb_vwv3, date); + WSET(buf, smb_vwv4, time); + + date_unix2dos(new_entry->mtime, &time, &date); + WSET(buf, smb_vwv5, date); + WSET(buf, smb_vwv6, time); + + return smb_request_ok_unlock(server, SMBsetattrE, 0, 0); +} + +/* smb_proc_setattr: for protocol >= LANMAN1 we expect the file to be + opened for writing. */ +int +smb_proc_setattr(struct smb_server *server, struct inode *inode, + struct smb_dirent *new_finfo) +{ + struct smb_dirent *finfo = SMB_FINFO(inode); + int result; + + if (server->protocol >= PROTOCOL_LANMAN1) { + if ((result = smb_make_open(inode, O_RDWR)) < 0) + return result; + return smb_proc_setattrE(server, finfo->fileid, new_finfo); + } else { + return smb_proc_setattr_core(server, finfo->path, finfo->len, + new_finfo); + } +} + +int +smb_proc_dskattr(struct super_block *super, struct smb_dskattr *attr) +{ + int error; + char *p; + struct smb_server *server = &(SMB_SBP(super)->s_server); + + smb_lock_server(server); + + retry: + smb_setup_header(server, SMBdskattr, 0, 0); + + if ((error = smb_request_ok(server, SMBdskattr, 5, 0)) < 0) { + if (smb_retry(server)) { + goto retry; + } + smb_unlock_server(server); + return error; + } + + p = SMB_VWV(server->packet); + p = smb_decode_word(p, &attr->total); + p = smb_decode_word(p, &attr->allocblocks); + p = smb_decode_word(p, &attr->blocksize); + p = smb_decode_word(p, &attr->free); + smb_unlock_server(server); + return 0; +} + +/*****************************************************************************/ +/* */ +/* Mount/umount operations. */ +/* */ +/*****************************************************************************/ + +struct smb_prots { + enum smb_protocol prot; + char *name; +}; + +/* smb_proc_reconnect: We expect the server to be locked, so that you + can call the routine from within smb_retry. The socket must be + created, like after a user-level socket()-call. It may not be + connected. */ + +int +smb_proc_reconnect(struct smb_server *server) +{ + struct smb_prots prots[] = + { { PROTOCOL_CORE, "PC NETWORK PROGRAM 1.0"}, + { PROTOCOL_COREPLUS,"MICROSOFT NETWORKS 1.03"}, +#ifdef LANMAN1 + { PROTOCOL_LANMAN1,"MICROSOFT NETWORKS 3.0"}, + { PROTOCOL_LANMAN1,"LANMAN1.0"}, +#endif +#ifdef LANMAN2 + { PROTOCOL_LANMAN2,"LM1.2X002"}, +#endif + {-1, NULL} }; + char dev[] = "A:"; + int i, plength; + int max_xmit = 1024; /* Space needed for first request. */ + int given_max_xmit = server->m.max_xmit; + int result; + byte *p; + + if ((result = smb_connect(server)) < 0) { + DPRINTK("smb_proc_reconnect: could not smb_connect\n"); + goto fail; + } + + /* Here we assume that the connection is valid */ + server->state = CONN_VALID; + + if (server->packet != NULL) { + smb_kfree_s(server->packet, server->max_xmit); + } + + server->packet = smb_kmalloc(max_xmit, GFP_KERNEL); + + if (server->packet == NULL) { + printk("smb_proc_connect: No memory! Bailing out.\n"); + result = -ENOMEM; + goto fail; + } + + server->max_xmit = max_xmit; + + /* + * Start with an RFC1002 session request packet. + */ + p = server->packet + 4; + + p = smb_name_mangle(p, server->m.server_name); + p = smb_name_mangle(p, server->m.client_name); + + smb_encode_smb_length(server->packet, + (void *)p - (void *)(server->packet)); + + server->packet[0] = 0x81; /* SESSION REQUEST */ + + if (smb_catch_keepalive(server) < 0) { + printk("smb_proc_connect: could not catch_keepalives\n"); + } + + if ((result = smb_request(server)) < 0) { + printk("smb_proc_connect: Failed to send SESSION REQUEST.\n"); + smb_dont_catch_keepalive(server); + goto fail; + } + + if (server->packet[0] != 0x82) { + printk("smb_proc_connect: Did not recieve positive response " + "(err = %x)\n", + server->packet[0]); + smb_dont_catch_keepalive(server); +#if DEBUG_SMB > 0 + smb_dump_packet(server->packet); +#endif + result = -EIO; + goto fail; + } + + DPRINTK("smb_proc_connect: Passed SESSION REQUEST.\n"); + + /* Now we are ready to send a SMB Negotiate Protocol packet. */ + memset(server->packet, 0, SMB_HEADER_LEN); + + plength = 0; + for (i = 0; prots[i].name != NULL; i++) { + plength += strlen(prots[i].name) + 2; + } + + smb_setup_header(server, SMBnegprot, 0, plength); + + p = SMB_BUF(server->packet); + + for (i = 0; prots[i].name != NULL; i++) { + p = smb_encode_dialect(p,prots[i].name, strlen(prots[i].name)); + } + + if ((result = smb_request_ok(server, SMBnegprot, 1, -1)) < 0) { + printk("smb_proc_connect: Failure requesting SMBnegprot\n"); + smb_dont_catch_keepalive(server); + goto fail; + } else { + DDPRINTK("smb_proc_connect: Request SMBnegprot.."); + } + + DDPRINTK("Verified!\n"); + + p = SMB_VWV(server->packet); + p = smb_decode_word(p, (word *)&i); + server->protocol = prots[i].prot; + + DPRINTK("smb_proc_connect: Server wants %s protocol.\n", + prots[i].name); + + if (server->protocol > PROTOCOL_LANMAN1) { + + word passlen = strlen(server->m.password); + word userlen = strlen(server->m.username); + + DPRINTK("smb_proc_connect: password = %s\n", + server->m.password); + DPRINTK("smb_proc_connect: usernam = %s\n", + server->m.username); + + p = smb_decode_word(p, &(server->maxxmt)); + p = smb_decode_word(p, &(server->maxmux)); + p = smb_decode_word(p, &(server->maxvcs)); + p = smb_decode_word(p, &(server->blkmode)); + p = smb_decode_dword(p, &(server->sesskey)); + + smb_setup_header(server, SMBsesssetupX, 10, + 2 + userlen + passlen); + + WSET(server->packet, smb_vwv0, 0x00ff); + WSET(server->packet, smb_vwv1, 0); + WSET(server->packet, smb_vwv2, given_max_xmit); + WSET(server->packet, smb_vwv3, 2); + WSET(server->packet, smb_vwv4, server->pid); + DSET(server->packet, smb_vwv5, server->sesskey); + WSET(server->packet, smb_vwv7, passlen + 1); + WSET(server->packet, smb_vwv8, 0); + WSET(server->packet, smb_vwv9, 0); + + p = SMB_BUF(server->packet); + strcpy(p, server->m.password); + p += passlen + 1; + strcpy(p, server->m.username); + + if ((result = smb_request_ok(server,SMBsesssetupX,3,0)) < 0) { + DPRINTK("smb_proc_connect: SMBsessetupX failed\n"); + smb_dont_catch_keepalive(server); + goto fail; + } + smb_decode_word(server->packet+32, &(server->server_uid)); + } + + /* Fine! We have a connection, send a tcon message. */ + + smb_setup_header(server, SMBtcon, 0, + 6 + strlen(server->m.service) + + strlen(server->m.password) + strlen(dev)); + p = SMB_BUF(server->packet); + p = smb_encode_ascii(p, server->m.service, strlen(server->m.service)); + p = smb_encode_ascii(p,server->m.password, strlen(server->m.password)); + p = smb_encode_ascii(p, dev, strlen(dev)); + + if ((result = smb_request_ok(server, SMBtcon, 2, 0)) < 0) { + DPRINTK("smb_proc_connect: SMBtcon not verified.\n"); + smb_dont_catch_keepalive(server); + goto fail; + } + + DDPRINTK("OK! Managed to set up SMBtcon!\n"); + + p = SMB_VWV(server->packet); + p = smb_decode_word(p, &server->max_xmit); + + if (server->max_xmit > given_max_xmit) + server->max_xmit = given_max_xmit; + + p = smb_decode_word(p, &server->tid); + + /* Ok, everything is fine. max_xmit does not include */ + /* the TCP-SMB header of 4 bytes. */ + server->max_xmit += 4; + + DPRINTK("max_xmit = %d, tid = %d\n", server->max_xmit, server->tid); + + /* Now make a new packet with the correct size. */ + smb_kfree_s(server->packet, max_xmit); + + server->packet = smb_kmalloc(server->max_xmit, GFP_KERNEL); + if (server->packet == NULL) { + printk("smb_proc_connect: No memory left in end of " + "connection phase :-(\n"); + smb_dont_catch_keepalive(server); + goto fail; + } + + DPRINTK("smb_proc_connect: Normal exit\n"); + return 0; + + fail: + server->state = CONN_INVALID; + return result; +} + +/* smb_proc_reconnect: server->packet is allocated with + server->max_xmit bytes if and only if we return >= 0 */ +int +smb_proc_connect(struct smb_server *server) +{ + int result; + smb_lock_server(server); + result = smb_proc_reconnect(server); + if ((result < 0) && (server->packet != NULL)) { + smb_kfree_s(server->packet, server->max_xmit); + server->packet = NULL; + } + smb_unlock_server(server); + return result; +} + +int +smb_proc_disconnect(struct smb_server *server) +{ + smb_setup_header_exclusive(server, SMBtdis, 0, 0); + return smb_request_ok_unlock(server, SMBtdis, 0, 0); +} + +/* error code stuff - put together by Merik Karman + merik@blackadder.dsh.oz.au */ + +#if DEBUG_SMB > 0 + +typedef struct { + char *name; + int code; + char *message; +} err_code_struct; + +/* Dos Error Messages */ +err_code_struct dos_msgs[] = { + { "ERRbadfunc",1,"Invalid function."}, + { "ERRbadfile",2,"File not found."}, + { "ERRbadpath",3,"Directory invalid."}, + { "ERRnofids",4,"No file descriptors available"}, + { "ERRnoaccess",5,"Access denied."}, + { "ERRbadfid",6,"Invalid file handle."}, + { "ERRbadmcb",7,"Memory control blocks destroyed."}, + { "ERRnomem",8,"Insufficient server memory to perform the requested function."}, + { "ERRbadmem",9,"Invalid memory block address."}, + { "ERRbadenv",10,"Invalid environment."}, + { "ERRbadformat",11,"Invalid format."}, + { "ERRbadaccess",12,"Invalid open mode."}, + { "ERRbaddata",13,"Invalid data."}, + { "ERR",14,"reserved."}, + { "ERRbaddrive",15,"Invalid drive specified."}, + { "ERRremcd",16,"A Delete Directory request attempted to remove the server's current directory."}, + { "ERRdiffdevice",17,"Not same device."}, + { "ERRnofiles",18,"A File Search command can find no more files matching the specified criteria."}, + { "ERRbadshare",32,"The sharing mode specified for an Open conflicts with existing FIDs on the file."}, + { "ERRlock",33,"A Lock request conflicted with an existing lock or specified an invalid mode, or an Unlock requested attempted to remove a lock held by another process."}, + { "ERRfilexists",80,"The file named in a Create Directory, Make New File or Link request already exists."}, + { "ERRbadpipe",230,"Pipe invalid."}, + { "ERRpipebusy",231,"All instances of the requested pipe are busy."}, + { "ERRpipeclosing",232,"Pipe close in progress."}, + { "ERRnotconnected",233,"No process on other end of pipe."}, + { "ERRmoredata",234,"There is more data to be returned."}, + { NULL,-1,NULL}}; + +/* Server Error Messages */ +err_code_struct server_msgs[] = { + { "ERRerror",1,"Non-specific error code."}, + { "ERRbadpw",2,"Bad password - name/password pair in a Tree Connect or Session Setup are invalid."}, + { "ERRbadtype",3,"reserved."}, + { "ERRaccess",4,"The requester does not have the necessary access rights within the specified context for the requested function. The context is defined by the TID or the UID."}, + { "ERRinvnid",5,"The tree ID (TID) specified in a command was invalid."}, + { "ERRinvnetname",6,"Invalid network name in tree connect."}, + { "ERRinvdevice",7,"Invalid device - printer request made to non-printer connection or non-printer request made to printer connection."}, + { "ERRqfull",49,"Print queue full (files) -- returned by open print file."}, + { "ERRqtoobig",50,"Print queue full -- no space."}, + { "ERRqeof",51,"EOF on print queue dump."}, + { "ERRinvpfid",52,"Invalid print file FID."}, + { "ERRsmbcmd",64,"The server did not recognize the command received."}, + { "ERRsrverror",65,"The server encountered an internal error, e.g., system file unavailable."}, + { "ERRfilespecs",67,"The file handle (FID) and pathname parameters contained an invalid combination of values."}, + { "ERRreserved",68,"reserved."}, + { "ERRbadpermits",69,"The access permissions specified for a file or directory are not a valid combination. The server cannot set the requested attribute."}, + { "ERRreserved",70,"reserved."}, + { "ERRsetattrmode",71,"The attribute mode in the Set File Attribute request is invalid."}, + { "ERRpaused",81,"Server is paused."}, + { "ERRmsgoff",82,"Not receiving messages."}, + { "ERRnoroom",83,"No room to buffer message."}, + { "ERRrmuns",87,"Too many remote user names."}, + { "ERRtimeout",88,"Operation timed out."}, + { "ERRnoresource",89,"No resources currently available for request."}, + { "ERRtoomanyuids",90,"Too many UIDs active on this session."}, + { "ERRbaduid",91,"The UID is not known as a valid ID on this session."}, + { "ERRusempx",250,"Temp unable to support Raw, use MPX mode."}, + { "ERRusestd",251,"Temp unable to support Raw, use standard read/write."}, + { "ERRcontmpx",252,"Continue in MPX mode."}, + { "ERRreserved",253,"reserved."}, + { "ERRreserved",254,"reserved."}, + { "ERRnosupport",0xFFFF,"Function not supported."}, + { NULL,-1,NULL}}; + +/* Hard Error Messages */ +err_code_struct hard_msgs[] = { + { "ERRnowrite",19,"Attempt to write on write-protected diskette."}, + { "ERRbadunit",20,"Unknown unit."}, + { "ERRnotready",21,"Drive not ready."}, + { "ERRbadcmd",22,"Unknown command."}, + { "ERRdata",23,"Data error (CRC)."}, + { "ERRbadreq",24,"Bad request structure length."}, + { "ERRseek",25 ,"Seek error."}, + { "ERRbadmedia",26,"Unknown media type."}, + { "ERRbadsector",27,"Sector not found."}, + { "ERRnopaper",28,"Printer out of paper."}, + { "ERRwrite",29,"Write fault."}, + { "ERRread",30,"Read fault."}, + { "ERRgeneral",31,"General failure."}, + { "ERRbadshare",32,"A open conflicts with an existing open."}, + { "ERRlock",33,"A Lock request conflicted with an existing lock or specified an invalid mode, or an Unlock requested attempted to remove a lock held by another process."}, + { "ERRwrongdisk",34,"The wrong disk was found in a drive."}, + { "ERRFCBUnavail",35,"No FCBs are available to process request."}, + { "ERRsharebufexc",36,"A sharing buffer has been exceeded."}, + { NULL,-1,NULL} +}; + + +struct { + int code; + char *class; + err_code_struct *err_msgs; +} err_classes[] = { + { 0,"SUCCESS",NULL}, + { 0x01,"ERRDOS",dos_msgs}, + { 0x02,"ERRSRV",server_msgs}, + { 0x03,"ERRHRD",hard_msgs}, + { 0x04,"ERRXOS",NULL}, + { 0xE1,"ERRRMX1",NULL}, + { 0xE2,"ERRRMX2",NULL}, + { 0xE3,"ERRRMX3",NULL}, + { 0xFF,"ERRCMD",NULL}, + { -1,NULL,NULL} +}; + +void +smb_printerr(int class, int num) +{ + int i,j; + err_code_struct *err; + + for (i=0; err_classes[i].class; i++) { + if (err_classes[i].code != class) + continue; + if (!err_classes[i].err_msgs) { + printk("%s - %d", err_classes[i].class, num); + return; + } + + err = err_classes[i].err_msgs; + for (j=0; err[j].name; j++) { + if (num != err[j].code) + continue; + printk("%s - %s (%s)", + err_classes[i].class, err[j].name, + err[j].message); + return; + } + } + + printk("Unknown error - (%d,%d)", class, num); + return; +} + +#endif /* DEBUG_SMB > 0 */ + +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * Emacs will notice this stuff at the end of the file and automatically + * adjust the settings for this buffer only. This must remain at the end + * of the file. + * --------------------------------------------------------------------------- + * Local variables: + * c-indent-level: 8 + * c-brace-imaginary-offset: 0 + * c-brace-offset: -8 + * c-argdecl-indent: 8 + * c-label-offset: -8 + * c-continued-statement-offset: 8 + * c-continued-brace-offset: 0 + * End: + */ diff -u --recursive --new-file v1.3.6/linux/fs/smbfs/sock.c linux/fs/smbfs/sock.c --- v1.3.6/linux/fs/smbfs/sock.c Thu Jan 1 02:00:00 1970 +++ linux/fs/smbfs/sock.c Sat Jul 1 19:00:19 1995 @@ -0,0 +1,600 @@ +/* + * sock.c + * + * Copyright (C) 1995 by Paal-Kr. Engstad and Volker Lendecke + * + */ + +#include +#ifdef MODULE +#include +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "/usr/src/linux/include/net/ip.h" + +#include +#include + + +#define _S(nr) (1<<((nr)-1)) + +static void +smb_data_callback(struct sock *sk,int len) +{ + struct socket *sock = sk->socket; + + if(!sk->dead) + { + unsigned char peek_buf[4]; + int result; + unsigned short fs; + + fs = get_fs(); + set_fs(get_ds()); + + result = sock->ops->recvfrom(sock, (void *)peek_buf, 1, 1, + MSG_PEEK, NULL, NULL); + + while ((result != -EAGAIN) && (peek_buf[0] == 0x85)) { + + /* got SESSION KEEP ALIVE */ + result = sock->ops->recvfrom(sock, (void *)peek_buf, + 4, 1, 0, NULL, NULL); + + DDPRINTK("smb_data_callback:" + " got SESSION KEEP ALIVE\n"); + + if (result == -EAGAIN) + break; + + result = sock->ops->recvfrom(sock, (void *)peek_buf, + 1, 1, MSG_PEEK, + NULL, NULL); + + } + + set_fs(fs); + + if (result != -EAGAIN) { + wake_up_interruptible(sk->sleep); + } + } +} + +int +smb_catch_keepalive(struct smb_server *server) +{ + struct file *file; + struct inode *inode; + struct socket *sock; + struct sock *sk; + + if ( (server == NULL) + || ((file = server->sock_file) == NULL) + || ((inode = file->f_inode) == NULL) + || (!S_ISSOCK(inode->i_mode))) { + + printk("smb_catch_keepalive: did not get valid server!\n"); + server->data_ready = NULL; + return -EINVAL; + } + + sock = &(inode->u.socket_i); + + if (sock->type != SOCK_STREAM) { + printk("smb_catch_keepalive: did not get SOCK_STREAM\n"); + server->data_ready = NULL; + return -EINVAL; + } + + sk = (struct sock *)(sock->data); + + if (sk == NULL) { + printk("smb_catch_keepalive: sk == NULL"); + server->data_ready = NULL; + return -EINVAL; + } + + DDPRINTK("smb_catch_keepalive.: sk->d_r = %x, server->d_r = %x\n", + (unsigned int)(sk->data_ready), + (unsigned int)(server->data_ready)); + + if (sk->data_ready == smb_data_callback) { + printk("smb_catch_keepalive: already done\n"); + return -EINVAL; + } + + server->data_ready = sk->data_ready; + sk->data_ready = smb_data_callback; + return 0; +} + +int +smb_dont_catch_keepalive(struct smb_server *server) +{ + struct file *file; + struct inode *inode; + struct socket *sock; + struct sock *sk; + + if ( (server == NULL) + || ((file = server->sock_file) == NULL) + || ((inode = file->f_inode) == NULL) + || (!S_ISSOCK(inode->i_mode))) { + + printk("smb_dont_catch_keepalive: " + "did not get valid server!\n"); + return -EINVAL; + } + + sock = &(inode->u.socket_i); + + if (sock->type != SOCK_STREAM) { + printk("smb_dont_catch_keepalive: did not get SOCK_STREAM\n"); + return -EINVAL; + } + + sk = (struct sock *)(sock->data); + + if (sk == NULL) { + printk("smb_dont_catch_keepalive: sk == NULL"); + return -EINVAL; + } + + if (server->data_ready == NULL) { + printk("smb_dont_catch_keepalive: " + "server->data_ready == NULL\n"); + return -EINVAL; + } + + if (sk->data_ready != smb_data_callback) { + printk("smb_dont_catch_keepalive: " + "sk->data_callback != smb_data_callback\n"); + return -EINVAL; + } + + DDPRINTK("smb_dont_catch_keepalive: sk->d_r = %x, server->d_r = %x\n", + (unsigned int)(sk->data_ready), + (unsigned int)(server->data_ready)); + + sk->data_ready = server->data_ready; + server->data_ready = NULL; + return 0; +} + +/* + * smb_receive + * fs points to the correct segment, server != NULL, sock!=NULL + */ +static int +smb_receive(struct smb_server *server, struct socket *sock) +{ + int len, result; + unsigned char peek_buf[4]; + + re_recv: + + result = sock->ops->recvfrom(sock, (void *)peek_buf, 4, 0, + MSG_PEEK, NULL, NULL); + + if (result < 0) { + DPRINTK("smb_receive: recv error = %d\n", -result); + return result; + } + + if (result == 0) { + DPRINTK("smb_receive: got 0 bytes\n"); + return -EIO; + } + + switch (peek_buf[0]) { + + case 0x00: + case 0x82: + break; + + case 0x85: + DPRINTK("smb_receive: Got SESSION KEEP ALIVE\n"); + sock->ops->recvfrom(sock, (void *)peek_buf, 4, 1, + 0, NULL, NULL); + goto re_recv; + + default: + printk("smb_receive: Invalid packet\n"); + return -EIO; + } + + /* Length not including first four bytes. */ + len = smb_len(peek_buf) + 4; + if (len > server->max_xmit) { + printk("smb_receive: Received length (%d) > max_xmit (%d)!\n", + len, server->max_xmit); + return -EIO; + } + else + { + int already_read = 0; + + while (already_read < len) { + + result = sock->ops-> + recvfrom(sock, + (void *)(server->packet+already_read), + len - already_read, 0, 0, + NULL, NULL); + + if (result < 0) { + printk("SMB: notice message: error = %d\n", + -result); + return result; + } + + already_read += result; + } + result = already_read; + } + + server->rcls = *((unsigned char *)(server->packet+9)); + server->err = *((unsigned short *)(server->packet+11)); + + if (server->rcls != 0) { + DPRINTK("smb_response: rcls=%d, err=%d\n", + server->rcls, server->err); + } + + return result; +} + + +/* + * smb_receive's preconditions also apply here. + */ +static int +smb_receive_trans2(struct smb_server *server, struct socket *sock, + int *data_len, int *param_len, + char **data, char **param) +{ + int total_data=0; + int total_param=0; + int result; + unsigned char *inbuf = server->packet; + + *data_len = *param_len = 0; + + DDPRINTK("smb_receive_trans2: enter\n"); + + if ((result = smb_receive(server, sock)) < 0) { + return result; + } + + if (server->rcls != 0) { + return result; + } + + /* parse out the lengths */ + total_data = WVAL(inbuf,smb_tdrcnt); + total_param = WVAL(inbuf,smb_tprcnt); + + if ( (total_data > TRANS2_MAX_TRANSFER) + || (total_param > TRANS2_MAX_TRANSFER)) { + printk("smb_receive_trans2: data/param too long\n"); + return -EIO; + } + + /* allocate it */ + if ((*data = smb_kmalloc(total_data, GFP_KERNEL)) == NULL) { + printk("smb_receive_trans2: could not alloc data area\n"); + return -ENOMEM; + } + + if ((*param = smb_kmalloc(total_param, GFP_KERNEL)) == NULL) { + printk("smb_receive_trans2: could not alloc param area\n"); + smb_kfree_s(*data, total_data); + return -ENOMEM; + } + + DDPRINTK("smb_rec_trans2: total_data/param: %d/%d\n", + total_data, total_param); + + while (1) + { + if (WVAL(inbuf,smb_prdisp)+WVAL(inbuf, smb_prcnt) + > total_param) { + printk("smb_receive_trans2: invalid parameters\n"); + result = -EIO; + goto fail; + } + memcpy(*param + WVAL(inbuf,smb_prdisp), + smb_base(inbuf) + WVAL(inbuf,smb_proff), + WVAL(inbuf,smb_prcnt)); + *param_len += WVAL(inbuf,smb_prcnt); + + + if (WVAL(inbuf,smb_drdisp)+WVAL(inbuf, smb_drcnt)>total_data) { + printk("smb_receive_trans2: invalid data block\n"); + result = -EIO; + goto fail; + } + memcpy(*data + WVAL(inbuf,smb_drdisp), + smb_base(inbuf) + WVAL(inbuf,smb_droff), + WVAL(inbuf,smb_drcnt)); + *data_len += WVAL(inbuf,smb_drcnt); + + DDPRINTK("smb_rec_trans2: drcnt/prcnt: %d/%d\n", + WVAL(inbuf, smb_drcnt), WVAL(inbuf, smb_prcnt)); + + /* parse out the total lengths again - they can shrink! */ + + if ( (WVAL(inbuf,smb_tdrcnt) > total_data) + || (WVAL(inbuf,smb_tprcnt) > total_param)) { + printk("smb_receive_trans2: data/params grew!\n"); + result = -EIO; + goto fail; + } + + total_data = WVAL(inbuf,smb_tdrcnt); + total_param = WVAL(inbuf,smb_tprcnt); + + if (total_data <= *data_len && total_param <= *param_len) + break; + + if ((result = smb_receive(server, sock)) < 0) { + goto fail; + } + if (server->rcls != 0) { + result = -EIO; + goto fail; + } + } + + DDPRINTK("smb_receive_trans2: normal exit\n"); + + return 0; + + fail: + DPRINTK("smb_receive_trans2: failed exit\n"); + + smb_kfree_s(*param, 0); *param = NULL; + smb_kfree_s(*data, 0); *data = NULL; + return result; +} + +static inline struct socket * +server_sock(struct smb_server *server) +{ + struct file *file; + struct inode *inode; + + if (server == NULL) + return NULL; + if ((file = server->sock_file) == NULL) + return NULL; + if ((inode = file->f_inode) == NULL) + return NULL; + return &(inode->u.socket_i); +} + +int +smb_release(struct smb_server *server) +{ + struct socket *sock = server_sock(server); + int result; + + if (sock == NULL) + return -EINVAL; + + result = sock->ops->release(sock, NULL); + DPRINTK("smb_release: sock->ops->release = %d\n", result); + + /* inet_release does not set sock->state. Maybe someone is + confused about sock->state being SS_CONNECTED while there + is nothing behind it, so I set it to SS_UNCONNECTED.*/ + sock->state = SS_UNCONNECTED; + + result = sock->ops->create(sock, 0); + DPRINTK("smb_release: sock->ops->create = %d\n", result); + return result; +} + +int +smb_connect(struct smb_server *server) +{ + struct socket *sock = server_sock(server); + if (sock == NULL) + return -EINVAL; + if (sock->state != SS_UNCONNECTED) { + DPRINTK("smb_connect: socket is not unconnected: %d\n", + sock->state); + } + return sock->ops->connect(sock, (struct sockaddr *)&(server->m.addr), + sizeof(struct sockaddr_in), 0); +} + +/*****************************************************************************/ +/* */ +/* This routine was once taken from nfs, wich is for udp. Here TCP does */ +/* most of the ugly stuff for us (thanks, Alan!) */ +/* */ +/*****************************************************************************/ +int +smb_request(struct smb_server *server) +{ + unsigned long old_mask; + unsigned short fs; /* We fool the kernel to believe + we call from user space. */ + int len, result, result2; + + struct socket *sock = server_sock(server); + unsigned char *buffer = (server == NULL) ? NULL : server->packet; + + if ((sock == NULL) || (buffer == NULL)) { + printk("smb_request: Bad server!\n"); + return -EBADF; + } + + if (server->state != CONN_VALID) + return -EIO; + +#if 0 + while (server->lock) + sleep_on(&server->wait); + server->lock = 1; +#endif + + if ((result = smb_dont_catch_keepalive(server)) != 0) { + server->state = CONN_INVALID; + smb_invalidate_all_inodes(server); + return result; + } + + len = smb_len(buffer) + 4; + + DDPRINTK("smb_request: len = %d cmd = 0x%X\n", len, buffer[8]); + + old_mask = current->blocked; + current->blocked |= ~(_S(SIGKILL) | _S(SIGSTOP)); + fs = get_fs(); + set_fs(get_ds()); + + result = sock->ops->send(sock, (void *)buffer, len, 0, 0); + if (result < 0) { + printk("smb_request: send error = %d\n", result); + } + else { + result = smb_receive(server, sock); + } + + /* read/write errors are handled by errno */ + current->signal &= ~_S(SIGPIPE); + + current->blocked = old_mask; + set_fs(fs); + + if ((result2 = smb_catch_keepalive(server)) < 0) { + result = result2; + } + +#if 0 + server->lock = 0; + wake_up(&server->wait); +#endif + + if (result < 0) { + server->state = CONN_INVALID; + smb_invalidate_all_inodes(server); + } + + DDPRINTK("smb_request: result = %d\n", result); + + return result; +} + +/* + * This is not really a trans2 request, we assume that you only have + * one packet to send. + */ +int +smb_trans2_request(struct smb_server *server, + int *data_len, int *param_len, + char **data, char **param) +{ + unsigned long old_mask; + unsigned short fs; /* We fool the kernel to believe + we call from user space. */ + int len, result, result2; + + struct socket *sock = server_sock(server); + unsigned char *buffer = (server == NULL) ? NULL : server->packet; + + if ((sock == NULL) || (buffer == NULL)) { + printk("smb_trans2_request: Bad server!\n"); + return -EBADF; + } + + if (server->state != CONN_VALID) + return -EIO; + +#if 0 + while (server->lock) + sleep_on(&server->wait); + server->lock = 1; +#endif + + if ((result = smb_dont_catch_keepalive(server)) != 0) { + server->state = CONN_INVALID; + smb_invalidate_all_inodes(server); + return result; + } + + len = smb_len(buffer) + 4; + + DDPRINTK("smb_request: len = %d cmd = 0x%X\n", len, buffer[8]); + + old_mask = current->blocked; + current->blocked |= ~(_S(SIGKILL) | _S(SIGSTOP)); + fs = get_fs(); + set_fs(get_ds()); + + result = sock->ops->send(sock, (void *)buffer, len, 0, 0); + if (result < 0) { + printk("smb_trans2_request: send error = %d\n", result); + } + else { + result = smb_receive_trans2(server, sock, + data_len, param_len, + data, param); + } + + /* read/write errors are handled by errno */ + current->signal &= ~_S(SIGPIPE); + + current->blocked = old_mask; + set_fs(fs); + + if ((result2 = smb_catch_keepalive(server)) < 0) { + result = result2; + } + +#if 0 + server->lock = 0; + wake_up(&server->wait); +#endif + + if (result < 0) { + server->state = CONN_INVALID; + smb_invalidate_all_inodes(server); + } + + DDPRINTK("smb_trans2_request: result = %d\n", result); + + return result; +} + +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * Emacs will notice this stuff at the end of the file and automatically + * adjust the settings for this buffer only. This must remain at the end + * of the file. + * --------------------------------------------------------------------------- + * Local variables: + * c-indent-level: 8 + * c-brace-imaginary-offset: 0 + * c-brace-offset: -8 + * c-argdecl-indent: 8 + * c-label-offset: -8 + * c-continued-statement-offset: 8 + * c-continued-brace-offset: 0 + * End: + */ diff -u --recursive --new-file v1.3.6/linux/fs/umsdos/dir.c linux/fs/umsdos/dir.c --- v1.3.6/linux/fs/umsdos/dir.c Tue Jun 27 14:11:44 1995 +++ linux/fs/umsdos/dir.c Tue Jul 4 07:48:57 1995 @@ -50,7 +50,7 @@ */ static int umsdos_dir_once( void * buf, - char * name, + const char * name, int name_len, off_t offset, ino_t ino) @@ -58,10 +58,12 @@ int ret = -EINVAL; struct UMSDOS_DIR_ONCE *d = (struct UMSDOS_DIR_ONCE *)buf; if (d->count == 0){ - char zname[100]; - memcpy (zname,name,name_len); - zname[name_len] = '\0'; - PRINTK (("dir_once :%s: offset %ld\n",zname,offset)); + #if 0 + char zname[100]; + memcpy (zname,name,name_len); + zname[name_len] = '\0'; + Printk (("dir_once :%s: offset %Ld\n",zname,offset)); + #endif ret = d->filldir (d->dirbuf,name,name_len,offset,ino); d->stop = ret < 0; d->count = 1; @@ -160,6 +162,7 @@ }else{ struct inode *emd_dir = umsdos_emd_dir_lookup(dir,0); if (emd_dir != NULL){ + off_t start_fpos = filp->f_pos; if (filp->f_pos <= UMSDOS_SPECIAL_DIRFPOS+1) filp->f_pos = 0; PRINTK (("f_pos %lu i_size %ld\n",filp->f_pos,emd_dir->i_size)); ret = 0; @@ -246,12 +249,12 @@ (see comments at the beginning), we put back the special offset. */ - if (filp->f_pos == 0) filp->f_pos = UMSDOS_SPECIAL_DIRFPOS; + if (filp->f_pos == 0) filp->f_pos = start_fpos; iput(emd_dir); } } umsdos_endlookup(dir); - PRINTK (("read dir %p pos %lu ret %d\n",dir,filp->f_pos,ret)); + PRINTK (("read dir %p pos %Ld ret %d\n",dir,filp->f_pos,ret)); return ret; } /* @@ -279,7 +282,7 @@ if (bufk.count == 0) break; count += bufk.count; } - PRINTK (("UMSDOS_readdir out %d count %d pos %lu\n",ret,count + PRINTK (("UMSDOS_readdir out %d count %d pos %Ld\n",ret,count ,filp->f_pos)); return count == 0 ? -ENOENT : ret; } @@ -349,6 +352,42 @@ inode->i_mtime = entry->mtime; inode->i_uid = entry->uid; inode->i_gid = entry->gid; + /* #Specification: umsdos / conversion mode + The msdos fs can do some inline conversion + of the data of a file. It can translate + silently from MsDOS text file format to Unix + one (crlf -> lf) while reading, and the reverse + while writting. This is activated using the mount + option conv=.... + + This is not useful for Linux file in promoted + directory. It can even be harmful. For this + reason, the binary (no conversion) mode is + always activated. + */ + /* #Specification: umsdos / conversion mode / todo + A flag could be added to file and directories + forcing an automatic conversion mode (as + done with the msdos fs). + + This flag could be setup on a directory basis + (instead of file) and all file in it would + logically inherited. If the conversion mode + is active (conv=) then the i_binary flag would + be left untouched in those directories. + + It was proposed that the sticky bit was used + to set this. The problem is that new file would + be written incorrectly. The other problem is that + the sticky bit has a meaning for directories. So + another bit should be used (there is some space + in the EMD file for it) and a special utilities + would be used to assign the flag to a directory). + I don't think it is useful to assign this flag + on a single file. + */ + + MSDOS_I(inode)->i_binary = 1; /* #Specification: umsdos / i_nlink The nlink field of an inode is maintain by the MSDOS file system for directory and by UMSDOS for other file. The logic is that @@ -380,7 +419,7 @@ */ static int umsdos_filldir_k( void * buf, - char * name, + const char * name, int name_len, off_t offset, ino_t ino) @@ -399,7 +438,7 @@ static int umsdos_dir_search ( void * buf, - char * name, + const char * name, int name_len, off_t offset, ino_t ino) diff -u --recursive --new-file v1.3.6/linux/fs/umsdos/emd.c linux/fs/umsdos/emd.c --- v1.3.6/linux/fs/umsdos/emd.c Tue Jun 27 14:11:44 1995 +++ linux/fs/umsdos/emd.c Tue Jul 4 07:48:57 1995 @@ -89,7 +89,7 @@ filp->f_flags = 0; sizeread = umsdos_file_read_kmem (emd_dir,filp,buf,count); if (sizeread != count){ - printk ("UMSDOS: problem with EMD file. Can't read pos = %ld (%d != %d)\n" + printk ("UMSDOS: problem with EMD file. Can't read pos = %Ld (%d != %d)\n" ,filp->f_pos,sizeread,count); ret = -EIO; } diff -u --recursive --new-file v1.3.6/linux/fs/umsdos/ioctl.c linux/fs/umsdos/ioctl.c --- v1.3.6/linux/fs/umsdos/ioctl.c Tue Jun 27 14:11:44 1995 +++ linux/fs/umsdos/ioctl.c Tue Jul 4 07:48:57 1995 @@ -11,6 +11,7 @@ #include #include +#include #include #include #include @@ -31,7 +32,7 @@ */ static int umsdos_ioctl_fill( void * buf, - char * name, + const char * name, int name_len, off_t offset, ino_t ino) @@ -65,7 +66,13 @@ Only root (effective id) is allowed to do IOCTL on directory in UMSDOS. EPERM is returned for other user. */ - if (current->euid == 0 + /* + Well, not all case require write access, but it simplify the code + and let's face it, there is only one client (umssync) for all this + */ + if (verify_area(VERIFY_WRITE,(void*)data,sizeof(struct umsdos_ioctl)) < 0){ + ret = -EFAULT; + }else if (current->euid == 0 || cmd == UMSDOS_GETVERSION){ struct umsdos_ioctl *idata = (struct umsdos_ioctl *)data; ret = -EINVAL; diff -u --recursive --new-file v1.3.6/linux/fs/umsdos/rdir.c linux/fs/umsdos/rdir.c --- v1.3.6/linux/fs/umsdos/rdir.c Tue Jun 27 14:11:44 1995 +++ linux/fs/umsdos/rdir.c Tue Jul 4 07:48:57 1995 @@ -36,7 +36,7 @@ static int rdir_filldir( void * buf, - char * name, + const char * name, int name_len, off_t offset, ino_t ino) diff -u --recursive --new-file v1.3.6/linux/include/asm-alpha/checksum.h linux/include/asm-alpha/checksum.h --- v1.3.6/linux/include/asm-alpha/checksum.h Fri Jun 16 22:02:55 1995 +++ linux/include/asm-alpha/checksum.h Thu Jul 6 13:22:05 1995 @@ -6,7 +6,7 @@ * This is a version of ip_compute_csum() optimized for IP headers, * which always checksum on 4 octet boundaries. */ -extern inline unsigned short ip_fast_csum(unsigned char * iph, unsigned int ihl); +extern unsigned short ip_fast_csum(unsigned char * iph, unsigned int ihl); /* * computes the checksum of the TCP/UDP pseudo-header @@ -33,14 +33,19 @@ extern unsigned int csum_partial(unsigned char * buff, int len, unsigned int sum); /* - * the same as csum_partial, but copies from fs:src while it + * the same as csum_partial, but copies from src while it * checksums * * here even more important to align src and dst on a 32-bit (or even * better 64-bit) boundary */ +unsigned int csum_partial_copy( char *src, char *dst, int len, int sum); -extern unsigned int csum_partial_copyffs( char *src, char *dst, int len, int sum); +/* + * the same as csum_partial, but copies from user space (but on the alpha + * we have just one address space, so this is identical to the above) + */ +#define csum_partial_copy_fromuser csum_partial_copy /* diff -u --recursive --new-file v1.3.6/linux/include/asm-alpha/elf.h linux/include/asm-alpha/elf.h --- v1.3.6/linux/include/asm-alpha/elf.h Thu Jan 1 02:00:00 1970 +++ linux/include/asm-alpha/elf.h Wed Jul 5 12:53:22 1995 @@ -0,0 +1,17 @@ +#ifndef __ASMaxp_ELF_H +#define __ASMaxp_ELF_H + +/* + * ELF register definitions.. + */ + +#define ELF_NGREG 32 +#define ELF_NFPREG 32 + +typedef unsigned long elf_greg_t; +typedef elf_greg_t elf_gregset_t[ELF_NGREG]; + +typedef double elf_fpreg_t; +typedef elf_fpreg_t elf_fpregset_t[ELF_NFPREG]; + +#endif diff -u --recursive --new-file v1.3.6/linux/include/asm-alpha/io.h linux/include/asm-alpha/io.h --- v1.3.6/linux/include/asm-alpha/io.h Thu Jun 29 19:02:54 1995 +++ linux/include/asm-alpha/io.h Thu Jul 6 13:22:05 1995 @@ -107,4 +107,20 @@ extern void outsw (unsigned long port, void *dst, unsigned long count); extern void outsl (unsigned long port, void *dst, unsigned long count); +/* + * The "address" in IO memory space is not clearly either a integer or a + * pointer. We will accept both, thus the casts. + */ +#define readb(addr) ((unsigned char) (readb)((unsigned long)(addr))) +#define readw(addr) ((unsigned short) (readw)((unsigned long)(addr))) +#define readl(addr) ((unsigned int) (readl)((unsigned long)(addr))) + +#define writeb(b,addr) (writeb)((b),(unsigned long)(addr)) +#define writew(w,addr) (writew)((w),(unsigned long)(addr)) +#define writel(l,addr) (writel)((l),(unsigned long)(addr)) + +#define memset_io(addr,c,len) (memset_io)((unsigned long)(addr),(c),(len)) +#define memcpy_fromio(to,from,len) (memcpy_fromio)((to),(unsigned long)(from),(len)) +#define memcpy_toio(to,from,len) (memcpy_toio)((unsigned long)(to),(from),(len)) + #endif diff -u --recursive --new-file v1.3.6/linux/include/asm-alpha/jensen.h linux/include/asm-alpha/jensen.h --- v1.3.6/linux/include/asm-alpha/jensen.h Fri Jun 2 13:51:16 1995 +++ linux/include/asm-alpha/jensen.h Thu Jul 6 13:22:05 1995 @@ -263,7 +263,7 @@ extern unsigned long readw(unsigned long addr); extern unsigned long readl(unsigned long addr); -extern void writeb(unsigned short b, unsigned long addr); +extern void writeb(unsigned char b, unsigned long addr); extern void writew(unsigned short b, unsigned long addr); extern void writel(unsigned int b, unsigned long addr); diff -u --recursive --new-file v1.3.6/linux/include/asm-alpha/lca.h linux/include/asm-alpha/lca.h --- v1.3.6/linux/include/asm-alpha/lca.h Thu Jun 29 19:02:54 1995 +++ linux/include/asm-alpha/lca.h Thu Jul 6 13:22:05 1995 @@ -292,7 +292,7 @@ extern unsigned long readb(unsigned long addr); extern unsigned long readw(unsigned long addr); -extern void writeb(unsigned short b, unsigned long addr); +extern void writeb(unsigned char b, unsigned long addr); extern void writew(unsigned short b, unsigned long addr); #define inb(port) \ diff -u --recursive --new-file v1.3.6/linux/include/asm-alpha/string.h linux/include/asm-alpha/string.h --- v1.3.6/linux/include/asm-alpha/string.h Fri Jun 2 13:51:17 1995 +++ linux/include/asm-alpha/string.h Wed Jul 5 12:53:22 1995 @@ -7,7 +7,7 @@ #define memset(s, c, count) \ (__builtin_constant_p(c) ? \ - __constant_c_memset((s),(0x01010101UL*(unsigned char)c),(count)) : \ + __constant_c_memset((s),(0x0101010101010101UL*(unsigned char)c),(count)) : \ __memset((s),(c),(count))) #define memcpy(d,s,count) __memcpy((d),(s),(count)) diff -u --recursive --new-file v1.3.6/linux/include/asm-i386/checksum.h linux/include/asm-i386/checksum.h --- v1.3.6/linux/include/asm-i386/checksum.h Fri Jun 30 16:22:30 1995 +++ linux/include/asm-i386/checksum.h Thu Jul 6 13:22:05 1995 @@ -16,15 +16,24 @@ unsigned int csum_partial(unsigned char * buff, int len, unsigned int sum); /* - * the same as csum_partial, but copies from fs:src while it + * the same as csum_partial, but copies from src while it * checksums * * here even more important to align src and dst on a 32-bit (or even * better 64-bit) boundary */ -unsigned int csum_partial_copyffs( char *src, char *dst, int len, int sum); +unsigned int csum_partial_copy( char *src, char *dst, int len, int sum); + +/* + * the same as csum_partial_copy, but copies from user space. + * + * here even more important to align src and dst on a 32-bit (or even + * better 64-bit) boundary + */ + +unsigned int csum_partial_copy_fromuser( char *src, char *dst, int len, int sum); /* * This is a version of ip_compute_csum() optimized for IP headers, diff -u --recursive --new-file v1.3.6/linux/include/asm-i386/elf.h linux/include/asm-i386/elf.h --- v1.3.6/linux/include/asm-i386/elf.h Thu Jan 1 02:00:00 1970 +++ linux/include/asm-i386/elf.h Wed Jul 5 12:53:22 1995 @@ -0,0 +1,17 @@ +#ifndef __ASMi386_ELF_H +#define __ASMi386_ELF_H + +/* + * ELF register definitions.. + */ + +#include + +typedef unsigned long elf_greg_t; + +#define ELF_NGREG (sizeof (struct pt_regs) / sizeof(elf_greg_t)) +typedef elf_greg_t elf_gregset_t[ELF_NGREG]; + +typedef struct user_i387_struct elf_fpregset_t; + +#endif diff -u --recursive --new-file v1.3.6/linux/include/asm-i386/segment.h linux/include/asm-i386/segment.h --- v1.3.6/linux/include/asm-i386/segment.h Tue Jun 27 14:11:44 1995 +++ linux/include/asm-i386/segment.h Sun Jul 2 21:26:28 1995 @@ -30,6 +30,7 @@ */ struct __segment_dummy { unsigned long a[100]; }; #define __sd(x) ((struct __segment_dummy *) (x)) +#define __const_sd(x) ((const struct __segment_dummy *) (x)) static inline void __put_user(unsigned long x, void * y, int size) { @@ -62,17 +63,17 @@ case 1: __asm__ ("movb %%fs:%1,%b0" :"=q" (result) - :"m" (*__sd(y))); + :"m" (*__const_sd(y))); return (unsigned char) result; case 2: __asm__ ("movw %%fs:%1,%w0" :"=r" (result) - :"m" (*__sd(y))); + :"m" (*__const_sd(y))); return (unsigned short) result; case 4: __asm__ ("movl %%fs:%1,%0" :"=r" (result) - :"m" (*__sd(y))); + :"m" (*__const_sd(y))); return result; default: return bad_user_access_length(); diff -u --recursive --new-file v1.3.6/linux/include/asm-i386/string.h linux/include/asm-i386/string.h --- v1.3.6/linux/include/asm-i386/string.h Tue Jun 27 14:11:44 1995 +++ linux/include/asm-i386/string.h Sun Jul 2 21:26:28 1995 @@ -365,17 +365,17 @@ case 0: return to; case 1: - *(unsigned char *)to = *(unsigned char *)from; + *(unsigned char *)to = *(const unsigned char *)from; return to; case 2: - *(unsigned short *)to = *(unsigned short *)from; + *(unsigned short *)to = *(const unsigned short *)from; return to; case 3: - *(unsigned short *)to = *(unsigned short *)from; - *(2+(unsigned char *)to) = *(2+(unsigned char *)from); + *(unsigned short *)to = *(const unsigned short *)from; + *(2+(unsigned char *)to) = *(2+(const unsigned char *)from); return to; case 4: - *(unsigned long *)to = *(unsigned long *)from; + *(unsigned long *)to = *(const unsigned long *)from; return to; } #define COMMON(x) \ diff -u --recursive --new-file v1.3.6/linux/include/linux/atalk.h linux/include/linux/atalk.h --- v1.3.6/linux/include/linux/atalk.h Thu Jan 1 02:00:00 1970 +++ linux/include/linux/atalk.h Wed Jul 5 13:06:27 1995 @@ -0,0 +1,144 @@ +/* + * Appletalk networking structures + * + * The following are directly referenced from the University Of Michigan + * netatalk for compatibility reasons. + */ + +#ifndef __LINUX_ATALK_H__ +#define __LINUX_ATALK_H__ + +#define ATPORT_FIRST 1 +#define ATPORT_RESERVED 128 +#define ATPORT_LAST 255 +#define ATADDR_ANYNET (__u16)0 +#define ATADDR_ANYNODE (__u8)0 +#define ATADDR_ANYPORT (__u8)0 +#define ATADDR_BCAST (__u8)255 +#define DDP_MAXSZ 587 + +struct at_addr +{ + __u16 s_net; + __u8 s_node; +}; + +struct sockaddr_at +{ + short sat_family; + __u8 sat_port; + struct at_addr sat_addr; + char sat_zero[ 8 ]; +}; + +struct netrange +{ + __u8 nr_phase; + __u16 nr_firstnet; + __u16 nr_lastnet; +}; + +struct atalk_route +{ + struct device *dev; + struct at_addr target; + struct at_addr gateway; + int flags; + struct atalk_route *next; +}; + +struct atalk_iface +{ + struct device *dev; + struct at_addr address; /* Our address */ + int status; /* What are we doing ?? */ +#define ATIF_PROBE 1 /* Probing for an address */ +#define ATIF_PROBE_FAIL 2 /* Probe collided */ + struct netrange nets; /* Associated direct netrange */ + struct atalk_iface *next; +}; + +struct atalk_sock +{ + unsigned short dest_net; + unsigned short src_net; + unsigned char dest_node; + unsigned char src_node; + unsigned char dest_port; + unsigned char src_port; +}; + +#define DDP_MAXHOPS 15 /* 4 bits of hop counter */ + +#ifdef __KERNEL__ + +struct ddpehdr +{ + /* FIXME for bigendians */ + /*__u16 deh_pad:2,deh_hops:4,deh_len:10;*/ + __u16 deh_len:10,deh_hops:4,deh_pad:2; + __u16 deh_sum; + __u16 deh_dnet; + __u16 deh_snet; + __u8 deh_dnode; + __u8 deh_snode; + __u8 deh_dport; + __u8 deh_sport; + /* And netatalk apps expect to stick the type in themselves */ +}; + +/* + * Unused (and currently unsupported) + */ + +struct ddpshdr +{ + /* FIXME for bigendians */ + __u8 dsh_sport; + __u8 dsh_dport; + __u16 dsh_len:10, dsh_pad:6; + /* And netatalk apps expect to stick the type in themselves */ +}; + +/* Appletalk AARP headers */ + +struct elapaarp +{ + __u16 hw_type; +#define AARP_HW_TYPE_ETHERNET 1 +#define AARP_HW_TYPE_TOKENRING 2 + __u16 pa_type; + __u8 hw_len; + __u8 pa_len; +#define AARP_PA_ALEN 4 + __u16 function; +#define AARP_REQUEST 1 +#define AARP_REPLY 2 +#define AARP_PROBE 3 + __u8 hw_src[ETH_ALEN] __attribute__ ((packed)); + __u8 pa_src_zero __attribute__ ((packed)); + __u16 pa_src_net __attribute__ ((packed)); + __u8 pa_src_node __attribute__ ((packed)); + __u8 hw_dst[ETH_ALEN] __attribute__ ((packed)); + __u8 pa_dst_zero __attribute__ ((packed)); + __u16 pa_dst_net __attribute__ ((packed)); + __u8 pa_dst_node __attribute__ ((packed)); +}; + +typedef struct sock atalk_socket; + +#define AARP_EXPIRY_TIME (5*60*HZ) /* Not specified - how long till we drop a resolved entry */ +#define AARP_HASH_SIZE 16 /* Size of hash table */ +#define AARP_TICK_TIME (HZ/5) /* Fast retransmission timer when resolving */ +#define AARP_RETRANSMIT_LIMIT 10 /* Send 10 requests then give up (2 seconds) */ +#define AARP_RESOLVE_TIME (10*HZ) /* Some value bigger than total retransmit time + a bit for last reply to appear and to stop continual requests */ + +extern struct datalink_proto *ddp_dl, *aarp_dl; +extern void aarp_proto_init(void); +/* Inter module exports */ +extern struct atalk_iface *atalk_find_dev(struct device *dev); +extern struct at_addr *atalk_find_dev_addr(struct device *dev); +extern int aarp_send_ddp(struct device *dev,struct sk_buff *skb, struct at_addr *sa, void *hwaddr); +extern void aarp_send_probe(struct device *dev, struct at_addr *addr); +#endif +#endif diff -u --recursive --new-file v1.3.6/linux/include/linux/cdrom.h linux/include/linux/cdrom.h --- v1.3.6/linux/include/linux/cdrom.h Wed Jan 18 07:51:45 1995 +++ linux/include/linux/cdrom.h Sat Jul 1 19:05:59 1995 @@ -414,4 +414,14 @@ */ #define CDROMMULTISESSION 0x5310 /* (struct cdrom_multisession) */ +/* + * obtain the "universal product code" number + * (only some data disks have it coded) + */ +#define CDROM_GET_UPC 0x5311 /* 8 bytes returned */ + +#define CDROMRESET 0x5312 /* hard-reset the drive */ +#define CDROMVOLREAD 0x5313 /* let the drive tell its volume setting */ + /* (struct cdrom_volctrl) */ + #endif _LINUX_CDROM_H diff -u --recursive --new-file v1.3.6/linux/include/linux/cm206.h linux/include/linux/cm206.h --- v1.3.6/linux/include/linux/cm206.h Thu Jan 1 02:00:00 1970 +++ linux/include/linux/cm206.h Sat Jul 1 19:05:59 1995 @@ -0,0 +1,126 @@ +/* cm206.h Header file for cm206.c. + Copyright (c) 1995 David van Leeuwen +*/ + +/* First, the cm260 stuff */ +/* The ports and irq used. If it is not defined, make it variable, + and initialize them at some reasonable value */ + +#define CM206_BASE 0x340 +#define CM206_IRQ 11 + +#define r_data_status (CM206_BASE) +#define r_uart_receive (CM206_BASE+0x2) +#define r_fifo_output_buffer (CM206_BASE+0x4) +#define r_line_status (CM206_BASE+0x6) +#define r_data_control (CM206_BASE+0x8) +#define r_uart_transmit (CM206_BASE+0xa) +#define r_test_clock (CM206_BASE+0xc) +#define r_test_control (CM206_BASE+0xe) + +/* the data_status flags */ +#define ds_ram_size 0x4000 +#define ds_toc_ready 0x2000 +#define ds_fifo_empty 0x1000 +#define ds_sync_error 0x800 +#define ds_crc_error 0x400 +#define ds_data_error 0x200 +#define ds_fifo_overflow 0x100 +#define ds_data_ready 0x80 + +/* the line_status flags */ +#define ls_attention 0x10 +#define ls_parity_error 0x8 +#define ls_overrun 0x4 +#define ls_receive_buffer_full 0x2 +#define ls_transmitter_buffer_empty 0x1 + +/* the data control register flags */ +#define dc_read_q_channel 0x4000 +#define dc_mask_sync_error 0x2000 +#define dc_toc_enable 0x1000 +#define dc_no_stop_on_error 0x800 +#define dc_break 0x400 +#define dc_initialize 0x200 +#define dc_mask_transmit_ready 0x100 +#define dc_flag_enable 0x80 + +#define dc_normal (dc_mask_sync_error | dc_no_stop_on_error | \ + dc_mask_transmit_ready) + +/* now some constants related to the cm206 */ +/* another drive status byte, echoed by the cm206 on most commmands */ + +#define dsb_error_condition 0x1 +#define dsb_play_in_progress 0x4 +#define dsb_possible_media_change 0x8 +#define dsb_disc_present 0x10 +#define dsb_drive_not_ready 0x20 +#define dsb_tray_locked 0x40 +#define dsb_tray_not_closed 0x80 + +#define dsb_not_useful (dsb_drive_not_ready | dsb_tray_not_closed) + +/* the cm206 command set */ + +#define c_close_tray 0 +#define c_lock_tray 0x01 +#define c_unlock_tray 0x04 +#define c_open_tray 0x05 +#define c_seek 0x10 +#define c_read_data 0x20 +#define c_force_1x 0x21 +#define c_force_2x 0x22 +#define c_auto_mode 0x23 +#define c_play 0x30 +#define c_set_audio_mode 0x31 +#define c_read_current_q 0x41 +#define c_stream_q 0x42 +#define c_drive_status 0x50 +#define c_disc_status 0x51 +#define c_audio_status 0x52 +#define c_drive_configuration 0x53 +#define c_read_upc 0x60 +#define c_stop 0x70 +#define c_calc_checksum 0xe5 + +#define c_gimme 0xf8 + +/* finally, the (error) condition that the drive can be in * + * OK, this is not always an error, but let's prefix it with e_ */ + +#define e_none 0 +#define e_illegal_command 0x01 +#define e_sync 0x02 +#define e_seek 0x03 +#define e_parity 0x04 +#define e_focus 0x05 +#define e_header_sync 0x06 +#define e_code_incompatibility 0x07 +#define e_reset_done 0x08 +#define e_bad_parameter 0x09 +#define e_radial 0x0a +#define e_sub_code 0x0b +#define e_no_data_track 0x0c +#define e_scan 0x0d +#define e_tray_open 0x0f +#define e_no_disc 0x10 +#define e_tray stalled 0x11 + +/* drive configuration masks */ + +#define dcf_revision_code 0x7 +#define dcf_transfer_rate 0x60 +#define dcf_motorized_tray 0x80 + +/* disc status byte */ + +#define cds_multi_session 0x2 +#define cds_all_audio 0x8 +#define cds_xa_mode 0xf0 + +/* finally some ioctls for the driver */ + +#define CM206CTL_GET_STAT 0x2000 +#define CM206CTL_GET_LAST_STAT 0x2001 +#define CM206_RESET_DRIVE 0x2002 /* use with care */ diff -u --recursive --new-file v1.3.6/linux/include/linux/elfcore.h linux/include/linux/elfcore.h --- v1.3.6/linux/include/linux/elfcore.h Thu Jun 29 19:02:55 1995 +++ linux/include/linux/elfcore.h Wed Jul 5 12:53:22 1995 @@ -14,16 +14,7 @@ int si_errno; /* errno */ }; -typedef unsigned long elf_greg_t; -#define ELF_NGREG (sizeof (struct pt_regs) / sizeof(elf_greg_t)) -typedef elf_greg_t elf_gregset_t[ELF_NGREG]; -typedef struct -#ifdef __i386__ - user_i387_struct -#else -#error "The FPU in this arch is not supported by ELF core dump.". -#endif -elf_fpregset_t; +#include #ifndef __KERNEL__ typedef elf_greg_t greg_t; diff -u --recursive --new-file v1.3.6/linux/include/linux/genhd.h linux/include/linux/genhd.h --- v1.3.6/linux/include/linux/genhd.h Wed Dec 1 14:44:15 1993 +++ linux/include/linux/genhd.h Wed Jul 5 12:53:22 1995 @@ -8,6 +8,12 @@ * * */ + +#define CONFIG_MSDOS_PARTITION 1 + +#ifdef __alpha__ +#define CONFIG_OSF_PARTITION 1 +#endif #define EXTENDED_PARTITION 5 diff -u --recursive --new-file v1.3.6/linux/include/linux/gscd.h linux/include/linux/gscd.h --- v1.3.6/linux/include/linux/gscd.h Thu Jan 1 02:00:00 1970 +++ linux/include/linux/gscd.h Sat Jul 1 19:06:00 1995 @@ -0,0 +1,110 @@ +/* + * Definitions for a GoldStar R420 CD-ROM interface + * + * Copyright (C) 1995 Oliver Raupach + * Eberhard Moenkeberg + * + * Published under the GPL. + * + */ + + +/* The Interface Card default address is 0x340. This will work fo most + applications. Address selection is accomplished by jumpers PN801-1 to + PN801-4 on the GoldStar Interface Card. + Appropriate settings are: 0x300, 0x310, 0x320, 0x330, 0x340, 0x350, 0x360 + 0x370, 0x380, 0x390, 0x3A0, 0x3B0, 0x3C0, 0x3D0, 0x3E0, 0x3F0 */ + +/* insert here the I/O port address */ +#define GSCD_BASE_ADDR 0x340 + +/* change this to set the dma-channel */ +#define GSCD_DMA_CHANNEL 3 /* not used */ + +/************** nothing to set up below here *********************/ + +/* port access macro */ +#define GSCDPORT(x) (gscd_port + (x)) + +/* + * commands + * the lower nibble holds the command length + */ +#define CMD_STATUS 0x01 +#define CMD_READSUBQ 0x02 /* 1: ?, 2: UPC, 5: ? */ +#define CMD_SEEK 0x05 /* read_mode M-S-F */ +#define CMD_READ 0x07 /* read_mode M-S-F nsec_h nsec_l */ +#define CMD_RESET 0x11 +#define CMD_SETMODE 0x15 +#define CMD_PLAY 0x17 /* M-S-F M-S-F */ +#define CMD_LOCK_CTL 0x22 /* 0: unlock, 1: lock */ +#define CMD_IDENT 0x31 +#define CMD_SETSPEED 0x32 /* 0: auto */ /* ??? */ +#define CMD_GETMODE 0x41 +#define CMD_PAUSE 0x51 +#define CMD_READTOC 0x61 +#define CMD_DISKINFO 0x71 +#define CMD_TRAY_CTL 0x81 + +/* + * disk_state: + */ +#define ST_PLAYING 0x80 +#define ST_UNLOCKED 0x40 +#define ST_NO_DISK 0x20 +#define ST_DOOR_OPEN 0x10 +#define ST_x08 0x08 +#define ST_x04 0x04 +#define ST_INVALID 0x02 +#define ST_x01 0x01 + +/* + * cmd_type: + */ +#define TYPE_INFO 0x01 +#define TYPE_DATA 0x02 + +/* + * read_mode: + */ +#define MOD_POLLED 0x80 +#define MOD_x08 0x08 +#define MOD_RAW 0x04 + +#define READ_DATA(port, buf, nr) insb(port, buf, nr) + +#define SET_TIMER(func, jifs) \ + ((timer_table[GSCD_TIMER].expires = jiffies + jifs), \ + (timer_table[GSCD_TIMER].fn = func), \ + (timer_active |= 1< * Donald Becker, + * Alan Cox, + * Steve Whitehouse, * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -33,9 +35,18 @@ #define ETH_P_ECHO 0x0200 /* Ethernet Echo packet */ #define ETH_P_PUP 0x0400 /* Xerox PUP packet */ #define ETH_P_IP 0x0800 /* Internet Protocol packet */ +#define ETH_P_X25 0x0805 /* CCITT X.25 */ #define ETH_P_ARP 0x0806 /* Address Resolution packet */ +#define ETH_P_BPQ 0x08FF /* G8BPQ AX.25 Ethernet Packet [ NOT AN OFFICIALLY REGISTERED ID ] */ +#define ETH_P_DEC 0x6000 /* DEC Assigned proto */ +#define ETH_P_DNA_DL 0x6001 /* DEC DNA Dump/Load */ +#define ETH_P_DNA_RC 0x6002 /* DEC DNA Remote Console */ +#define ETH_P_DNA_RT 0x6003 /* DEC DNA Routing */ +#define ETH_P_LAT 0x6004 /* DEC LAT */ +#define ETH_P_DIAG 0x6005 /* DEC Diagnostics */ +#define ETH_P_CUST 0x6006 /* DEC Customer use */ +#define ETH_P_SCA 0x6007 /* DEC Systems Comms Arch */ #define ETH_P_RARP 0x8035 /* Reverse Addr Res packet */ -#define ETH_P_X25 0x0805 /* CCITT X.25 */ #define ETH_P_ATALK 0x809B /* Appletalk DDP */ #define ETH_P_AARP 0x80F3 /* Appletalk AARP */ #define ETH_P_IPX 0x8137 /* IPX over DIX */ @@ -44,6 +55,8 @@ #define ETH_P_ALL 0x0003 /* Every packet (be careful!!!) */ #define ETH_P_802_2 0x0004 /* 802.2 frames */ #define ETH_P_SNAP 0x0005 /* Internal only */ +#define ETH_P_DDCMP 0x0006 /* DEC DDCMP: Internal only */ + /* This is an Ethernet frame header. */ struct ethhdr { unsigned char h_dest[ETH_ALEN]; /* destination eth addr */ diff -u --recursive --new-file v1.3.6/linux/include/linux/in.h linux/include/linux/in.h --- v1.3.6/linux/include/linux/in.h Thu Feb 23 13:32:05 1995 +++ linux/include/linux/in.h Wed Jul 5 12:53:22 1995 @@ -18,6 +18,7 @@ #ifndef _LINUX_IN_H #define _LINUX_IN_H +#include /* Standard well-defined IP protocols. */ enum { @@ -38,7 +39,7 @@ /* Internet address. */ struct in_addr { - unsigned long int s_addr; + __u32 s_addr; }; /* Request struct for multicast socket ops */ diff -u --recursive --new-file v1.3.6/linux/include/linux/interrupt.h linux/include/linux/interrupt.h --- v1.3.6/linux/include/linux/interrupt.h Mon May 29 11:13:51 1995 +++ linux/include/linux/interrupt.h Sat Jul 1 19:06:00 1995 @@ -27,7 +27,8 @@ NET_BH, IMMEDIATE_BH, KEYBOARD_BH, - CYCLADES_BH + CYCLADES_BH, + CM206_BH }; extern inline void mark_bh(int nr) diff -u --recursive --new-file v1.3.6/linux/include/linux/major.h linux/include/linux/major.h --- v1.3.6/linux/include/linux/major.h Tue Apr 11 08:03:29 1995 +++ linux/include/linux/major.h Sat Jul 1 19:06:00 1995 @@ -33,11 +33,11 @@ * 13 - xt disk * 14 - sound card * 15 - cdu31a cdrom - * 16 - sockets - * 17 - af_unix - * 18 - af_inet + * 16 - sockets goldstar cdrom + * 17 - af_unix optics cdrom + * 18 - af_inet sanyo cdrom * 19 - cyclades /dev/ttyC* - * 20 - cyclades /dev/cub* + * 20 - cyclades /dev/cub* mitsumi (mcdx) cdrom * 21 - scsi generic * 22 - (at2disk) * 23 - mitsumi cdrom @@ -47,6 +47,7 @@ * 27 - qic117 tape matsushita cdrom 3 minors 0..3 * 28 - matsushita cdrom 4 minors 0..3 * 29 - aztech/orchid/okano/wearnes cdrom + * 32 - philips/lms cm206 cdrom */ #define UNNAMED_MAJOR 0 @@ -67,20 +68,25 @@ #define SOUND_MAJOR 14 #define CDU31A_CDROM_MAJOR 15 #define SOCKET_MAJOR 16 +#define GOLDSTAR_CDROM_MAJOR 16 #define AF_UNIX_MAJOR 17 +#define OPTICS_CDROM_MAJOR 17 #define AF_INET_MAJOR 18 +#define SANYO_CDROM_MAJOR 18 #define CYCLADES_MAJOR 19 #define CYCLADESAUX_MAJOR 20 +#define MITSUMI_X_CDROM_MAJOR 20 #define SCSI_GENERIC_MAJOR 21 #define IDE1_MAJOR 22 #define MITSUMI_CDROM_MAJOR 23 #define CDU535_CDROM_MAJOR 24 #define MATSUSHITA_CDROM_MAJOR 25 #define MATSUSHITA_CDROM2_MAJOR 26 +#define QIC117_TAPE_MAJOR 27 #define MATSUSHITA_CDROM3_MAJOR 27 #define MATSUSHITA_CDROM4_MAJOR 28 -#define QIC117_TAPE_MAJOR 27 #define AZTECH_CDROM_MAJOR 29 +#define CM206_CDROM_MAJOR 32 /* * Tests for SCSI devices. diff -u --recursive --new-file v1.3.6/linux/include/linux/mcdx.h linux/include/linux/mcdx.h --- v1.3.6/linux/include/linux/mcdx.h Thu Jan 1 02:00:00 1970 +++ linux/include/linux/mcdx.h Sat Jul 1 19:06:00 1995 @@ -0,0 +1,161 @@ +/* + * Definitions for the Mitsumi CDROM interface + * Copyright (C) 1995 Heiko Schlittermann + * VERSION: @VERSION@ + * + * 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; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Thanks to + * The Linux Community at all and ... + * Martin Harris (he wrote the first Mitsumi Driver) + * Eberhard Moenkeberg (he gave me much support and the initial kick) + * Bernd Huebner, Ruediger Helsch (Unifix-Software Gmbh, they + * improved the original driver) + * John Tombs, Bjorn Ekwall (module support) + * Daniel v. Mosnenck (he sent me the Technical and Programming Reference) + * Gerd Knorr (he lent me his PhotoCD) + * Nils Faerber and Roger E. Wolff (extensivly tested the LU portion) + * ... somebody forgotten? + * + */ + +/* + * The following lines are for user configuration + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * + * {0|1} -- 1 if you want the driver detect your drive, may crash and + * needs a long time to seek. The higher the address the longer the + * seek. + * + * WARNING: AUTOPROBE doesn't work. + */ +#define MCDX_AUTOPROBE 0 + +/* + * Drive specific settings according to the jumpers on the controller + * board(s). + * o MCDX_NDRIVES : number of used entries of the following table + * o MCDX_DRIVEMAP : table of {i/o base, irq} per controller + * + * NOTE: I didn't get a drive at irq 9(2) working. Not even alone. + */ +#if MCDX_AUTOPROBE == 0 + #define MCDX_NDRIVES 1 + #define MCDX_DRIVEMAP { \ + {0x300, 10}, \ + {0x304, 05}, \ + {0x000, 00}, \ + {0x000, 00}, \ + {0x000, 00}, \ + } +#else + #error Autoprobing is not implemented yet. +#endif + +/* The name of the device */ +#define MCD "mcdx" + +#ifdef NOWARN +#define WARN(x) +#else +#define WARN(x) warn x +#endif + +#if MCDX_DEBUG +#define TRACE(x) trace x +#define INIT 0 +#define MALLOC 0 +#define IOCTL 0 +#define OPENCLOSE 0 +#define HW 0 +#define TALK 0 +#define IRQ 0 +#define TRANSFER 0 +#define REQUEST 0 +#define MCDX_DEBUG_TALK 0 +#else +#define TRACE(x) +#endif + +/* The following addresses are taken from the Mitsumi Reference + * and describe the possible i/o range for the controller. + */ +#define MCDX_IO_BEGIN ((char*) 0x300) /* first base of i/o addr */ +#define MCDX_IO_END ((char*) 0x3fc) /* last base of i/o addr */ + +/* Per controller 4 bytes i/o are needed. */ +#define MCDX_IO_SIZE 4 + +/* + * The Ports & bits + */ + +#define MCDX_RBIT_OPEN 0x80 +#define MCDX_RBIT_DISKSET 0x40 +#define MCDX_RBIT_CHANGED 0x20 +#define MCDX_RBIT_CHECK 0x10 +#define MCDX_RBIT_AUDIOTR 0x08 +#define MCDX_RBIT_RDERR 0x04 +#define MCDX_RBIT_AUDIOBS 0x02 +#define MCDX_RBIT_CMDERR 0x01 +#define MCDX_RBIT_DOOR 0x10 +#define MCDX_RBIT_STEN 0x04 +#define MCDX_RBIT_DTEN 0x02 + + +/* + * The commands. + */ + +#define OPCODE 1 /* offset of opcode */ +#define MCDX_CMD_REQUEST_TOC 1, 0x10 +#define MCDX_CMD_REQUEST_STATUS 1, 0x40 +#define MCDX_CMD_RESET 1, 0x60 +#define MCDX_CMD_REQUEST_DRIVE_MODE 1, 0xc2 +#define MCDX_CMD_SET_INTERLEAVE 2, 0xc8, 0 +#define MCDX_CMD_DATAMODE_SET 2, 0xa0, 0 + #define MCDX_DATAMODE1 0x01 + #define MCDX_DATAMODE2 0x02 +#define MCDX_CMD_LOCK_DOOR 2, 0xfe, 0 + +#define READ_AHEAD 4 /* 8 Sectors (4K) */ + +/* Useful macros */ +#define e_door(x) ((x) & MCDX_RBIT_OPEN) +#define e_check(x) (~(x) & MCDX_RBIT_CHECK) +#define e_notset(x) (~(x) & MCDX_RBIT_DISKSET) +#define e_changed(x) ((x) & MCDX_RBIT_CHANGED) +#define e_audio(x) ((x) & MCDX_RBIT_AUDIOTR) +#define e_audiobusy(x) ((x) & MCDX_RBIT_AUDIOBS) +#define e_cmderr(x) ((x) & MCDX_RBIT_CMDERR) +#define e_readerr(x) ((x) & MCDX_RBIT_RDERR) + +/** no drive specific */ +#define MCDX_CDBLK 2048 /* 2048 cooked data each blk */ + +#define MCDX_DATA_TIMEOUT 10 /* jiffies */ + +/* + * Access to the msf array + */ +#define MSF_MIN 0 /* minute */ +#define MSF_SEC 1 /* second */ +#define MSF_FRM 2 /* frame */ + +/* + * Errors + */ +#define MCDX_E 1 /* unspec error */ +#define MCDX_EOM 2 /* end of media */ diff -u --recursive --new-file v1.3.6/linux/include/linux/msg.h linux/include/linux/msg.h --- v1.3.6/linux/include/linux/msg.h Fri Jun 16 22:02:55 1995 +++ linux/include/linux/msg.h Sun Jul 2 21:26:28 1995 @@ -67,11 +67,11 @@ #define MSG_STAT 11 #define MSG_INFO 12 -extern asmlinkage int sys_msgget (key_t key, int msgflg); -extern asmlinkage int sys_msgsnd (int msqid, struct msgbuf *msgp, size_t msgsz, int msgflg); -extern asmlinkage int sys_msgrcv (int msqid, struct msgbuf *msgp, size_t msgsz, long msgtyp, +asmlinkage int sys_msgget (key_t key, int msgflg); +asmlinkage int sys_msgsnd (int msqid, struct msgbuf *msgp, size_t msgsz, int msgflg); +asmlinkage int sys_msgrcv (int msqid, struct msgbuf *msgp, size_t msgsz, long msgtyp, int msgflg); -extern asmlinkage int sys_msgctl (int msqid, int cmd, struct msqid_ds *buf); +asmlinkage int sys_msgctl (int msqid, int cmd, struct msqid_ds *buf); #endif /* __KERNEL__ */ diff -u --recursive --new-file v1.3.6/linux/include/linux/netdevice.h linux/include/linux/netdevice.h --- v1.3.6/linux/include/linux/netdevice.h Fri Jun 30 16:22:30 1995 +++ linux/include/linux/netdevice.h Thu Jul 6 13:22:05 1995 @@ -73,11 +73,11 @@ unsigned long mem_end; /* sahared mem end */ unsigned long mem_start; /* shared mem start */ unsigned long base_addr; /* device I/O address */ + unsigned long tbusy; /* transmitter busy must be long for bitops */ unsigned char irq; /* device IRQ number */ /* Low-level status flags. */ volatile unsigned char start, /* start an operation */ - tbusy, /* transmitter busy */ interrupt; /* interrupt arrived */ struct device *next; diff -u --recursive --new-file v1.3.6/linux/include/linux/optcd.h linux/include/linux/optcd.h --- v1.3.6/linux/include/linux/optcd.h Thu Jan 1 02:00:00 1970 +++ linux/include/linux/optcd.h Sat Jul 1 19:06:00 1995 @@ -0,0 +1,200 @@ + +/* Defines for the Optics Storage 8000AT CDROM drive. */ + +#ifndef _LINUX_OPTCD_H + +#define _LINUX_OPTCD_H + +/* Drive registers */ +#define OPTCD_PORTBASE 0x340 +/* Read */ +#define DATA_PORT optcd_port /* Read data/status */ +#define STATUS_PORT optcd_port+1 /* Indicate data/status availability */ +/* Write */ +#define COMIN_PORT optcd_port /* For passing command/parameter */ +#define RESET_PORT optcd_port+1 /* Write anything and wait 0.5 sec */ +#define HCON_PORT optcd_port+2 /* Host Xfer Configuration */ + + +/* Command completion/status read from DATA register */ +#define ST_DRVERR 0x80 +#define ST_DOOR_OPEN 0x40 +#define ST_MIXEDMODE_DISK 0x20 +#define ST_MODE_BITS 0x1c +#define ST_M_STOP 0x00 +#define ST_M_READ 0x04 +#define ST_M_AUDIO 0x04 +#define ST_M_PAUSE 0x08 +#define ST_M_INITIAL 0x0c +#define ST_M_ERROR 0x10 +#define ST_M_OTHERS 0x14 +#define ST_MODE2TRACK 0x02 +#define ST_DSK_CHG 0x01 +#define ST_L_LOCK 0x01 +#define ST_CMD_OK 0x00 +#define ST_OP_OK 0x01 +#define ST_PA_OK 0x02 +#define ST_OP_ERROR 0x05 +#define ST_PA_ERROR 0x06 + +/* Error codes (appear as command completion code from DATA register) */ +/* Player related errors */ +#define ERR_ILLCMD 0x11 /* Illegal command to player module */ +#define ERR_ILLPARM 0x12 /* Illegal parameter to player module */ +#define ERR_SLEDGE 0x13 +#define ERR_FOCUS 0x14 +#define ERR_MOTOR 0x15 +#define ERR_RADIAL 0x16 +#define ERR_PLL 0x17 /* PLL lock error */ +#define ERR_SUB_TIM 0x18 /* Subcode timeout error */ +#define ERR_SUB_NF 0x19 /* Subcode not found error */ +#define ERR_TRAY 0x1a +#define ERR_TOC 0x1b /* Table of Contents read error */ +#define ERR_JUMP 0x1c +/* Data errors */ +#define ERR_MODE 0x21 +#define ERR_FORM 0x22 +#define ERR_HEADADDR 0x23 /* Header Address not found */ +#define ERR_CRC 0x24 +#define ERR_ECC 0x25 /* Uncorrectable ECC error */ +#define ERR_CRC_UNC 0x26 /* CRC error and uncorrectable error */ +#define ERR_ILLBSYNC 0x27 /* Illegal block sync error */ +#define ERR_VDST 0x28 /* VDST not found */ +/* Timeout errors */ +#define ERR_READ_TIM 0x31 /* Read timeout error */ +#define ERR_DEC_STP 0x32 /* Decoder stopped */ +#define ERR_DEC_TIM 0x33 /* Decoder interrupt timeout error */ +/* Function abort codes */ +#define ERR_KEY 0x41 /* Key -Detected abort */ +#define ERR_READ_FINISH 0x42 /* Read Finish */ +/* Second Byte diagnostic codes */ +#define ERR_NOBSYNC 0x01 /* No block sync */ +#define ERR_SHORTB 0x02 /* Short block */ +#define ERR_LONGB 0x03 /* Long block */ +#define ERR_SHORTDSP 0x04 /* Short DSP word */ +#define ERR_LONGDSP 0x05 /* Long DSP word */ + + +/* Status availability flags read from STATUS register */ +#define FL_EJECT 0x20 +#define FL_WAIT 0x10 /* active low */ +#define FL_EOP 0x08 /* active low */ +#define FL_STEN 0x04 /* Status available when low */ +#define FL_DTEN 0x02 /* Data available when low */ +#define FL_DRQ 0x01 /* active low */ +#define FL_RESET 0xde /* These bits are high after a reset */ +#define FL_STDT (FL_STEN|FL_DTEN) + + +/* Transfer mode, written to HCON register */ +#define HCON_DTS 0x08 +#define HCON_SDRQB 0x04 +#define HCON_LOHI 0x02 +#define HCON_DMA16 0x01 + + +/* Drive command set, written to COMIN register */ +/* Quick response commands */ +#define COMDRVST 0x20 /* Drive Status Read */ +#define COMERRST 0x21 /* Error Status Read */ +#define COMIOCTLISTAT 0x22 /* Status Read; reset disk changed bit */ +#define COMINITSINGLE 0x28 /* Initialize Single Speed */ +#define COMINITDOUBLE 0x29 /* Initialize Double Speed */ +#define COMUNLOCK 0x30 /* Unlock */ +#define COMLOCK 0x31 /* Lock */ +#define COMLOCKST 0x32 /* Lock/Unlock Status */ +#define COMVERSION 0x40 /* Get Firmware Revision */ +#define COMVOIDREADMODE 0x50 /* Void Data Read Mode */ +/* Read commands */ +#define COMFETCH 0x60 /* Prefetch Data */ +#define COMREAD 0x61 /* Read */ +#define COMREADRAW 0x62 /* Read Raw Data */ +#define COMREADALL 0x63 /* Read All 2646 Bytes */ +/* Player control commands */ +#define COMLEADIN 0x70 /* Seek To Lead-in */ +#define COMSEEK 0x71 /* Seek */ +#define COMPAUSEON 0x80 /* Pause On */ +#define COMPAUSEOFF 0x81 /* Pause Off */ +#define COMSTOP 0x82 /* Stop */ +#define COMOPEN 0x90 /* Open Tray Door */ +#define COMCLOSE 0x91 /* Close Tray Door */ +#define COMPLAY 0xa0 /* Audio Play */ +#define COMPLAY_TNO 0xa2 /* Audio Play By Track Number */ +#define COMSUBQ 0xb0 /* Read Sub-q Code */ +#define COMLOCATION 0xb1 /* Read Head Position */ +/* Audio control commands */ +#define COMCHCTRL 0xc0 /* Audio Channel Control */ +/* Miscellaneous (test) commands */ +#define COMDRVTEST 0xd0 /* Write Test Bytes */ +#define COMTEST 0xd1 /* Diagnostic Test */ + + +#define BUSY_TIMEOUT 10000000 /* for busy wait */ +#define SLEEP_TIMEOUT 400 /* for timer wait */ +#define READ_TIMEOUT 3000 /* for poll wait */ +#define RESET_WAIT 1000 + +#define SET_TIMER(func, jifs) \ + delay_timer.expires = jifs; \ + delay_timer.function = (void *) func; \ + add_timer(&delay_timer); +#define CLEAR_TIMER del_timer(&delay_timer) + +#define MAX_TRACKS 104 + +struct msf { + unsigned char min; + unsigned char sec; + unsigned char frame; +}; + +struct opt_Play_msf { + struct msf start; + struct msf end; +}; + +struct opt_DiskInfo { + unsigned char first; + unsigned char last; + struct msf diskLength; + struct msf firstTrack; +}; + +struct opt_Toc { + unsigned char ctrl_addr; + unsigned char track; + unsigned char pointIndex; + struct msf trackTime; + struct msf diskTime; +}; + + +#define CURRENT_VALID \ + (CURRENT && MAJOR(CURRENT -> dev) == MAJOR_NR \ + && CURRENT -> cmd == READ && CURRENT -> sector != -1) + + +#undef DEBUG_DRIVE_IF /* Low level drive interface */ +#undef DEBUG_COMMANDS /* Commands sent to drive */ +#undef DEBUG_VFS /* VFS interface */ +#undef DEBUG_CONV /* Address conversions */ +#undef DEBUG_TOC /* Q-channel and Table of Contents */ +#undef DEBUG_BUFFERS /* Buffering and block size conversion */ +#undef DEBUG_REQUEST /* Request mechanism */ +#undef DEBUG_STATE /* State machine */ + + +/* Low level drive interface */ + +/* Errors that can occur in the low level interface */ +#define ERR_IF_CMD_TIMEOUT 0x100 +#define ERR_IF_ERR_TIMEOUT 0x101 +#define ERR_IF_RESP_TIMEOUT 0x102 +#define ERR_IF_DATA_TIMEOUT 0x103 +#define ERR_IF_NOSTAT 0x104 +/* Errors in table of contents */ +#define ERR_TOC_MISSINGINFO 0x120 +#define ERR_TOC_MISSINGENTRY 0x121 + +/* End .h defines */ +#endif _LINUX_OPTCD_H diff -u --recursive --new-file v1.3.6/linux/include/linux/sbpcd.h linux/include/linux/sbpcd.h --- v1.3.6/linux/include/linux/sbpcd.h Tue Jun 27 14:11:46 1995 +++ linux/include/linux/sbpcd.h Sat Jul 1 19:35:18 1995 @@ -121,7 +121,7 @@ #define _LINUX_SBPCD_H /*==========================================================================*/ /*==========================================================================*/ -#define LONG_TIMING 1 /* test against timeouts with "gold" CDs on CR-521 */ +#define LONG_TIMING 0 /* test against timeouts with "gold" CDs on CR-521 */ #undef FUTURE #define TEST_UPC 0 @@ -139,8 +139,6 @@ /* * "private" IOCTL functions */ -#define CDROMRESET 0x5380 /* hard-rest the drive */ -#define CDROMVOLREAD 0x5381 /* let the drive tell its volume settings */ #define CDROMAUDIOBUFSIZ 0x5382 /* set the audio buffer size */ /*==========================================================================*/ diff -u --recursive --new-file v1.3.6/linux/include/linux/sched.h linux/include/linux/sched.h --- v1.3.6/linux/include/linux/sched.h Fri Jun 16 22:02:55 1995 +++ linux/include/linux/sched.h Wed Jul 5 12:53:22 1995 @@ -215,6 +215,12 @@ #define COPYFD 0x00000200 /* set if fd's should be copied, not shared (NI) */ /* + * Limit the stack by to some sane default: root can always + * increase this limit if needed.. 8MB seems reasonable. + */ +#define _STK_LIM (8*1024*1024) + +/* * INIT_TASK is used to set up the first task table, touch at * your own risk!. Base=0, limit=0x1fffff (=2MB) */ @@ -233,7 +239,7 @@ /* uid etc */ 0,0,0,0,0,0,0,0, \ /* timeout */ 0,0,0,0,0,0,0,0,0,0,0,0, \ /* rlimits */ { {LONG_MAX, LONG_MAX}, {LONG_MAX, LONG_MAX}, \ - {LONG_MAX, LONG_MAX}, {LONG_MAX, LONG_MAX}, \ + {LONG_MAX, LONG_MAX}, {_STK_LIM, _STK_LIM}, \ { 0, LONG_MAX}, {LONG_MAX, LONG_MAX}, \ {MAX_TASKS_PER_USER, MAX_TASKS_PER_USER}, {NR_OPEN, NR_OPEN}}, \ /* math */ 0, \ diff -u --recursive --new-file v1.3.6/linux/include/linux/sem.h linux/include/linux/sem.h --- v1.3.6/linux/include/linux/sem.h Fri Jun 16 22:02:55 1995 +++ linux/include/linux/sem.h Sun Jul 2 21:26:28 1995 @@ -103,9 +103,9 @@ short * semadj; /* array of adjustments, one per semaphore */ }; -extern asmlinkage int sys_semget (key_t key, int nsems, int semflg); -extern asmlinkage int sys_semop (int semid, struct sembuf *sops, unsigned nsops); -extern asmlinkage int sys_semctl (int semid, int semnum, int cmd, union semun arg); +asmlinkage int sys_semget (key_t key, int nsems, int semflg); +asmlinkage int sys_semop (int semid, struct sembuf *sops, unsigned nsops); +asmlinkage int sys_semctl (int semid, int semnum, int cmd, union semun arg); #endif /* __KERNEL__ */ diff -u --recursive --new-file v1.3.6/linux/include/linux/shm.h linux/include/linux/shm.h --- v1.3.6/linux/include/linux/shm.h Fri Jun 16 22:02:55 1995 +++ linux/include/linux/shm.h Sun Jul 2 21:26:28 1995 @@ -59,10 +59,10 @@ ulong swap_successes; }; -extern asmlinkage int sys_shmget (key_t key, int size, int flag); -extern asmlinkage int sys_shmat (int shmid, char *shmaddr, int shmflg, ulong *addr); -extern asmlinkage int sys_shmdt (char *shmaddr); -extern asmlinkage int sys_shmctl (int shmid, int cmd, struct shmid_ds *buf); +asmlinkage int sys_shmget (key_t key, int size, int flag); +asmlinkage int sys_shmat (int shmid, char *shmaddr, int shmflg, ulong *addr); +asmlinkage int sys_shmdt (char *shmaddr); +asmlinkage int sys_shmctl (int shmid, int cmd, struct shmid_ds *buf); #endif /* __KERNEL__ */ diff -u --recursive --new-file v1.3.6/linux/include/linux/sjcd.h linux/include/linux/sjcd.h --- v1.3.6/linux/include/linux/sjcd.h Thu Jan 1 02:00:00 1970 +++ linux/include/linux/sjcd.h Sat Jul 1 19:06:00 1995 @@ -0,0 +1,133 @@ +/* + * Definitions for a Sanyo CD-ROM interface + * + * Copyright (C) 1995 Vadim V. Model + * + * model@cecmow.enet.dec.com + * vadim@rbrf.msk.su + * vadim@ipsun.ras.ru + * + */ + +#ifndef __SJCD_H__ +#define __SJCD_H__ + +/* + * Change this to set the I/O port address. + */ +#define SJCD_BASE_ADDR 0x340 + +/* + * Change this to set the irq. + */ +#define SJCD_INTR_NR 10 + +/* + * port access macros + */ +#define SJCDPORT( x ) ( sjcd_port + ( x ) ) + +/* status bits */ + +#define SST_NOT_READY 0x10 /* no disk in the drive */ +#define SST_MEDIA_CHANGED 0x20 /* disk is changed */ +#define SST_DOOR_OPENED 0x40 /* door is open */ + +/* flag bits */ + +/* commands */ + +#define SCMD_EJECT_TRAY 0xD0 /* eject tray if not locked */ +#define SCMD_LOCK_TRAY 0xD2 /* lock tray when in */ +#define SCMD_UNLOCK_TRAY 0xD4 /* unlock tray when in */ +#define SCMD_CLOSE_TRAY 0xD6 /* load tray in */ + +#define SCMD_RESET 0xFA /* soft reset */ +#define SCMD_GET_STATUS 0x80 +#define SCMD_GET_VERSION 0xCC + +#define SCMD_DATA_READ 0xA0 +#define SCMD_SEEK 0xA0 +#define SCMD_PLAY 0xA0 + +#define SCMD_GET_QINFO 0xA8 + +#define SCMD_SET_MODE 0xC4 +#define SCMD_MODE_PLAY 0xE0 +#define SCMD_MODE_COOKED 0xF8 +#define SCMD_MODE_RAW 0xF9 +#define SCMD_MODE_x20_BIT 0x20 + +#define SCMD_SET_VOLUME 0xAE +#define SCMD_PAUSE 0xE0 +#define SCMD_STOP 0xE0 + +#define SCMD_GET_DISK_INFO 0xAA +#define SCMD_GET_1_TRACK 0xA0 /* get the first track information */ +#define SCMD_GET_L_TRACK 0xA1 /* get the last track information */ +#define SCMD_GET_D_SIZE 0xA2 /* get the whole disk information */ + +/* + * borrowed from hd.c + */ +#define S_READ_DATA( port, buf, nr ) insb( port, buf, nr ) + +#define SJCD_MAX_TRACKS 100 + +struct msf { + unsigned char min; + unsigned char sec; + unsigned char frame; +}; + +struct sjcd_hw_disk_info { + unsigned char track_control; + unsigned char track_no; + unsigned char x, y, z; + union { + unsigned char track_no; + struct msf track_msf; + } un; +}; + +struct sjcd_hw_qinfo { + unsigned char track_control; + unsigned char track_no; + unsigned char x; + struct msf rel; + struct msf abs; +}; + +struct sjcd_play_msf { + struct msf start; + struct msf end; +}; + +struct sjcd_disk_info { + unsigned char first; + unsigned char last; + struct msf disk_length; + struct msf first_track; +}; + +struct sjcd_toc { + unsigned char ctrl_addr; + unsigned char track; + unsigned char point_index; + struct msf track_time; + struct msf disk_time; +}; + +struct sjcd_stat { + int ticks; + int tticks[ 8 ]; + int idle_ticks; + int start_ticks; + int mode_ticks; + int read_ticks; + int data_ticks; + int stop_ticks; + int stopping_ticks; +}; + +#endif diff -u --recursive --new-file v1.3.6/linux/include/linux/skbuff.h linux/include/linux/skbuff.h --- v1.3.6/linux/include/linux/skbuff.h Fri Jun 30 16:22:30 1995 +++ linux/include/linux/skbuff.h Wed Jul 5 13:06:27 1995 @@ -18,9 +18,10 @@ #include #include -/* #define CONFIG_SKB_CHECK 1 */ +#define CONFIG_SKB_CHECK 0 #define HAVE_ALLOC_SKB /* For the drivers to know */ +#define HAVE_ALIGNABLE_SKB /* Ditto 8) */ #define FREE_READ 1 @@ -55,11 +56,18 @@ unsigned char *raw; unsigned long seq; } h; + + union { /* As yet incomplete physical layer views */ + unsigned char *raw; + struct ethhdr *ethernet; + } mac; + struct iphdr *ip_hdr; /* For IPPROTO_RAW */ unsigned long len; /* Length of actual data */ unsigned long saddr; /* IP source address */ unsigned long daddr; /* IP target address */ unsigned long raddr; /* IP next hop address */ + unsigned long csum; /* Checksum */ volatile char acked, /* Are we acked ? */ used, /* Are we in use ? */ free, /* How to free this buffer */ @@ -67,7 +75,8 @@ unsigned char tries, /* Times tried */ lock, /* Are we locked ? */ localroute, /* Local routing asserted for this frame */ - pkt_type; /* Packet class */ + pkt_type, /* Packet class */ + ip_summed; /* Driver fed us an IP checksum */ #define PACKET_HOST 0 /* To us */ #define PACKET_BROADCAST 1 /* To all */ #define PACKET_MULTICAST 2 /* To group */ @@ -84,7 +93,7 @@ #define SK_WMEM_MAX 32767 #define SK_RMEM_MAX 32767 -#ifdef CONFIG_SKB_CHECK +#if CONFIG_SKB_CHECK #define SK_FREED_SKB 0x0DE2C0DE #define SK_GOOD_SKB 0xDEC0DED1 #define SK_HEAD_SKB 0x12231298 diff -u --recursive --new-file v1.3.6/linux/include/linux/smb.h linux/include/linux/smb.h --- v1.3.6/linux/include/linux/smb.h Thu Jan 1 02:00:00 1970 +++ linux/include/linux/smb.h Sat Jul 1 19:00:19 1995 @@ -0,0 +1,123 @@ +/* + * smb.h + * + * Copyright (C) 1995 by Paal-Kr. Engstad and Volker Lendecke + * + */ + +#ifndef _LINUX_SMB_H +#define _LINUX_SMB_H + +#define SMB_PORT 139 +#define SMB_MAXNAMELEN 255 +#define SMB_MAXPATHLEN 1024 + +#define SMB_DEF_MAX_XMIT 32768 + +/* Allocate max. 1 page */ +#define TRANS2_MAX_TRANSFER (4096-17) + +#include +#ifdef __KERNEL__ +typedef u8 byte; +typedef u16 word; +typedef u32 dword; +#else +typedef unsigned char byte; +typedef unsigned short word; +typedef unsigned long dword; +#endif + +/* + * Set/Get values in SMB-byte order + */ +#define ARCH i386 +#if (ARCH == i386) +#define BVAL(p,off) (*((byte *)(((void *)p)+off))) +#define WVAL(p,off) (*((word *)(((void *)p)+off))) +#define DVAL(p,off) (*((dword *)(((void *)p)+off))) +#define BSET(p,off,new) (*((byte *)(((void *)p)+off))=(new)) +#define WSET(p,off,new) (*((word *)(((void *)p)+off))=(new)) +#define DSET(p,off,new) (*((dword *)(((void *)p)+off))=(new)) + +/* where to find the base of the SMB packet proper */ +#define smb_base(buf) ((byte *)(((byte *)(buf))+4)) + +#else +#error "Currently only on 386, sorry" +#endif + + +#define LANMAN1 +#define LANMAN2 + +enum smb_protocol { + PROTOCOL_NONE, + PROTOCOL_CORE, + PROTOCOL_COREPLUS, + PROTOCOL_LANMAN1, + PROTOCOL_LANMAN2, + PROTOCOL_NT1 +}; + +enum smb_case_hndl { + CASE_DEFAULT, + CASE_LOWER, + CASE_UPPER +}; + +#ifdef __KERNEL__ + +enum smb_conn_state { + CONN_VALID, /* everything's fine */ + CONN_INVALID, /* Something went wrong, but did not + try to reconnect yet. */ + CONN_RETRIED /* Tried a reconnection, but was refused */ +}; + +struct smb_dskattr { + word total; + word allocblocks; + word blocksize; + word free; +}; + +/* + * Contains all relevant data on a SMB networked file. + */ +struct smb_dirent { + int opened; /* is it open on the fileserver? */ + word fileid; /* What id to handle a file with? */ + word attr; /* Attribute fields, DOS value */ + + time_t atime, mtime, /* Times, as seen by the server, normalized */ + ctime; /* to UTC. The ugly conversion happens in */ + /* proc.c */ + + unsigned long size; /* File size. */ + unsigned short access; /* Access bits. */ + unsigned long f_pos; /* File position. (For readdir.) */ + char* path; /* Complete path, MS-DOS notation, with '\' */ + int len; /* Namelength. */ +}; + +#endif /* __KERNEL__ */ +#endif /* _LINUX_SMB_H */ + + +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * Emacs will notice this stuff at the end of the file and automatically + * adjust the settings for this buffer only. This must remain at the end + * of the file. + * --------------------------------------------------------------------------- + * Local variables: + * c-indent-level: 8 + * c-brace-imaginary-offset: 0 + * c-brace-offset: -8 + * c-argdecl-indent: 8 + * c-label-offset: -8 + * c-continued-statement-offset: 8 + * c-continued-brace-offset: 0 + * End: + */ diff -u --recursive --new-file v1.3.6/linux/include/linux/smb_fs.h linux/include/linux/smb_fs.h --- v1.3.6/linux/include/linux/smb_fs.h Thu Jan 1 02:00:00 1970 +++ linux/include/linux/smb_fs.h Sat Jul 1 19:00:19 1995 @@ -0,0 +1,174 @@ +/* + * smb_fs.h + * + * Copyright (C) 1995 by Paal-Kr. Engstad and Volker Lendecke + * + */ + +#ifndef _LINUX_SMB_FS_H +#define _LINUX_SMB_FS_H + +#include +#include +#include +#include + +#include +#include +#include + +/* + * ioctl commands + */ +#define SMB_IOC_GETMOUNTUID _IOR('u', 1, uid_t) + +#ifdef __KERNEL__ + +/* + * The readdir cache size controls how many directory entries are cached. + */ +#define SMB_READDIR_CACHE_SIZE 64 + +/* + * This defines the number of filenames cached in memory to avoid + * constructing filenames from \ + */ +#define SMB_CACHE_TABLE_SIZE 64 + +#define SMB_SUPER_MAGIC 0x517B + + + +#define SMB_SBP(sb) ((struct smb_sb_info *)(sb->u.generic_sbp)) +#define SMB_INOP(inode) ((struct smb_inode_info *)(inode->u.generic_ip)) + +#define SMB_SERVER(inode) (&(SMB_SBP(inode->i_sb)->s_server)) +#define SMB_SERVATTR(inode) (&(SMB_SBP(inode->i_sb)->s_attr)) + +#define SMB_FINFO(inode) (&(SMB_INOP(inode)->finfo)) + +#define SMB_HEADER_LEN 37 /* includes everything up to, but not + * including smb_bcc */ + +static inline int min(int a, int b) { + return a + +extern int smb_malloced; +extern int smb_current_malloced; + +static inline void * +smb_kmalloc(unsigned int size, int priority) +{ + smb_malloced += 1; + smb_current_malloced += 1; + return kmalloc(size, priority); +} + +static inline void +smb_kfree_s(void *obj, int size) +{ + smb_current_malloced -= 1; + kfree_s(obj, size); +} + +#else /* DEBUG_SMB_MALLOC */ + +#define smb_kmalloc(s,p) kmalloc(s,p) +#define smb_kfree_s(o,s) kfree_s(o,s) + +#endif /* DEBUG_SMB_MALLOC */ + +#if DEBUG_SMB > 0 +#define DPRINTK(format, args...) printk(format , ## args) +#else +#define DPRINTK(format, args...) +#endif + +#if DEBUG_SMB > 1 +#define DDPRINTK(format, args...) printk(format , ## args) +#else +#define DDPRINTK(format, args...) +#endif + + +/* linux/fs/smbfs/file.c */ +extern struct inode_operations smb_file_inode_operations; +int smb_make_open(struct inode *i, int right); + +/* linux/fs/smbfs/dir.c */ +extern struct inode_operations smb_dir_inode_operations; +void smb_free_inode_info(struct smb_inode_info *i); +void smb_free_all_inodes(struct smb_server *server); +int smb_init_root(struct smb_server *server); +void smb_init_dir_cache(void); +void smb_invalid_dir_cache(unsigned long ino); +void smb_invalidate_all_inodes(struct smb_server *server); +void smb_free_dir_cache(void); + +/* linux/fs/smbfs/ioctl.c */ +int smb_ioctl (struct inode * inode, struct file * filp, + unsigned int cmd, unsigned long arg); + +/* linux/fs/smbfs/inode.c */ +struct super_block *smb_read_super(struct super_block *sb, + void *raw_data, int silent); +int smb_notify_change(struct inode *inode, struct iattr *attr); +void smb_invalidate_connection(struct smb_server *server); +int smb_conn_is_valid(struct smb_server *server); + +/* linux/fs/smbfs/proc.c */ +dword smb_len(unsigned char *packet); +int smb_proc_open(struct smb_server *server, const char *pathname, + int len, struct smb_dirent *entry); +int smb_proc_close(struct smb_server *server, struct smb_dirent *finfo); +int smb_proc_read(struct smb_server *server, struct smb_dirent *finfo, + off_t offset, long count, char *data, int fs); +int smb_proc_write(struct smb_server *server, struct smb_dirent *finfo, + off_t offset, int count, char *data); +int smb_proc_create(struct smb_server *server, const char *path, + int len, struct smb_dirent *entry); +int smb_proc_mknew(struct smb_server *server, const char *path, int len, + struct smb_dirent *entry); +int smb_proc_mv(struct smb_server *server, const char *opath, const int olen, + const char *npath, const int nlen); +int smb_proc_mkdir(struct smb_server *server, const char *path, const int len); +int smb_proc_rmdir(struct smb_server *server, const char *path, const int len); +int smb_proc_unlink(struct smb_server *server, const char *path, + const int len); +int smb_proc_readdir(struct smb_server *server, struct inode *dir, + int fpos, int cache_size, + struct smb_dirent *entry); +int smb_proc_getattr(struct smb_server *server, const char *path, + int len, struct smb_dirent *entry); +int smb_proc_setattr(struct smb_server *server, + struct inode *ino, + struct smb_dirent *new_finfo); +int smb_proc_chkpath(struct smb_server *server, char *path, int len, + int *result); +int smb_proc_dskattr(struct super_block *super, struct smb_dskattr *attr); +int smb_proc_reconnect(struct smb_server *server); +int smb_proc_connect(struct smb_server *server); +int smb_proc_disconnect(struct smb_server *server); +int smb_proc_trunc(struct smb_server *server, word fid, dword length); + +/* linux/fs/smbfs/sock.c */ +int smb_release(struct smb_server *server); +int smb_connect(struct smb_server *server); +int smb_request(struct smb_server *server); +int smb_catch_keepalive(struct smb_server *server); +int smb_dont_catch_keepalive(struct smb_server *server); +int smb_trans2_request(struct smb_server *server, + int *data_len, int *param_len, + char **data, char **param); + +/* linux/fs/smbfs/mmap.c */ +int smb_mmap(struct inode * inode, struct file * file, struct vm_area_struct * vma); + +#endif /* __KERNEL__ */ + +#endif /* _LINUX_SMB_FS_H */ diff -u --recursive --new-file v1.3.6/linux/include/linux/smb_fs_i.h linux/include/linux/smb_fs_i.h --- v1.3.6/linux/include/linux/smb_fs_i.h Thu Jan 1 02:00:00 1970 +++ linux/include/linux/smb_fs_i.h Sat Jul 1 19:00:19 1995 @@ -0,0 +1,51 @@ +/* + * smb_fs_i.h + * + * Copyright (C) 1995 by Paal-Kr. Engstad and Volker Lendecke + * + */ + +#ifndef _LINUX_SMB_FS_I +#define _LINUX_SMB_FS_I + +#ifdef __KERNEL__ +#include + +enum smb_inode_state { + INODE_VALID = 19, /* Inode currently in use */ + INODE_LOOKED_UP, /* directly before iget */ + INODE_CACHED, /* in a path to an inode which is in use */ + INODE_INVALID +}; + +/* + * smb fs inode data (in memory only) + */ +struct smb_inode_info { + enum smb_inode_state state; + int nused; /* for directories: + number of references in memory */ + struct smb_inode_info *dir; + struct smb_inode_info *next, *prev; + struct smb_dirent finfo; +}; + +#endif +#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-indent-level: 8 + * c-brace-imaginary-offset: 0 + * c-brace-offset: -8 + * c-argdecl-indent: 8 + * c-label-offset: -8 + * c-continued-statement-offset: 8 + * c-continued-brace-offset: 0 + * End: + */ diff -u --recursive --new-file v1.3.6/linux/include/linux/smb_fs_sb.h linux/include/linux/smb_fs_sb.h --- v1.3.6/linux/include/linux/smb_fs_sb.h Thu Jan 1 02:00:00 1970 +++ linux/include/linux/smb_fs_sb.h Sat Jul 1 19:00:19 1995 @@ -0,0 +1,78 @@ +/* + * smb_fs_sb.h + * + * Copyright (C) 1995 by Paal-Kr. Engstad and Volker Lendecke + * + */ + +#ifndef _SMB_FS_SB +#define _SMB_FS_SB + +#include +#include +#include +#include + +#ifdef __KERNEL__ + +struct smb_server { + enum smb_protocol protocol; /* The protocol this + connection accepts. */ + enum smb_case_hndl case_handling; + struct file * sock_file; /* The socket we transfer + data on. */ + int lock; /* To prevent mismatch in + protocols. */ + struct wait_queue *wait; + + word max_xmit; + char hostname[256]; + word pid; + word server_uid; + word mid; + word tid; + + struct smb_mount_data m; /* We store the complete information here + * to be able to reconnect. + */ + + unsigned short rcls; /* The error codes we received */ + unsigned short err; + unsigned char * packet; + + enum smb_conn_state state; + unsigned long reconnect_time; /* The time of the last attempt */ + + /* The following are LANMAN 1.0 options transferred to us in + SMBnegprot */ + word secmode; + word maxxmt; + word maxmux; + word maxvcs; + word blkmode; + dword sesskey; + + /* We use our on data_ready callback, but need the original one */ + void *data_ready; + + /* We do not have unique numbers for files in the smb protocol + like NFS-filehandles. (SMB was designed for DOS, not for + UNIX!) So we have to create our own inode numbers. We keep + a complete path of smb_inode_info's to each active + inode. The inode number is then created by the address of + this structure. */ + struct smb_inode_info root; +}; + +/* + * This is the part of the super-block (in memory) for the SMB file system. + */ + +struct smb_sb_info { + struct smb_server s_server; + struct smb_dskattr s_attr; +}; + +#endif /* __KERNEL__ */ + +#endif diff -u --recursive --new-file v1.3.6/linux/include/linux/smb_mount.h linux/include/linux/smb_mount.h --- v1.3.6/linux/include/linux/smb_mount.h Thu Jan 1 02:00:00 1970 +++ linux/include/linux/smb_mount.h Sat Jul 1 19:00:19 1995 @@ -0,0 +1,40 @@ +/* + * smb_mount.h + * + * Copyright (C) 1995 by Paal-Kr. Engstad and Volker Lendecke + * + */ + +#ifndef _LINUX_SMB_MOUNT_H +#define _LINUX_SMB_MOUNT_H + +#include +#include + +#define SMB_MOUNT_VERSION 4 + +struct smb_mount_data { + int version; + unsigned int fd; + uid_t mounted_uid; /* Who may umount() this filesystem? */ + struct sockaddr_in addr; + + char server_name[17]; + char client_name[17]; + char service[64]; + char root_path[64]; + + char username[64]; + char password[64]; + + unsigned short max_xmit; + + uid_t uid; + gid_t gid; + mode_t file_mode; + mode_t dir_mode; +}; + +#endif + + diff -u --recursive --new-file v1.3.6/linux/include/linux/smbno.h linux/include/linux/smbno.h --- v1.3.6/linux/include/linux/smbno.h Thu Jan 1 02:00:00 1970 +++ linux/include/linux/smbno.h Sat Jul 1 19:00:19 1995 @@ -0,0 +1,269 @@ +#ifndef _SMBNO_H_ +#define _SMBNO_H_ + +/* these define the attribute byte as seen by DOS */ +#define aRONLY (1L<<0) +#define aHIDDEN (1L<<1) +#define aSYSTEM (1L<<2) +#define aVOLID (1L<<3) +#define aDIR (1L<<4) +#define aARCH (1L<<5) + +/* error classes */ +#define SUCCESS 0 /* The request was successful. */ +#define ERRDOS 0x01 /* Error is from the core DOS operating system set. */ +#define ERRSRV 0x02 /* Error is generated by the server network file manager.*/ +#define ERRHRD 0x03 /* Error is an hardware error. */ +#define ERRCMD 0xFF /* Command was not in the "SMB" format. */ + +/* SMB X/Open error codes for the ERRdos error class */ + +#define ERRbadfunc 1 /* Invalid function (or system call) */ +#define ERRbadfile 2 /* File not found (pathname error) */ +#define ERRbadpath 3 /* Directory not found */ +#define ERRnofids 4 /* Too many open files */ +#define ERRnoaccess 5 /* Access denied */ +#define ERRbadfid 6 /* Invalid fid */ +#define ERRbadmcb 7 /* Memory control blocks destroyed */ +#define ERRnomem 8 /* Out of memory */ +#define ERRbadmem 9 /* Invalid memory block address */ +#define ERRbadenv 10 /* Invalid environment */ +#define ERRbadformat 11 /* Invalid format */ +#define ERRbadaccess 12 /* Invalid open mode */ +#define ERRbaddata 13 /* Invalid data (only from ioctl call) */ +#define ERRres 14 /* reserved */ +#define ERRbaddrive 15 /* Invalid drive */ +#define ERRremcd 16 /* Attempt to delete current directory */ +#define ERRdiffdevice 17 /* rename/move across different filesystems */ +#define ERRnofiles 18 /* no more files found in file search */ +#define ERRbadshare 32 /* Share mode on file conflict with open mode */ +#define ERRlock 33 /* Lock request conflicts with existing lock */ +#define ERRfilexists 80 /* File in operation already exists */ +#define ERRbadpipe 230 /* Named pipe invalid */ +#define ERRpipebusy 231 /* All instances of pipe are busy */ +#define ERRpipeclosing 232 /* named pipe close in progress */ +#define ERRnotconnected 233 /* No process on other end of named pipe */ +#define ERRmoredata 234 /* More data to be returned */ +#define ERROR_EAS_DIDNT_FIT 275 /* Extended attributes didn't fit */ +#define ERROR_EAS_NOT_SUPPORTED 282 /* Extended attributes not suppored */ + +/* Error codes for the ERRSRV class */ + +#define ERRerror 1 /* Non specific error code */ +#define ERRbadpw 2 /* Bad password */ +#define ERRbadtype 3 /* reserved */ +#define ERRaccess 4 /* No permissions to do the requested operation */ +#define ERRinvnid 5 /* tid invalid */ +#define ERRinvnetname 6 /* Invalid servername */ +#define ERRinvdevice 7 /* Invalid device */ +#define ERRqfull 49 /* Print queue full */ +#define ERRqtoobig 50 /* Queued item too big */ +#define ERRinvpfid 52 /* Invalid print file in smb_fid */ +#define ERRsmbcmd 64 /* Unrecognised command */ +#define ERRsrverror 65 /* smb server internal error */ +#define ERRfilespecs 67 /* fid and pathname invalid combination */ +#define ERRbadlink 68 /* reserved */ +#define ERRbadpermits 69 /* Access specified for a file is not valid */ +#define ERRbadpid 70 /* reserved */ +#define ERRsetattrmode 71 /* attribute mode invalid */ +#define ERRpaused 81 /* Message server paused */ +#define ERRmsgoff 82 /* Not receiving messages */ +#define ERRnoroom 83 /* No room for message */ +#define ERRrmuns 87 /* too many remote usernames */ +#define ERRtimeout 88 /* operation timed out */ +#define ERRnoresource 89 /* No resources currently available for request. */ +#define ERRtoomanyuids 90 /* too many userids */ +#define ERRbaduid 91 /* bad userid */ +#define ERRuseMPX 250 /* temporarily unable to use raw mode, use MPX mode */ +#define ERRuseSTD 251 /* temporarily unable to use raw mode, use std.mode */ +#define ERRcontMPX 252 /* resume MPX mode */ +#define ERRbadPW /* reserved */ +#define ERRnosupport 0xFFFF + +/* Error codes for the ERRHRD class */ + +#define ERRnowrite 19 /* read only media */ +#define ERRbadunit 20 /* Unknown device */ +#define ERRnotready 21 /* Drive not ready */ +#define ERRbadcmd 22 /* Unknown command */ +#define ERRdata 23 /* Data (CRC) error */ +#define ERRbadreq 24 /* Bad request structure length */ +#define ERRseek 25 +#define ERRbadmedia 26 +#define ERRbadsector 27 +#define ERRnopaper 28 +#define ERRwrite 29 /* write fault */ +#define ERRread 30 /* read fault */ +#define ERRgeneral 31 /* General hardware failure */ +#define ERRwrongdisk 34 +#define ERRFCBunavail 35 +#define ERRsharebufexc 36 /* share buffer exceeded */ +#define ERRdiskfull 39 + +/* offsets into message for common items */ +#define smb_com 8 +#define smb_rcls 9 +#define smb_reh 10 +#define smb_err 11 +#define smb_flg 13 +#define smb_flg2 14 +#define smb_reb 13 +#define smb_tid 28 +#define smb_pid 30 +#define smb_uid 32 +#define smb_mid 34 +#define smb_wct 36 +#define smb_vwv 37 +#define smb_vwv0 37 +#define smb_vwv1 39 +#define smb_vwv2 41 +#define smb_vwv3 43 +#define smb_vwv4 45 +#define smb_vwv5 47 +#define smb_vwv6 49 +#define smb_vwv7 51 +#define smb_vwv8 53 +#define smb_vwv9 55 +#define smb_vwv10 57 +#define smb_vwv11 59 +#define smb_vwv12 61 +#define smb_vwv13 63 +#define smb_vwv14 65 + +/* these are the trans2 sub fields for primary requests */ +#define smb_tpscnt smb_vwv0 +#define smb_tdscnt smb_vwv1 +#define smb_mprcnt smb_vwv2 +#define smb_mdrcnt smb_vwv3 +#define smb_msrcnt smb_vwv4 +#define smb_flags smb_vwv5 +#define smb_timeout smb_vwv6 +#define smb_pscnt smb_vwv9 +#define smb_psoff smb_vwv10 +#define smb_dscnt smb_vwv11 +#define smb_dsoff smb_vwv12 +#define smb_suwcnt smb_vwv13 +#define smb_setup smb_vwv14 +#define smb_setup0 smb_setup +#define smb_setup1 (smb_setup+2) +#define smb_setup2 (smb_setup+4) + +/* these are for the secondary requests */ +#define smb_spscnt smb_vwv2 +#define smb_spsoff smb_vwv3 +#define smb_spsdisp smb_vwv4 +#define smb_sdscnt smb_vwv5 +#define smb_sdsoff smb_vwv6 +#define smb_sdsdisp smb_vwv7 +#define smb_sfid smb_vwv8 + +/* and these for responses */ +#define smb_tprcnt smb_vwv0 +#define smb_tdrcnt smb_vwv1 +#define smb_prcnt smb_vwv3 +#define smb_proff smb_vwv4 +#define smb_prdisp smb_vwv5 +#define smb_drcnt smb_vwv6 +#define smb_droff smb_vwv7 +#define smb_drdisp smb_vwv8 + +/* the complete */ +#define SMBmkdir 0x00 /* create directory */ +#define SMBrmdir 0x01 /* delete directory */ +#define SMBopen 0x02 /* open file */ +#define SMBcreate 0x03 /* create file */ +#define SMBclose 0x04 /* close file */ +#define SMBflush 0x05 /* flush file */ +#define SMBunlink 0x06 /* delete file */ +#define SMBmv 0x07 /* rename file */ +#define SMBgetatr 0x08 /* get file attributes */ +#define SMBsetatr 0x09 /* set file attributes */ +#define SMBread 0x0A /* read from file */ +#define SMBwrite 0x0B /* write to file */ +#define SMBlock 0x0C /* lock byte range */ +#define SMBunlock 0x0D /* unlock byte range */ +#define SMBctemp 0x0E /* create temporary file */ +#define SMBmknew 0x0F /* make new file */ +#define SMBchkpth 0x10 /* check directory path */ +#define SMBexit 0x11 /* process exit */ +#define SMBlseek 0x12 /* seek */ +#define SMBtcon 0x70 /* tree connect */ +#define SMBtconX 0x75 /* tree connect and X*/ +#define SMBtdis 0x71 /* tree disconnect */ +#define SMBnegprot 0x72 /* negotiate protocol */ +#define SMBdskattr 0x80 /* get disk attributes */ +#define SMBsearch 0x81 /* search directory */ +#define SMBsplopen 0xC0 /* open print spool file */ +#define SMBsplwr 0xC1 /* write to print spool file */ +#define SMBsplclose 0xC2 /* close print spool file */ +#define SMBsplretq 0xC3 /* return print queue */ +#define SMBsends 0xD0 /* send single block message */ +#define SMBsendb 0xD1 /* send broadcast message */ +#define SMBfwdname 0xD2 /* forward user name */ +#define SMBcancelf 0xD3 /* cancel forward */ +#define SMBgetmac 0xD4 /* get machine name */ +#define SMBsendstrt 0xD5 /* send start of multi-block message */ +#define SMBsendend 0xD6 /* send end of multi-block message */ +#define SMBsendtxt 0xD7 /* send text of multi-block message */ + +/* Core+ protocol */ +#define SMBlockread 0x13 /* Lock a range and read */ +#define SMBwriteunlock 0x14 /* Unlock a range then write */ +#define SMBreadbraw 0x1a /* read a block of data with no smb header */ +#define SMBwritebraw 0x1d /* write a block of data with no smb header */ +#define SMBwritec 0x20 /* secondary write request */ +#define SMBwriteclose 0x2c /* write a file then close it */ + +/* dos extended protocol */ +#define SMBreadBraw 0x1A /* read block raw */ +#define SMBreadBmpx 0x1B /* read block multiplexed */ +#define SMBreadBs 0x1C /* read block (secondary response) */ +#define SMBwriteBraw 0x1D /* write block raw */ +#define SMBwriteBmpx 0x1E /* write block multiplexed */ +#define SMBwriteBs 0x1F /* write block (secondary request) */ +#define SMBwriteC 0x20 /* write complete response */ +#define SMBsetattrE 0x22 /* set file attributes expanded */ +#define SMBgetattrE 0x23 /* get file attributes expanded */ +#define SMBlockingX 0x24 /* lock/unlock byte ranges and X */ +#define SMBtrans 0x25 /* transaction - name, bytes in/out */ +#define SMBtranss 0x26 /* transaction (secondary request/response) */ +#define SMBioctl 0x27 /* IOCTL */ +#define SMBioctls 0x28 /* IOCTL (secondary request/response) */ +#define SMBcopy 0x29 /* copy */ +#define SMBmove 0x2A /* move */ +#define SMBecho 0x2B /* echo */ +#define SMBopenX 0x2D /* open and X */ +#define SMBreadX 0x2E /* read and X */ +#define SMBwriteX 0x2F /* write and X */ +#define SMBsesssetupX 0x73 /* Session Set Up & X (including User Logon) */ +#define SMBtconX 0x75 /* tree connect and X */ +#define SMBffirst 0x82 /* find first */ +#define SMBfunique 0x83 /* find unique */ +#define SMBfclose 0x84 /* find close */ +#define SMBinvalid 0xFE /* invalid command */ + + +/* Extended 2.0 protocol */ +#define SMBtrans2 0x32 /* TRANS2 protocol set */ +#define SMBtranss2 0x33 /* TRANS2 protocol set, secondary command */ +#define SMBfindclose 0x34 /* Terminate a TRANSACT2_FINDFIRST */ +#define SMBfindnclose 0x35 /* Terminate a TRANSACT2_FINDNOTIFYFIRST */ +#define SMBulogoffX 0x74 /* user logoff */ + +/* these are the TRANS2 sub commands */ +#define TRANSACT2_OPEN 0 +#define TRANSACT2_FINDFIRST 1 +#define TRANSACT2_FINDNEXT 2 +#define TRANSACT2_QFSINFO 3 +#define TRANSACT2_SETFSINFO 4 +#define TRANSACT2_QPATHINFO 5 +#define TRANSACT2_SETPATHINFO 6 +#define TRANSACT2_QFILEINFO 7 +#define TRANSACT2_SETFILEINFO 8 +#define TRANSACT2_FSCTL 9 +#define TRANSACT2_IOCTL 10 +#define TRANSACT2_FINDNOTIFYFIRST 11 +#define TRANSACT2_FINDNOTIFYNEXT 12 +#define TRANSACT2_MKDIR 13 + +#endif /* _SMBNO_H_ */ diff -u --recursive --new-file v1.3.6/linux/include/linux/stats206.h linux/include/linux/stats206.h --- v1.3.6/linux/include/linux/stats206.h Thu Jan 1 02:00:00 1970 +++ linux/include/linux/stats206.h Sat Jul 1 19:06:00 1995 @@ -0,0 +1,34 @@ +/* stats206.h. Define constants to gather statistics on the cm206 behavior. + Copyright (c) 1995 David van Leeuwen. + + This is published under the Gnu Public Licence, read the header in + the file cm206.c. +*/ + +/* This is an ugly way to guarantee that the names of the statistics + * are the same in the code and in the diagnostics program. */ + +#ifdef __KERNEL__ +#define x(a) st_ ## a +#define y enum +#else +#define x(a) #a +#define y char * stats_name[] = +#endif + +y {x(interrupt), x(data_ready), x(fifo_overflow), x(data_error), + x(crc_error), x(sync_error), x(lost_intr), x(echo), + x(write_timeout), x(receive_timeout), x(read_timeout), + x(dsb_timeout), x(stop_0xff), x(back_read_timeout), + x(sector_transferred), x(read_restarted), x(read_background), + x(bh), x(open), x(ioctl_multisession) +#ifdef __KERNEL__ + , x(last_entry) +#endif + }; + +#ifdef __KERNEL__ +#define NR_STATS st_last_entry +#else +#define NR_STATS sizeof(stats_name)/sizeof(char*) +#endif diff -u --recursive --new-file v1.3.6/linux/include/linux/timer.h linux/include/linux/timer.h --- v1.3.6/linux/include/linux/timer.h Sun Jan 22 21:30:17 1995 +++ linux/include/linux/timer.h Sat Jul 1 19:06:00 1995 @@ -31,6 +31,10 @@ * * MCD_TIMER Mitsumi CD-ROM Timer * + * GSCD_TIMER Goldstar CD-ROM Timer + * + * OPTCD_TIMER Optics Storage CD-ROM Timer + * */ #define BLANK_TIMER 0 @@ -48,6 +52,8 @@ #define MCD_TIMER 23 #define HD_TIMER2 24 +#define GSCD_TIMER 25 +#define OPTCD_TIMER 26 struct timer_struct { unsigned long expires; diff -u --recursive --new-file v1.3.6/linux/include/net/arp.h linux/include/net/arp.h --- v1.3.6/linux/include/net/arp.h Tue Jun 6 11:22:17 1995 +++ linux/include/net/arp.h Thu Jul 6 13:22:05 1995 @@ -3,18 +3,19 @@ #define _ARP_H extern void arp_init(void); -extern void arp_destroy(unsigned long paddr, int force); +extern void arp_destroy(u32 paddr, int force); extern void arp_device_down(struct device *dev); extern int arp_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt); -extern int arp_find(unsigned char *haddr, unsigned long paddr, - struct device *dev, unsigned long saddr, struct sk_buff *skb); +extern int arp_query(unsigned char *haddr, u32 paddr, unsigned short type); +extern int arp_find(unsigned char *haddr, u32 paddr, + struct device *dev, u32 saddr, struct sk_buff *skb); extern int arp_get_info(char *buffer, char **start, off_t origin, int length); extern int arp_ioctl(unsigned int cmd, void *arg); -extern void arp_send(int type, int ptype, unsigned long dest_ip, - struct device *dev, unsigned long src_ip, +extern void arp_send(int type, int ptype, u32 dest_ip, + struct device *dev, u32 src_ip, unsigned char *dest_hw, unsigned char *src_hw); -extern int arp_find_cache(unsigned char *dp, unsigned long daddr, struct device *dev); +extern int arp_find_cache(unsigned char *dp, u32 daddr, struct device *dev); extern unsigned long arp_cache_stamp; #endif /* _ARP_H */ diff -u --recursive --new-file v1.3.6/linux/include/net/atalk.h linux/include/net/atalk.h --- v1.3.6/linux/include/net/atalk.h Tue Jun 6 11:22:17 1995 +++ linux/include/net/atalk.h Thu Jan 1 02:00:00 1970 @@ -1,144 +0,0 @@ -/* - * Appletalk networking structures - * - * The following are directly referenced from the University Of Michigan - * netatalk for compatibility reasons. - */ - -#ifndef __LINUX_ATALK_H__ -#define __LINUX_ATALK_H__ - -#define ATPORT_FIRST 1 -#define ATPORT_RESERVED 128 -#define ATPORT_LAST 255 -#define ATADDR_ANYNET (__u16)0 -#define ATADDR_ANYNODE (__u8)0 -#define ATADDR_ANYPORT (__u8)0 -#define ATADDR_BCAST (__u8)255 -#define DDP_MAXSZ 587 - -struct at_addr -{ - __u16 s_net; - __u8 s_node; -}; - -struct sockaddr_at -{ - short sat_family; - __u8 sat_port; - struct at_addr sat_addr; - char sat_zero[ 8 ]; -}; - -struct netrange -{ - __u8 nr_phase; - __u16 nr_firstnet; - __u16 nr_lastnet; -}; - -struct atalk_route -{ - struct device *dev; - struct at_addr target; - struct at_addr gateway; - int flags; - struct atalk_route *next; -}; - -struct atalk_iface -{ - struct device *dev; - struct at_addr address; /* Our address */ - int status; /* What are we doing ?? */ -#define ATIF_PROBE 1 /* Probing for an address */ -#define ATIF_PROBE_FAIL 2 /* Probe collided */ - struct netrange nets; /* Associated direct netrange */ - struct atalk_iface *next; -}; - -struct atalk_sock -{ - unsigned short dest_net; - unsigned short src_net; - unsigned char dest_node; - unsigned char src_node; - unsigned char dest_port; - unsigned char src_port; -}; - -#define DDP_MAXHOPS 15 /* 4 bits of hop counter */ - -#ifdef __KERNEL__ - -struct ddpehdr -{ - /* FIXME for bigendians */ - /*__u16 deh_pad:2,deh_hops:4,deh_len:10;*/ - __u16 deh_len:10,deh_hops:4,deh_pad:2; - __u16 deh_sum; - __u16 deh_dnet; - __u16 deh_snet; - __u8 deh_dnode; - __u8 deh_snode; - __u8 deh_dport; - __u8 deh_sport; - /* And netatalk apps expect to stick the type in themselves */ -}; - -/* - * Unused (and currently unsupported) - */ - -struct ddpshdr -{ - /* FIXME for bigendians */ - __u8 dsh_sport; - __u8 dsh_dport; - __u16 dsh_len:10, dsh_pad:6; - /* And netatalk apps expect to stick the type in themselves */ -}; - -/* Appletalk AARP headers */ - -struct elapaarp -{ - __u16 hw_type; -#define AARP_HW_TYPE_ETHERNET 1 -#define AARP_HW_TYPE_TOKENRING 2 - __u16 pa_type; - __u8 hw_len; - __u8 pa_len; -#define AARP_PA_ALEN 4 - __u16 function; -#define AARP_REQUEST 1 -#define AARP_REPLY 2 -#define AARP_PROBE 3 - __u8 hw_src[ETH_ALEN] __attribute__ ((packed)); - __u8 pa_src_zero __attribute__ ((packed)); - __u16 pa_src_net __attribute__ ((packed)); - __u8 pa_src_node __attribute__ ((packed)); - __u8 hw_dst[ETH_ALEN] __attribute__ ((packed)); - __u8 pa_dst_zero __attribute__ ((packed)); - __u16 pa_dst_net __attribute__ ((packed)); - __u8 pa_dst_node __attribute__ ((packed)); -}; - -typedef struct sock atalk_socket; - -#define AARP_EXPIRY_TIME (5*60*HZ) /* Not specified - how long till we drop a resolved entry */ -#define AARP_HASH_SIZE 16 /* Size of hash table */ -#define AARP_TICK_TIME (HZ/5) /* Fast retransmission timer when resolving */ -#define AARP_RETRANSMIT_LIMIT 10 /* Send 10 requests then give up (2 seconds) */ -#define AARP_RESOLVE_TIME (10*HZ) /* Some value bigger than total retransmit time + a bit for last reply to appear and to stop continual requests */ - -extern struct datalink_proto *ddp_dl, *aarp_dl; -extern void aarp_proto_init(void); -/* Inter module exports */ -extern struct atalk_iface *atalk_find_dev(struct device *dev); -extern struct at_addr *atalk_find_dev_addr(struct device *dev); -extern int aarp_send_ddp(struct device *dev,struct sk_buff *skb, struct at_addr *sa, void *hwaddr); -extern void aarp_send_probe(struct device *dev, struct at_addr *addr); -#endif -#endif diff -u --recursive --new-file v1.3.6/linux/include/net/ax25.h linux/include/net/ax25.h --- v1.3.6/linux/include/net/ax25.h Fri Jun 30 16:22:30 1995 +++ linux/include/net/ax25.h Wed Jul 5 13:06:27 1995 @@ -7,6 +7,13 @@ #ifndef _AX25_H #define _AX25_H #include + +#define AX25_BPQ_HEADER_LEN 16 +#define AX25_KISS_HEADER_LEN 1 + +#define AX25_MAX_HEADER_LEN 56 +#define AX25_HEADER_LEN 17 +#define AX25_ADDR_LEN 7 #define AX25_P_IP 0xCC #define AX25_P_ARP 0xCD @@ -126,11 +133,10 @@ struct sock *sk; /* Backlink to socket */ } ax25_cb; -/* ax25.c */ +/* af_ax25.c */ extern char *ax2asc(ax25_address *); extern int ax25cmp(ax25_address *, ax25_address *); -extern int ax25_send_frame(struct sk_buff *, ax25_address *, ax25_address *, struct device *); -extern int ax25_rcv(struct sk_buff *,struct device *,struct packet_type *); +extern int ax25_send_frame(struct sk_buff *, ax25_address *, ax25_address *, ax25_digi *, struct device *); extern void ax25_destroy_socket(ax25_cb *); extern struct device *ax25rtr_get_dev(ax25_address *); extern int ax25_encapsulate(struct sk_buff *, struct device *, unsigned short, @@ -140,6 +146,7 @@ extern ax25_uid_assoc *ax25_uid_list; extern int ax25_uid_policy; extern ax25_address *ax25_findbyuid(uid_t); +extern void ax25_queue_xmit(struct sk_buff *, struct device *, int); #include "ax25call.h" @@ -184,5 +191,8 @@ /* ax25_timer */ extern void ax25_set_timer(ax25_cb *); + +/* slip.c */ +extern int sl_get_ax25_mode(struct device *); #endif diff -u --recursive --new-file v1.3.6/linux/include/net/netrom.h linux/include/net/netrom.h --- v1.3.6/linux/include/net/netrom.h Fri Jun 30 16:22:30 1995 +++ linux/include/net/netrom.h Wed Jul 5 13:06:27 1995 @@ -7,6 +7,9 @@ #ifndef _NETROM_H #define _NETROM_H #include + +#define NR_NETWORK_LEN 15 +#define NR_TRANSPORT_LEN 5 #define NR_PROTO_IP 0x0C @@ -72,6 +75,7 @@ struct nr_neigh { struct nr_neigh *next; ax25_address callsign; + ax25_digi *digipeat; struct device *dev; unsigned char quality; unsigned char locked; @@ -79,7 +83,7 @@ unsigned short number; }; -/* netrom.c */ +/* af_netrom.c */ extern struct nr_parms_struct nr_default; extern int nr_rx_frame(struct sk_buff *, struct device *); extern void nr_destroy_socket(struct sock *); @@ -110,7 +114,7 @@ extern struct device *nr_dev_get(ax25_address *); extern int nr_rt_ioctl(unsigned int, void *); extern void nr_link_failed(ax25_address *, struct device *); -extern int nr_route_frame(struct sk_buff *, struct device *); +extern int nr_route_frame(struct sk_buff *, ax25_cb *); extern int nr_nodes_get_info(char *, char **, off_t, int); extern int nr_neigh_get_info(char *, char **, off_t, int); diff -u --recursive --new-file v1.3.6/linux/include/net/route.h linux/include/net/route.h --- v1.3.6/linux/include/net/route.h Fri Jun 30 16:22:30 1995 +++ linux/include/net/route.h Fri Jun 30 16:46:17 1995 @@ -32,9 +32,9 @@ unsigned long rt_dst; unsigned long rt_mask; unsigned long rt_gateway; - unsigned char rt_flags; - unsigned char rt_metric; - short rt_refcnt; + unsigned short rt_flags; + unsigned short rt_metric; + unsigned int rt_refcnt; unsigned long rt_use; unsigned short rt_mss; unsigned short rt_irtt; diff -u --recursive --new-file v1.3.6/linux/include/net/sock.h linux/include/net/sock.h --- v1.3.6/linux/include/net/sock.h Fri Jun 30 16:22:30 1995 +++ linux/include/net/sock.h Wed Jul 5 13:06:27 1995 @@ -48,7 +48,7 @@ #include "ipx.h" #endif #ifdef CONFIG_ATALK -#include "atalk.h" +#include #endif #include diff -u --recursive --new-file v1.3.6/linux/include/net/tcp.h linux/include/net/tcp.h --- v1.3.6/linux/include/net/tcp.h Tue Jun 27 14:11:47 1995 +++ linux/include/net/tcp.h Thu Jul 6 14:04:43 1995 @@ -20,10 +20,10 @@ #include -#define MAX_SYN_SIZE 44 + MAX_HEADER -#define MAX_FIN_SIZE 40 + MAX_HEADER -#define MAX_ACK_SIZE 40 + MAX_HEADER -#define MAX_RESET_SIZE 40 + MAX_HEADER +#define MAX_SYN_SIZE 44 + MAX_HEADER + 15 +#define MAX_FIN_SIZE 40 + MAX_HEADER + 15 +#define MAX_ACK_SIZE 40 + MAX_HEADER + 15 +#define MAX_RESET_SIZE 40 + MAX_HEADER + 15 #define MAX_WINDOW 16384 #define MIN_WINDOW 2048 #define MAX_ACK_BACKLOG 2 diff -u --recursive --new-file v1.3.6/linux/init/main.c linux/init/main.c --- v1.3.6/linux/init/main.c Tue Jun 27 14:11:47 1995 +++ linux/init/main.c Sat Jul 1 19:06:00 1995 @@ -54,8 +54,6 @@ extern void eth_setup(char *str, int *ints); extern void xd_setup(char *str, int *ints); extern void floppy_setup(char *str, int *ints); -extern void mcd_setup(char *str, int *ints); -extern void aztcd_setup(char *str, int *ints); extern void st_setup(char *str, int *ints); extern void st0x_setup(char *str, int *ints); extern void tmc8xx_setup(char *str, int *ints); @@ -68,15 +66,36 @@ extern void buslogic_setup(char *str, int *ints); extern void scsi_luns_setup(char *str, int *ints); extern void sound_setup(char *str, int *ints); -#ifdef CONFIG_SBPCD -extern void sbpcd_setup(char *str, int *ints); -#endif CONFIG_SBPCD #ifdef CONFIG_CDU31A extern void cdu31a_setup(char *str, int *ints); #endif CONFIG_CDU31A +#ifdef CONFIG_MCD +extern void mcd_setup(char *str, int *ints); +#endif CONFIG_MCD +#ifdef CONFIG_MCDX +extern void mcdx_setup(char *str, int *ints); +#endif CONFIG_MCDX +#ifdef CONFIG_SBPCD +extern void sbpcd_setup(char *str, int *ints); +#endif CONFIG_SBPCD +#ifdef CONFIG_AZTCD +extern void aztcd_setup(char *str, int *ints); +#endif CONFIG_AZTCD #ifdef CONFIG_CDU535 extern void sonycd535_setup(char *str, int *ints); #endif CONFIG_CDU535 +#ifdef CONFIG_GSCD +extern void gscd_setup(char *str, int *ints); +#endif CONFIG_GSCD +#ifdef CONFIG_CM206 +extern void cm206_setup(char *str, int *ints); +#endif CONFIG_CM206 +#ifdef CONFIG_OPTCD +extern void optcd_setup(char *str, int *ints); +#endif CONFIG_OPTCD +#ifdef CONFIG_SJCD +extern void sjcd_setup(char *str, int *ints); +#endif CONFIG_SJCD void ramdisk_setup(char *str, int *ints); #ifdef CONFIG_SYSVIPC @@ -187,24 +206,39 @@ #ifdef CONFIG_BLK_DEV_FD { "floppy=", floppy_setup }, #endif +#ifdef CONFIG_CDU31A + { "cdu31a=", cdu31a_setup }, +#endif CONFIG_CDU31A #ifdef CONFIG_MCD { "mcd=", mcd_setup }, -#endif +#endif CONFIG_MCD +#ifdef CONFIG_MCDX + { "mcdx=", mcdx_setup }, +#endif CONFIG_MCDX +#ifdef CONFIG_SBPCD + { "sbpcd=", sbpcd_setup }, +#endif CONFIG_SBPCD #ifdef CONFIG_AZTCD { "aztcd=", aztcd_setup }, -#endif +#endif CONFIG_AZTCD #ifdef CONFIG_CDU535 { "sonycd535=", sonycd535_setup }, #endif CONFIG_CDU535 +#ifdef CONFIG_GSCD + { "gscd=", gscd_setup }, +#endif CONFIG_GSCD +#ifdef CONFIG_CM206 + { "cm206=", cm206_setup }, +#endif CONFIG_CM206 +#ifdef CONFIG_OPTCD + { "optcd=", optcd_setup }, +#endif CONFIG_OPTCD +#ifdef CONFIG_SJCD + { "sjcd=", sjcd_setup }, +#endif CONFIG_SJCD #ifdef CONFIG_SOUND { "sound=", sound_setup }, #endif -#ifdef CONFIG_SBPCD - { "sbpcd=", sbpcd_setup }, -#endif CONFIG_SBPCD -#ifdef CONFIG_CDU31A - { "cdu31a=", cdu31a_setup }, -#endif CONFIG_CDU31A { 0, 0 } }; diff -u --recursive --new-file v1.3.6/linux/kernel/Makefile linux/kernel/Makefile --- v1.3.6/linux/kernel/Makefile Mon Jan 23 10:38:30 1995 +++ linux/kernel/Makefile Tue Jul 4 07:59:54 1995 @@ -26,7 +26,7 @@ include ../versions.mk -kernel.o: $(SYMTAB_OBJS) $(OBJS) +kernel.o: $(SYMTAB_OBJS:.o=.ver) $(SYMTAB_OBJS) $(OBJS) $(LD) -r -o kernel.o $(SYMTAB_OBJS) $(OBJS) sync diff -u --recursive --new-file v1.3.6/linux/kernel/ksyms.c linux/kernel/ksyms.c --- v1.3.6/linux/kernel/ksyms.c Fri Jun 30 16:22:30 1995 +++ linux/kernel/ksyms.c Tue Jul 4 07:59:54 1995 @@ -57,6 +57,10 @@ #include #endif +#if defined(CONFIG_PROC_FS) +#include +#endif + #include extern char *get_options(char *str, int *ints); extern void set_device_ro(int dev,int flag); @@ -80,6 +84,11 @@ off_t offset, int length, int inode, int func) = 0; /* Dirty hack */ +#if defined(CONFIG_PROC_FS) +extern struct proc_dir_entry scsi_dir[]; +extern struct proc_dir_entry scsi_hba_dir[]; +#endif + extern int sys_tz; extern int request_dma(unsigned int dmanr, char * deviceID); extern void free_dma(unsigned int dmanr); @@ -222,6 +231,7 @@ X(disable_irq), X(bh_active), X(bh_mask), + X(bh_base), X(add_timer), X(del_timer), X(tq_timer), @@ -375,6 +385,23 @@ X(mem_map), X(print_msg), X(print_status), + X(gendisk_head), /* Needed for sd.c */ + X(resetup_one_dev), /* Needed for sd.c */ +#else + /* + * With no scsi configured, we still need to export a few + * symbols so that scsi can be loaded later via insmod. + */ + X(intr_count), + X(mem_map), + X(gendisk_head), + X(resetup_one_dev), + +#if defined(CONFIG_PROC_FS) + X(scsi_dir), + X(scsi_hba_dir), +#endif + X(dispatch_scsi_info_ptr), #endif /* Added to make file system as module */ X(set_writetime), diff -u --recursive --new-file v1.3.6/linux/kernel/sys.c linux/kernel/sys.c --- v1.3.6/linux/kernel/sys.c Fri Jun 30 16:22:30 1995 +++ linux/kernel/sys.c Thu Jul 6 13:24:46 1995 @@ -195,6 +195,7 @@ asmlinkage int sys_setregid(gid_t rgid, gid_t egid) { int old_rgid = current->gid; + int old_egid = current->egid; if (rgid != (gid_t) -1) { if ((old_rgid == rgid) || @@ -219,6 +220,8 @@ (egid != (gid_t) -1 && egid != old_rgid)) current->sgid = current->egid; current->fsgid = current->egid; + if (current->egid != old_egid) + current->dumpable = 0; return 0; } @@ -227,12 +230,16 @@ */ asmlinkage int sys_setgid(gid_t gid) { + int old_egid = current->egid; + if (suser()) current->gid = current->egid = current->sgid = current->fsgid = gid; else if ((gid == current->gid) || (gid == current->sgid)) current->egid = current->fsgid = gid; else return -EPERM; + if (current->egid != old_egid) + current->dumpable = 0; return 0; } @@ -284,6 +291,7 @@ asmlinkage int sys_setreuid(uid_t ruid, uid_t euid) { int old_ruid = current->uid; + int old_euid = current->euid; if (ruid != (uid_t) -1) { if ((old_ruid == ruid) || @@ -308,6 +316,8 @@ (euid != (uid_t) -1 && euid != old_ruid)) current->suid = current->euid; current->fsuid = current->euid; + if (current->euid != old_euid) + current->dumpable = 0; return 0; } @@ -324,12 +334,16 @@ */ asmlinkage int sys_setuid(uid_t uid) { + int old_euid = current->euid; + if (suser()) current->uid = current->euid = current->suid = current->fsuid = uid; else if ((uid == current->uid) || (uid == current->suid)) current->fsuid = current->euid = uid; else return -EPERM; + if (current->euid != old_euid) + current->dumpable = 0; return(0); } @@ -346,6 +360,8 @@ if (uid == current->uid || uid == current->euid || uid == current->suid || uid == current->fsuid || suser()) current->fsuid = uid; + if (current->fsuid != old_fsuid) + current->dumpable = 0; return old_fsuid; } @@ -359,6 +375,8 @@ if (gid == current->gid || gid == current->egid || gid == current->sgid || gid == current->fsgid || suser()) current->fsgid = gid; + if (current->fsgid != old_fsgid) + current->dumpable = 0; return old_fsgid; } diff -u --recursive --new-file v1.3.6/linux/net/802/p8022.c linux/net/802/p8022.c --- v1.3.6/linux/net/802/p8022.c Fri Jun 30 16:22:30 1995 +++ linux/net/802/p8022.c Wed Jul 5 13:06:27 1995 @@ -6,6 +6,13 @@ static struct datalink_proto *p8022_list = NULL; +/* + * We don't handle the loopback SAP stuff, the extended + * 802.2 command set, multicast SAP identifiers and non UI + * frames. We have the absolute minimum needed for IPX, + * IP and Appletalk phase 2. + */ + static struct datalink_proto * find_8022_client(unsigned char type) { diff -u --recursive --new-file v1.3.6/linux/net/802/tr.c linux/net/802/tr.c --- v1.3.6/linux/net/802/tr.c Fri Jun 30 16:22:30 1995 +++ linux/net/802/tr.c Wed Jul 5 13:06:27 1995 @@ -92,6 +92,8 @@ struct trh_hdr *trh=(struct trh_hdr *)skb->data; struct trllc *trllc=(struct trllc *)(skb->data+sizeof(struct trh_hdr)); + skb_pull(skb,dev->hard_header_len); + if(trh->saddr[0] & TR_RII) tr_add_rif_info(trh); diff -u --recursive --new-file v1.3.6/linux/net/Changes linux/net/Changes --- v1.3.6/linux/net/Changes Fri Jun 30 16:22:30 1995 +++ linux/net/Changes Wed Jul 5 13:06:27 1995 @@ -100,25 +100,33 @@ ------->>>>> NET3 030 <<<<<---------- +o Long word align ethernet IP headers (64byte align for pentium) [TESTED] + (less helpful than I'd have liked) +o Fixed variable length header support to really work [TESTED] +o Mend appletalk/ipx partially [IN] +o Start playing with input checksum & copy [IN] +o Fixed PPP and other oddments [IN] +o Mended IPIP [Might work ;)] + +------->>>>> 1.3.7 <<<<<---------- + o Finish merging the bridge code o Device locking -o Faster ip_csum o SIOCSLEEPRT patch o Options support in ip_build_xmit [PENDING] o Fast checksum/copy on outgoing TCP -o Long word align ethernet IP headers (64byte align for pentium) [TESTING - EMAIL FOR INFO] o Explode/implode headers for alpha,mips etc. o Fast dev_grab_next() transmit reload function and dev_push_failed() ?? -o Faster ip_forward -o Faster loopback frame forwarding. +o Faster ip_forward [PENDING] o Forwarding queue control (+ fairness algorithms ??) o IP forward flow control. o Infinite PPP/SLIP devices. -o PI2 card doesn't do AX.25 VC yet +o PI2 card doesn't do AX.25 VC yet [PENDING] o AX.25 set protocol type o Clean up RAW AX.25 sockets. o Finish 802.2 Class I code to be compliant to the oddities of 802.2 +o Full variable length AX.25 support [JSN doing] 0.2 --- diff -u --recursive --new-file v1.3.6/linux/net/appletalk/aarp.c linux/net/appletalk/aarp.c --- v1.3.6/linux/net/appletalk/aarp.c Fri Jun 30 16:22:30 1995 +++ linux/net/appletalk/aarp.c Wed Jul 5 14:13:04 1995 @@ -46,7 +46,7 @@ #include #include #include -#include +#include #ifdef CONFIG_ATALK /* @@ -103,7 +103,7 @@ struct device *dev=a->dev; int len=dev->hard_header_len+sizeof(struct elapaarp)+aarp_dl->header_length; struct sk_buff *skb=alloc_skb(len, GFP_ATOMIC); - struct elapaarp *eah=(struct elapaarp *)(skb->data+dev->hard_header_len+aarp_dl->header_length); + struct elapaarp *eah; struct at_addr *sat=atalk_find_dev_addr(dev); if(skb==NULL || sat==NULL) @@ -112,10 +112,11 @@ /* * Set up the buffer. */ - + + skb_reserve(skb,dev->hard_header_len+aarp_dl->header_length); + eah = (struct elapaarp *)skb_put(skb,sizeof(struct elapaarp)); skb->arp = 1; skb->free = 1; - skb_put(skb,len); skb->dev = a->dev; /* @@ -164,7 +165,7 @@ { int len=dev->hard_header_len+sizeof(struct elapaarp)+aarp_dl->header_length; struct sk_buff *skb=alloc_skb(len, GFP_ATOMIC); - struct elapaarp *eah=(struct elapaarp *)(skb->data+dev->hard_header_len+aarp_dl->header_length); + struct elapaarp *eah; if(skb==NULL) return; @@ -172,7 +173,9 @@ /* * Set up the buffer. */ - + + skb_reserve(skb,dev->hard_header_len+aarp_dl->header_length); + eah = (struct elapaarp *)skb_put(skb,sizeof(struct elapaarp)); skb->arp = 1; skb->free = 1; skb_put(skb,len); @@ -225,7 +228,7 @@ { int len=dev->hard_header_len+sizeof(struct elapaarp)+aarp_dl->header_length; struct sk_buff *skb=alloc_skb(len, GFP_ATOMIC); - struct elapaarp *eah=(struct elapaarp *)(skb->data+dev->hard_header_len+aarp_dl->header_length); + struct elapaarp *eah; static char aarp_eth_multicast[ETH_ALEN]={ 0x09, 0x00, 0x07, 0xFF, 0xFF, 0xFF }; if(skb==NULL) @@ -234,7 +237,10 @@ /* * Set up the buffer. */ - + + skb_reserve(skb,dev->hard_header_len+aarp_dl->header_length); + eah = (struct elapaarp *)skb_put(skb,sizeof(struct elapaarp)); + skb->arp = 1; skb->free = 1; skb_put(skb,len); @@ -575,8 +581,6 @@ kfree_skb(skb, FREE_READ); return 0; } - - skb_pull(skb,dev->hard_header_len); /* * Frame size ok ? diff -u --recursive --new-file v1.3.6/linux/net/appletalk/ddp.c linux/net/appletalk/ddp.c --- v1.3.6/linux/net/appletalk/ddp.c Fri Jun 30 16:22:30 1995 +++ linux/net/appletalk/ddp.c Wed Jul 5 13:06:27 1995 @@ -46,7 +46,7 @@ #include #include #include -#include +#include #ifdef CONFIG_ATALK @@ -1334,10 +1334,6 @@ struct sockaddr_at tosat; int origlen; - /* First strip the MAC header */ - - skb_pull(skb,dev->hard_header_len); - /* Size check */ if(skb->lenarp=1; skb_reserve(skb,ddp_dl->header_length); skb_reserve(skb,dev->hard_header_len); - skb_put(skb,size); skb->dev=dev; if(sk->debug) printk("SK %p: Begin build.\n", sk); - skb->h.raw=skb->data; - - ddp=(struct ddpehdr *)skb->h.raw; + ddp=(struct ddpehdr *)skb_put(skb,sizeof(struct ddpehdr)); ddp->deh_pad=0; ddp->deh_hops=0; ddp->deh_len=len+sizeof(*ddp); @@ -1579,7 +1572,7 @@ if(sk->debug) printk("SK %p: Copy user data (%d bytes).\n", sk, len); - memcpy_fromfs((char *)(ddp+1),ubuf,len); + memcpy_fromfs(skb_put(skb,len),ubuf,len); if(sk->no_check==1) ddp->deh_sum=0; @@ -1616,6 +1609,7 @@ sk->wmem_alloc-=skb->truesize; ddp_dl->datalink_header(ddp_dl, skb, dev->dev_addr); skb->sk = NULL; + skb->mac.raw=skb->data; skb->h.raw = skb->data + ddp_dl->header_length + dev->hard_header_len; skb_pull(skb,dev->hard_header_len); skb_pull(skb,ddp_dl->header_length); diff -u --recursive --new-file v1.3.6/linux/net/ax25/README.AX25 linux/net/ax25/README.AX25 --- v1.3.6/linux/net/ax25/README.AX25 Tue Jun 6 11:22:15 1995 +++ linux/net/ax25/README.AX25 Wed Jul 5 13:06:27 1995 @@ -1,20 +1,50 @@ -This is a working version of the new state machine code for AX25 under -Linux. It is closely based on the SDL diagrams published in the ARRL 7th -Computer Networking Conference papers, and they should be referred to when -reading the code, notably the stuff in ax25_in.c. The next stage is to -separate the ax25 control block from the socket and then add NET/ROM and -connected mode IP. I would also like to add the extended AX25 designed by a -Dutch station which allows for window sizes up to 127. - -This code will work the same as the old code, although the display in -/proc/net/ax25 is a little different, but should be understandable. Please -give this code a work out and report any bugs to me either at -jsn@cs.nott.ac.uk or at GB7DAD.GBR.EU. - -This code has taught me a lot about the internals of the networking side of -Linux especially skbuff handling and I now feel happy about implementing the -higher level protocols. +This is version 029 of the new AX.25 and NET/ROM code for Linux. It +incorporates many enhancements since the last release, notably the rewriting +of the connected mode IP code and the IP over NET/ROM code. The opportunity +has been taken to add the G8BPQ NET/ROM extensions and to add BPQ Ethernet +support. The latter has been much eased by the use of the new variable +length header code by Alan Cox. -73's +To use the BPQ Ethernet option, first up the ethernet interface in the usual +manner, the IP address of the interface is not that important but it will +be required for the ARP table. Next create an ARP entry in the ARP table of +type ax25 for the interface binding it to an AX.25 callsign, this callsign +will be the callsign of that interface. By default BPQ Ethernet uses a +multi-cast address, this implementation does not, instead the standard +ethernet broadcast address is used. Therefore the NET.CFG file for the +ODI driver should look similar to this: -Jonathan +------------------------------ cut here ------------------------------------ + +LINK SUPPORT + + MAX STACKS 1 + MAX BOARDS 1 + +LINK DRIVER E2000 ; or other MLID to suit your card + + INT 10 ; + PORT 300 ; to suit your card + + FRAME ETHERNET_II + + PROTOCOL BPQ 8FF ETHERNET_II ; required for BPQ - can change PID + +BPQPARMS ; optional - only needed if you want + ; to override the default target addr + + ETH_ADDR FF:FF:FF:FF:FF:FF ; Target address + +----------------------------- cut here ------------------------------------- + +The above configuration assumes that only BPQ Ethernet is being used. + +It is not possible to run IP over AX.25 on the BPQ Ethernet port. To simply +route IP frames to (say) eth0 would create standard ethernet IP frames and +completely bypass the AX.25 code. However it is possible to use IP over +NET/ROM across a BPQ Ethernet link, the performance of such a system is +very acceptable indeed. + +Jonathan Naylor G4KLX + +g4klx@amsat.org diff -u --recursive --new-file v1.3.6/linux/net/ax25/af_ax25.c linux/net/ax25/af_ax25.c --- v1.3.6/linux/net/ax25/af_ax25.c Fri Jun 30 16:22:31 1995 +++ linux/net/ax25/af_ax25.c Wed Jul 5 13:06:28 1995 @@ -56,7 +56,9 @@ * Jonathan(G4KLX) and removed all the old Berkeley, added IP mode registration. * Darryl(G7LED) stuff. Cross-port digipeating. Minor fixes and enhancements. * Alan(GW4PTS) Missed suser() on axassociate checks - * AX.25 030 Alan(GW4PTS) Switched to new buffers. Not tested netrom/new buffers yet. + * AX.25 030 Alan(GW4PTS) Added variable length headers. + * Jonathan(G4KLX) Added BPQ Ethernet interface. + * Steven(GW7RRM) * * To do: * Support use as digipeater, including an on/off ioctl @@ -534,15 +536,14 @@ return ax25; } -int ax25_send_frame(struct sk_buff *skb, ax25_address *src, ax25_address *dest, struct device *dev) +int ax25_send_frame(struct sk_buff *skb, ax25_address *src, ax25_address *dest, + ax25_digi *digi, struct device *dev) { ax25_cb *ax25; if (skb == NULL) return 0; - skb->h.raw = skb->data + 15; - /* * Look for an existing connection. */ @@ -564,6 +565,14 @@ memcpy(&ax25->source_addr, src, sizeof(ax25_address)); memcpy(&ax25->dest_addr, dest, sizeof(ax25_address)); + if (digi != NULL) { + if ((ax25->digipeat = kmalloc(sizeof(ax25_digi), GFP_ATOMIC)) == NULL) { + kfree_s(ax25, sizeof(ax25)); + return 0; + } + memcpy(ax25->digipeat, digi, sizeof(ax25_digi)); + } + ax25_establish_data_link(ax25); ax25_insert_socket(ax25); @@ -585,11 +594,23 @@ struct device *ax25rtr_get_dev(ax25_address *addr) { struct device *dev; + ax25_address dev_addr; for (dev = dev_base; dev != NULL; dev = dev->next) { - if ((dev->flags & IFF_UP) && dev->type == ARPHRD_AX25) { /* Active kiss ax25 mode */ - if (ax25cmp(addr, (ax25_address *)dev->dev_addr) == 0) - return dev; + if (dev->flags & IFF_UP) { + switch (dev->type) { + case ARPHRD_AX25: /* Active kiss ax25 mode */ + if (ax25cmp(addr, (ax25_address *)dev->dev_addr) == 0) + return dev; + break; + case ARPHRD_ETHER: + if (arp_query((unsigned char *)&dev_addr, dev->pa_addr, ARPHRD_AX25)) + if (ax25cmp(addr, &dev_addr) == 0) + return dev; + break; + default: + break; + } } } @@ -632,14 +653,14 @@ return err; opt = get_fs_long((unsigned long *)optval); - + switch (optname) { case AX25_WINDOW: if (opt < 1 || opt > 7) return -EINVAL; sk->ax25->window = opt; return 0; - + case AX25_T1: if (opt < 1) return -EINVAL; @@ -651,23 +672,23 @@ return -EINVAL; sk->ax25->t2 = opt * PR_SLOWHZ; return 0; - + case AX25_N2: if (opt < 1 || opt > 31) return -EINVAL; sk->ax25->n2 = opt; return 0; - + case AX25_T3: if (opt < 1) return -EINVAL; sk->ax25->t3 = opt * PR_SLOWHZ; return 0; - + case AX25_BACKOFF: sk->ax25->backoff = opt ? 1 : 0; return 0; - + default: return -ENOPROTOOPT; } @@ -687,7 +708,7 @@ if (level != SOL_AX25) return -EOPNOTSUPP; - + switch (optname) { case AX25_WINDOW: val = sk->ax25->window; @@ -696,23 +717,23 @@ case AX25_T1: val = sk->ax25->t1 / PR_SLOWHZ; break; - + case AX25_T2: val = sk->ax25->t2 / PR_SLOWHZ; break; - + case AX25_N2: val = sk->ax25->n2; break; - + case AX25_T3: val = sk->ax25->t3 / PR_SLOWHZ; break; - + case AX25_BACKOFF: val = sk->ax25->backoff; break; - + default: return -ENOPROTOOPT; } @@ -934,7 +955,7 @@ break; case AX25_STATE_1: - ax25_send_control(sk->ax25, DISC | PF, C_RESPONSE); + ax25_send_control(sk->ax25, DISC | PF, C_COMMAND); sk->ax25->state = AX25_STATE_0; sk->dead = 1; sk->state_change(sk); @@ -1238,9 +1259,8 @@ return 0; } -int ax25_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *ptype) +static int ax25_rcv(struct sk_buff *skb, struct device *dev, ax25_address *dev_addr, struct packet_type *ptype) { - unsigned char *data; struct sock *make; struct sock *sk; int type = 0; @@ -1249,30 +1269,19 @@ ax25_address src, dest; struct sock *raw; int mine = 0; - - data=skb->data; - + /* * Process the AX.25/LAPB frame. */ - skb->sk = NULL; /* Initially we don't know who its for */ - - if ((*data & 0x0F) != 0) { - kfree_skb(skb, FREE_READ); /* Not a KISS data frame */ - return 0; - } - - data++; - /* * Parse the address header. */ - if ((data = ax25_parse_addr(data, skb->len + dev->hard_header_len - 1, &src, &dest, &dp, &type)) == NULL) { + if (ax25_parse_addr(skb->data, skb->len, &src, &dest, &dp, &type) == NULL) { kfree_skb(skb, FREE_READ); return 0; } - + /* * Send the frame to the AX.25 auto-router */ @@ -1282,7 +1291,7 @@ * Ours perhaps ? */ if (dp.lastrepeat + 1 < dp.ndigi) { /* Not yet digipeated completely */ - if (ax25cmp(&dp.calls[dp.lastrepeat + 1], (ax25_address *)dev->dev_addr) == 0) { + if (ax25cmp(&dp.calls[dp.lastrepeat + 1], dev_addr) == 0) { /* We are the digipeater. Mark ourselves as repeated and throw the packet back out of the same device */ dp.lastrepeat++; @@ -1297,9 +1306,9 @@ dev = dev_scan; } #endif - build_ax25_addr(skb->data + 1, &src, &dest, &dp, type); + build_ax25_addr(skb->data, &src, &dest, &dp, type); skb->arp = 1; - dev_queue_xmit(skb, dev, SOPRI_NORMAL); + ax25_queue_xmit(skb, dev, SOPRI_NORMAL); } else { kfree_skb(skb, FREE_READ); } @@ -1307,9 +1316,13 @@ return 0; } - + /* + * Pull of the AX.25 headers leaving the CTRL/PID bytes + */ + skb_pull(skb, size_ax25_addr(&dp)); + /* For our port addreses ? */ - if (ax25cmp(&dest, (ax25_address *)dev->dev_addr) == 0) + if (ax25cmp(&dest, dev_addr) == 0) mine = 1; #ifdef CONFIG_NETROM @@ -1318,28 +1331,28 @@ mine = 1; #endif - if ((*data & ~0x10) == LAPB_UI) { /* UI frame - bypass LAPB processing */ - data++; - skb->h.raw = data + 1; /* skip pid */ + if ((*skb->data & ~0x10) == LAPB_UI) { /* UI frame - bypass LAPB processing */ + skb->h.raw = skb->data + 2; /* skip control and pid */ if ((raw = ax25_addr_match(&dest)) != NULL) - ax25_send_to_raw(raw, skb, (int)*data); + ax25_send_to_raw(raw, skb, skb->data[1]); - if (!mine && ax25cmp(&dest, (ax25_address *)dev->broadcast) != 0) - { + if (!mine && ax25cmp(&dest, (ax25_address *)dev->broadcast) != 0) { kfree_skb(skb, FREE_READ); return 0; } /* Now we are pointing at the pid byte */ - switch (*data++) { + switch (skb->data[1]) { #ifdef CONFIG_INET case AX25_P_IP: + skb_pull(skb,2); /* drop PID/CTRL */ ax25_ip_mode_set(&src, dev, 'D'); ip_rcv(skb, dev, ptype); /* Note ptype here is the wrong one, fix me later */ break; case AX25_P_ARP: + skb_pull(skb,2); arp_rcv(skb, dev, ptype); /* Note ptype here is wrong... */ break; #endif @@ -1350,9 +1363,9 @@ kfree_skb(skb, FREE_READ); } else { /* - * Remove kiss/headers + * Remove the control and PID. */ - skb_pull(skb,3+size_ax25_addr(&dp)); + skb_pull(skb, 2); skb_queue_tail(&sk->receive_queue, skb); skb->sk = sk; sk->rmem_alloc += skb->truesize; @@ -1373,29 +1386,24 @@ } /* LAPB */ - - /* - * Pull of the AX.25 headers leaving the CTRL/PID bytes - */ - skb_pull(skb, 1+size_ax25_addr(&dp)); - if ((ax25 = ax25_find_cb(&dest, &src, dev)) != NULL) { - skb->h.raw = data; - /* Process the frame. If it is queued up internally it returns one otherwise we - free it immediately. This routine itself wakes the user context layers so we - do no further work */ + /* + * Process the frame. If it is queued up internally it returns one otherwise we + * free it immediately. This routine itself wakes the user context layers so we + * do no further work + */ if (ax25_process_rx_frame(ax25, skb, type) == 0) kfree_skb(skb, FREE_READ); return 0; } - if ((data[0] & 0xEF) != SABM) { + if ((*skb->data & 0xEF) != SABM) { /* * Never reply to a DM. Also ignore any connects for * addresses that are not our interfaces and not a socket. */ - if ((data[0] & 0xEF) != DM && mine) + if ((*skb->data & 0xEF) != DM && mine) ax25_return_dm(dev, &src, &dest, &dp); kfree_skb(skb, FREE_READ); @@ -1413,25 +1421,6 @@ ax25 = make->ax25; - /* - * Sort out any digipeated paths. - */ - if (dp.ndigi != 0 && ax25->digipeat == NULL && (ax25->digipeat = kmalloc(sizeof(ax25_digi), GFP_ATOMIC)) == NULL) { - kfree_skb(skb, FREE_READ); - ax25_destroy_socket(ax25); - return 0; - } - - if (dp.ndigi == 0) { - if (ax25->digipeat != NULL) { - kfree_s(ax25->digipeat, sizeof(ax25_digi)); - ax25->digipeat = NULL; - } - } else { - /* Reverse the source SABM's path */ - ax25_digi_invert(&dp, ax25->digipeat); - } - skb_queue_head(&sk->receive_queue, skb); skb->sk = make; @@ -1446,12 +1435,6 @@ return 0; } - if (dp.ndigi != 0) { - ax25_return_dm(dev, &src, &dest, &dp); - kfree_skb(skb, FREE_READ); - return 0; - } - if ((ax25 = ax25_create_cb()) == NULL) { ax25_return_dm(dev, &src, &dest, &dp); kfree_skb(skb, FREE_READ); @@ -1469,6 +1452,25 @@ memcpy(&ax25->source_addr, &dest, sizeof(ax25_address)); memcpy(&ax25->dest_addr, &src, sizeof(ax25_address)); + /* + * Sort out any digipeated paths. + */ + if (dp.ndigi != 0 && ax25->digipeat == NULL && (ax25->digipeat = kmalloc(sizeof(ax25_digi), GFP_ATOMIC)) == NULL) { + kfree_skb(skb, FREE_READ); + ax25_destroy_socket(ax25); + return 0; + } + + if (dp.ndigi == 0) { + if (ax25->digipeat != NULL) { + kfree_s(ax25->digipeat, sizeof(ax25_digi)); + ax25->digipeat = NULL; + } + } else { + /* Reverse the source SABM's path */ + ax25_digi_invert(&dp, ax25->digipeat); + } + ax25->device = dev; ax25_send_control(ax25, UA | PF, C_RESPONSE); @@ -1490,6 +1492,46 @@ return 0; } +/* + * Receive an AX.25 frame via a SLIP interface. + */ +static int kiss_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *ptype) +{ + skb->sk = NULL; /* Initially we don't know who its for */ + + if ((*skb->data & 0x0F) != 0) { + kfree_skb(skb, FREE_READ); /* Not a KISS data frame */ + return 0; + } + + skb_pull(skb, AX25_KISS_HEADER_LEN); /* Remove the KISS byte */ + + return ax25_rcv(skb, dev, (ax25_address *)dev->dev_addr, ptype); +} + +/* + * Receive an AX.25 frame via an Ethernet interface. + */ +static int bpq_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *ptype) +{ + ax25_address port_call; + int len; + + skb->sk = NULL; /* Initially we don't know who its for */ + + if (!arp_query((unsigned char *)&port_call, dev->pa_addr, ARPHRD_AX25)) { + kfree_skb(skb, FREE_READ); /* We have no port callsign */ + return 0; + } + + len = skb->data[14] + skb->data[15] * 256 - 5; + + skb_pull(skb, AX25_BPQ_HEADER_LEN); /* Remove the BPQ Header */ + skb_trim(skb, len); /* Set the length of the data */ + + return ax25_rcv(skb, dev, &port_call, ptype); +} + static int ax25_sendto(struct socket *sock, void *ubuf, int len, int noblock, unsigned flags, struct sockaddr *usip, int addr_len) { @@ -1575,8 +1617,8 @@ if (sk->debug) printk("AX.25: sendto: building packet.\n"); - size = 2 + len + 1 + size_ax25_addr(dp); - /* 2 bytes for PID and (U)I frame byte: 15+ for KISS data & calls */ + /* Assume the worst case */ + size = len + 2 + size_ax25_addr(dp) + AX25_BPQ_HEADER_LEN; if ((skb = sock_alloc_send_skb(sk, size, 0, &err)) == NULL) return err; @@ -1584,46 +1626,60 @@ skb->sk = sk; skb->free = 1; skb->arp = 1; - skb_reserve(skb, 3+size_ax25_addr(dp)); - asmptr = skb_push(skb,3+size_ax25_addr(dp)); - if (sk->debug) { - printk("Building AX.25 Header (dp=%p).\n", dp); - if (dp != 0) - printk("Num digipeaters=%d\n", dp->ndigi); - } - /* Build an AX.25 header */ - *asmptr++ = 0; /* KISS data */ - asmptr += (lv = build_ax25_addr(asmptr, &sk->ax25->source_addr, &sax.sax25_call, dp, C_COMMAND)); - if (sk->debug) - printk("Built header (%d bytes)\n",lv); - skb->h.raw = asmptr; - - if (sk->debug) - printk("base=%p pos=%p\n", skb->data, asmptr); - *asmptr++ = LAPB_UI; /* Datagram - will get replaced for I frames */ - *asmptr++ = sk->protocol; /* AX.25 TEXT by default */ - + skb_reserve(skb, size - len); + if (sk->debug) printk("AX.25: Appending user data\n"); /* User data follows immediately after the AX.25 data */ - memcpy_fromfs(skb_put(skb,len), ubuf, len); + memcpy_fromfs(skb_put(skb, len), ubuf, len); + + /* Add the PID, usually AX25_TEXT */ + asmptr = skb_push(skb, 1); + *asmptr = sk->protocol; + if (sk->debug) printk("AX.25: Transmitting buffer\n"); + if (sk->type == SOCK_SEQPACKET) { /* Connected mode sockets go via the LAPB machine */ if (sk->state != TCP_ESTABLISHED) { kfree_skb(skb, FREE_WRITE); return -ENOTCONN; } + ax25_output(sk->ax25, skb); /* Shove it onto the queue and kick */ + return len; } else { + asmptr = skb_push(skb, 1 + size_ax25_addr(dp)); + + if (sk->debug) { + printk("Building AX.25 Header (dp=%p).\n", dp); + if (dp != 0) + printk("Num digipeaters=%d\n", dp->ndigi); + } + + /* Build an AX.25 header */ + asmptr += (lv = build_ax25_addr(asmptr, &sk->ax25->source_addr, &sax.sax25_call, dp, C_COMMAND)); + + if (sk->debug) + printk("Built header (%d bytes)\n",lv); + + skb->h.raw = asmptr; + + if (sk->debug) + printk("base=%p pos=%p\n", skb->data, asmptr); + + *asmptr = LAPB_UI; + /* Datagram frames go straight out of the door as UI */ - dev_queue_xmit(skb, sk->ax25->device, SOPRI_NORMAL); + ax25_queue_xmit(skb, sk->ax25->device, SOPRI_NORMAL); + return len; } + } static int ax25_send(struct socket *sock, void *ubuf, int size, int noblock, unsigned flags) @@ -1645,7 +1701,7 @@ int copied = 0; struct sk_buff *skb; int er; - int bias=0; + int bias = 0; if (sk->err) { er = -sk->err; @@ -1657,18 +1713,17 @@ *addr_len = sizeof(*sax); /* This works for seqpacket too. The receiver has ordered the queue for us! We do one quick check first though */ - if (sk->type == SOCK_SEQPACKET) - { - if(sk->state != TCP_ESTABLISHED) + if (sk->type == SOCK_SEQPACKET) { + if (sk->state != TCP_ESTABLISHED) return -ENOTCONN; - bias=2; + bias = 2; } /* Now we can treat all alike */ if ((skb = skb_recv_datagram(sk, flags, noblock, &er)) == NULL) return er; - copied= (size < skb->len-bias) ? size : skb->len-bias; + copied = (size < skb->len - bias) ? size : skb->len - bias; skb_copy_datagram(skb, bias, ubuf, copied); if (sax) { @@ -1685,12 +1740,12 @@ addrptr += sizeof(*sax); while (ct < digi.ndigi) { - memcpy(addrptr, &digi. calls[ct], 7); - addrptr += 7; + memcpy(addrptr, &digi. calls[ct], AX25_ADDR_LEN); + addrptr += AX25_ADDR_LEN; ct++; } if (addr_len) - *addr_len = sizeof(*sax) + 7 * digi.ndigi; + *addr_len = sizeof(*sax) + AX25_ADDR_LEN * digi.ndigi; } skb_free_datagram(skb); @@ -1819,7 +1874,7 @@ cli(); - len += sprintf(buffer, "dest_addr src_addr dev st vs vr va t1 t2 t3 n2 rtt wnd Snd-Q Rcv-Q\n"); + len += sprintf(buffer, "dest_addr src_addr dev st vs vr va t1 t2 t3 n2 rtt wnd Snd-Q Rcv-Q\n"); for (ax25 = ax25_list; ax25 != NULL; ax25 = ax25->next) { if ((dev = ax25->device) == NULL) @@ -1829,7 +1884,7 @@ len += sprintf(buffer + len, "%-9s ", ax2asc(&ax25->dest_addr)); - len += sprintf(buffer + len, "%-9s %-3s %2d %2d %2d %2d %3d/%03d %2d/%02d %3d/%03d %2d/%02d %3d %3d", + len += sprintf(buffer + len, "%-9s %-4s %2d %2d %2d %2d %3d/%03d %2d/%02d %3d/%03d %2d/%02d %3d %3d", ax2asc(&ax25->source_addr), devname, ax25->state, ax25->vs, ax25->vr, ax25->va, @@ -1904,7 +1959,16 @@ { 0, /* MUTTER ntohs(ETH_P_AX25),*/ 0, /* copy */ - ax25_rcv, + kiss_rcv, + NULL, + NULL, +}; + +static struct packet_type bpq_packet_type = +{ + 0, /* MUTTER ntohs(ETH_P_BPQ),*/ + 0, /* copy */ + bpq_rcv, NULL, NULL, }; @@ -1919,8 +1983,45 @@ sock_register(ax25_proto_ops.family, &ax25_proto_ops); ax25_packet_type.type = htons(ETH_P_AX25); dev_add_pack(&ax25_packet_type); + bpq_packet_type.type = htons(ETH_P_BPQ); + dev_add_pack(&bpq_packet_type); register_netdevice_notifier(&ax25_dev_notifier); - printk("GW4PTS/G4KLX AX.25 for Linux. Version 0.29 ALPHA for Linux NET3.029 (Linux 1.3.0)\n"); + printk("GW4PTS/G4KLX AX.25 for Linux. Version 0.30 ALPHA for Linux NET3.030 (Linux 1.3.0)\n"); +} + +/* + * A small shim to dev_queue_xmit to handle the difference between + * KISS AX.25 and BPQ AX.25. + */ +void ax25_queue_xmit(struct sk_buff *skb, struct device *dev, int pri) +{ + static char bcast_addr[6] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; + unsigned char *ptr; + int size; + + if (dev->type == ARPHRD_ETHER) { + if (skb_headroom(skb) < AX25_BPQ_HEADER_LEN) { + printk("ax25_queue_xmit: not enough space to add BPQ Ether header\n"); + skb->free = 1; + kfree_skb(skb, FREE_WRITE); + return; + } + + size = skb->len; + + ptr = skb_push(skb, 2); + + *ptr++ = (size + 5) % 256; + *ptr++ = (size + 5) / 256; + + dev->hard_header(skb, dev, ETH_P_BPQ, bcast_addr, NULL, 0); + } else { + ptr = skb_push(skb, 1); + + *ptr++ = 0; /* KISS */ + } + + dev_queue_xmit(skb, dev, pri); } /*******************************************************************************************************************\ @@ -1940,15 +2041,17 @@ void *saddr, unsigned len) { /* header is an AX.25 UI frame from us to them */ - unsigned char *buff=skb_push(skb,17); + unsigned char *buff = skb_push(skb, AX25_HEADER_LEN); + *buff++ = 0; /* KISS DATA */ if (daddr != NULL) memcpy(buff, daddr, dev->addr_len); /* Address specified */ + buff[6] &= ~LAPB_C; buff[6] &= ~LAPB_E; buff[6] |= SSID_SPARE; - buff += 7; + buff += AX25_ADDR_LEN; if (saddr != NULL) memcpy(buff, saddr, dev->addr_len); @@ -1958,7 +2061,8 @@ buff[6] &= ~LAPB_C; buff[6] |= LAPB_E; buff[6] |= SSID_SPARE; - buff += 7; + buff += AX25_ADDR_LEN; + *buff++ = LAPB_UI; /* UI */ /* Append a suitable AX.25 PID */ @@ -1970,26 +2074,39 @@ case ETH_P_ARP: *buff++ = AX25_P_ARP; break; - default: *buff++ = 0; break; } - if (daddr != NULL) - return 17; + if (daddr != NULL) + return AX25_HEADER_LEN; - return -17; /* Unfinished header */ + return -AX25_HEADER_LEN; /* Unfinished header */ } int ax25_rebuild_header(unsigned char *bp, struct device *dev, unsigned long dest, struct sk_buff *skb) { + int mode; + if (arp_find(bp + 1, dest, dev, dev->pa_addr, skb)) return 1; + if (bp[16] == AX25_P_IP) { + mode = ax25_ip_mode_get((ax25_address *)(bp + 1), dev); + + if (mode == 'V' || mode == 'v' || (mode == ' ' && sl_get_ax25_mode(dev))) { + skb_device_unlock(skb); + skb_pull(skb, AX25_HEADER_LEN - 1); /* Keep PID */ + ax25_send_frame(skb, (ax25_address *)(bp + 8), (ax25_address *)(bp + 1), NULL, dev); + return 1; + } + } + bp[7] &= ~LAPB_C; bp[7] &= ~LAPB_E; bp[7] |= SSID_SPARE; + bp[14] &= ~LAPB_C; bp[14] |= LAPB_E; bp[14] |= SSID_SPARE; diff -u --recursive --new-file v1.3.6/linux/net/ax25/ax25_in.c linux/net/ax25/ax25_in.c --- v1.3.6/linux/net/ax25/ax25_in.c Fri Jun 30 16:22:31 1995 +++ linux/net/ax25/ax25_in.c Wed Jul 5 13:06:27 1995 @@ -57,22 +57,24 @@ * This is where all valid I frames are sent to, to be dispatched to * whichever protocol requires them. */ -static int ax25_rx_iframe(ax25_cb *ax25, struct sk_buff *skb, unsigned char *iframe) +static int ax25_rx_iframe(ax25_cb *ax25, struct sk_buff *skb) { int queued = 0; - switch (iframe[1]) { + skb->h.raw = skb->data; + + switch (skb->data[1]) { #ifdef CONFIG_NETROM case AX25_P_NETROM: - /* We can't handle digipeated NET/ROM frames */ - if (ax25->digipeat == NULL) - queued = nr_route_frame(skb, ax25->device); + skb_pull(skb, 2); + queued = nr_route_frame(skb, ax25); break; #endif #ifdef CONFIG_INET case AX25_P_IP: ax25_ip_mode_set(&ax25->dest_addr, ax25->device, 'V'); - skb->h.raw = skb->data; + skb->h.raw += 2; + skb_push(skb, skb->dev->hard_header_len); ip_rcv(skb, skb->dev, NULL); /* Wrong ptype */ queued = 1; break; @@ -99,9 +101,9 @@ * The handling of the timer(s) is in file ax25_timer.c. * Handling of state 0 and connection release is in ax25.c. */ -static int ax25_state1_machine(ax25_cb *ax25, struct sk_buff *skb, unsigned char *frame, int frametype, int type) +static int ax25_state1_machine(ax25_cb *ax25, struct sk_buff *skb, int frametype, int type) { - int pf = frame[0] & PF; + int pf = skb->data[0] & PF; switch (frametype) { case SABM: @@ -157,9 +159,9 @@ * The handling of the timer(s) is in file ax25_timer.c * Handling of state 0 and connection release is in ax25.c. */ -static int ax25_state2_machine(ax25_cb *ax25, struct sk_buff *skb, unsigned char *frame, int frametype, int type) +static int ax25_state2_machine(ax25_cb *ax25, struct sk_buff *skb, int frametype, int type) { - int pf = frame[0] & PF; + int pf = skb->data[0] & PF; switch (frametype) { case SABM: @@ -216,11 +218,11 @@ * The handling of the timer(s) is in file ax25_timer.c * Handling of state 0 and connection release is in ax25.c. */ -static int ax25_state3_machine(ax25_cb *ax25, struct sk_buff *skb, unsigned char *frame, int frametype, int type) +static int ax25_state3_machine(ax25_cb *ax25, struct sk_buff *skb, int frametype, int type) { - unsigned short nr = (frame[0] >> 5) & 7; - unsigned short ns = (frame[0] >> 1) & 7; - int pf = frame[0] & PF; + unsigned short nr = (skb->data[0] >> 5) & 7; + unsigned short ns = (skb->data[0] >> 1) & 7; + int pf = skb->data[0] & PF; int queued = 0; switch (frametype) { @@ -320,7 +322,7 @@ break; } if (ns == ax25->vr) { - queued = ax25_rx_iframe(ax25, skb, frame); + queued = ax25_rx_iframe(ax25, skb); if (ax25->condition & OWN_RX_BUSY_CONDITION) { if (pf) ax25_enquiry_response(ax25); break; @@ -364,11 +366,11 @@ * The handling of the timer(s) is in file ax25_timer.c * Handling of state 0 and connection release is in ax25.c. */ -static int ax25_state4_machine(ax25_cb *ax25, struct sk_buff *skb, unsigned char *frame, int frametype, int type) +static int ax25_state4_machine(ax25_cb *ax25, struct sk_buff *skb, int frametype, int type) { - unsigned short nr = (frame[0] >> 5) & 7; - unsigned short ns = (frame[0] >> 1) & 7; - int pf = frame[0] & PF; + unsigned short nr = (skb->data[0] >> 5) & 7; + unsigned short ns = (skb->data[0] >> 1) & 7; + int pf = skb->data[0] & PF; int queued = 0; switch (frametype) { @@ -511,7 +513,7 @@ break; } if (ns == ax25->vr) { - queued = ax25_rx_iframe(ax25, skb, frame); + queued = ax25_rx_iframe(ax25, skb); if (ax25->condition & OWN_RX_BUSY_CONDITION) { if (pf) ax25_enquiry_response(ax25); break; @@ -556,7 +558,6 @@ int ax25_process_rx_frame(ax25_cb *ax25, struct sk_buff *skb, int type) { int queued = 0, frametype; - unsigned char *frame; if (ax25->state != AX25_STATE_1 && ax25->state != AX25_STATE_2 && ax25->state != AX25_STATE_3 && ax25->state != AX25_STATE_4) { @@ -566,22 +567,20 @@ del_timer(&ax25->timer); - frame = skb->h.raw; - - frametype = ax25_decode(frame); + frametype = ax25_decode(skb->data); switch (ax25->state) { case AX25_STATE_1: - queued = ax25_state1_machine(ax25, skb, frame, frametype, type); + queued = ax25_state1_machine(ax25, skb, frametype, type); break; case AX25_STATE_2: - queued = ax25_state2_machine(ax25, skb, frame, frametype, type); + queued = ax25_state2_machine(ax25, skb, frametype, type); break; case AX25_STATE_3: - queued = ax25_state3_machine(ax25, skb, frame, frametype, type); + queued = ax25_state3_machine(ax25, skb, frametype, type); break; case AX25_STATE_4: - queued = ax25_state4_machine(ax25, skb, frame, frametype, type); + queued = ax25_state4_machine(ax25, skb, frametype, type); break; } diff -u --recursive --new-file v1.3.6/linux/net/ax25/ax25_out.c linux/net/ax25/ax25_out.c --- v1.3.6/linux/net/ax25/ax25_out.c Tue Jun 6 12:16:43 1995 +++ linux/net/ax25/ax25_out.c Wed Jul 5 13:06:27 1995 @@ -68,7 +68,7 @@ if (skb == NULL) return; - frame = skb->h.raw; /* KISS + header */ + frame = skb_push(skb, 1); /* KISS + header */ *frame = I; *frame |= poll_bit; @@ -146,7 +146,7 @@ void ax25_transmit_buffer(ax25_cb *ax25, struct sk_buff *skb, int type) { - unsigned char *ptr = skb->data; + unsigned char *ptr; if (ax25->device == NULL) { if (ax25->sk != NULL) { @@ -159,12 +159,19 @@ return; } - *ptr++ = 0; /* KISS data */ - ptr += build_ax25_addr(ptr, &ax25->source_addr, &ax25->dest_addr, ax25->digipeat, type); + if (skb_headroom(skb) < size_ax25_addr(ax25->digipeat)) { + printk("ax25_transmit_buffer: not enough room for digi-peaters\n"); + skb->free = 1; + kfree_skb(skb, FREE_WRITE); + return; + } + + ptr = skb_push(skb, size_ax25_addr(ax25->digipeat)); + build_ax25_addr(ptr, &ax25->source_addr, &ax25->dest_addr, ax25->digipeat, type); skb->arp = 1; - dev_queue_xmit(skb, ax25->device, SOPRI_NORMAL); + ax25_queue_xmit(skb, ax25->device, SOPRI_NORMAL); } /* diff -u --recursive --new-file v1.3.6/linux/net/ax25/ax25_route.c linux/net/ax25/ax25_route.c --- v1.3.6/linux/net/ax25/ax25_route.c Fri Jun 30 16:22:31 1995 +++ linux/net/ax25/ax25_route.c Wed Jul 5 13:06:27 1995 @@ -145,10 +145,10 @@ cli(); - len += sprintf(buffer, "callsign dev count time mode\n"); + len += sprintf(buffer, "callsign dev count time mode\n"); for (ax25_rt = ax25_route; ax25_rt != NULL; ax25_rt = ax25_rt->next) { - len += sprintf(buffer + len, "%-9s %-3s %5d %9d", + len += sprintf(buffer + len, "%-9s %-4s %5d %9d", ax2asc(&ax25_rt->callsign), ax25_rt->dev ? ax25_rt->dev->name : "???", ax25_rt->n, diff -u --recursive --new-file v1.3.6/linux/net/ax25/ax25_subr.c linux/net/ax25/ax25_subr.c --- v1.3.6/linux/net/ax25/ax25_subr.c Fri Jun 30 16:22:31 1995 +++ linux/net/ax25/ax25_subr.c Wed Jul 5 13:06:27 1995 @@ -143,25 +143,22 @@ struct sk_buff *skb; unsigned char *dptr; struct device *dev; - int asize; if ((dev = ax25->device) == NULL) return; /* Route died */ - asize= 1+size_ax25_addr(ax25->digipeat); - - if ((skb = alloc_skb(16 + asize, GFP_ATOMIC)) == NULL) + if ((skb = alloc_skb(AX25_BPQ_HEADER_LEN + size_ax25_addr(ax25->digipeat) + 1, GFP_ATOMIC)) == NULL) return; - skb_reserve(skb, asize); - + + skb_reserve(skb, AX25_BPQ_HEADER_LEN + size_ax25_addr(ax25->digipeat)); + if (ax25->sk != NULL) { skb->sk = ax25->sk; ax25->sk->wmem_alloc += skb->truesize; } /* Assume a response - address structure for DTE */ - dptr = skb_put(skb,1); - + dptr = skb_put(skb, 1); if ((frametype & U) == S) /* S frames carry NR */ frametype |= (ax25->vr << 5); @@ -169,7 +166,7 @@ *dptr = frametype; skb->free = 1; - skb_push(skb,asize); + ax25_transmit_buffer(ax25, skb, type); } @@ -183,35 +180,33 @@ struct sk_buff *skb; char *dptr; ax25_digi retdigi; - int len = 2 + size_ax25_addr(digi); - if ((skb = alloc_skb(len, GFP_ATOMIC)) == NULL) + if (dev == NULL) + return; + + if ((skb = alloc_skb(AX25_BPQ_HEADER_LEN + size_ax25_addr(digi) + 1, GFP_ATOMIC)) == NULL) return; /* Next SABM will get DM'd */ - skb_reserve(skb,len-1); + skb_reserve(skb, AX25_BPQ_HEADER_LEN + size_ax25_addr(digi)); ax25_digi_invert(digi, &retdigi); - dptr = skb_put(skb,1); + dptr = skb_put(skb, 1); skb->sk = NULL; *dptr = DM | PF; - if (dev == NULL) - return; - /* - * Do the address ourselves. + * Do the address ourselves */ - dptr = skb_push(skb, len-1); - *dptr++ = 0; - dptr += build_ax25_addr(dptr, dest, src, &retdigi, C_RESPONSE); + dptr = skb_push(skb, size_ax25_addr(digi)); + dptr += build_ax25_addr(dptr, dest, src, &retdigi, C_RESPONSE); skb->arp = 1; skb->free = 1; - dev_queue_xmit(skb, dev, SOPRI_NORMAL); + ax25_queue_xmit(skb, dev, SOPRI_NORMAL); } /* @@ -233,7 +228,7 @@ } /* - * Calculate the r Round Trip Time + * Calculate the Round Trip Time */ void ax25_calculate_rtt(ax25_cb *ax25) { @@ -273,10 +268,10 @@ } /* Copy to, from */ - if (dest != NULL) memcpy(dest, buf + 0, 7); - if (src != NULL) memcpy(src, buf + 7, 7); - buf += 14; - len -= 14; + if (dest != NULL) memcpy(dest, buf + 0, AX25_ADDR_LEN); + if (src != NULL) memcpy(src, buf + 7, AX25_ADDR_LEN); + buf += 2 * AX25_ADDR_LEN; + len -= 2 * AX25_ADDR_LEN; digi->lastrepeat = -1; digi->ndigi = 0; @@ -286,7 +281,7 @@ if (len < 7) return NULL; /* Short packet */ if (digi != NULL) { - memcpy(&digi->calls[d], buf, 7); + memcpy(&digi->calls[d], buf, AX25_ADDR_LEN); digi->ndigi = d + 1; if (buf[6] & AX25_REPEATED) { digi->repeated[d] = 1; @@ -296,8 +291,8 @@ } } - buf += 7; - len -= 7; + buf += AX25_ADDR_LEN; + len -= AX25_ADDR_LEN; d++; } @@ -313,7 +308,7 @@ int len = 0; int ct = 0; - memcpy(buf, dest, 7); + memcpy(buf, dest, AX25_ADDR_LEN); if (flag != C_COMMAND && flag != C_RESPONSE) printk("build_ax25_addr: Bogus flag %d\n!", flag); @@ -322,9 +317,9 @@ if (flag == C_COMMAND) buf[6] |= LAPB_C; - buf += 7; - len += 7; - memcpy(buf, src, 7); + buf += AX25_ADDR_LEN; + len += AX25_ADDR_LEN; + memcpy(buf, src, AX25_ADDR_LEN); buf[6] &= ~(LAPB_E | LAPB_C); buf[6] |= SSID_SPARE; @@ -334,14 +329,14 @@ */ if (d == NULL || d->ndigi == 0) { buf[6] |= LAPB_E; - return 14; + return 2 * AX25_ADDR_LEN; } - buf += 7; - len += 7; + buf += AX25_ADDR_LEN; + len += AX25_ADDR_LEN; while (ct < d->ndigi) { - memcpy(buf, &d->calls[ct], 7); + memcpy(buf, &d->calls[ct], AX25_ADDR_LEN); if (d->repeated[ct]) buf[6] |= AX25_REPEATED; else @@ -349,8 +344,8 @@ buf[6] &= ~LAPB_E; buf[6] |= SSID_SPARE; - buf += 7; - len += 7; + buf += AX25_ADDR_LEN; + len += AX25_ADDR_LEN; ct++; } @@ -362,9 +357,9 @@ int size_ax25_addr(ax25_digi *dp) { if (dp == NULL) - return 14; + return 2 * AX25_ADDR_LEN; - return 14 + (7 * dp->ndigi); + return AX25_ADDR_LEN * (2 + dp->ndigi); } /* diff -u --recursive --new-file v1.3.6/linux/net/core/dev.c linux/net/core/dev.c --- v1.3.6/linux/net/core/dev.c Fri Jun 30 16:22:31 1995 +++ linux/net/core/dev.c Wed Jul 5 13:06:27 1995 @@ -93,7 +93,7 @@ static struct sk_buff_head backlog = { (struct sk_buff *)&backlog, (struct sk_buff *)&backlog -#ifdef CONFIG_SKB_CHECK +#if CONFIG_SKB_CHECK ,SK_HEAD_SKB #endif }; @@ -320,7 +320,7 @@ if(pri>=0 && !skb_device_locked(skb)) skb_device_lock(skb); /* Shove a lock on the frame */ -#ifdef CONFIG_SKB_CHECK +#if CONFIG_SKB_CHECK IS_SKB(skb); #endif skb->dev = dev; @@ -444,7 +444,7 @@ /* * Add it to the "backlog" queue. */ -#ifdef CONFIG_SKB_CHECK +#if CONFIG_SKB_CHECK IS_SKB(skb); #endif skb_queue_tail(&backlog,skb); @@ -647,7 +647,7 @@ * skb->h.raw point to the MAC and encapsulated data */ - skb->h.raw = skb->data+skb->dev->hard_header_len; + skb->h.raw = skb->data; /* * Fetch the packet protocol ID. diff -u --recursive --new-file v1.3.6/linux/net/core/skbuff.c linux/net/core/skbuff.c --- v1.3.6/linux/net/core/skbuff.c Fri Jun 30 16:22:31 1995 +++ linux/net/core/skbuff.c Wed Jul 5 13:06:27 1995 @@ -179,7 +179,7 @@ #endif -#ifdef CONFIG_SKB_CHECK +#if CONFIG_SKB_CHECK void skb_queue_head_init(struct sk_buff_head *list) { list->prev = (struct sk_buff *)list; @@ -440,7 +440,7 @@ __builtin_return_address(0)); return; } -#ifdef CONFIG_SKB_CHECK +#if CONFIG_SKB_CHECK IS_SKB(skb); #endif if (skb->lock) @@ -544,6 +544,7 @@ skb->localroute=0; skb->stamp.tv_sec=0; /* No idea about time */ skb->localroute = 0; + skb->ip_summed = 0; save_flags(flags); cli(); net_skbcount++; diff -u --recursive --new-file v1.3.6/linux/net/core/sock.c linux/net/core/sock.c --- v1.3.6/linux/net/core/sock.c Fri Jun 30 16:22:31 1995 +++ linux/net/core/sock.c Wed Jul 5 13:06:27 1995 @@ -382,7 +382,7 @@ void sock_wfree(struct sock *sk, struct sk_buff *skb) { int s=skb->truesize; -#ifdef CONFIG_SKB_CHECK +#if CONFIG_SKB_CHECK IS_SKB(skb); #endif kfree_skbmem(skb); @@ -403,7 +403,7 @@ void sock_rfree(struct sock *sk, struct sk_buff *skb) { int s=skb->truesize; -#ifdef CONFIG_SKB_CHECK +#if CONFIG_SKB_CHECK IS_SKB(skb); #endif kfree_skbmem(skb); diff -u --recursive --new-file v1.3.6/linux/net/ethernet/eth.c linux/net/ethernet/eth.c --- v1.3.6/linux/net/ethernet/eth.c Fri Jun 30 16:22:31 1995 +++ linux/net/ethernet/eth.c Wed Jul 5 13:06:27 1995 @@ -24,7 +24,8 @@ * and changes for new arp and skbuff. * Alan Cox : Redid header building to reflect new format. * Alan Cox : ARP only when compiled with CONFIG_INET - * Greg Page : 802.2 and SNAP stuff + * Greg Page : 802.2 and SNAP stuff. + * Alan Cox : MAC layer pointers/new format. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -48,6 +49,7 @@ #include #include #include +#include void eth_setup(char *str, int *ints) { @@ -166,9 +168,13 @@ unsigned short eth_type_trans(struct sk_buff *skb, struct device *dev) { - struct ethhdr *eth = (struct ethhdr *) skb->data; + struct ethhdr *eth; unsigned char *rawp; + skb->mac.raw=skb->data; + skb_pull(skb,14); + eth= skb->mac.ethernet; + if(*eth->h_dest&1) { if(memcmp(eth->h_dest,dev->broadcast, ETH_ALEN)==0) @@ -186,11 +192,20 @@ if (ntohs(eth->h_proto) >= 1536) return eth->h_proto; - rawp = (unsigned char *)(eth + 1); + rawp = skb->data; + /* + * This is a magic hack to spot IPX packets. Older Novell breaks + * the protocol design and runs IPX over 802.3 without an 802.2 LLC + * layer. We look for FFFF which isnt a used 802.2 SSAP/DSAP. This + * won't work for fault tolerant netware but does for the rest. + */ if (*(unsigned short *)rawp == 0xFFFF) return htons(ETH_P_802_3); + /* + * Real 802.2 LLC + */ return htons(ETH_P_802_2); } @@ -214,3 +229,20 @@ } } +/* + * Copy from an ethernet device memory space to an sk_buff while checksumming if IP + */ + +void eth_copy_and_sum(struct sk_buff *dest,unsigned char *src, int length, int base) +{ + struct ethhdr *eth=(struct ethhdr *)dest->data; + memcpy(dest->data,src,34); /* ethernet is always >= 60 */ + length-=34; + if(eth->h_proto!=htons(ETH_P_IP)) + { + memcpy(dest->data+34,src+34,length); + return; + } + dest->csum=csum_partial_copy(src+34,dest->data+34,length,base); + dest->ip_summed=1; +} diff -u --recursive --new-file v1.3.6/linux/net/ipv4/af_inet.c linux/net/ipv4/af_inet.c --- v1.3.6/linux/net/ipv4/af_inet.c Fri Jun 30 16:22:31 1995 +++ linux/net/ipv4/af_inet.c Thu Jul 6 13:24:59 1995 @@ -1280,6 +1280,7 @@ { struct sock *sk=(struct sock *)sock->data; int err; + int tmp; switch(cmd) { @@ -1288,7 +1289,11 @@ err=verify_area(VERIFY_READ,(int *)arg,sizeof(long)); if(err) return err; - sk->proc = get_fs_long((int *) arg); + tmp = get_fs_long((int *) arg); + /* see inet_fcntl */ + if (current->pid != tmp && current->pgrp != -tmp && !suser()) + return -EPERM; + sk->proc = tmp; return(0); case FIOGETOWN: case SIOCGPGRP: diff -u --recursive --new-file v1.3.6/linux/net/ipv4/arp.c linux/net/ipv4/arp.c --- v1.3.6/linux/net/ipv4/arp.c Fri Jun 30 16:22:31 1995 +++ linux/net/ipv4/arp.c Thu Jul 6 13:22:05 1995 @@ -86,8 +86,8 @@ struct arp_table *next; /* Linked entry list */ unsigned long last_used; /* For expiry */ unsigned int flags; /* Control status */ - unsigned long ip; /* ip address of entry */ - unsigned long mask; /* netmask - used for generalised proxy arps (tridge) */ + u32 ip; /* ip address of entry */ + u32 mask; /* netmask - used for generalised proxy arps (tridge) */ unsigned char ha[MAX_ADDR_LEN]; /* Hardware address */ unsigned char hlen; /* Length of hardware address */ unsigned short htype; /* Type of hardware in use */ @@ -143,7 +143,7 @@ /* Forward declarations. */ static void arp_check_expire (unsigned long); -static struct arp_table *arp_lookup(unsigned long paddr, enum proxy proxy); +static struct arp_table *arp_lookup(u32 paddr, enum proxy proxy); static struct timer_list arp_timer = @@ -307,8 +307,8 @@ * message. */ -void arp_send(int type, int ptype, unsigned long dest_ip, - struct device *dev, unsigned long src_ip, +void arp_send(int type, int ptype, u32 dest_ip, + struct device *dev, u32 src_ip, unsigned char *dest_hw, unsigned char *src_hw) { struct sk_buff *skb; @@ -406,7 +406,7 @@ if (--entry->retries > 0) { - unsigned long ip = entry->ip; + u32 ip = entry->ip; struct device *dev = entry->dev; /* Set new timer. */ @@ -493,14 +493,6 @@ else dev_queue_xmit(skb,skb->dev,skb->sk->priority); } - else - { - /* This routine is only ever called when 'entry' is - complete. Thus this can't fail. */ - printk("arp_send_q: The impossible occurred. Please notify Alan.\n"); - printk("arp_send_q: active entity %s\n",in_ntoa(entry->ip)); - printk("arp_send_q: failed to find %s\n",in_ntoa(skb->raddr)); - } } restore_flags(flags); } @@ -510,7 +502,7 @@ * Delete an ARP mapping entry in the cache. */ -void arp_destroy(unsigned long ip_addr, int force) +void arp_destroy(u32 ip_addr, int force) { int checked_proxies = 0; struct arp_table *entry; @@ -571,15 +563,10 @@ int addr_hint,hlen,htype; unsigned long hash; unsigned char ha[MAX_ADDR_LEN]; /* So we can enable ints again. */ - long sip,tip; unsigned char *sha,*tha; + u32 sip,tip; /* - * ARP carries the MAC addresses wrapped in the packet. We can't sanity - * check this as proxy arp has them different. - */ - skb_pull(skb,dev->hard_header_len); -/* * The hardware length of the packet should match the hardware length * of the device. Similarly, the hardware types should match. The * device should be ARP-able. Also, if pln is not 4, then the lookup @@ -839,16 +826,49 @@ /* + * Find an arp mapping in the cache. If not found, return false. + */ + +int arp_query(unsigned char *haddr, u32 paddr, unsigned short type) +{ + struct arp_table *entry; + unsigned long hash = HASH(paddr); + + /* + * Find an entry + */ + cli(); + + for (entry = arp_tables[hash]; entry != NULL; entry = entry->next) + if (entry->ip == paddr && entry->htype == type) + break; + + if (entry != NULL) { + /* + * Update the record + */ + + entry->last_used = jiffies; + memcpy(haddr, entry->ha, entry->hlen); + sti(); + return 1; + } + + sti(); + return 0; +} + +/* * Find an arp mapping in the cache. If not found, post a request. */ -int arp_find(unsigned char *haddr, unsigned long paddr, struct device *dev, - unsigned long saddr, struct sk_buff *skb) +int arp_find(unsigned char *haddr, u32 paddr, struct device *dev, + u32 saddr, struct sk_buff *skb) { struct arp_table *entry; unsigned long hash; #ifdef CONFIG_IP_MULTICAST - unsigned long taddr; + u32 taddr; #endif switch (ip_chk_addr(paddr)) @@ -1063,7 +1083,7 @@ * for proxy entries, otherwise the netmask will be used */ -static struct arp_table *arp_lookup(unsigned long paddr, enum proxy proxy) +static struct arp_table *arp_lookup(u32 paddr, enum proxy proxy) { struct arp_table *entry; unsigned long hash = HASH(paddr); @@ -1082,14 +1102,14 @@ } -int arp_find_cache(unsigned char *dp, unsigned long daddr, struct device *dev) +int arp_find_cache(unsigned char *dp, u32 daddr, struct device *dev) { /* * We need the broadcast/multicast awareness here and the find routine split up. */ struct arp_table *entry; #ifdef CONFIG_IP_MULTICAST - unsigned long taddr; + u32 taddr; #endif switch (ip_chk_addr(daddr)) @@ -1143,8 +1163,8 @@ struct arp_table *entry; struct sockaddr_in *si; int htype, hlen; - unsigned long ip; struct rtable *rt; + u32 ip; memcpy_fromfs(&r, req, sizeof(r)); diff -u --recursive --new-file v1.3.6/linux/net/ipv4/icmp.c linux/net/ipv4/icmp.c --- v1.3.6/linux/net/ipv4/icmp.c Fri Jun 30 16:22:31 1995 +++ linux/net/ipv4/icmp.c Thu Jul 6 14:04:42 1995 @@ -32,6 +32,7 @@ * Stefan Becker : ICMP redirects in icmp_send(). * Peter Belding : Tightened up ICMP redirect handling * Alan Cox : Tightened even more. + * Arnt Gulbrandsen: Misplaced #endif with net redirect and break * * * @@ -213,7 +214,7 @@ len = dev->hard_header_len + sizeof(struct iphdr) + sizeof(struct icmphdr) + sizeof(struct iphdr) + 32; /* amount of header to return */ - skb = (struct sk_buff *) alloc_skb(len, GFP_ATOMIC); + skb = (struct sk_buff *) alloc_skb(len+15, GFP_ATOMIC); if (skb == NULL) { icmp_statistics.IcmpOutErrors++; @@ -380,8 +381,8 @@ #ifdef not_a_good_idea ip_rt_add((RTF_DYNAMIC | RTF_MODIFIED | RTF_GATEWAY), ip, 0, icmph->un.gateway, dev,0, 0, 0); - break; #endif + break; case ICMP_REDIR_HOST: /* * Add better route to host. @@ -434,7 +435,7 @@ icmp_statistics.IcmpOutEchoReps++; icmp_statistics.IcmpOutMsgs++; - size = dev->hard_header_len + 64 + len; + size = dev->hard_header_len + 64 + len + 15; skb2 = alloc_skb(size, GFP_ATOMIC); if (skb2 == NULL) @@ -508,7 +509,7 @@ /* correct answers are possible for everything >= 12 */ } - size = dev->hard_header_len + 84; + size = dev->hard_header_len + 84 + 15; if (! (skb2 = alloc_skb(size, GFP_ATOMIC))) { @@ -599,7 +600,7 @@ icmp_statistics.IcmpOutMsgs++; icmp_statistics.IcmpOutAddrMaskReps++; - size = dev->hard_header_len + 64 + len; + size = dev->hard_header_len + 64 + len + 15; skb2 = alloc_skb(size, GFP_ATOMIC); if (skb2 == NULL) { diff -u --recursive --new-file v1.3.6/linux/net/ipv4/ip.c linux/net/ipv4/ip.c --- v1.3.6/linux/net/ipv4/ip.c Fri Jun 30 16:22:32 1995 +++ linux/net/ipv4/ip.c Thu Jul 6 14:04:42 1995 @@ -185,7 +185,7 @@ * Build a hardware header. Source address is our mac, destination unknown * (rebuild header will sort this out) */ - skb_reserve(skb,dev->hard_header_len); + skb_reserve(skb,(dev->hard_header_len+15)&~15); /* 16 byte aligned IP headers are good */ mac = dev->hard_header(skb, dev, ETH_P_IP, NULL, NULL, len); if (mac < 0) { @@ -307,15 +307,15 @@ */ iph=(struct iphdr *)skb_put(skb,sizeof(struct iphdr)); - + iph->version = 4; + iph->ihl = 5; iph->tos = tos; iph->frag_off = 0; iph->ttl = ttl; iph->daddr = daddr; iph->saddr = saddr; iph->protocol = type; - iph->ihl = 5; skb->ip_hdr = iph; return(20 + tmp); /* IP header plus MAC header size */ @@ -502,7 +502,7 @@ * Allocate memory for the IP header (plus 8 octets for ICMP). */ - ihlen = (iph->ihl * sizeof(unsigned long)); + ihlen = iph->ihl * 4; qp->iph = (struct iphdr *) kmalloc(64 + 8, GFP_ATOMIC); if (qp->iph == NULL) { @@ -628,7 +628,7 @@ /* Done with all fragments. Fixup the new IP header. */ iph = skb->h.iph; iph->frag_off = 0; - iph->tot_len = htons((iph->ihl * sizeof(unsigned long)) + count); + iph->tot_len = htons((iph->ihl * 4) + count); skb->ip_hdr = iph; ip_statistics.IpReasmOKs++; @@ -700,7 +700,7 @@ * Determine the position of this fragment. */ - ihl = (iph->ihl * sizeof(unsigned long)); + ihl = iph->ihl * 4; end = offset + ntohs(iph->tot_len) - ihl; /* @@ -857,7 +857,7 @@ * Setup starting values. */ - hlen = (iph->ihl * sizeof(unsigned long)); + hlen = iph->ihl * 4; left = ntohs(iph->tot_len) - hlen; /* Space per frame */ hlen += dev->hard_header_len; /* Total header size */ mtu = (dev->mtu - hlen); /* Size of data space */ @@ -901,7 +901,7 @@ */ if (is_frag & 2) - offset = (ntohs(iph->frag_off) & 0x1fff) << 3; + offset = (ntohs(iph->frag_off) & IP_OFFSET) << 3; else offset = 0; @@ -927,7 +927,7 @@ * Allocate buffer. */ - if ((skb2 = alloc_skb(len + hlen,GFP_ATOMIC)) == NULL) + if ((skb2 = alloc_skb(len + hlen+15,GFP_ATOMIC)) == NULL) { NETDEBUG(printk("IP: frag: no memory for new fragment!\n")); ip_statistics.IpFragFails++; @@ -1160,7 +1160,7 @@ * data so the problem goes away then. */ - skb2 = alloc_skb(dev2->hard_header_len + skb->len, GFP_ATOMIC); + skb2 = alloc_skb(dev2->hard_header_len + skb->len + 15, GFP_ATOMIC); /* * This is rare and since IP is tolerant of network failures @@ -1250,13 +1250,6 @@ int err; #endif - /* - * IP is layered, throw away the - * MAC addresses. - */ - - skb_pull(skb,dev->hard_header_len); - ip_statistics.IpInReceives++; /* @@ -1332,7 +1325,9 @@ int opt_space=4*(iph->ihl-5); int opt_size; unsigned char *opt_ptr=skb->h.raw+sizeof(struct iphdr); - + + skb->ip_summed=0; /* Our free checksum is bogus for this case */ + while(opt_space>0) { if(*opt_ptr==IPOPT_NOOP) @@ -1385,7 +1380,7 @@ if(opt_ptr[0]!=IPOPT_RR) { int t; - target_addr=*(long *)(&opt_ptr[opt_ptr[2]]); /* Get hop */ + target_addr=*(u32 *)(&opt_ptr[opt_ptr[2]]); /* Get hop */ t=ip_chk_addr(target_addr); if(t==IS_MULTICAST||t==IS_BROADCAST) { @@ -1395,7 +1390,7 @@ return -EINVAL; } } - *(long *)(&opt_ptr[opt_ptr[2]])=skb->dev->pa_addr; /* Record hop */ + *(u32 *)(&opt_ptr[opt_ptr[2]])=skb->dev->pa_addr; /* Record hop */ break; case IPOPT_TIMESTAMP: /* @@ -1420,13 +1415,13 @@ if(iph->frag_off) { - if (iph->frag_off & 0x0020) + if (iph->frag_off & htons(IP_MF)) is_frag|=1; /* * Last fragment ? */ - if (ntohs(iph->frag_off) & 0x1fff) + if (iph->frag_off & htons(IP_OFFSET)) is_frag|=2; } @@ -2005,8 +2000,8 @@ if(err) return err; - val = get_fs_long((unsigned long *)optval); - ucval=get_fs_byte((unsigned char *)optval); + val = get_user((int *) optval); + ucval=get_user((unsigned char *) optval); if(level!=SOL_IP) return -EOPNOTSUPP; @@ -2277,7 +2272,7 @@ err=verify_area(VERIFY_WRITE, optval, len); if(err) return err; - put_fs_long(len,(unsigned long *) optlen); + put_user(len,(int *) optlen); memcpy_tofs((void *)optval,sk->ip_mc_name, len); return 0; #endif @@ -2287,12 +2282,12 @@ err=verify_area(VERIFY_WRITE, optlen, sizeof(int)); if(err) return err; - put_fs_long(sizeof(int),(unsigned long *) optlen); + put_user(sizeof(int),(int *) optlen); err=verify_area(VERIFY_WRITE, optval, sizeof(int)); if(err) return err; - put_fs_long(val,(unsigned long *)optval); + put_user(val,(int *) optval); return(0); } @@ -2475,10 +2470,10 @@ char *data; /* - * Get the memory we require. + * Get the memory we require with some space left for alignment. */ - skb = sock_alloc_send_skb(sk, fraglen, 0, &error); + skb = sock_alloc_send_skb(sk, fraglen+15, 0, &error); if (skb == NULL) return(error); @@ -2494,7 +2489,7 @@ skb->arp = 0; skb->saddr = saddr; skb->raddr = (rt&&rt->rt_gateway) ? rt->rt_gateway : daddr; - skb_reserve(skb,dev->hard_header_len); + skb_reserve(skb,(dev->hard_header_len+15)&~15); data = skb_put(skb, fraglen-dev->hard_header_len); /* diff -u --recursive --new-file v1.3.6/linux/net/ipv4/packet.c linux/net/ipv4/packet.c --- v1.3.6/linux/net/ipv4/packet.c Fri Jun 30 16:22:32 1995 +++ linux/net/ipv4/packet.c Wed Jul 5 13:06:28 1995 @@ -28,6 +28,7 @@ * dubious gcc output. Can you read * compiler: it said _VOLATILE_ * Richard Kooijman : Timestamp fixes. + * Alan Cox : New buffers. Use sk->mac.raw * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -80,6 +81,12 @@ */ sk = (struct sock *) pt->data; + + /* + * Yank back the headers + */ + + skb_push(skb,skb->data-skb->mac.raw); /* * The SOCK_PACKET socket receives _all_ frames. diff -u --recursive --new-file v1.3.6/linux/net/ipv4/rarp.c linux/net/ipv4/rarp.c --- v1.3.6/linux/net/ipv4/rarp.c Fri Jun 30 16:22:32 1995 +++ linux/net/ipv4/rarp.c Wed Jul 5 13:06:28 1995 @@ -151,8 +151,6 @@ long sip,tip; unsigned char *sha,*tha; /* s for "source", t for "target" */ - skb_pull(skb,dev->hard_header_len); - /* * If this test doesn't pass, it's not IP, or we should ignore it anyway */ diff -u --recursive --new-file v1.3.6/linux/net/ipv4/tcp.c linux/net/ipv4/tcp.c --- v1.3.6/linux/net/ipv4/tcp.c Fri Jun 30 16:22:32 1995 +++ linux/net/ipv4/tcp.c Thu Jul 6 14:04:43 1995 @@ -1030,22 +1030,20 @@ sk->inuse = 1; amount = tcp_readable(sk); release_sock(sk); - err=verify_area(VERIFY_WRITE,(void *)arg, - sizeof(unsigned long)); + err=verify_area(VERIFY_WRITE,(void *)arg, sizeof(int)); if(err) return err; - put_fs_long(amount,(unsigned long *)arg); + put_user(amount, (int *)arg); return(0); } case SIOCATMARK: { int answ = sk->urg_data && sk->urg_seq == sk->copied_seq; - err = verify_area(VERIFY_WRITE,(void *) arg, - sizeof(unsigned long)); + err = verify_area(VERIFY_WRITE,(void *) arg, sizeof(int)); if (err) return err; - put_fs_long(answ,(int *) arg); + put_user(answ,(int *) arg); return(0); } case TIOCOUTQ: @@ -1054,11 +1052,10 @@ if (sk->state == TCP_LISTEN) return(-EINVAL); amount = sk->prot->wspace(sk); - err=verify_area(VERIFY_WRITE,(void *)arg, - sizeof(unsigned long)); + err=verify_area(VERIFY_WRITE,(void *)arg, sizeof(int)); if(err) return err; - put_fs_long(amount,(unsigned long *)arg); + put_user(amount, (int *)arg); return(0); } default: @@ -1075,10 +1072,9 @@ */ unsigned short tcp_check(struct tcphdr *th, int len, - unsigned long saddr, unsigned long daddr) + unsigned long saddr, unsigned long daddr, unsigned long base) { - return csum_tcpudp_magic(saddr,daddr,len,IPPROTO_TCP, - csum_partial((char *)th,len,0)); + return csum_tcpudp_magic(saddr,daddr,len,IPPROTO_TCP,base); } @@ -1087,7 +1083,8 @@ unsigned long daddr, int len, struct sock *sk) { th->check = 0; - th->check = tcp_check(th, len, saddr, daddr); + th->check = tcp_check(th, len, saddr, daddr, + csum_partial((char *)th,len,0)); return; } @@ -1602,7 +1599,7 @@ * NB: following must be mtu, because mss can be increased. * mss is always <= mtu */ - skb = prot->wmalloc(sk, sk->mtu + 128 + prot->max_header, 0, GFP_KERNEL); + skb = prot->wmalloc(sk, sk->mtu + 128 + prot->max_header + 15, 0, GFP_KERNEL); sk->inuse = 1; send_tmp = skb; } @@ -1612,7 +1609,7 @@ * We will release the socket in case we sleep here. */ release_sock(sk); - skb = prot->wmalloc(sk, copy + prot->max_header , 0, GFP_KERNEL); + skb = prot->wmalloc(sk, copy + prot->max_header + 15 , 0, GFP_KERNEL); sk->inuse = 1; } @@ -4476,7 +4473,6 @@ int syn_ok=0; tcp_statistics.TcpInSegs++; - if(skb->pkt_type!=PACKET_HOST) { kfree_skb(skb,FREE_READ); @@ -4519,7 +4515,13 @@ * Pull up the IP header. */ skb_pull(skb, skb->h.raw-skb->data); - if (tcp_check(th, len, saddr, daddr )) + /* + * Try to use the device checksum if provided. + */ + if ( + (skb->ip_summed && tcp_check(th, len, saddr, daddr, skb->csum ))|| + (!skb->ip_summed && tcp_check(th, len, saddr, daddr, csum_partial((char *)th, len, 0))) + ) { skb->sk = NULL; kfree_skb(skb,FREE_READ); @@ -4924,7 +4926,7 @@ buff = sk->prot->wmalloc(sk, win_size + th->doff * 4 + (iph->ihl << 2) + - skb->dev->hard_header_len, + skb->dev->hard_header_len + 15, 1, GFP_ATOMIC); if ( buff == NULL ) return; @@ -5119,7 +5121,7 @@ if(err) return err; - val = get_fs_long((unsigned long *)optval); + val = get_user((int *)optval); switch(optname) { @@ -5162,12 +5164,12 @@ err=verify_area(VERIFY_WRITE, optlen, sizeof(int)); if(err) return err; - put_fs_long(sizeof(int),(unsigned long *) optlen); + put_user(sizeof(int),(int *) optlen); err=verify_area(VERIFY_WRITE, optval, sizeof(int)); if(err) return err; - put_fs_long(val,(unsigned long *)optval); + put_user(val,(int *)optval); return(0); } diff -u --recursive --new-file v1.3.6/linux/net/ipv4/udp.c linux/net/ipv4/udp.c --- v1.3.6/linux/net/ipv4/udp.c Fri Jun 30 16:22:33 1995 +++ linux/net/ipv4/udp.c Thu Jul 6 13:22:05 1995 @@ -165,10 +165,9 @@ } -static unsigned short udp_check(struct udphdr *uh, int len, unsigned long saddr, unsigned long daddr) +static unsigned short udp_check(struct udphdr *uh, int len, unsigned long saddr, unsigned long daddr, unsigned long base) { - return(csum_tcpudp_magic(saddr, daddr, len, IPPROTO_UDP, - csum_partial((char*)uh, len, 0))); + return(csum_tcpudp_magic(saddr, daddr, len, IPPROTO_UDP, base)); } struct udpfakehdr @@ -204,7 +203,7 @@ src = ufh->from; dst = to+sizeof(struct udphdr); } - ufh->wcheck = csum_partial_copyffs(src, dst, len, ufh->wcheck); + ufh->wcheck = csum_partial_copy_fromuser(src, dst, len, ufh->wcheck); if (offset == 0) { ufh->wcheck = csum_partial((char *)ufh, sizeof(struct udphdr), @@ -243,7 +242,7 @@ src = ufh->from; dst = to+sizeof(struct udphdr); } - memcpy_fromfs(src,dst,len); + memcpy_fromfs(dst,src,len); if (offset == 0) memcpy(to, ufh, sizeof(struct udphdr)); } @@ -542,7 +541,11 @@ return(0); } - if (uh->check && udp_check(uh, len, saddr, daddr)) + if (uh->check && ( + ( skb->ip_summed && udp_check(uh, len, saddr, daddr, skb->csum ) ) || + ( !skb->ip_summed && udp_check(uh, len, saddr, daddr,csum_partial((char*)uh, len, 0))) + ) + ) { /* wants to know, who sent it, to go and stomp on the garbage sender... */ diff -u --recursive --new-file v1.3.6/linux/net/ipx/af_ipx.c linux/net/ipx/af_ipx.c --- v1.3.6/linux/net/ipx/af_ipx.c Fri Jun 30 16:22:34 1995 +++ linux/net/ipx/af_ipx.c Wed Jul 5 13:06:28 1995 @@ -1635,12 +1635,6 @@ ipx_packet *ipx; - /* - * Throw away the MAC layer - */ - - skb_pull(skb,dev->hard_header_len); - ipx=(ipx_packet *)skb->h.raw; if(ipx->ipx_checksum!=IPX_NO_CHECKSUM) { diff -u --recursive --new-file v1.3.6/linux/net/netrom/af_netrom.c linux/net/netrom/af_netrom.c --- v1.3.6/linux/net/netrom/af_netrom.c Fri Jun 30 16:22:34 1995 +++ linux/net/netrom/af_netrom.c Wed Jul 5 13:06:28 1995 @@ -870,12 +870,12 @@ unsigned short frametype, window, timeout; skb->sk = NULL; /* Initially we don't know who its for */ - + /* * skb->data points to the netrom frame start */ - - src = (ax25_address *)(skb->data); + + src = (ax25_address *)(skb->data + 0); dest = (ax25_address *)(skb->data + 7); circuit_index = skb->data[15]; @@ -887,7 +887,8 @@ * Check for an incoming IP over NET/ROM frame. */ if ((frametype & 0x0F) == NR_PROTOEXT && circuit_index == NR_PROTO_IP && circuit_id == NR_PROTO_IP) { - skb->h.raw = skb->data + 20; + skb_pull(skb, NR_NETWORK_LEN + NR_TRANSPORT_LEN); + skb->h.raw = skb->data; return nr_rx_ip(skb, dev); } @@ -898,12 +899,15 @@ * a Connect Request base it on their circuit ID. */ if (((frametype & 0x0F) != NR_CONNREQ && (sk = nr_find_socket(circuit_index, circuit_id, SOCK_SEQPACKET)) != NULL) || - ((frametype & 0x0F) == NR_CONNREQ && (sk = nr_find_peer(circuit_index, circuit_id, SOCK_SEQPACKET)) != NULL)) - { - if((frametype & 0x0F) == NR_CONNACK && skb->len == 39) /* ??? size check --FIXME-- */ + ((frametype & 0x0F) == NR_CONNREQ && (sk = nr_find_peer(circuit_index, circuit_id, SOCK_SEQPACKET)) != NULL)) { + skb_pull(skb, NR_NETWORK_LEN); + skb->h.raw = skb->data + NR_TRANSPORT_LEN; + + if ((frametype & 0x0F) == NR_CONNACK && skb->len == 7) sk->nr->bpqext = 1; else sk->nr->bpqext = 0; + return nr_process_rx_frame(sk, skb); } @@ -917,7 +921,7 @@ return 0; } - user = (ax25_address *)(skb->data + 11); + user = (ax25_address *)(skb->data + 21); window = skb->data[20]; skb->sk = make; @@ -942,7 +946,7 @@ /* L4 timeout negotiation */ if (skb->len == 37) { - timeout = skb->data[53] * 256 + skb->data[52]; + timeout = skb->data[36] * 256 + skb->data[35]; if (timeout * PR_SLOWHZ < make->nr->rtt * 2) make->nr->rtt = (timeout * PR_SLOWHZ) / 2; make->nr->bpqext = 1; @@ -1018,7 +1022,7 @@ if (sk->debug) printk("NET/ROM: sendto: building packet.\n"); - size = len + 37; + size = len + AX25_BPQ_HEADER_LEN + AX25_MAX_HEADER_LEN + 2 + NR_NETWORK_LEN + NR_TRANSPORT_LEN; if ((skb = sock_alloc_send_skb(sk, size, 0, &err)) == NULL) return err; @@ -1026,35 +1030,18 @@ skb->sk = sk; skb->free = 1; skb->arp = 1; - skb_reserve(skb,37); + + skb_reserve(skb, size - len); /* - * Push down the NetROM header + * Push down the NET/ROM header */ - - asmptr = skb_push(skb,20); + + asmptr = skb_push(skb, NR_TRANSPORT_LEN); if (sk->debug) printk("Building NET/ROM Header.\n"); - /* Build a NET/ROM Network header */ - - *asmptr++ = AX25_P_NETROM; - - memcpy(asmptr, &sk->nr->source_addr, sizeof(ax25_address)); - asmptr[6] &= ~LAPB_C; - asmptr[6] &= ~LAPB_E; - asmptr[6] |= SSID_SPARE; - asmptr += 7; - - memcpy(asmptr, &sax.sax25_call, sizeof(ax25_address)); - asmptr[6] &= ~LAPB_C; - asmptr[6] |= LAPB_E; - asmptr[6] |= SSID_SPARE; - asmptr += 7; - - *asmptr++ = nr_default.ttl; - /* Build a NET/ROM Transport header */ *asmptr++ = sk->nr->your_index; @@ -1067,11 +1054,12 @@ printk("Built header.\n"); /* - * Put the data on the end. + * Put the data on the end */ - - skb->h.raw = skb_put(skb,len); - asmptr=skb->h.raw; + + skb->h.raw = skb_put(skb, len); + + asmptr = skb->h.raw; if (sk->debug) printk("NET/ROM: Appending user data\n"); @@ -1128,10 +1116,9 @@ if ((skb = skb_recv_datagram(sk, flags, noblock, &er)) == NULL) return er; - /* Allow for the 20 byte netrom header */ - copied = (size < skb->len-20) ? size : skb->len-20; + copied = (size < skb->len - NR_TRANSPORT_LEN) ? size : skb->len - NR_TRANSPORT_LEN; - skb_copy_datagram(skb, 20, ubuf, copied); + skb_copy_datagram(skb, 0, ubuf, copied); if (sax != NULL) { struct sockaddr_ax25 addr; @@ -1198,7 +1185,7 @@ struct sk_buff *skb; /* These two are safe on a single CPU system as only user tasks fiddle here */ if ((skb = skb_peek(&sk->receive_queue)) != NULL) - amount = skb->len-20; + amount = skb->len - 20; if ((err = verify_area(VERIFY_WRITE, (void *)arg, sizeof(unsigned long))) != 0) return err; put_fs_long(amount, (unsigned long *)arg); @@ -1351,7 +1338,7 @@ { sock_register(nr_proto_ops.family, &nr_proto_ops); register_netdevice_notifier(&nr_dev_notifier); - printk("G4KLX NET/ROM for Linux. Version 0.3 ALPHA for AX25 029 Linux 1.3.0\n"); + printk("G4KLX NET/ROM for Linux. Version 0.3 ALPHA for AX25 030 Linux 1.3.0\n"); nr_default.quality = NR_DEFAULT_QUAL; nr_default.obs_count = NR_DEFAULT_OBS; diff -u --recursive --new-file v1.3.6/linux/net/netrom/nr_dev.c linux/net/netrom/nr_dev.c --- v1.3.6/linux/net/netrom/nr_dev.c Fri Jun 30 16:22:34 1995 +++ linux/net/netrom/nr_dev.c Wed Jul 5 13:06:28 1995 @@ -46,59 +46,48 @@ #include /* - * Only allow IP over NET/ROM frames through if the netrom device is up. + * Only allow IP over NET/ROM frames through if the netrom device is up. */ int nr_rx_ip(struct sk_buff *skb, struct device *dev) { struct enet_statistics *stats = (struct enet_statistics *)dev->priv; - if (!dev->start) { + if (!dev->start) + { stats->rx_errors++; return 0; } stats->rx_packets++; - skb->protocol=htons(ETH_P_IP); + skb->protocol = htons(ETH_P_IP); + /* Spoof incoming device */ - skb->dev=dev; + skb->dev = dev; - ip_rcv(skb, dev, NULL); + skb->h.raw = skb->data; + ip_rcv(skb, skb->dev, NULL); return 1; } -/* - * We can't handle ARP so put some identification characters into the ARP - * packet so that the transmit routine can identify it, and throw it away. - */ - static int nr_header(struct sk_buff *skb, struct device *dev, unsigned short type, void *daddr, void *saddr, unsigned len) { - unsigned char *buff=skb_push(skb,37); - if (type == ETH_P_ARP) { - *buff++ = 0xFF; /* Mark it */ - *buff++ = 0xFE; - return 37; - } + unsigned char *buff = skb_push(skb, NR_NETWORK_LEN + NR_TRANSPORT_LEN); - buff += 16; - - *buff++ = AX25_P_NETROM; - memcpy(buff, (saddr != NULL) ? saddr : dev->dev_addr, dev->addr_len); buff[6] &= ~LAPB_C; buff[6] &= ~LAPB_E; buff[6] |= SSID_SPARE; - buff += dev->addr_len; + buff += AX25_ADDR_LEN; if (daddr != NULL) memcpy(buff, daddr, dev->addr_len); buff[6] &= ~LAPB_C; buff[6] |= LAPB_E; buff[6] |= SSID_SPARE; - buff += dev->addr_len; + buff += AX25_ADDR_LEN; *buff++ = nr_default.ttl; @@ -117,20 +106,35 @@ static int nr_rebuild_header(void *buff, struct device *dev, unsigned long raddr, struct sk_buff *skb) { + struct enet_statistics *stats = (struct enet_statistics *)dev->priv; unsigned char *bp = (unsigned char *)buff; - if (arp_find(bp + 24, raddr, dev, dev->pa_addr, skb)) + skb_device_unlock(skb); + + if (!arp_query(bp + 7, raddr, ARPHRD_NETROM)) { + skb->free = 1; + kfree_skb(skb, FREE_WRITE); return 1; + } - bp[23] &= ~LAPB_C; - bp[23] &= ~LAPB_E; - bp[23] |= SSID_SPARE; + bp[6] &= ~LAPB_C; + bp[6] &= ~LAPB_E; + bp[6] |= SSID_SPARE; + bp += AX25_ADDR_LEN; - bp[30] &= ~LAPB_C; - bp[30] |= LAPB_E; - bp[30] |= SSID_SPARE; + bp[6] &= ~LAPB_C; + bp[6] |= LAPB_E; + bp[6] |= SSID_SPARE; + + if (!nr_route_frame(skb, NULL)) { + skb->free = 1; + kfree_skb(skb, FREE_WRITE); + stats->tx_errors++; + } - return 0; + stats->tx_packets++; + + return 1; } static int nr_set_mac_address(struct device *dev, void *addr) @@ -159,7 +163,6 @@ static int nr_xmit(struct sk_buff *skb, struct device *dev) { struct enet_statistics *stats = (struct enet_statistics *)dev->priv; - struct sk_buff *skbn; if (skb == NULL || dev == NULL) return 0; @@ -181,25 +184,9 @@ sti(); - if (skb->data[0] != 0xFF && skb->data[1] != 0xFE) { - if ((skbn = skb_clone(skb, GFP_ATOMIC)) == NULL) { - dev->tbusy = 0; - stats->tx_errors++; - return 1; - } - - if (!nr_route_frame(skbn, NULL)) { - skbn->free = 1; - kfree_skb(skbn, FREE_WRITE); - dev->tbusy = 0; - stats->tx_errors++; - return 1; - } - } - dev_kfree_skb(skb, FREE_WRITE); - stats->tx_packets++; + stats->tx_errors++; dev->tbusy = 0; @@ -224,8 +211,8 @@ dev->stop = nr_close; dev->hard_header = nr_header; - dev->hard_header_len = 37; - dev->addr_len = 7; + dev->hard_header_len = AX25_BPQ_HEADER_LEN + AX25_MAX_HEADER_LEN + 2 + NR_NETWORK_LEN + NR_TRANSPORT_LEN; + dev->addr_len = AX25_ADDR_LEN; dev->type = ARPHRD_NETROM; dev->rebuild_header = nr_rebuild_header; dev->set_mac_address = nr_set_mac_address; diff -u --recursive --new-file v1.3.6/linux/net/netrom/nr_in.c linux/net/netrom/nr_in.c --- v1.3.6/linux/net/netrom/nr_in.c Fri Jun 30 16:22:34 1995 +++ linux/net/netrom/nr_in.c Wed Jul 5 13:06:28 1995 @@ -58,9 +58,9 @@ case NR_CONNACK: nr_calculate_rtt(sk); - sk->window = skb->data[37]; - sk->nr->your_index = skb->data[34]; - sk->nr->your_id = skb->data[35]; + sk->window = skb->data[5]; + sk->nr->your_index = skb->data[2]; + sk->nr->your_id = skb->data[3]; sk->nr->t1timer = 0; sk->nr->t2timer = 0; sk->nr->t4timer = 0; @@ -135,8 +135,8 @@ unsigned short nr, ns; int queued = 0; - nr = skb->data[18]; - ns = skb->data[17]; + nr = skb->data[3]; + ns = skb->data[2]; switch (frametype) { @@ -241,7 +241,7 @@ do { save_vr = sk->nr->vr; while ((skbn = skb_dequeue(&sk->nr->reseq_queue)) != NULL) { - ns = skbn->data[17]; + ns = skbn->data[2]; if (ns == sk->nr->vr) { if (sock_queue_rcv_skb(sk, skbn) == 0) { sk->nr->vr = (sk->nr->vr + 1) % NR_MODULUS; @@ -293,7 +293,7 @@ del_timer(&sk->timer); - frametype = skb->data[19]; + frametype = skb->data[4]; switch (sk->nr->state) { diff -u --recursive --new-file v1.3.6/linux/net/netrom/nr_out.c linux/net/netrom/nr_out.c --- v1.3.6/linux/net/netrom/nr_out.c Fri Jun 30 16:22:34 1995 +++ linux/net/netrom/nr_out.c Wed Jul 5 13:06:28 1995 @@ -56,15 +56,11 @@ */ static void nr_send_iframe(struct sock *sk, struct sk_buff *skb) { - unsigned char *dptr; - if (skb == NULL) return; - dptr = skb->data + 17; - - *dptr++ = sk->nr->vs; - *dptr++ = sk->nr->vr; + skb->data[2] = sk->nr->vs; + skb->data[3] = sk->nr->vr; nr_transmit_buffer(sk, skb); } @@ -151,24 +147,21 @@ unsigned char *dptr; /* - * Add the protocol byte + * Add the protocol byte and network header. */ - - dptr = skb_push(skb,1); + dptr = skb_push(skb, NR_NETWORK_LEN); - *dptr++ = AX25_P_NETROM; - memcpy(dptr, &sk->nr->source_addr, sizeof(ax25_address)); dptr[6] &= ~LAPB_C; dptr[6] &= ~LAPB_E; dptr[6] |= SSID_SPARE; - dptr += 7; + dptr += AX25_ADDR_LEN; memcpy(dptr, &sk->nr->dest_addr, sizeof(ax25_address)); dptr[6] &= ~LAPB_C; dptr[6] |= LAPB_E; dptr[6] |= SSID_SPARE; - dptr += 7; + dptr += AX25_ADDR_LEN; *dptr++ = nr_default.ttl; diff -u --recursive --new-file v1.3.6/linux/net/netrom/nr_route.c linux/net/netrom/nr_route.c --- v1.3.6/linux/net/netrom/nr_route.c Fri Jun 30 16:22:34 1995 +++ linux/net/netrom/nr_route.c Wed Jul 5 13:06:28 1995 @@ -39,6 +39,7 @@ #include #include #include +#include #include #include #include @@ -61,7 +62,7 @@ * neighbour if it is new. */ static int nr_add_node(ax25_address *nr, char *mnemonic, ax25_address *ax25, - struct device *dev, int quality, int obs_count) + ax25_digi *ax25_digi, struct device *dev, int quality, int obs_count) { struct nr_node *nr_node; struct nr_neigh *nr_neigh; @@ -86,11 +87,20 @@ memcpy(&nr_neigh->callsign, ax25, sizeof(ax25_address)); + nr_neigh->digipeat= NULL; nr_neigh->dev = dev; nr_neigh->quality = nr_default.quality; nr_neigh->locked = 0; nr_neigh->count = 0; nr_neigh->number = nr_neigh_no++; + + if (ax25_digi != NULL) { + if ((nr_neigh->digipeat = kmalloc(sizeof(*ax25_digi), GFP_KERNEL)) == NULL) { + kfree_s(nr_neigh, sizeof(*nr_neigh)); + return -ENOMEM; + } + memcpy(nr_neigh->digipeat, ax25_digi, sizeof(*ax25_digi)); + } save_flags(flags); cli(); @@ -250,6 +260,8 @@ if ((s = nr_neigh_list) == nr_neigh) { nr_neigh_list = nr_neigh->next; restore_flags(flags); + if (nr_neigh->digipeat != NULL) + kfree_s(nr_neigh->digipeat, sizeof(ax25_digi)); kfree_s(nr_neigh, sizeof(struct nr_neigh)); return; } @@ -258,6 +270,8 @@ if (s->next == nr_neigh) { s->next = nr_neigh->next; restore_flags(flags); + if (nr_neigh->digipeat != NULL) + kfree_s(nr_neigh->digipeat, sizeof(ax25_digi)); kfree_s(nr_neigh, sizeof(struct nr_neigh)); return; } @@ -340,6 +354,7 @@ memcpy(&nr_neigh->callsign, callsign, sizeof(ax25_address)); + nr_neigh->digipeat= NULL; nr_neigh->dev = dev; nr_neigh->quality = quality; nr_neigh->locked = 1; @@ -492,16 +507,22 @@ /* * Check that the device given is a valid AX.25 interface that is "up". + * Or a valid ethernet interface with an AX.25 callsign binding. */ static struct device *nr_ax25_dev_get(char *devname) { struct device *dev; + ax25_address callsign; if ((dev = dev_get(devname)) == NULL) return NULL; if ((dev->flags & IFF_UP) && dev->type == ARPHRD_AX25) return dev; + + if ((dev->flags & IFF_UP) && dev->type == ARPHRD_ETHER) + if (arp_query((unsigned char *)&callsign, dev->pa_addr, ARPHRD_AX25)) + return dev; return NULL; } @@ -557,7 +578,7 @@ return nr_add_node(&nr_route.callsign, nr_route.mnemonic, &nr_route.neighbour, - dev, nr_route.quality, + NULL, dev, nr_route.quality, nr_route.obs_count); case NETROM_NEIGH: return nr_add_neigh(&nr_route.callsign, @@ -611,30 +632,28 @@ } /* - * Route a frame to an appropriate AX.25 connection. A NULL dev means - * that the frame was generated internally. + * Route a frame to an appropriate AX.25 connection. A NULL ax25_cb + * indicates an internally generated frame. */ -int nr_route_frame(struct sk_buff *skb, struct device *device) +int nr_route_frame(struct sk_buff *skb, ax25_cb *ax25) { - ax25_address *ax25_src, *ax25_dest; - ax25_address *nr_src, *nr_dest; + ax25_address *nr_src, *nr_dest; struct nr_neigh *nr_neigh; struct nr_node *nr_node; struct device *dev; + unsigned char *dptr; - ax25_dest = (ax25_address *)(skb->data + 1); - ax25_src = (ax25_address *)(skb->data + 8); - nr_src = (ax25_address *)(skb->data + 17); - nr_dest = (ax25_address *)(skb->data + 24); + nr_src = (ax25_address *)(skb->data + 0); + nr_dest = (ax25_address *)(skb->data + 7); - if (device != NULL) - nr_add_node(nr_src, "", ax25_src, device, 0, nr_default.obs_count); + if (ax25 != NULL) + nr_add_node(nr_src, "", &ax25->dest_addr, ax25->digipeat, ax25->device, 0, nr_default.obs_count); if ((dev = nr_dev_get(nr_dest)) != NULL) /* Its for me */ return nr_rx_frame(skb, dev); /* Its Time-To-Live has expired */ - if (--skb->data[31] == 0) + if (--skb->data[14] == 0) return 0; for (nr_node = nr_node_list; nr_node != NULL; nr_node = nr_node->next) @@ -654,11 +673,10 @@ if ((dev = nr_dev_first()) == NULL) return 0; -/* if (device != NULL) - skb->len += dev->hard_header_len;*/ + dptr = skb_push(skb, 1); + *dptr = AX25_P_NETROM; - skb_push(skb,17); - ax25_send_frame(skb, (ax25_address *)dev->dev_addr, &nr_neigh->callsign, nr_neigh->dev); + ax25_send_frame(skb, (ax25_address *)dev->dev_addr, &nr_neigh->callsign, nr_neigh->digipeat, nr_neigh->dev); return 1; } @@ -676,14 +694,14 @@ len += sprintf(buffer, "callsign mnemonic w n qual obs neigh qual obs neigh qual obs neigh\n"); for (nr_node = nr_node_list; nr_node != NULL; nr_node = nr_node->next) { - len += sprintf(buffer + len, "%-9s %-7s %d %d ", + len += sprintf(buffer + len, "%-9s %-7s %d %d", ax2asc(&nr_node->callsign), nr_node->mnemonic, nr_node->which + 1, nr_node->count); for (i = 0; i < nr_node->count; i++) { - len += sprintf(buffer + len, " %3d %d %05d", + len += sprintf(buffer + len, " %3d %d %05d", nr_node->routes[i].quality, nr_node->routes[i].obs_count, nr_node->routes[i].neighbour); @@ -721,10 +739,10 @@ cli(); - len += sprintf(buffer, "addr callsign dev qual lock count\n"); + len += sprintf(buffer, "addr callsign dev qual lock count\n"); for (nr_neigh = nr_neigh_list; nr_neigh != NULL; nr_neigh = nr_neigh->next) { - len += sprintf(buffer + len, "%05d %-9s %-3s %3d %d %3d\n", + len += sprintf(buffer + len, "%05d %-9s %-4s %3d %d %3d\n", nr_neigh->number, ax2asc(&nr_neigh->callsign), nr_neigh->dev ? nr_neigh->dev->name : "???", diff -u --recursive --new-file v1.3.6/linux/net/netrom/nr_subr.c linux/net/netrom/nr_subr.c --- v1.3.6/linux/net/netrom/nr_subr.c Fri Jun 30 16:22:34 1995 +++ linux/net/netrom/nr_subr.c Wed Jul 5 13:06:28 1995 @@ -152,13 +152,20 @@ struct sk_buff *skb; unsigned char *dptr; int len, timeout; + + len = AX25_BPQ_HEADER_LEN + AX25_MAX_HEADER_LEN + 2 + NR_NETWORK_LEN + NR_TRANSPORT_LEN; switch (frametype & 0x0F) { - case NR_CONNREQ: len = 54; break; - case NR_CONNACK: len = (sk->nr->bpqext) ? 39 : 38; break; - case NR_DISCREQ: len = 37; break; - case NR_DISCACK: len = 37; break; - case NR_INFOACK: len = 37; break; + case NR_CONNREQ: + len += 17; + break; + case NR_CONNACK: + len += (sk->nr->bpqext) ? 2 : 1; + break; + case NR_DISCREQ: + case NR_DISCACK: + case NR_INFOACK: + break; default: printk("nr_write_internal: invalid frame type %d\n", frametype); return; @@ -168,34 +175,34 @@ return; /* - * Space for AX.25 + * Space for AX.25 and NET/ROM network header */ - skb_reserve(skb,17); + skb_reserve(skb, AX25_BPQ_HEADER_LEN + AX25_MAX_HEADER_LEN + 2 + NR_NETWORK_LEN); - dptr = skb_put(skb,len-17); + dptr = skb_put(skb, skb_tailroom(skb)); switch (frametype & 0x0F) { case NR_CONNREQ: - timeout = (sk->nr->rtt / PR_SLOWHZ) * 2; - *dptr++ = sk->nr->my_index; - *dptr++ = sk->nr->my_id; - *dptr++ = 0; - *dptr++ = 0; - *dptr++ = frametype; - *dptr++ = sk->window; + timeout = (sk->nr->rtt / PR_SLOWHZ) * 2; + *dptr++ = sk->nr->my_index; + *dptr++ = sk->nr->my_id; + *dptr++ = 0; + *dptr++ = 0; + *dptr++ = frametype; + *dptr++ = sk->window; memcpy(dptr, &sk->nr->user_addr, sizeof(ax25_address)); dptr[6] &= ~LAPB_C; dptr[6] &= ~LAPB_E; dptr[6] |= SSID_SPARE; - dptr += 7; + dptr += AX25_ADDR_LEN; memcpy(dptr, &sk->nr->source_addr, sizeof(ax25_address)); dptr[6] &= ~LAPB_C; dptr[6] &= ~LAPB_E; dptr[6] |= SSID_SPARE; - dptr += 7; - *dptr++ = timeout % 256; - *dptr++ = timeout / 256; + dptr += AX25_ADDR_LEN; + *dptr++ = timeout % 256; + *dptr++ = timeout / 256; break; case NR_CONNACK: @@ -239,31 +246,33 @@ { struct sk_buff *skbn; unsigned char *dptr; + int len; + + len = AX25_BPQ_HEADER_LEN + AX25_MAX_HEADER_LEN + 2 + NR_NETWORK_LEN + NR_TRANSPORT_LEN + 1; - if ((skbn = alloc_skb(38, GFP_ATOMIC)) == NULL) + if ((skbn = alloc_skb(len, GFP_ATOMIC)) == NULL) return; - skb_reserve(skbn,17); - dptr = skb_put(skbn,21); + skb_reserve(skbn, AX25_BPQ_HEADER_LEN + AX25_MAX_HEADER_LEN + 2); - *dptr++ = AX25_P_NETROM; - - memcpy(dptr, skb->data + 24, 7); + dptr = skb_put(skbn, NR_NETWORK_LEN + NR_TRANSPORT_LEN); + + memcpy(dptr, skb->data + 7, AX25_ADDR_LEN); dptr[6] &= ~LAPB_C; dptr[6] &= ~LAPB_E; dptr[6] |= SSID_SPARE; - dptr += 7; + dptr += AX25_ADDR_LEN; - memcpy(dptr, skb->data + 17, 7); + memcpy(dptr, skb->data + 0, AX25_ADDR_LEN); dptr[6] &= ~LAPB_C; dptr[6] |= LAPB_E; dptr[6] |= SSID_SPARE; - dptr += 7; + dptr += AX25_ADDR_LEN; *dptr++ = nr_default.ttl; - *dptr++ = skb->data[32]; - *dptr++ = skb->data[33]; + *dptr++ = skb->data[15]; + *dptr++ = skb->data[16]; *dptr++ = 0; *dptr++ = 0; *dptr++ = NR_CONNACK + NR_CHOKE_FLAG;