diff -u --recursive --new-file v2.1.78/linux/Documentation/Configure.help linux/Documentation/Configure.help --- v2.1.78/linux/Documentation/Configure.help Fri Jan 2 14:37:01 1998 +++ linux/Documentation/Configure.help Sat Jan 10 10:42:54 1998 @@ -333,17 +333,6 @@ enable DMA for drives which were not enabled automatically. You can get the latest version of the hdparm utility via anonymous FTP from sunsite.unc.edu/pub/Linux/system/hardware/ - It is safe to say Y to this question. - - If your PCI system uses IDE drive(s) (as opposed to SCSI, say) - and is capable of bus-master DMA operation (most Pentium PCI - systems), you will want to enable this option to allow use of - bus-mastering DMA data transfers. Read the comments at the - beginning of drivers/block/idedma.c and Documentation/ide.txt. - You can get the latest version of the hdparm utility via - ftp (user: anonymous) from - sunsite.unc.edu/pub/Linux/kernel/patches/diskdrives/; it is - used to tune your harddisk. It is safe to say Y to this question. Other IDE chipset support diff -u --recursive --new-file v2.1.78/linux/Documentation/filesystems/fat_cvf.txt linux/Documentation/filesystems/fat_cvf.txt --- v2.1.78/linux/Documentation/filesystems/fat_cvf.txt Wed Dec 31 16:00:00 1969 +++ linux/Documentation/filesystems/fat_cvf.txt Thu Jan 8 14:02:41 1998 @@ -0,0 +1,190 @@ +This is the main documentation for the CVF-FAT filesystem extension. 31DEC1997 + + +Table of Contents: + +1. The idea of CVF-FAT +2. Restrictions +3. Mount options +4. Description of the CVF-FAT interface +5. CVF Modules + +------------------------------------------------------------------------------ + + +1. The idea of CVF-FAT +------------------------------------------------------------------------------ + +CVF-FAT is a FAT filesystem extension that provides a generic interface for +Compressed Volume Files in FAT partitions. Popular CVF software, for +example, are Microsoft's Doublespace/Drivespace and Stac's Stacker. +Using the CVF-FAT interface, it is possible to load a module that handles +all the low-level disk access that has to do with on-the-fly compression +and decompression. All other part of FAT filesystem access is still handled +by the FAT, MSDOS or VFAT or even UMSDOS driver. + +CVF access works by redirecting certain low-level routines from the FAT +driver to a loadable, CVF-format specific module. This module must fake +a normal FAT filesystem to the FAT driver while doing all the extra stuff +like compression and decompression silently. + + +2. Restrictions +------------------------------------------------------------------------------ + +- BMAP problems + + CVF filesystems cannot do bmap. It's impossible by principle. Thus + all actions that require bmap do not work (swapping, writable mmapping). + Read-only mmapping works because the FAT driver has a hack for this + situation :) Well, with some tricks writable mmapping could work, + (proof: they did under old dmsdos), but..... (hint: readpage/writepage + interface functions) ...... but the FAT driver has to support them + first without bmap :-) + + We'll see. If someone points me to an application that needs this, I + might be persuaded to implement it :). CVF-FAT is already prepared + for using readpage. + +- DOSEMU users attention + + You may have to unmount all CVF partitions before running DOSEMU depending + on your configuration. If DOSEMU is configured to use wholedisk or + partition access (this is often the case to let DOSEMU access + compressed partitions) there's a risk of destroying your compressed + partitions or crashing your system because of confused drivers. + + Note that it is always safe to redirect the compressed partitions with + lredir or emufs.sys. Refer to the DOSEMU documentation for details. + + +3. Mount options +------------------------------------------------------------------------------ + +The CVF-FAT extension currently adds the following options to the FAT +driver's standard options: + + cvf_format=xxx + Forces the driver to use the CVF module "xxx" instead of auto-detection. + This is only necessary if the CVF format is not recognized corrrectly + because of bugs or incompatibilities in the CVF modules. (It skips + the detect_cvf call.) "xxx" may be the text "none" (without the quotes) + to inhibit using any of the loaded CVF modules, just in case a CVF + module insists on mounting plain FAT filesystems by misunderstanding :) + + cvf_options=yyy + Option string passed to the CVF module. I.e. only the "yyy" is passed + (without the quotes). The documentation for each CVF module should + explain it since it is interpreted only by the CVF module. Note that + the string must not contain a comma (",") - this would lead to + misinterpretation by the FAT driver, which would recognize the text + after a comma as a FAT driver option and might get confused or print + strange error messages. The documentation for the CVF module should + offer a different seperation symbol, for example the dot ".", which + is only valid inside the string "yyy". + + +4. Description of the CVF-FAT interface +------------------------------------------------------------------------------ + +Assuming you want to write your own CVF module, you need to write a lot of +interface funtions. Most of them are covered in the kernel documentation +you can find on the net, and thus won't be described here. They have been +marked with "[...]" :-) Take a look at include/linux/fat_cvf.h. + +struct cvf_format +{ int cvf_version; + char* cvf_version_text; + unsigned long int flags; + int (*detect_cvf) (struct super_block*sb); + int (*mount_cvf) (struct super_block*sb,char*options); + int (*unmount_cvf) (struct super_block*sb); + [...] + void (*cvf_zero_cluster) (struct inode*inode,int clusternr); +} + +This structure defines the capabilities of a CVF module. It must be filled +out completely by a CVF module. Consider it as a kind of form that is used +to introduce the module to the FAT/CVF-FAT driver. + +It contains... + - cvf_version: + A version id which must be uniqe. Choose one. + - cvf_version_text: + A human readable version string that should be one short word + describing the CVF format the module implements. This text is used + for the cvf_format option. This name must also be uniqe. + - flags: + Bit coded flags, currently only used for a readpage/mmap hack that + provides both mmap and readpage functionality. If CVF_USE_READPAGE + is set, mmap is set to generic_file_mmap and readpage is caught + and redirected to the cvf_readpage function. If it is not set, + readpage is set to generic_readpage and mmap is caught and redirected + to cvf_mmap. + - detect_cvf: + A function that is called to decide whether the filesystem is a CVF of + the type the module supports. The detect_cvf function must return 0 + for "NO, I DON'T KNOW THIS GARBAGE" or anything !=0 for "YES, THIS IS + THE KIND OF CVF I SUPPORT". The function must maintain the module + usage counters for safety, i.e. do MOD_INC_USE_COUNT at the beginning + and MOD_DEC_USE_COUNT at the end. The function *must not* assume that + successful recongition would lead to a call of the mount_cvf function + later. + - mount_cvf: + A function that sets up some values or initializes something additional + to what has to be done when a CVF is mounted. This is called at the + end of fat_read_super and must return 0 on success. Definitely, this + function must increment the module usage counter by MOD_INC_USE_COUNT. + This mount_cvf function is also responsible for interpreting a CVF + module specific option string (the "yyy" from the FAT mount option + "cvf_options=yyy") which cannot contain a comma (use for example the + dot "." as option separator symbol). + - unmount_cvf: + A function that is called when the filesystem is unmounted. Most likely + it only frees up some memory and calls MOD_DEC_USE_COUNT. The return + value might be ignored (it currently is ignored). + - [...]: + All other interface functions are "caught" FAT driver functions, i.e. + are executed by the FAT driver *instead* of the original FAT driver + functions. NULL means use the original FAT driver functions instead. + If you really want "no action", write a function that does nothing and + hang it in instead. + - cvf_zero_cluster: + The cvf_zero_cluster function is called when the fat driver wants to + zero out a (new) cluster. This is important for directories (mkdir). + If it is NULL, the FAT driver defaults to overwriting the whole + cluster with zeros. Note that clusternr is absolute, not relative + to the provided inode. + +Notes: + 1. The cvf_bmap function should be ignored. It really should never + get called from somewhere. I recommend redirecting it to a panic + or fatal error message so bugs show up immediately. + 2. The cvf_writepage function is ignored. This is because the fat + driver doesn't support it. This might change in future. I recommend + setting it to NULL (i.e use default). + +int register_cvf_format(struct cvf_format*cvf_format); + If you have just set up a variable containing the above structure, + call this function to introduce your CVF format to the FAT/CVF-FAT + driver. This is usually done in init_module. Be sure to check the + return value. Zero means success, everything else causes a kernel + message printed in the syslog describing the error that occured. + Typical errors are: + - a module with the same version id is already registered or + - too many CVF formats. Hack fs/fat/cvf.c if you need more. + +int unregister_cvf_format(struct cvf_format*cvf_format); + This is usually called in cleanup_module. Return value =0 means + success. An error only occurs if you try to unregister a CVF format + that has not been previously registered. The code uses the version id + to distinguish the modules, so be sure to keep it uniqe. + +5. CVS Modules +------------------------------------------------------------------------------ + +Refer to the dmsdos module (the successor of the dmsdos filesystem) for a +sample implementation. It can currently be found at + + ftp://fb9nt.uni-duisburg.de/pub/linux/dmsdos + diff -u --recursive --new-file v2.1.78/linux/Makefile linux/Makefile --- v2.1.78/linux/Makefile Tue Jan 6 09:37:32 1998 +++ linux/Makefile Tue Jan 6 09:37:18 1998 @@ -1,6 +1,6 @@ VERSION = 2 PATCHLEVEL = 1 -SUBLEVEL = 78 +SUBLEVEL = 79 ARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/) diff -u --recursive --new-file v2.1.78/linux/arch/alpha/kernel/entry.S linux/arch/alpha/kernel/entry.S --- v2.1.78/linux/arch/alpha/kernel/entry.S Tue Dec 23 16:30:59 1997 +++ linux/arch/alpha/kernel/entry.S Sat Jan 10 11:58:12 1998 @@ -29,11 +29,10 @@ /* * task structure offsets */ -#define TASK_STATE 0 -#define TASK_COUNTER 8 -#define TASK_PRIORITY 16 -#define TASK_FLAGS 24 -#define TASK_SIGPENDING 32 +#define TASK_STATE 0 +#define TASK_FLAGS 8 +#define TASK_SIGPENDING 16 +#define TASK_SIZE 24 /* * task flags (must match include/linux/sched.h): diff -u --recursive --new-file v2.1.78/linux/arch/i386/kernel/entry.S linux/arch/i386/kernel/entry.S --- v2.1.78/linux/arch/i386/kernel/entry.S Tue Dec 2 16:45:17 1997 +++ linux/arch/i386/kernel/entry.S Sat Jan 10 11:57:29 1998 @@ -71,13 +71,10 @@ * these are offsets into the task-struct. */ state = 0 -counter = 4 -priority = 8 -flags = 12 -sigpending = 16 -dbgreg6 = 44 -dbgreg7 = 48 -exec_domain = 52 +flags = 4 +sigpending = 8 +addr_limit = 12 +exec_domain = 16 ENOSYS = 38 diff -u --recursive --new-file v2.1.78/linux/arch/i386/kernel/i386_ksyms.c linux/arch/i386/kernel/i386_ksyms.c --- v2.1.78/linux/arch/i386/kernel/i386_ksyms.c Sun Dec 21 22:36:12 1997 +++ linux/arch/i386/kernel/i386_ksyms.c Sat Jan 10 18:04:59 1998 @@ -47,6 +47,20 @@ EXPORT_SYMBOL(__delay); EXPORT_SYMBOL(__const_udelay); +EXPORT_SYMBOL_NOVERS(__get_user_1); +EXPORT_SYMBOL_NOVERS(__get_user_2); +EXPORT_SYMBOL_NOVERS(__get_user_4); +EXPORT_SYMBOL_NOVERS(__put_user_1); +EXPORT_SYMBOL_NOVERS(__put_user_2); +EXPORT_SYMBOL_NOVERS(__put_user_4); + +EXPORT_SYMBOL(strncpy_from_user); +EXPORT_SYMBOL(__strncpy_from_user); +EXPORT_SYMBOL(clear_user); +EXPORT_SYMBOL(__clear_user); +EXPORT_SYMBOL(__generic_copy_from_user); +EXPORT_SYMBOL(__generic_copy_to_user); +EXPORT_SYMBOL(strlen_user); #ifdef __SMP__ EXPORT_SYMBOL(apic_reg); /* Needed internally for the I386 inlines */ @@ -79,3 +93,4 @@ EXPORT_SYMBOL(mca_isenabled); EXPORT_SYMBOL(mca_isadapter); #endif + diff -u --recursive --new-file v2.1.78/linux/arch/i386/lib/Makefile linux/arch/i386/lib/Makefile --- v2.1.78/linux/arch/i386/lib/Makefile Sat Nov 29 11:25:09 1997 +++ linux/arch/i386/lib/Makefile Sat Jan 10 14:51:20 1998 @@ -11,6 +11,6 @@ endif L_TARGET = lib.a -L_OBJS = checksum.o semaphore.o locks.o delay.o +L_OBJS = checksum.o semaphore.o locks.o delay.o usercopy.o getuser.o putuser.o include $(TOPDIR)/Rules.make diff -u --recursive --new-file v2.1.78/linux/arch/i386/lib/getuser.S linux/arch/i386/lib/getuser.S --- v2.1.78/linux/arch/i386/lib/getuser.S Wed Dec 31 16:00:00 1969 +++ linux/arch/i386/lib/getuser.S Sat Jan 10 21:37:34 1998 @@ -0,0 +1,73 @@ +/* + * __get_user functions. + * + * (C) Copyright 1998 Linus Torvalds + * + * These functions have a non-standard call interface + * to make them more efficient, especially as they + * return an error value in addition to the "real" + * return value. + */ + +/* + * __get_user_X + * + * Inputs: %eax contains the address + * + * Outputs: %eax is error code (0 or -EFAULT) + * %edx contains zero-extended value + * + * These functions should not modify any other registers, + * as they get called from within inline assembly. + */ + +addr_limit = 12 + +.text +.align 4 +.globl __get_user_1 +__get_user_1: + movl %esp,%edx + andl $0xffffe000,%edx + cmpl %eax,addr_limit(%edx) + jnb bad_get_user +1: movzbl (%eax),%edx + xorl %eax,%eax + ret + +.align 4 +.globl __get_user_2 +__get_user_2: + addl $1,%eax + movl %esp,%edx + jc bad_get_user + andl $0xffffe000,%edx + cmpl %eax,addr_limit(%edx) + jnb bad_get_user +2: movzwl -1(%eax),%edx + xorl %eax,%eax + ret + +.align 4 +.globl __get_user_4 +__get_user_4: + addl $3,%eax + movl %esp,%edx + jc bad_get_user + andl $0xffffe000,%edx + cmpl %eax,addr_limit(%edx) + jnb bad_get_user +3: movl -3(%eax),%edx + xorl %eax,%eax + ret + +bad_get_user: + xorl %edx,%edx + movl $-14,%eax + ret + +.section __ex_table,"a" + .long 1b,bad_get_user + .long 2b,bad_get_user + .long 3b,bad_get_user +.previous diff -u --recursive --new-file v2.1.78/linux/arch/i386/lib/putuser.S linux/arch/i386/lib/putuser.S --- v2.1.78/linux/arch/i386/lib/putuser.S Wed Dec 31 16:00:00 1969 +++ linux/arch/i386/lib/putuser.S Sat Jan 10 21:37:34 1998 @@ -0,0 +1,71 @@ +/* + * __put_user functions. + * + * (C) Copyright 1998 Linus Torvalds + * + * These functions have a non-standard call interface + * to make them more efficient. + */ + +/* + * __put_user_X + * + * Inputs: %eax contains the address + * %edx contains the value + * + * Outputs: %eax is error code (0 or -EFAULT) + * %ecx is corrupted (will contain "current_task"). + * + * These functions should not modify any other registers, + * as they get called from within inline assembly. + */ + +addr_limit = 12 + +.text +.align 4 +.globl __put_user_1 +__put_user_1: + movl %esp,%ecx + andl $0xffffe000,%ecx + cmpl %eax,addr_limit(%ecx) + jnb bad_put_user +1: movb %dl,(%eax) + xorl %eax,%eax + ret + +.align 4 +.globl __put_user_2 +__put_user_2: + addl $1,%eax + movl %esp,%ecx + jc bad_put_user + andl $0xffffe000,%ecx + cmpl %eax,addr_limit(%ecx) + jnb bad_put_user +2: movw %dx,-1(%eax) + xorl %eax,%eax + ret + +.align 4 +.globl __put_user_4 +__put_user_4: + addl $3,%eax + movl %esp,%ecx + jc bad_put_user + andl $0xffffe000,%ecx + cmpl %eax,addr_limit(%ecx) + jnb bad_put_user +3: movl %edx,-3(%eax) + xorl %eax,%eax + ret + +bad_put_user: + movl $-14,%eax + ret + +.section __ex_table,"a" + .long 1b,bad_put_user + .long 2b,bad_put_user + .long 3b,bad_put_user +.previous diff -u --recursive --new-file v2.1.78/linux/arch/i386/lib/usercopy.c linux/arch/i386/lib/usercopy.c --- v2.1.78/linux/arch/i386/lib/usercopy.c Wed Dec 31 16:00:00 1969 +++ linux/arch/i386/lib/usercopy.c Sat Jan 10 21:28:41 1998 @@ -0,0 +1,136 @@ +/* + * User address space access functions. + * The non inlined parts of asm-i386/uaccess.h are here. + * + * Copyright 1997 Andi Kleen + * Copyright 1997 Linus Torvalds + */ +#include + +inline unsigned long +__generic_copy_to_user(void *to, const void *from, unsigned long n) +{ + if (access_ok(VERIFY_WRITE, to, n)) + __copy_user(to,from,n); + return n; +} + +inline unsigned long +__generic_copy_from_user(void *to, const void *from, unsigned long n) +{ + if (access_ok(VERIFY_READ, from, n)) + __copy_user(to,from,n); + return n; +} + + +/* + * Copy a null terminated string from userspace. + */ + +#define __do_strncpy_from_user(dst,src,count,res) \ + __asm__ __volatile__( \ + " testl %1,%1\n" \ + " jz 2f\n" \ + "0: lodsb\n" \ + " stosb\n" \ + " testb %%al,%%al\n" \ + " jz 1f\n" \ + " decl %1\n" \ + " jnz 0b\n" \ + "1: subl %1,%0\n" \ + "2:\n" \ + ".section .fixup,\"ax\"\n" \ + "3: movl %2,%0\n" \ + " jmp 2b\n" \ + ".previous\n" \ + ".section __ex_table,\"a\"\n" \ + " .align 4\n" \ + " .long 0b,3b\n" \ + ".previous" \ + : "=d"(res), "=c"(count) \ + : "i"(-EFAULT), "0"(count), "1"(count), "S"(src), "D"(dst) \ + : "si", "di", "ax", "memory") + +long +__strncpy_from_user(char *dst, const char *src, long count) +{ + long res; + __do_strncpy_from_user(dst, src, count, res); + return res; +} + +long +strncpy_from_user(char *dst, const char *src, long count) +{ + long res = -EFAULT; + if (access_ok(VERIFY_READ, src, 1)) + __do_strncpy_from_user(dst, src, count, res); + return res; +} + + +/* + * Zero Userspace + */ + +#define __do_clear_user(addr,size) \ + __asm__ __volatile__( \ + "0: rep; stosl\n" \ + " movl %1,%0\n" \ + "1: rep; stosb\n" \ + "2:\n" \ + ".section .fixup,\"ax\"\n" \ + "3: lea 0(%1,%0,4),%0\n" \ + " jmp 2b\n" \ + ".previous\n" \ + ".section __ex_table,\"a\"\n" \ + " .align 4\n" \ + " .long 0b,3b\n" \ + " .long 1b,2b\n" \ + ".previous" \ + : "=c"(size) \ + : "r"(size & 3), "0"(size / 4), "D"(addr), "a"(0) \ + : "di") + +unsigned long +clear_user(void *to, unsigned long n) +{ + if (access_ok(VERIFY_WRITE, to, n)) + __do_clear_user(to, n); + return n; +} + +unsigned long +__clear_user(void *to, unsigned long n) +{ + __do_clear_user(to, n); + return n; +} + +/* + * Return the size of a string (including the ending 0) + * + * Return 0 for error + */ + +long strlen_user(const char *s) +{ + unsigned long res; + + __asm__ __volatile__( + "0: repne; scasb\n" + " notl %0\n" + "1:\n" + ".section .fixup,\"ax\"\n" + "2: xorl %0,%0\n" + " jmp 1b\n" + ".previous\n" + ".section __ex_table,\"a\"\n" + " .align 4\n" + " .long 0b,2b\n" + ".previous" + :"=c" (res), "=D" (s) + :"1" (s), "a" (0), "0" (-__addr_ok(s))); + return res & -__addr_ok(s); +} diff -u --recursive --new-file v2.1.78/linux/arch/i386/mm/fault.c linux/arch/i386/mm/fault.c --- v2.1.78/linux/arch/i386/mm/fault.c Sun Dec 21 22:36:12 1997 +++ linux/arch/i386/mm/fault.c Wed Jan 7 12:04:52 1998 @@ -192,11 +192,6 @@ /* Are we prepared to handle this kernel fault? */ if ((fixup = search_exception_table(regs->eip)) != 0) { - printk(KERN_DEBUG "%s: Exception at [<%lx>] cr2=%lx (fixup: %lx)\n", - tsk->comm, - regs->eip, - address, - fixup); regs->eip = fixup; goto out; } diff -u --recursive --new-file v2.1.78/linux/drivers/block/ide-cd.c linux/drivers/block/ide-cd.c --- v2.1.78/linux/drivers/block/ide-cd.c Tue Jan 6 09:37:33 1998 +++ linux/drivers/block/ide-cd.c Sat Jan 10 10:42:55 1998 @@ -2772,6 +2772,17 @@ return nslots; } +static void ide_cdrom_add_settings(ide_drive_t *drive) +{ + int major = HWIF(drive)->major; + int minor = drive->select.b.unit << PARTN_BITS; + + ide_add_setting(drive, "breada_readahead", SETTING_RW, BLKRAGET, BLKRASET, TYPE_INT, 0, 255, 1, 2, &read_ahead[major], NULL); + ide_add_setting(drive, "file_readahead", SETTING_RW, BLKFRAGET, BLKFRASET, TYPE_INTA, 0, INT_MAX, 1, 1024, &max_readahead[major][minor], NULL); + ide_add_setting(drive, "max_kb_per_request", SETTING_RW, BLKSECTGET, BLKSECTSET, TYPE_INTA, 1, 255, 1, 2, &max_sectors[major][minor], NULL); + ide_add_setting(drive, "dsc_overlap", SETTING_RW, -1, -1, TYPE_BYTE, 0, 1, 1, 1, &drive->dsc_overlap, NULL); +} + static int ide_cdrom_setup (ide_drive_t *drive) { @@ -2884,6 +2895,7 @@ info->devinfo.handle = NULL; return 1; } + ide_cdrom_add_settings(drive); return 0; } @@ -2942,13 +2954,6 @@ return 0; } -int ide_cdrom_init (void); -static ide_module_t ide_cdrom_module = { - IDE_DRIVER_MODULE, - ide_cdrom_init, - NULL -}; - static ide_driver_t ide_cdrom_driver = { "ide-cdrom", /* name */ IDECD_VERSION, /* version */ @@ -2969,6 +2974,13 @@ NULL /* proc */ }; +int ide_cdrom_init (void); +static ide_module_t ide_cdrom_module = { + IDE_DRIVER_MODULE, + ide_cdrom_init, + &ide_cdrom_driver, + NULL +}; #ifdef MODULE int init_module (void) @@ -2981,7 +2993,7 @@ ide_drive_t *drive; int failed = 0; - while ((drive = ide_scan_devices (ide_cdrom, &ide_cdrom_driver, failed)) != NULL) + while ((drive = ide_scan_devices (ide_cdrom, ide_cdrom_driver.name, &ide_cdrom_driver, failed)) != NULL) if (ide_cdrom_cleanup (drive)) { printk ("%s: cleanup_module() called while still busy\n", drive->name); failed++; @@ -2997,7 +3009,7 @@ int failed = 0; MOD_INC_USE_COUNT; - while ((drive = ide_scan_devices (ide_cdrom, NULL, failed++)) != NULL) { + while ((drive = ide_scan_devices (ide_cdrom, ide_cdrom_driver.name, NULL, failed++)) != NULL) { info = (struct cdrom_info *) kmalloc (sizeof (struct cdrom_info), GFP_KERNEL); if (info == NULL) { printk ("%s: Can't allocate a cdrom structure\n", drive->name); diff -u --recursive --new-file v2.1.78/linux/drivers/block/ide-disk.c linux/drivers/block/ide-disk.c --- v2.1.78/linux/drivers/block/ide-disk.c Sun Dec 21 22:36:12 1997 +++ linux/drivers/block/ide-disk.c Sat Jan 10 10:42:55 1998 @@ -1,5 +1,5 @@ /* - * linux/drivers/block/ide-disk.c Version 1.03 Nov 30, 1997 + * linux/drivers/block/ide-disk.c Version 1.04 Jan 7, 1998 * * Copyright (C) 1994-1998 Linus Torvalds & authors (see below) */ @@ -13,11 +13,12 @@ * Version 1.00 move disk only code from ide.c to ide-disk.c * support optional byte-swapping of all data * Version 1.01 fix previous byte-swapping code - * Verions 1.02 remove ", LBA" from drive identification msgs - * Verions 1.03 fix display of id->buf_size for big-endian + * Version 1.02 remove ", LBA" from drive identification msgs + * Version 1.03 fix display of id->buf_size for big-endian + * Version 1.04 add /proc configurable settings and S.M.A.R.T support */ -#define IDEDISK_VERSION "1.03" +#define IDEDISK_VERSION "1.04" #undef REALLY_SLOW_IO /* most systems can safely undef this */ @@ -372,17 +373,13 @@ { MOD_INC_USE_COUNT; if (drive->removable && drive->usage == 1) { - byte door_lock[] = {WIN_DOORLOCK,0,0,0}; - struct request rq; check_disk_change(inode->i_rdev); - ide_init_drive_cmd (&rq); - rq.buffer = door_lock; /* * Ignore the return code from door_lock, * since the open() has already succeeded, * and the door_lock is irrelevant at this point. */ - (void) ide_do_drive_cmd(drive, &rq, ide_wait); + (void) ide_wait_cmd(drive, WIN_DOORLOCK, 0, 0, 0, NULL); } return 0; } @@ -390,12 +387,8 @@ static void idedisk_release (struct inode *inode, struct file *filp, ide_drive_t *drive) { if (drive->removable && !drive->usage) { - byte door_unlock[] = {WIN_DOORUNLOCK,0,0,0}; - struct request rq; invalidate_buffers(inode->i_rdev); - ide_init_drive_cmd (&rq); - rq.buffer = door_unlock; - (void) ide_do_drive_cmd(drive, &rq, ide_wait); + (void) ide_wait_cmd(drive, WIN_DOORUNLOCK, 0, 0, 0, NULL); } MOD_DEC_USE_COUNT; } @@ -481,18 +474,106 @@ PROC_IDE_READ_RETURN(page,start,off,count,eof,len); } +static int smart_enable(ide_drive_t *drive) +{ + return ide_wait_cmd(drive, WIN_SMART, 0, SMART_ENABLE, 0, NULL); +} + +static int get_smart_values(ide_drive_t *drive, byte *buf) +{ + (void) smart_enable(drive); + return ide_wait_cmd(drive, WIN_SMART, 0, SMART_READ_VALUES, 1, buf); +} + +static int get_smart_thresholds(ide_drive_t *drive, byte *buf) +{ + (void) smart_enable(drive); + return ide_wait_cmd(drive, WIN_SMART, 0, SMART_READ_THRESHOLDS, 1, buf); +} + +static int proc_idedisk_read_smart_thresholds + (char *page, char **start, off_t off, int count, int *eof, void *data) +{ + ide_drive_t *drive = (ide_drive_t *)data; + int len = 0, i = 0; + + if (!get_smart_thresholds(drive, page)) { + unsigned short *val = ((unsigned short *)page) + 2; + char *out = ((char *)val) + (SECTOR_WORDS * 4); + page = out; + do { + out += sprintf(out, "%04x%c", le16_to_cpu(*val), (++i & 7) ? ' ' : '\n'); + val += 1; + } while (i < (SECTOR_WORDS * 2)); + len = out - page; + } + PROC_IDE_READ_RETURN(page,start,off,count,eof,len); +} + +static int proc_idedisk_read_smart_values + (char *page, char **start, off_t off, int count, int *eof, void *data) +{ + ide_drive_t *drive = (ide_drive_t *)data; + int len = 0, i = 0; + + if (!get_smart_values(drive, page)) { + unsigned short *val = ((unsigned short *)page) + 2; + char *out = ((char *)val) + (SECTOR_WORDS * 4); + page = out; + do { + out += sprintf(out, "%04x%c", le16_to_cpu(*val), (++i & 7) ? ' ' : '\n'); + val += 1; + } while (i < (SECTOR_WORDS * 2)); + len = out - page; + } + PROC_IDE_READ_RETURN(page,start,off,count,eof,len); +} + static ide_proc_entry_t idedisk_proc[] = { { "cache", proc_idedisk_read_cache, NULL }, { "geometry", proc_ide_read_geometry, NULL }, + { "smart_values", proc_idedisk_read_smart_values, NULL }, + { "smart_thresholds", proc_idedisk_read_smart_thresholds, NULL }, { NULL, NULL, NULL } }; -int idedisk_init (void); -static ide_module_t idedisk_module = { - IDE_DRIVER_MODULE, - idedisk_init, - NULL -}; +static int set_multcount(ide_drive_t *drive, int arg) +{ + struct request rq; + + if (drive->special.b.set_multmode) + return -EBUSY; + ide_init_drive_cmd (&rq); + drive->mult_req = arg; + drive->special.b.set_multmode = 1; + (void) ide_do_drive_cmd (drive, &rq, ide_wait); + return (drive->mult_count == arg) ? 0 : -EIO; +} + +static int set_nowerr(ide_drive_t *drive, int arg) +{ + drive->nowerr = arg; + drive->bad_wstat = arg ? BAD_R_STAT : BAD_W_STAT; + return 0; +} + +static void idedisk_add_settings(ide_drive_t *drive) +{ + struct hd_driveid *id = drive->id; + int major = HWIF(drive)->major; + int minor = drive->select.b.unit << PARTN_BITS; + + ide_add_setting(drive, "bios_cyl", SETTING_RW, -1, -1, TYPE_SHORT, 0, 1023, 1, 1, &drive->bios_cyl, NULL); + ide_add_setting(drive, "bios_head", SETTING_RW, -1, -1, TYPE_BYTE, 0, 255, 1, 1, &drive->bios_head, NULL); + ide_add_setting(drive, "bios_sect", SETTING_RW, -1, -1, TYPE_BYTE, 0, 63, 1, 1, &drive->bios_sect, NULL); + ide_add_setting(drive, "bswap", SETTING_READ, -1, -1, TYPE_BYTE, 0, 1, 1, 1, &drive->bswap, NULL); + ide_add_setting(drive, "multcount", id ? SETTING_RW : SETTING_READ, HDIO_GET_MULTCOUNT, HDIO_SET_MULTCOUNT, TYPE_BYTE, 0, id ? id->max_multsect : 0, 1, 2, &drive->mult_count, set_multcount); + ide_add_setting(drive, "nowerr", SETTING_RW, HDIO_GET_NOWERR, HDIO_SET_NOWERR, TYPE_BYTE, 0, 1, 1, 1, &drive->nowerr, set_nowerr); + ide_add_setting(drive, "breada_readahead", SETTING_RW, BLKRAGET, BLKRASET, TYPE_INT, 0, 255, 1, 2, &read_ahead[major], NULL); + ide_add_setting(drive, "file_readahead", SETTING_RW, BLKFRAGET, BLKFRASET, TYPE_INTA, 0, INT_MAX, 1, 1024, &max_readahead[major][minor], NULL); + ide_add_setting(drive, "max_kb_per_request", SETTING_RW, BLKSECTGET, BLKSECTSET, TYPE_INTA, 1, 255, 1, 2, &max_sectors[major][minor], NULL); + +} /* * IDE subdriver functions, registered with ide.c @@ -517,6 +598,14 @@ idedisk_proc /* proc */ }; +int idedisk_init (void); +static ide_module_t idedisk_module = { + IDE_DRIVER_MODULE, + idedisk_init, + &idedisk_driver, + NULL +}; + static int idedisk_cleanup (ide_drive_t *drive) { return ide_unregister_subdriver(drive); @@ -527,6 +616,8 @@ struct hd_driveid *id = drive->id; unsigned long capacity, check; + idedisk_add_settings(drive); + if (id == NULL) return; @@ -615,7 +706,7 @@ int failed = 0; MOD_INC_USE_COUNT; - while ((drive = ide_scan_devices (ide_disk, NULL, failed++)) != NULL) { + while ((drive = ide_scan_devices (ide_disk, idedisk_driver.name, NULL, failed++)) != NULL) { /* SunDisk drives: ignore "second" drive; can mess up non-Sun systems! FIXME */ struct hd_driveid *id = drive->id; @@ -650,7 +741,7 @@ ide_drive_t *drive; int failed = 0; - while ((drive = ide_scan_devices (ide_disk, &idedisk_driver, failed)) != NULL) + while ((drive = ide_scan_devices (ide_disk, idedisk_driver.name, &idedisk_driver, failed)) != NULL) if (idedisk_cleanup (drive)) { printk (KERN_ERR "%s: cleanup_module() called while still busy\n", drive->name); failed++; diff -u --recursive --new-file v2.1.78/linux/drivers/block/ide-floppy.c linux/drivers/block/ide-floppy.c --- v2.1.78/linux/drivers/block/ide-floppy.c Sun Dec 21 22:36:12 1997 +++ linux/drivers/block/ide-floppy.c Sat Jan 10 10:42:55 1998 @@ -1327,6 +1327,20 @@ return 0; } +static void idefloppy_add_settings(ide_drive_t *drive) +{ + int major = HWIF(drive)->major; + int minor = drive->select.b.unit << PARTN_BITS; + + ide_add_setting(drive, "bios_cyl", SETTING_RW, -1, -1, TYPE_SHORT, 0, 1023, 1, 1, &drive->bios_cyl, NULL); + ide_add_setting(drive, "bios_head", SETTING_RW, -1, -1, TYPE_BYTE, 0, 255, 1, 1, &drive->bios_head, NULL); + ide_add_setting(drive, "bios_sect", SETTING_RW, -1, -1, TYPE_BYTE, 0, 63, 1, 1, &drive->bios_sect, NULL); + ide_add_setting(drive, "breada_readahead", SETTING_RW, BLKRAGET, BLKRASET, TYPE_INT, 0, 255, 1, 2, &read_ahead[major], NULL); + ide_add_setting(drive, "file_readahead", SETTING_RW, BLKFRAGET, BLKFRASET, TYPE_INTA, 0, INT_MAX, 1, 1024, &max_readahead[major][minor], NULL); + ide_add_setting(drive, "max_kb_per_request", SETTING_RW, BLKSECTGET, BLKSECTSET, TYPE_INTA, 1, 255, 1, 2, &max_sectors[major][minor], NULL); + +} + /* * Driver initialization. */ @@ -1351,6 +1365,7 @@ } (void) idefloppy_get_capacity (drive); + idefloppy_add_settings(drive); } static int idefloppy_cleanup (ide_drive_t *drive) @@ -1369,13 +1384,6 @@ { NULL, NULL, NULL } }; -int idefloppy_init (void); -static ide_module_t idefloppy_module = { - IDE_DRIVER_MODULE, - idefloppy_init, - NULL -}; - /* * IDE subdriver functions, registered with ide.c */ @@ -1399,6 +1407,14 @@ idefloppy_proc /* proc */ }; +int idefloppy_init (void); +static ide_module_t idefloppy_module = { + IDE_DRIVER_MODULE, + idefloppy_init, + &idefloppy_driver, + NULL +}; + /* * idefloppy_init will register the driver for each floppy. */ @@ -1409,7 +1425,7 @@ int failed = 0; MOD_INC_USE_COUNT; - while ((drive = ide_scan_devices (ide_floppy, NULL, failed++)) != NULL) { + while ((drive = ide_scan_devices (ide_floppy, idefloppy_driver.name, NULL, failed++)) != NULL) { if (!idefloppy_identify_device (drive, drive->id)) { printk (KERN_ERR "ide-floppy: %s: not supported by this version of ide-floppy\n", drive->name); continue; @@ -1442,7 +1458,7 @@ ide_drive_t *drive; int failed = 0; - while ((drive = ide_scan_devices (ide_floppy, &idefloppy_driver, failed)) != NULL) + while ((drive = ide_scan_devices (ide_floppy, idefloppy_driver.name, &idefloppy_driver, failed)) != NULL) if (idefloppy_cleanup (drive)) { printk ("%s: cleanup_module() called while still busy\n", drive->name); failed++; diff -u --recursive --new-file v2.1.78/linux/drivers/block/ide-probe.c linux/drivers/block/ide-probe.c --- v2.1.78/linux/drivers/block/ide-probe.c Sun Dec 21 22:36:12 1997 +++ linux/drivers/block/ide-probe.c Sat Jan 10 10:42:55 1998 @@ -624,6 +624,11 @@ for (gdp = &gendisk_head; *gdp; gdp = &((*gdp)->next)) ; hwif->gd = *gdp = gd; /* link onto tail of list */ + + for (unit = 0; unit < units; ++unit) { + if (hwif->drives[unit].present) + ide_add_generic_settings(hwif->drives + unit); + } } static int hwif_init (ide_hwif_t *hwif) diff -u --recursive --new-file v2.1.78/linux/drivers/block/ide-proc.c linux/drivers/block/ide-proc.c --- v2.1.78/linux/drivers/block/ide-proc.c Fri Jan 2 14:37:01 1998 +++ linux/drivers/block/ide-proc.c Sat Jan 10 10:42:55 1998 @@ -1,5 +1,5 @@ /* - * linux/drivers/block/ide-proc.c Version 1.02 December 31, 1997 + * linux/drivers/block/ide-proc.c Version 1.03 January 2, 1998 * * Copyright (C) 1997-1998 Mark Lord */ @@ -38,8 +38,15 @@ * If there is an error *anywhere* in the string of registers/data * then *none* of the writes will be performed. * - * Also useful, "cat /proc/ide0/hda/identify" will issue an IDENTIFY - * (or PACKET_IDENTIFY) command to /dev/hda, and then dump out the + * Drive/Driver settings can be retrieved by reading the drive's + * "settings" files. e.g. "cat /proc/ide0/hda/settings" + * To write a new value "val" into a specific setting "name", use: + * echo "name:val" >/proc/ide/ide0/hda/settings + * + * Also useful, "cat /proc/ide0/hda/[identify, smart_values, + * smart_thresholds, capabilities]" will issue an IDENTIFY / + * PACKET_IDENTIFY / SMART_READ_VALUES / SMART_READ_THRESHOLDS / + * SENSE CAPABILITIES command to /dev/hda, and then dump out the * returned data as 256 16-bit words. The "hdparm" utility will * be updated someday soon to use this mechanism. * @@ -80,6 +87,16 @@ return digit; } +static int ide_getdigit(char c) +{ + int digit; + if (isdigit(c)) + digit = c - '0'; + else + digit = -1; + return digit; +} + static int xx_xx_parse_error (const char *data, unsigned long len, const char *msg) { char errbuf[16]; @@ -237,6 +254,24 @@ return xx_xx_parse_error(start, startn, msg); } +static int proc_ide_read_drivers + (char *page, char **start, off_t off, int count, int *eof, void *data) +{ + char *out = page; + int len; + ide_module_t *p = ide_modules; + ide_driver_t *driver; + + while (p) { + driver = (ide_driver_t *) p->info; + if (p->type == IDE_DRIVER_MODULE && driver) + out += sprintf(out, "%s version %s\n", driver->name, driver->version); + p = p->next; + } + len = out - page; + PROC_IDE_READ_RETURN(page,start,off,count,eof,len); +} + static int proc_ide_read_config (char *page, char **start, off_t off, int count, int *eof, void *data) { @@ -325,22 +360,9 @@ PROC_IDE_READ_RETURN(page,start,off,count,eof,len); } -static int proc_ide_get_identify (ide_drive_t *drive, byte *buf) +static int proc_ide_get_identify(ide_drive_t *drive, byte *buf) { - struct request rq; - byte *end; - - ide_init_drive_cmd(&rq); - rq.buffer = buf; - *buf++ = (drive->media == ide_disk) ? WIN_IDENTIFY : WIN_PIDENTIFY; - *buf++ = 0; - *buf++ = 0; - *buf++ = 1; - end = buf + (SECTOR_WORDS * 4); - while (buf != end) - *buf++ = 0; /* pre-zero it, in case identify fails */ - (void) ide_do_drive_cmd(drive, &rq, ide_wait); - return 0; + return ide_wait_cmd(drive, (drive->media == ide_disk) ? WIN_IDENTIFY : WIN_PIDENTIFY, 0, 0, 1, buf); } static int proc_ide_read_identify @@ -366,25 +388,130 @@ (char *page, char **start, off_t off, int count, int *eof, void *data) { ide_drive_t *drive = (ide_drive_t *) data; - int major = HWIF(drive)->major; - int minor = drive->select.b.unit << PARTN_BITS; + ide_settings_t *setting = (ide_settings_t *) drive->settings; char *out = page; - int len; + int len, rc, mul_factor, div_factor; - out += sprintf(out,"multcount %i\n", drive->mult_count); - out += sprintf(out,"io_32bit %i\n", drive->io_32bit); - out += sprintf(out,"unmaskirq %i\n", drive->unmask); - out += sprintf(out,"using_dma %i\n", drive->using_dma); - out += sprintf(out,"nowerr %i\n", drive->bad_wstat == BAD_R_STAT); - out += sprintf(out,"keepsettings %i\n", drive->keep_settings); - out += sprintf(out,"nice %i/%i/%i\n", drive->nice0, drive->nice1, drive->nice2); - out += sprintf(out,"dsc_overlap %i\n", drive->dsc_overlap); - out += sprintf(out,"max_sectors %i\n", max_sectors[major][minor]); - out += sprintf(out,"readahead %i\n", max_readahead[major][minor] / 1024); + out += sprintf(out, "name\t\t\tvalue\t\tmin\t\tmax\t\tmode\n"); + out += sprintf(out, "----\t\t\t-----\t\t---\t\t---\t\t----\n"); + while(setting) { + mul_factor = setting->mul_factor; + div_factor = setting->div_factor; + out += sprintf(out, "%-24s", setting->name); + if ((rc = ide_read_setting(drive, setting)) >= 0) + out += sprintf(out, "%-16d", rc * mul_factor / div_factor); + else + out += sprintf(out, "%-16s", "write-only"); + out += sprintf(out, "%-16d%-16d", (setting->min * mul_factor + div_factor - 1) / div_factor, setting->max * mul_factor / div_factor); + if (setting->rw & SETTING_READ) + out += sprintf(out, "r"); + if (setting->rw & SETTING_WRITE) + out += sprintf(out, "w"); + out += sprintf(out, "\n"); + setting = setting->next; + } len = out - page; PROC_IDE_READ_RETURN(page,start,off,count,eof,len); } +#define MAX_LEN 30 + +static int proc_ide_write_settings + (struct file *file, const char *buffer, unsigned long count, void *data) +{ + ide_drive_t *drive = (ide_drive_t *) data; + ide_hwif_t *hwif = HWIF(drive); + char name[MAX_LEN + 1]; + int for_real = 0, len; + unsigned long n, flags; + const char *start = NULL; + ide_settings_t *setting; + + if (!suser()) + return -EACCES; + + /* + * Skip over leading whitespace + */ + while (count && isspace(*buffer)) { + --count; + ++buffer; + } + /* + * Do one full pass to verify all parameters, + * then do another to actually write the pci regs. + */ + save_flags(flags); + do { + const char *p; + if (for_real) { + unsigned long timeout = jiffies + (3 * HZ); + ide_hwgroup_t *mygroup = (ide_hwgroup_t *)(hwif->hwgroup); + ide_hwgroup_t *mategroup = NULL; + if (hwif->mate && hwif->mate->hwgroup) + mategroup = (ide_hwgroup_t *)(hwif->mate->hwgroup); + cli(); /* ensure all PCI writes are done together */ + while (mygroup->active || (mategroup && mategroup->active)) { + restore_flags(flags); + if (0 < (signed long)(jiffies - timeout)) { + printk("/proc/ide/%s/pci: channel(s) busy, cannot write\n", hwif->name); + return -EBUSY; + } + cli(); + } + } + p = buffer; + n = count; + while (n > 0) { + int d, digits; + unsigned int val = 0; + start = p; + + while (n > 0 && *p != ':') { + --n; + p++; + } + if (*p != ':') + goto parse_error; + len = IDE_MIN(p - start, MAX_LEN); + strncpy(name, start, IDE_MIN(len, MAX_LEN)); + name[len] = 0; + + if (n > 0) { + --n; + p++; + } else + goto parse_error; + + digits = 0; + while (n > 0 && (d = ide_getdigit(*p)) >= 0) { + val = (val * 10) + d; + --n; + ++p; + ++digits; + } + if (n > 0 && !isspace(*p)) + goto parse_error; + while (n > 0 && isspace(*p)) { + --n; + ++p; + } + setting = ide_find_setting_by_name(drive, name); + if (!setting) + goto parse_error; + + if (for_real) + ide_write_setting(drive, setting, val * setting->div_factor / setting->mul_factor); + } + } while (!for_real++); + restore_flags(flags); + return count; +parse_error: + restore_flags(flags); + printk("proc_ide_write_settings(): parse error\n"); + return -EINVAL; +} + int proc_ide_read_capacity (char *page, char **start, off_t off, int count, int *eof, void *data) { @@ -437,6 +564,18 @@ PROC_IDE_READ_RETURN(page,start,off,count,eof,len); } +static int proc_ide_write_driver + (struct file *file, const char *buffer, unsigned long count, void *data) +{ + ide_drive_t *drive = (ide_drive_t *) data; + + if (!suser()) + return -EACCES; + if (ide_replace_subdriver(drive, buffer)) + return -EINVAL; + return count; +} + static int proc_ide_read_media (char *page, char **start, off_t off, int count, int *eof, void *data) { @@ -461,13 +600,12 @@ PROC_IDE_READ_RETURN(page,start,off,count,eof,len); } - static ide_proc_entry_t generic_drive_entries[] = { - { "driver", proc_ide_read_driver, NULL }, + { "driver", proc_ide_read_driver, proc_ide_write_driver }, { "identify", proc_ide_read_identify, NULL }, { "media", proc_ide_read_media, NULL }, { "model", proc_ide_read_dmodel, NULL }, - { "settings", proc_ide_read_settings, NULL }, + { "settings", proc_ide_read_settings, proc_ide_write_settings }, { NULL, NULL, NULL } }; @@ -497,9 +635,16 @@ } } -static void create_proc_ide_drives (ide_hwif_t *hwif, struct proc_dir_entry *parent) +static int proc_ide_readlink(struct proc_dir_entry *de, char *page) +{ + int n = (de->name[2] - 'a') / 2; + return sprintf(page, "ide%d/%s", n, de->name); +} + +static void create_proc_ide_drives (ide_hwif_t *hwif, struct proc_dir_entry *parent, struct proc_dir_entry *root) { int d; + struct proc_dir_entry *ent; for (d = 0; d < MAX_DRIVES; d++) { ide_drive_t *drive = &hwif->drives[d]; @@ -509,6 +654,12 @@ drive->proc = create_proc_entry(drive->name, S_IFDIR, parent); if (drive->proc) ide_add_proc_entries(drive, generic_drive_entries); + + ent = create_proc_entry(drive->name, S_IFLNK | S_IRUGO | S_IWUGO | S_IXUGO, root); + if (!ent) return; + ent->data = drive; + ent->readlink_proc = proc_ide_readlink; + ent->nlink = 1; } } @@ -555,14 +706,18 @@ ent->data = hwif; ent->read_proc = proc_ide_read_type; - create_proc_ide_drives(hwif, hwif_ent); + create_proc_ide_drives(hwif, hwif_ent, parent); } } void proc_ide_init(void) { - struct proc_dir_entry *ent; - ent = create_proc_entry("ide", S_IFDIR, 0); + struct proc_dir_entry *root, *ent; + root = create_proc_entry("ide", S_IFDIR, 0); + if (!root) return; + create_proc_ide_interfaces(root); + + ent = create_proc_entry("drivers", 0, root); if (!ent) return; - create_proc_ide_interfaces(ent); + ent->read_proc = proc_ide_read_drivers; } diff -u --recursive --new-file v2.1.78/linux/drivers/block/ide-tape.c linux/drivers/block/ide-tape.c --- v2.1.78/linux/drivers/block/ide-tape.c Sun Dec 21 22:36:12 1997 +++ linux/drivers/block/ide-tape.c Sat Jan 10 10:42:55 1998 @@ -1,7 +1,7 @@ /* - * linux/drivers/block/ide-tape.c Version 1.12 Dec 7, 1997 + * linux/drivers/block/ide-tape.c Version 1.13 Jan 2, 1998 * - * Copyright (C) 1995, 1996 Gadi Oxman + * Copyright (C) 1995 - 1998 Gadi Oxman * * This driver was constructed as a student project in the software laboratory * of the faculty of electrical engineering in the Technion - Israel's @@ -211,6 +211,7 @@ * of bytes written to the tape was not an integral * number of tape blocks. * Add support for INTERRUPT DRQ devices. + * Ver 1.13 Jan 2 98 Add "speed == 0" work-around for HP COLORADO 5GB * * Here are some words from the first releases of hd.c, which are quoted * in ide.c and apply here as well: @@ -320,7 +321,7 @@ * sharing a (fast) ATA-2 disk with any (slow) new ATAPI device. */ -#define IDETAPE_VERSION "1.12" +#define IDETAPE_VERSION "1.13" #include #include @@ -675,7 +676,7 @@ */ int nr_stages; /* Number of currently used stages */ int nr_pending_stages; /* Number of pending stages */ - int max_stages; /* We will not allocate more than this number of stages */ + int max_stages, min_pipeline, max_pipeline; /* We will not allocate more than this number of stages */ idetape_stage_t *first_stage; /* The first stage which will be removed from the pipeline */ idetape_stage_t *active_stage; /* The currently active stage */ idetape_stage_t *next_stage; /* Will be serviced after the currently active request */ @@ -1409,12 +1410,15 @@ static void idetape_increase_max_pipeline_stages (ide_drive_t *drive) { idetape_tape_t *tape = drive->driver_data; + int increase = (tape->max_pipeline - tape->min_pipeline) / 10; #if IDETAPE_DEBUG_LOG printk (KERN_INFO "Reached idetape_increase_max_pipeline_stages\n"); #endif /* IDETAPE_DEBUG_LOG */ - tape->max_stages = IDE_MIN (tape->max_stages + IDETAPE_INCREASE_STAGES_RATE, IDETAPE_MAX_PIPELINE_STAGES); + tape->max_stages += increase; + tape->max_stages = IDE_MAX(tape->max_stages, tape->min_pipeline); + tape->max_stages = IDE_MIN(tape->max_stages, tape->max_pipeline); } /* @@ -2520,7 +2524,7 @@ while (tape->first_stage != NULL) idetape_remove_stage_head (drive); tape->nr_pending_stages = 0; - tape->max_stages = IDETAPE_MIN_PIPELINE_STAGES; + tape->max_stages = tape->min_pipeline; } /* @@ -2610,7 +2614,7 @@ * as some systems are constantly on, and the system load * can be totally different on the next backup). */ - tape->max_stages = IDETAPE_MIN_PIPELINE_STAGES; + tape->max_stages = tape->min_pipeline; #if IDETAPE_DEBUG_BUGS if (tape->first_stage != NULL || tape->next_stage != NULL || tape->last_stage != NULL || tape->nr_stages != 0) { printk (KERN_ERR "ide-tape: ide-tape pipeline bug\n"); @@ -3460,6 +3464,15 @@ capabilities->speed = ntohs (capabilities->speed); capabilities->buffer_size = ntohs (capabilities->buffer_size); + if (!capabilities->speed) { + printk("ide-tape: %s: overriding capabilities->speed (assuming 650KB/sec)\n", drive->name); + capabilities->speed = 650; + } + if (!capabilities->max_speed) { + printk("ide-tape: %s: overriding capabilities->max_speed (assuming 650KB/sec)\n", drive->name); + capabilities->max_speed = 650; + } + tape->capabilities = *capabilities; /* Save us a copy */ tape->tape_block_size = capabilities->blk512 ? 512:1024; #if IDETAPE_DEBUG_LOG @@ -3493,6 +3506,24 @@ #endif /* IDETAPE_DEBUG_LOG */ } +static void idetape_add_settings(ide_drive_t *drive) +{ + idetape_tape_t *tape = drive->driver_data; + +/* + * drive setting name read/write ioctl ioctl data type min max mul_factor div_factor data pointer set function + */ + ide_add_setting(drive, "buffer", SETTING_READ, -1, -1, TYPE_SHORT, 0, 0xffff, 1, 2, &tape->capabilities.buffer_size, NULL); + ide_add_setting(drive, "pipeline_min", SETTING_RW, -1, -1, TYPE_INT, 0, 0xffff, tape->stage_size / 1024, 1, &tape->min_pipeline, NULL); + ide_add_setting(drive, "pipeline", SETTING_RW, -1, -1, TYPE_INT, 0, 0xffff, tape->stage_size / 1024, 1, &tape->max_stages, NULL); + ide_add_setting(drive, "pipeline_max", SETTING_RW, -1, -1, TYPE_INT, 0, 0xffff, tape->stage_size / 1024, 1, &tape->max_pipeline, NULL); + ide_add_setting(drive, "pipeline_used",SETTING_READ, -1, -1, TYPE_INT, 0, 0xffff, tape->stage_size / 1024, 1, &tape->nr_stages, NULL); + ide_add_setting(drive, "speed", SETTING_READ, -1, -1, TYPE_SHORT, 0, 0xffff, 1, 1, &tape->capabilities.speed, NULL); + ide_add_setting(drive, "stage", SETTING_READ, -1, -1, TYPE_INT, 0, 0xffff, 1, 1024, &tape->stage_size, NULL); + ide_add_setting(drive, "tdsc", SETTING_RW, -1, -1, TYPE_INT, IDETAPE_DSC_RW_MIN, IDETAPE_DSC_RW_MAX, 1000, HZ, &tape->best_dsc_rw_frequency, NULL); + ide_add_setting(drive, "dsc_overlap", SETTING_RW, -1, -1, TYPE_BYTE, 0, 1, 1, 1, &drive->dsc_overlap, NULL); +} + /* * ide_setup is called to: * @@ -3521,7 +3552,9 @@ tape->name[0] = 'h'; tape->name[1] = 't'; tape->name[2] = '0' + minor; tape->chrdev_direction = idetape_direction_none; tape->pc = tape->pc_stack; - tape->max_stages = IDETAPE_MIN_PIPELINE_STAGES; + tape->min_pipeline = IDETAPE_MIN_PIPELINE_STAGES; + tape->max_pipeline = IDETAPE_MAX_PIPELINE_STAGES; + tape->max_stages = tape->min_pipeline; *((unsigned short *) &gcw) = drive->id->config; if (gcw.drq_type == 1) set_bit(IDETAPE_DRQ_INTERRUPT, &tape->flags); @@ -3577,6 +3610,8 @@ drive->name, tape->name, tape->capabilities.speed, (tape->capabilities.buffer_size * 512) / tape->stage_size, tape->stage_size / 1024, tape->max_stages * tape->stage_size / 1024, tape->best_dsc_rw_frequency * 1000 / HZ, drive->using_dma ? ", DMA":""); + + idetape_add_settings(drive); } static int idetape_cleanup (ide_drive_t *drive) @@ -3605,18 +3640,6 @@ return 0; } -static int proc_idetape_read_buffer - (char *page, char **start, off_t off, int count, int *eof, void *data) -{ - ide_drive_t *drive = (ide_drive_t *) data; - idetape_tape_t *tape = drive->driver_data; - char *out = page; - int len; - - len = sprintf(out,"%d\n", tape->capabilities.buffer_size / 2); - PROC_IDE_READ_RETURN(page,start,off,count,eof,len); -} - static int proc_idetape_read_name (char *page, char **start, off_t off, int count, int *eof, void *data) { @@ -3629,72 +3652,11 @@ PROC_IDE_READ_RETURN(page,start,off,count,eof,len); } -static int proc_idetape_read_pipeline - (char *page, char **start, off_t off, int count, int *eof, void *data) -{ - ide_drive_t *drive = (ide_drive_t *) data; - idetape_tape_t *tape = drive->driver_data; - char *out = page; - int len; - - len = sprintf(out,"%d\n", tape->max_stages * tape->stage_size / 1024); - PROC_IDE_READ_RETURN(page,start,off,count,eof,len); -} - -static int proc_idetape_read_speed - (char *page, char **start, off_t off, int count, int *eof, void *data) -{ - ide_drive_t *drive = (ide_drive_t *) data; - idetape_tape_t *tape = drive->driver_data; - char *out = page; - int len; - - len = sprintf(out,"%d\n", tape->capabilities.speed); - PROC_IDE_READ_RETURN(page,start,off,count,eof,len); -} - -static int proc_idetape_read_stage - (char *page, char **start, off_t off, int count, int *eof, void *data) -{ - ide_drive_t *drive = (ide_drive_t *) data; - idetape_tape_t *tape = drive->driver_data; - char *out = page; - int len; - - len = sprintf(out,"%d\n", tape->stage_size / 1024); - PROC_IDE_READ_RETURN(page,start,off,count,eof,len); -} - -static int proc_idetape_read_tdsc - (char *page, char **start, off_t off, int count, int *eof, void *data) -{ - ide_drive_t *drive = (ide_drive_t *) data; - idetape_tape_t *tape = drive->driver_data; - char *out = page; - int len; - - len = sprintf(out,"%lu\n", tape->best_dsc_rw_frequency * 1000 / HZ); - PROC_IDE_READ_RETURN(page,start,off,count,eof,len); -} - static ide_proc_entry_t idetape_proc[] = { - { "buffer", proc_idetape_read_buffer, NULL }, { "name", proc_idetape_read_name, NULL }, - { "pipeline", proc_idetape_read_pipeline, NULL }, - { "speed", proc_idetape_read_speed, NULL }, - { "stage", proc_idetape_read_stage, NULL }, - { "tdsc", proc_idetape_read_tdsc, NULL }, { NULL, NULL, NULL } }; -int idetape_init (void); - -static ide_module_t idetape_module = { - IDE_DRIVER_MODULE, - idetape_init, - NULL -}; - /* * IDE subdriver functions, registered with ide.c */ @@ -3718,6 +3680,14 @@ idetape_proc /* proc */ }; +int idetape_init (void); +static ide_module_t idetape_module = { + IDE_DRIVER_MODULE, + idetape_init, + &idetape_driver, + NULL +}; + /* * Our character device supporting functions, passed to register_chrdev. */ @@ -3751,7 +3721,7 @@ for (minor = 0; minor < MAX_HWIFS * MAX_DRIVES; minor++ ) idetape_chrdevs[minor].drive = NULL; - if ((drive = ide_scan_devices (ide_tape, NULL, failed++)) == NULL) { + if ((drive = ide_scan_devices (ide_tape, idetape_driver.name, NULL, failed++)) == NULL) { ide_register_module (&idetape_module); MOD_DEC_USE_COUNT; return 0; @@ -3780,7 +3750,7 @@ idetape_setup (drive, tape, minor); idetape_chrdevs[minor].drive = drive; supported++; failed--; - } while ((drive = ide_scan_devices (ide_tape, NULL, failed++)) != NULL); + } while ((drive = ide_scan_devices (ide_tape, idetape_driver.name, NULL, failed++)) != NULL); if (!idetape_chrdev_present && !supported) { unregister_chrdev (IDETAPE_MAJOR, "ht"); } else diff -u --recursive --new-file v2.1.78/linux/drivers/block/ide.c linux/drivers/block/ide.c --- v2.1.78/linux/drivers/block/ide.c Sun Dec 21 22:36:13 1997 +++ linux/drivers/block/ide.c Sat Jan 10 10:42:55 1998 @@ -1,5 +1,5 @@ /* - * linux/drivers/block/ide.c Version 6.11 December 5, 1997 + * linux/drivers/block/ide.c Version 6.12 January 2, 1998 * * Copyright (C) 1994-1998 Linus Torvalds & authors (see below) */ @@ -98,6 +98,8 @@ * Version 6.11 fix probe error in ide_scan_devices() * fix ancient "jiffies" polling bugs * mask all hwgroup interrupts on each irq entry + * Version 6.12 integrate ioctl and proc interfaces + * fix parsing of "idex=" command line parameter * * Some additional driver compile-time options are in ide.h * @@ -151,7 +153,7 @@ /* * ide_modules keeps track of the available IDE chipset/probe/driver modules. */ -static ide_module_t *ide_modules = NULL; +ide_module_t *ide_modules = NULL; /* * This is declared extern in ide.h, for access by other IDE modules: @@ -809,7 +811,8 @@ { struct request *rq = HWGROUP(drive)->rq; byte *args = (byte *) rq->buffer; - byte test, stat = GET_STAT(); + byte stat = GET_STAT(); + int retries = 10; ide_sti(); if ((stat & DRQ_STAT) && args && args[3]) { @@ -817,12 +820,11 @@ drive->io_32bit = 0; ide_input_data(drive, &args[4], args[3] * SECTOR_WORDS); drive->io_32bit = io_32bit; - stat = GET_STAT(); + while (((stat = GET_STAT()) & BUSY_STAT) && retries--) + udelay(100); } - test = stat; - if (drive->media == ide_cdrom) - test = stat &~BUSY_STAT; - if (OK_STAT(test,READY_STAT,BAD_STAT)) + + if (OK_STAT(stat, READY_STAT, BAD_STAT)) ide_end_drive_cmd (drive, stat, GET_ERR()); else ide_error(drive, "drive_cmd", stat); /* calls ide_end_drive_cmd */ @@ -901,6 +903,10 @@ printk("%s: DRIVE_CMD cmd=0x%02x sc=0x%02x fr=0x%02x xx=0x%02x\n", drive->name, args[0], args[1], args[2], args[3]); #endif + if (args[0] == WIN_SMART) { + OUT_BYTE(0x4f, IDE_LCYL_REG); + OUT_BYTE(0xc2, IDE_HCYL_REG); + } OUT_BYTE(args[2],IDE_FEATURE_REG); ide_cmd(drive, args[0], args[1], &drive_cmd_intr); return; @@ -1556,6 +1562,22 @@ return 0; } +int ide_replace_subdriver(ide_drive_t *drive, const char *driver) +{ + if (!drive->present || drive->busy || drive->usage) + goto abort; + if (drive->driver != NULL && DRIVER(drive)->cleanup(drive)) + goto abort; + strncpy(drive->driver_req, driver, 9); + ide_init_module(IDE_DRIVER_MODULE); + drive->driver_req[0] = 0; + ide_init_module(IDE_DRIVER_MODULE); + if (DRIVER(drive) && !strcmp(DRIVER(drive)->name, driver)) + return 0; +abort: + return 1; +} + void ide_unregister (unsigned int index) { struct gendisk *gd, **gdp; @@ -1697,20 +1719,229 @@ return hwif->present ? index : -1; } +void ide_add_setting(ide_drive_t *drive, char *name, int rw, int read_ioctl, int write_ioctl, int data_type, int min, int max, int mul_factor, int div_factor, void *data, ide_procset_t *set) +{ + ide_settings_t **p = (ide_settings_t **) &drive->settings, *setting = NULL; + + while ((*p) && strcmp((*p)->name, name) < 0) + p = &((*p)->next); + if ((setting = kmalloc(sizeof(*setting), GFP_KERNEL)) == NULL) + goto abort; + memset(setting, 0, sizeof(*setting)); + if ((setting->name = kmalloc(strlen(name) + 1, GFP_KERNEL)) == NULL) + goto abort; + strcpy(setting->name, name); setting->rw = rw; + setting->read_ioctl = read_ioctl; setting->write_ioctl = write_ioctl; + setting->data_type = data_type; setting->min = min; + setting->max = max; setting->mul_factor = mul_factor; + setting->div_factor = div_factor; setting->data = data; + setting->set = set; setting->next = *p; + if (drive->driver) + setting->auto_remove = 1; + *p = setting; + return; +abort: + if (setting) + kfree(setting); +} + +void ide_remove_setting(ide_drive_t *drive, char *name) +{ + ide_settings_t **p = (ide_settings_t **) &drive->settings, *setting; + + while ((*p) && strcmp((*p)->name, name)) + p = &((*p)->next); + if ((setting = (*p)) == NULL) + return; + (*p) = setting->next; + kfree(setting->name); + kfree(setting); +} + +static ide_settings_t *ide_find_setting_by_ioctl(ide_drive_t *drive, int cmd) +{ + ide_settings_t *setting = drive->settings; + + while (setting) { + if (setting->read_ioctl == cmd || setting->write_ioctl == cmd) + break; + setting = setting->next; + } + return setting; +} + +ide_settings_t *ide_find_setting_by_name(ide_drive_t *drive, char *name) +{ + ide_settings_t *setting = drive->settings; + + while (setting) { + if (strcmp(setting->name, name) == 0) + break; + setting = setting->next; + } + return setting; +} + +static void auto_remove_settings(ide_drive_t *drive) +{ + ide_settings_t *setting; +repeat: + setting = drive->settings; + while (setting) { + if (setting->auto_remove) { + ide_remove_setting(drive, setting->name); + goto repeat; + } + setting = setting->next; + } +} + +int ide_read_setting(ide_drive_t *drive, ide_settings_t *setting) +{ + if (!(setting->rw & SETTING_READ)) + return -EINVAL; + switch(setting->data_type) { + case TYPE_BYTE: + return *((u8 *) setting->data); + case TYPE_SHORT: + return *((u16 *) setting->data); + case TYPE_INT: + case TYPE_INTA: + return *((u32 *) setting->data); + default: + return -EINVAL; + } +} + +int ide_write_setting(ide_drive_t *drive, ide_settings_t *setting, int val) +{ + unsigned long flags; + int i, rc = 0; + u32 *p; + + if (!suser()) + return -EACCES; + if (!(setting->rw & SETTING_WRITE)) + return -EPERM; + if (val < setting->min || val > setting->max) + return -EINVAL; + save_flags(flags); + cli(); + if (setting->set) + rc = setting->set(drive, val); + else switch (setting->data_type) { + case TYPE_BYTE: + *((u8 *) setting->data) = val; + break; + case TYPE_SHORT: + *((u16 *) setting->data) = val; + break; + case TYPE_INT: + *((u32 *) setting->data) = val; + break; + case TYPE_INTA: + p = (u32 *) setting->data; + for (i = 0; i < 1 << PARTN_BITS; i++, p++) + *p = val; + break; + } + restore_flags(flags); + return rc; +} + +static int set_io_32bit(ide_drive_t *drive, int arg) +{ + drive->io_32bit = arg; +#ifdef CONFIG_BLK_DEV_DTC2278 + if (HWIF(drive)->chipset == ide_dtc2278) + HWIF(drive)->drives[!drive->select.b.unit].io_32bit = arg; +#endif /* CONFIG_BLK_DEV_DTC2278 */ + return 0; +} + +static int set_using_dma(ide_drive_t *drive, int arg) +{ + if (!drive->driver || !DRIVER(drive)->supports_dma) + return -EPERM; + if (!drive->id || !(drive->id->capability & 1) || !HWIF(drive)->dmaproc) + return -EPERM; + if (HWIF(drive)->dmaproc(arg ? ide_dma_on : ide_dma_off, drive)) + return -EIO; + return 0; +} + +static int set_pio_mode(ide_drive_t *drive, int arg) +{ + struct request rq; + + if (!HWIF(drive)->tuneproc) + return -ENOSYS; + if (drive->special.b.set_tune) + return -EBUSY; + ide_init_drive_cmd(&rq); + drive->tune_req = (byte) arg; + drive->special.b.set_tune = 1; + (void) ide_do_drive_cmd (drive, &rq, ide_wait); + return 0; +} + +void ide_add_generic_settings(ide_drive_t *drive) +{ +/* + * drive setting name read/write access read ioctl write ioctl data type min max mul_factor div_factor data pointer set function + */ + ide_add_setting(drive, "io_32bit", drive->no_io_32bit ? SETTING_READ : SETTING_RW, HDIO_GET_32BIT, HDIO_SET_32BIT, TYPE_BYTE, 0, 1 + (SUPPORT_VLB_SYNC << 1), 1, 1, &drive->io_32bit, set_io_32bit); + ide_add_setting(drive, "keepsettings", SETTING_RW, HDIO_GET_KEEPSETTINGS, HDIO_SET_KEEPSETTINGS, TYPE_BYTE, 0, 1, 1, 1, &drive->keep_settings, NULL); + ide_add_setting(drive, "nice1", SETTING_RW, -1, -1, TYPE_BYTE, 0, 1, 1, 1, &drive->nice1, NULL); + ide_add_setting(drive, "pio_mode", SETTING_WRITE, -1, HDIO_SET_PIO_MODE, TYPE_BYTE, 0, 255, 1, 1, NULL, set_pio_mode); + ide_add_setting(drive, "slow", SETTING_RW, -1, -1, TYPE_BYTE, 0, 1, 1, 1, &drive->slow, NULL); + ide_add_setting(drive, "unmaskirq", drive->no_unmask ? SETTING_READ : SETTING_RW, HDIO_GET_UNMASKINTR, HDIO_SET_UNMASKINTR, TYPE_BYTE, 0, 1, 1, 1, &drive->unmask, NULL); + ide_add_setting(drive, "using_dma", SETTING_RW, HDIO_GET_DMA, HDIO_SET_DMA, TYPE_BYTE, 0, 1, 1, 1, &drive->using_dma, set_using_dma); +} + +int ide_wait_cmd (ide_drive_t *drive, int cmd, int nsect, int feature, int sectors, byte *buf) +{ + struct request rq; + byte buffer[4]; + + if (!buf) + buf = buffer; + memset(buf, 0, 4 + SECTOR_WORDS * 4 * sectors); + ide_init_drive_cmd(&rq); + rq.buffer = buf; + *buf++ = cmd; + *buf++ = nsect; + *buf++ = feature; + *buf++ = sectors; + return ide_do_drive_cmd(drive, &rq, ide_wait); +} + static int ide_ioctl (struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { int err, major, minor; ide_drive_t *drive; - unsigned long flags; struct request rq; kdev_t dev; + ide_settings_t *setting; if (!inode || !(dev = inode->i_rdev)) return -EINVAL; major = MAJOR(dev); minor = MINOR(dev); if ((drive = get_info_ptr(inode->i_rdev)) == NULL) return -ENODEV; + + if ((setting = ide_find_setting_by_ioctl(drive, cmd)) != NULL) { + if (cmd == setting->read_ioctl) { + err = ide_read_setting(drive, setting); + return err >= 0 ? put_user(err, (long *) arg) : err; + } else { + if ((MINOR(inode->i_rdev) & PARTN_MASK)) + return -EINVAL; + return ide_write_setting(drive, setting, arg); + } + } + ide_init_drive_cmd (&rq); switch (cmd) { case HDIO_GETGEO: @@ -1730,54 +1961,13 @@ invalidate_buffers(inode->i_rdev); return 0; - case BLKRASET: - if (!suser()) return -EACCES; - if(arg > 0xff) return -EINVAL; - read_ahead[MAJOR(inode->i_rdev)] = arg; - return 0; - - case BLKRAGET: - return put_user(read_ahead[MAJOR(inode->i_rdev)], (long *) arg); - case BLKGETSIZE: /* Return device size */ return put_user(drive->part[MINOR(inode->i_rdev)&PARTN_MASK].nr_sects, (long *) arg); - case BLKFRASET: - if (!suser()) return -EACCES; - max_readahead[major][minor] = arg; - return 0; - - case BLKFRAGET: - return put_user(max_readahead[major][minor], (long *) arg); - - case BLKSECTSET: - if (!suser()) return -EACCES; - if (!arg || arg > 0xff) return -EINVAL; - max_sectors[major][minor] = arg; - return 0; - - case BLKSECTGET: - return put_user(max_sectors[major][minor], (long *) arg); - case BLKRRPART: /* Re-read partition tables */ if (!suser()) return -EACCES; return ide_revalidate_disk(inode->i_rdev); - case HDIO_GET_KEEPSETTINGS: - return put_user(drive->keep_settings, (long *) arg); - - case HDIO_GET_UNMASKINTR: - return put_user(drive->unmask, (long *) arg); - - case HDIO_GET_DMA: - return put_user(drive->using_dma, (long *) arg); - - case HDIO_GET_32BIT: - return put_user(drive->io_32bit, (long *) arg); - - case HDIO_GET_MULTCOUNT: - return put_user(drive->mult_count, (long *) arg); - case HDIO_GET_IDENTITY: if (MINOR(inode->i_rdev) & PARTN_MASK) return -EINVAL; @@ -1792,99 +1982,13 @@ #endif return 0; - case HDIO_GET_NOWERR: - return put_user(drive->bad_wstat == BAD_R_STAT, (long *) arg); - case HDIO_GET_NICE: - { - long nice = 0; - - nice |= drive->dsc_overlap << IDE_NICE_DSC_OVERLAP; - nice |= drive->atapi_overlap << IDE_NICE_ATAPI_OVERLAP; - nice |= drive->nice0 << IDE_NICE_0; - nice |= drive->nice1 << IDE_NICE_1; - nice |= drive->nice2 << IDE_NICE_2; - return put_user(nice, (long *) arg); - } - - case HDIO_SET_DMA: - if (!suser()) return -EACCES; - if (drive->driver != NULL && !DRIVER(drive)->supports_dma) - return -EPERM; - if (!drive->id || !(drive->id->capability & 1) || !HWIF(drive)->dmaproc) - return -EPERM; - case HDIO_SET_KEEPSETTINGS: - case HDIO_SET_UNMASKINTR: - case HDIO_SET_NOWERR: - if (arg > 1) - return -EINVAL; - case HDIO_SET_32BIT: - if (!suser()) return -EACCES; - if ((MINOR(inode->i_rdev) & PARTN_MASK)) - return -EINVAL; - save_flags(flags); - cli(); - switch (cmd) { - case HDIO_SET_DMA: - if (!(HWIF(drive)->dmaproc)) { - restore_flags(flags); - return -EPERM; - } - if (HWIF(drive)->dmaproc(arg ? ide_dma_on : ide_dma_off, drive)) { - restore_flags(flags); - return -EIO; - } - break; - case HDIO_SET_KEEPSETTINGS: - drive->keep_settings = arg; - break; - case HDIO_SET_UNMASKINTR: - if (arg && drive->no_unmask) { - restore_flags(flags); - return -EPERM; - } - drive->unmask = arg; - break; - case HDIO_SET_NOWERR: - drive->bad_wstat = arg ? BAD_R_STAT : BAD_W_STAT; - break; - case HDIO_SET_32BIT: - if (arg > (1 + (SUPPORT_VLB_SYNC<<1))) { - restore_flags(flags); - return -EINVAL; - } - if (arg && drive->no_io_32bit) { - restore_flags(flags); - return -EPERM; - } - drive->io_32bit = arg; -#ifdef CONFIG_BLK_DEV_DTC2278 - if (HWIF(drive)->chipset == ide_dtc2278) - HWIF(drive)->drives[!drive->select.b.unit].io_32bit = arg; -#endif /* CONFIG_BLK_DEV_DTC2278 */ - break; - } - restore_flags(flags); - return 0; - - case HDIO_SET_MULTCOUNT: - if (!suser()) return -EACCES; - if (MINOR(inode->i_rdev) & PARTN_MASK) - return -EINVAL; - if (drive->id && arg > drive->id->max_multsect) - return -EINVAL; - save_flags(flags); - cli(); - if (drive->special.b.set_multmode) { - restore_flags(flags); - return -EBUSY; - } - drive->mult_req = arg; - drive->special.b.set_multmode = 1; - restore_flags(flags); - (void) ide_do_drive_cmd (drive, &rq, ide_wait); - return (drive->mult_count == arg) ? 0 : -EIO; - + return put_user(drive->dsc_overlap << IDE_NICE_DSC_OVERLAP | + drive->atapi_overlap << IDE_NICE_ATAPI_OVERLAP | + drive->nice0 << IDE_NICE_0 | + drive->nice1 << IDE_NICE_1 | + drive->nice2 << IDE_NICE_2, + (long *) arg); case HDIO_DRIVE_CMD: { byte args[4], *argbuf = args; @@ -1901,31 +2005,13 @@ return -ENOMEM; memcpy(argbuf, args, 4); } - rq.buffer = argbuf; - err = ide_do_drive_cmd(drive, &rq, ide_wait); + err = ide_wait_cmd(drive, args[0], args[1], args[2], args[3], argbuf); if (copy_to_user((void *)arg, argbuf, argsize)) err = -EFAULT; if (argsize > 4) kfree(argbuf); return err; } - case HDIO_SET_PIO_MODE: - if (!suser()) return -EACCES; - if (MINOR(inode->i_rdev) & PARTN_MASK) - return -EINVAL; - if (!HWIF(drive)->tuneproc) - return -ENOSYS; - save_flags(flags); - cli(); - if (drive->special.b.set_tune) { - restore_flags(flags); - return -EBUSY; - } - drive->tune_req = (byte) arg; - drive->special.b.set_tune = 1; - restore_flags(flags); - (void) ide_do_drive_cmd (drive, &rq, ide_wait); - return 0; case HDIO_SCAN_HWIF: { @@ -2223,7 +2309,7 @@ if (i > 0 || i <= -7) { /* is parameter a chipset name? */ if (hwif->chipset != ide_unknown) goto bad_option; /* chipset already specified */ - if (i != -7 && hw != 0) + if (i <= -7 && hw != 0) goto bad_hwif; /* chipset drivers are for "ide0=" only */ if (ide_hwifs[hw^1].chipset != ide_unknown) goto bad_option; /* chipset for 2nd port already specified */ @@ -2578,7 +2664,7 @@ if (d->special == NULL) d->special = default_special; } -ide_drive_t *ide_scan_devices (byte media, ide_driver_t *driver, int n) +ide_drive_t *ide_scan_devices (byte media, const char *name, ide_driver_t *driver, int n) { unsigned int unit, index, i; @@ -2588,12 +2674,15 @@ search: for (index = 0, i = 0; index < MAX_HWIFS; ++index) { ide_hwif_t *hwif = &ide_hwifs[index]; - if (hwif->present) { - for (unit = 0; unit < MAX_DRIVES; ++unit) { - ide_drive_t *drive = &hwif->drives[unit]; - if (drive->present && drive->media == media && drive->driver == driver && ++i > n) - return drive; - } + if (!hwif->present) + continue; + for (unit = 0; unit < MAX_DRIVES; ++unit) { + ide_drive_t *drive = &hwif->drives[unit]; + char *req = drive->driver_req; + if (*req && !strstr(name, req)) + continue; + if (drive->present && drive->media == media && drive->driver == driver && ++i > n) + return drive; } } return NULL; @@ -2642,6 +2731,7 @@ } ide_remove_proc_entries(drive, DRIVER(drive)->proc); ide_remove_proc_entries(drive, generic_subdriver_entries); + auto_remove_settings(drive); drive->driver = NULL; restore_flags(flags); return 0; @@ -2735,6 +2825,8 @@ EXPORT_SYMBOL(ide_stall_queue); EXPORT_SYMBOL(ide_add_proc_entries); EXPORT_SYMBOL(ide_remove_proc_entries); +EXPORT_SYMBOL(ide_add_setting); +EXPORT_SYMBOL(ide_remove_setting); EXPORT_SYMBOL(proc_ide_read_geometry); EXPORT_SYMBOL(ide_register); diff -u --recursive --new-file v2.1.78/linux/drivers/block/ide.h linux/drivers/block/ide.h --- v2.1.78/linux/drivers/block/ide.h Fri Jan 2 14:37:01 1998 +++ linux/drivers/block/ide.h Sat Jan 10 18:11:54 1998 @@ -206,23 +206,23 @@ special_t special; /* special action flags */ unsigned present : 1; /* drive is physically present */ unsigned noprobe : 1; /* from: hdx=noprobe */ - unsigned keep_settings : 1; /* restore settings after drive reset */ + byte keep_settings; /* restore settings after drive reset */ unsigned busy : 1; /* currently doing revalidate_disk() */ unsigned removable : 1; /* 1 if need to do check_media_change */ - unsigned using_dma : 1; /* disk is using dma for read/write */ + byte using_dma; /* disk is using dma for read/write */ unsigned forced_geom : 1; /* 1 if hdx=c,h,s was given at boot */ - unsigned unmask : 1; /* flag: okay to unmask other irqs */ + byte unmask; /* flag: okay to unmask other irqs */ unsigned no_unmask : 1; /* disallow setting unmask bit */ unsigned no_io_32bit : 1; /* disallow enabling 32bit I/O */ unsigned nobios : 1; /* flag: do not probe bios for drive */ - unsigned slow : 1; /* flag: slow data port */ + byte slow; /* flag: slow data port */ unsigned autotune : 2; /* 1=autotune, 2=noautotune, 0=default */ unsigned revalidate : 1; /* request revalidation */ - unsigned bswap : 1; /* flag: byte swap data */ - unsigned dsc_overlap : 1; /* flag: DSC overlap */ + byte bswap; /* flag: byte swap data */ + byte dsc_overlap; /* flag: DSC overlap */ unsigned atapi_overlap : 1; /* flag: ATAPI overlap (not supported) */ unsigned nice0 : 1; /* flag: give obvious excess bandwidth */ - unsigned nice1 : 1; /* flag: give potential excess bandwidth */ + byte nice1; /* flag: give potential excess bandwidth */ unsigned nice2 : 1; /* flag: give a share in our own bandwidth */ #if FAKE_FDISK_FOR_EZDRIVE unsigned remap_0_to_1 : 1; /* flag: partitioned with ezdrive */ @@ -236,6 +236,7 @@ byte tune_req; /* requested drive tuning setting */ byte io_32bit; /* 0=16-bit, 1=32-bit, 2/3=32bit+sync */ byte bad_wstat; /* used for ignoring WRERR_STAT */ + byte nowerr; /* used for ignoring WRERR_STAT */ byte sect0; /* offset of first sector for DM6:DDO */ byte usage; /* current "open()" count for drive */ byte head; /* "real" number of heads */ @@ -253,6 +254,8 @@ void *driver; /* (ide_driver_t *) */ void *driver_data; /* extra driver data */ struct proc_dir_entry *proc; /* /proc/ide/ directory entry */ + void *settings; /* /proc/ide/ drive settings */ + char driver_req[10]; /* requests specific driver */ } ide_drive_t; /* @@ -362,6 +365,43 @@ } ide_hwgroup_t; /* + * configurable drive settings + */ + +#define TYPE_INT 0 +#define TYPE_INTA 1 +#define TYPE_BYTE 2 +#define TYPE_SHORT 3 + +#define SETTING_READ (1 << 0) +#define SETTING_WRITE (1 << 1) +#define SETTING_RW (SETTING_READ | SETTING_WRITE) + +typedef int (ide_procset_t)(ide_drive_t *, int); +typedef struct ide_settings_s { + char *name; + int rw; + int read_ioctl; + int write_ioctl; + int data_type; + int min; + int max; + int mul_factor; + int div_factor; + void *data; + ide_procset_t *set; + int auto_remove; + struct ide_settings_s *next; +} ide_settings_t; + +void ide_add_setting(ide_drive_t *drive, char *name, int rw, int read_ioctl, int write_ioctl, int data_type, int min, int max, int mul_factor, int div_factor, void *data, ide_procset_t *set); +void ide_remove_setting(ide_drive_t *drive, char *name); +ide_settings_t *ide_find_setting_by_name(ide_drive_t *drive, char *name); +int ide_read_setting(ide_drive_t *t, ide_settings_t *setting); +int ide_write_setting(ide_drive_t *drive, ide_settings_t *setting, int val); +void ide_add_generic_settings(ide_drive_t *drive); + +/* * /proc/ide interface */ typedef struct { @@ -407,6 +447,7 @@ typedef void (ide_pre_reset_proc)(ide_drive_t *); typedef unsigned long (ide_capacity_proc)(ide_drive_t *); typedef void (ide_special_proc)(ide_drive_t *); +typedef void (ide_setting_proc)(ide_drive_t *); typedef struct ide_driver_s { const char *name; @@ -442,6 +483,7 @@ typedef struct ide_module_s { int type; ide_module_init_proc *init; + void *info; struct ide_module_s *next; } ide_module_t; @@ -455,6 +497,7 @@ */ #ifndef _IDE_C extern ide_hwif_t ide_hwifs[]; /* master data repository */ +extern ide_module_t *ide_modules; #endif /* @@ -588,6 +631,11 @@ void ide_end_drive_cmd (ide_drive_t *drive, byte stat, byte err); /* + * Issue ATA command and wait for completion. + */ +int ide_wait_cmd (ide_drive_t *drive, int cmd, int nsect, int feature, int sectors, byte *buf); + +/* * ide_system_bus_speed() returns what we think is the system VESA/PCI * bus speed (in MHz). This is used for calculating interface PIO timings. * The default is 40 for known PCI systems, 50 otherwise. @@ -651,9 +699,10 @@ int ide_register_module (ide_module_t *module); void ide_unregister_module (ide_module_t *module); -ide_drive_t *ide_scan_devices (byte media, ide_driver_t *driver, int n); +ide_drive_t *ide_scan_devices (byte media, const char *name, ide_driver_t *driver, int n); int ide_register_subdriver (ide_drive_t *drive, ide_driver_t *driver, int version); int ide_unregister_subdriver (ide_drive_t *drive); +int ide_replace_subdriver(ide_drive_t *drive, const char *driver); #ifdef CONFIG_BLK_DEV_IDEPCI unsigned long ide_find_free_region (unsigned short size) __init; diff -u --recursive --new-file v2.1.78/linux/drivers/net/de4x5.c linux/drivers/net/de4x5.c --- v2.1.78/linux/drivers/net/de4x5.c Tue Dec 23 16:30:59 1997 +++ linux/drivers/net/de4x5.c Sat Jan 10 10:46:51 1998 @@ -364,11 +364,16 @@ Added generic MII PHY functionality to deal with newer PHY chips. Fix the mess in 2.1.67. + 0.532 5-Jan-98 Fix bug in mii_get_phy() reported by + . + Fix bug in pci_probe() for 64 bit systems reported + by . + 0.533 9-Jan-98 Fix more 64 bit bugs reported by . ========================================================================= */ -static const char *version = "de4x5.c:T0.531 1997/12/21 davies@maniac.ultranet.com\n"; +static const char *version = "de4x5.c:V0.533 1998/1/9 davies@maniac.ultranet.com\n"; #include @@ -763,7 +768,7 @@ struct { void *priv; /* Original kmalloc'd mem addr */ void *buf; /* Original kmalloc'd mem addr */ - int lock; /* Lock the cache accesses */ + u_long lock; /* Lock the cache accesses */ s32 csr0; /* Saved Bus Mode Register */ s32 csr6; /* Saved Operating Mode Reg. */ s32 csr7; /* Saved IRQ Mask Register */ @@ -2076,8 +2081,8 @@ { u_char pb, pbus, dev_num, dnum, dev_fn, timer; u_short dev_id, vendor, index, status; - u_int irq = 0, device, class = DE4X5_CLASS_CODE; - u_long iobase; + u_int tmp, irq = 0, device, class = DE4X5_CLASS_CODE; + u_long iobase = 0; /* Clear upper 32 bits in Alphas */ struct bus_type *lp = &bus; if (lastPCI == NO_MORE_PCI) return; @@ -2137,8 +2142,8 @@ /* Get the board I/O address (64 bits on sparc64) */ #ifndef __sparc_v9__ - pcibios_read_config_dword(pb, PCI_DEVICE, PCI_BASE_ADDRESS_0, - (int *)&iobase); + pcibios_read_config_dword(pb, PCI_DEVICE, PCI_BASE_ADDRESS_0, &tmp); + iobase = tmp; #else iobase = pdev->base_address[0]; #endif @@ -2211,8 +2216,8 @@ { u_char pb, dev_fn; u_short dev_id, dev_num, vendor, status; - u_int irq = 0, device, class = DE4X5_CLASS_CODE; - u_long iobase; + u_int tmp, irq = 0, device, class = DE4X5_CLASS_CODE; + u_long iobase = 0; /* Clear upper 32 bits in Alphas */ int i, j; struct bus_type *lp = &bus; @@ -2250,8 +2255,8 @@ /* Get the board I/O address (64 bits on sparc64) */ #ifndef __sparc_v9__ - pcibios_read_config_dword(pb, PCI_DEVICE, PCI_BASE_ADDRESS_0, - (int *)&iobase); + pcibios_read_config_dword(pb, PCI_DEVICE, PCI_BASE_ADDRESS_0, &tmp); + iobase = tmp; #else iobase = pdev->base_address[0]; #endif @@ -4985,7 +4990,9 @@ lp->phy[k].spd.reg = GENERIC_REG; /* ANLPA register */ lp->phy[k].spd.mask = GENERIC_MASK; /* 100Mb/s technologies */ lp->phy[k].spd.value = GENERIC_VALUE; /* TX & T4, H/F Duplex */ - printk("%s: Found MII device not currently supported. Please mail the following dump to\nthe author:\n", dev->name); + lp->mii_cnt++; + lp->active++; + printk("%s: Using generic MII device control. If the board doesn't operate, \nplease mail the following dump to the author:\n", dev->name); j = de4x5_debug; de4x5_debug |= DEBUG_MII; de4x5_dbg_mii(dev, k); diff -u --recursive --new-file v2.1.78/linux/drivers/scsi/ide-scsi.c linux/drivers/scsi/ide-scsi.c --- v2.1.78/linux/drivers/scsi/ide-scsi.c Fri Dec 19 15:52:59 1997 +++ linux/drivers/scsi/ide-scsi.c Sat Jan 10 10:42:55 1998 @@ -1,7 +1,7 @@ /* - * linux/drivers/scsi/ide-scsi.c Version 0.4 Dec 7, 1997 + * linux/drivers/scsi/ide-scsi.c Version 0.5 Jan 2, 1998 * - * Copyright (C) 1996, 1997 Gadi Oxman + * Copyright (C) 1996 - 1998 Gadi Oxman */ /* @@ -18,9 +18,11 @@ * Added Scatter/Gather and DMA support. * Ver 0.4 Dec 7 97 Add support for ATAPI PD/CD drives. * Use variable timeout for each command. + * Ver 0.5 Jan 2 98 Fix previous PD/CD support. + * Allow disabling of SCSI-6 to SCSI-10 transformation. */ -#define IDESCSI_VERSION "0.4" +#define IDESCSI_VERSION "0.5" #include #include @@ -71,6 +73,7 @@ ide_drive_t *drive; idescsi_pc_t *pc; /* Current packet command */ unsigned int flags; /* Status/Action flags */ + int transform; /* Transform SCSI-6 commands */ } idescsi_scsi_t; /* @@ -102,7 +105,7 @@ } /* - * PIO data transfer routines using the scather gather table. + * PIO data transfer routines using the scatter gather table. */ static void idescsi_input_buffers (ide_drive_t *drive, idescsi_pc_t *pc, unsigned int bcount) { @@ -110,7 +113,7 @@ while (bcount) { if (pc->sg - (struct scatterlist *) pc->scsi_cmd->request_buffer > pc->scsi_cmd->use_sg) { - printk (KERN_ERR "ide-scsi: scather gather table too small, discarding data\n"); + printk (KERN_ERR "ide-scsi: scatter gather table too small, discarding data\n"); idescsi_discard_data (drive, bcount); return; } @@ -130,7 +133,7 @@ while (bcount) { if (pc->sg - (struct scatterlist *) pc->scsi_cmd->request_buffer > pc->scsi_cmd->use_sg) { - printk (KERN_ERR "ide-scsi: scather gather table too small, padding with zeros\n"); + printk (KERN_ERR "ide-scsi: scatter gather table too small, padding with zeros\n"); idescsi_output_zeros (drive, bcount); return; } @@ -150,14 +153,17 @@ */ static inline void idescsi_transform_pc1 (ide_drive_t *drive, idescsi_pc_t *pc) { + idescsi_scsi_t *scsi = drive->driver_data; u8 *c = pc->c, *buf = pc->buffer, *sc = pc->scsi_cmd->cmnd; int i; + if (!scsi->transform) + return; if (drive->media == ide_cdrom) { if (c[0] == READ_6 || c[0] == WRITE_6) { c[8] = c[4]; c[5] = c[3]; c[4] = c[2]; c[3] = c[1] & 0x1f; c[2] = 0; c[1] &= 0xe0; - c[0] = READ_10; + c[0] += (READ_10 - READ_6); } if (c[0] == MODE_SENSE || (c[0] == MODE_SELECT && buf[3] == 8)) { pc->request_transfer -= 4; @@ -172,9 +178,12 @@ static inline void idescsi_transform_pc2 (ide_drive_t *drive, idescsi_pc_t *pc) { + idescsi_scsi_t *scsi = drive->driver_data; u8 *buf = pc->buffer; int i; + if (!scsi->transform) + return; if (drive->media == ide_cdrom) { if (pc->c[0] == MODE_SENSE_10 && pc->scsi_cmd->cmnd[0] == MODE_SENSE) { buf[0] = buf[1]; buf[1] = buf[2]; @@ -182,6 +191,8 @@ for (i = pc->buffer_size - 1; i >= 12; i--) buf[i] = buf[i - 4]; for (i = 11; i >= 4; i--) buf[i] = 0; } + if (pc->c[0] == INQUIRY) + buf[2] |= 2; } } @@ -400,6 +411,19 @@ static ide_drive_t *idescsi_drives[MAX_HWIFS * MAX_DRIVES]; static int idescsi_initialized = 0; +static void idescsi_add_settings(ide_drive_t *drive) +{ + idescsi_scsi_t *scsi = drive->driver_data; + +/* + * drive setting name read/write ioctl ioctl data type min max mul_factor div_factor data pointer set function + */ + ide_add_setting(drive, "bios_cyl", SETTING_RW, -1, -1, TYPE_SHORT, 0, 1023, 1, 1, &drive->bios_cyl, NULL); + ide_add_setting(drive, "bios_head", SETTING_RW, -1, -1, TYPE_BYTE, 0, 255, 1, 1, &drive->bios_head, NULL); + ide_add_setting(drive, "bios_sect", SETTING_RW, -1, -1, TYPE_BYTE, 0, 63, 1, 1, &drive->bios_sect, NULL); + ide_add_setting(drive, "transform", SETTING_RW, -1, -1, TYPE_INT, 0, 1, 1, 1, &scsi->transform, NULL); +} + /* * Driver initialization. */ @@ -413,6 +437,8 @@ scsi->drive = drive; if (drive->id && (drive->id->config & 0x0060) == 0x20) set_bit (IDESCSI_DRQ_INTERRUPT, &scsi->flags); + scsi->transform = 1; + idescsi_add_settings(drive); } static int idescsi_cleanup (ide_drive_t *drive) @@ -426,13 +452,6 @@ return 0; } -int idescsi_init (void); -static ide_module_t idescsi_module = { - IDE_DRIVER_MODULE, - idescsi_init, - NULL -}; - /* * IDE subdriver functions, registered with ide.c */ @@ -456,6 +475,14 @@ NULL /* proc */ }; +int idescsi_init (void); +static ide_module_t idescsi_module = { + IDE_DRIVER_MODULE, + idescsi_init, + &idescsi_driver, + NULL +}; + static struct proc_dir_entry idescsi_proc_dir = {PROC_SCSI_IDESCSI, 8, "ide-scsi", S_IFDIR | S_IRUGO | S_IXUGO, 2}; /* @@ -476,7 +503,7 @@ MOD_INC_USE_COUNT; for (i = 0; media[i] != 255; i++) { failed = 0; - while ((drive = ide_scan_devices (media[i], NULL, failed++)) != NULL) { + while ((drive = ide_scan_devices (media[i], idescsi_driver.name, NULL, failed++)) != NULL) { if ((scsi = (idescsi_scsi_t *) kmalloc (sizeof (idescsi_scsi_t), GFP_KERNEL)) == NULL) { printk (KERN_ERR "ide-scsi: %s: Can't allocate a scsi structure\n", drive->name); continue; @@ -664,10 +691,10 @@ { ide_drive_t *drive = idescsi_drives[disk->device->id]; - if (drive->cyl && drive->head && drive->sect) { - parm[0] = drive->head; - parm[1] = drive->sect; - parm[2] = drive->cyl; + if (drive->bios_cyl && drive->bios_head && drive->bios_sect) { + parm[0] = drive->bios_head; + parm[1] = drive->bios_sect; + parm[2] = drive->bios_cyl; } return 0; } @@ -692,7 +719,7 @@ scsi_unregister_module (MODULE_SCSI_HA, &idescsi_template); for (i = 0; media[i] != 255; i++) { failed = 0; - while ((drive = ide_scan_devices (media[i], &idescsi_driver, failed)) != NULL) + while ((drive = ide_scan_devices (media[i], idescsi_driver.name, &idescsi_driver, failed)) != NULL) if (idescsi_cleanup (drive)) { printk ("%s: cleanup_module() called while still busy\n", drive->name); failed++; diff -u --recursive --new-file v2.1.78/linux/drivers/scsi/scsi_error.c linux/drivers/scsi/scsi_error.c --- v2.1.78/linux/drivers/scsi/scsi_error.c Sun Dec 21 22:36:15 1997 +++ linux/drivers/scsi/scsi_error.c Thu Jan 8 20:35:43 1998 @@ -62,7 +62,7 @@ #define HOST_RESET_SETTLE_TIME 10*HZ -static const char RCSid[] = "$Header: /mnt/ide/home/eric/CVSROOT/linux/drivers/scsi/scsi_error.c,v 1.9 1997/12/07 23:38:23 eric Exp $"; +static const char RCSid[] = "$Header: /mnt/ide/home/eric/CVSROOT/linux/drivers/scsi/scsi_error.c,v 1.10 1997/12/08 04:50:35 eric Exp $"; STATIC int scsi_check_sense (Scsi_Cmnd * SCpnt); STATIC int scsi_request_sense(Scsi_Cmnd *); @@ -1088,10 +1088,12 @@ case MEDIUM_ERROR: return FAILED; + case ILLEGAL_REQUEST: + return SUCCESS; + case BLANK_CHECK: case DATA_PROTECT: case HARDWARE_ERROR: - case ILLEGAL_REQUEST: default: return FAILED; } diff -u --recursive --new-file v2.1.78/linux/drivers/scsi/scsi_obsolete.c linux/drivers/scsi/scsi_obsolete.c --- v2.1.78/linux/drivers/scsi/scsi_obsolete.c Sun Dec 21 22:36:15 1997 +++ linux/drivers/scsi/scsi_obsolete.c Thu Jan 8 20:35:43 1998 @@ -76,7 +76,7 @@ #undef USE_STATIC_SCSI_MEMORY /* -static const char RCSid[] = "$Header: /mnt/ide/home/eric/linux/drivers/scsi/RCS/scsi_obsolete.c,v 1.3 1997/04/29 04:25:08 eric Exp $"; +static const char RCSid[] = "$Header: /mnt/ide/home/eric/CVSROOT/linux/drivers/scsi/scsi_obsolete.c,v 1.1 1997/05/18 23:27:21 eric Exp $"; */ diff -u --recursive --new-file v2.1.78/linux/drivers/scsi/scsi_syms.c linux/drivers/scsi/scsi_syms.c --- v2.1.78/linux/drivers/scsi/scsi_syms.c Fri Jan 2 14:37:02 1998 +++ linux/drivers/scsi/scsi_syms.c Thu Jan 8 20:35:43 1998 @@ -69,6 +69,8 @@ EXPORT_SYMBOL(scsi_logging_level); #endif +EXPORT_SYMBOL(scsi_sleep); + #if defined(CONFIG_PROC_FS) EXPORT_SYMBOL(proc_print_scsidevice); #endif diff -u --recursive --new-file v2.1.78/linux/drivers/scsi/sd.c linux/drivers/scsi/sd.c --- v2.1.78/linux/drivers/scsi/sd.c Sun Dec 21 22:36:15 1997 +++ linux/drivers/scsi/sd.c Sat Jan 10 10:50:07 1998 @@ -1494,12 +1494,19 @@ static void sd_finish() { + struct gendisk *gendisk; int i; blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST; - sd_gendisk.next = gendisk_head; - gendisk_head = &sd_gendisk; + for (gendisk = gendisk_head; gendisk != NULL; gendisk = gendisk->next) + if (gendisk == &sd_gendisk) + break; + if (gendisk == NULL) + { + sd_gendisk.next = gendisk_head; + gendisk_head = &sd_gendisk; + } for (i = 0; i < sd_template.dev_max; ++i) if (!rscsi_disks[i].capacity && diff -u --recursive --new-file v2.1.78/linux/drivers/scsi/sr.c linux/drivers/scsi/sr.c --- v2.1.78/linux/drivers/scsi/sr.c Sun Dec 21 22:36:15 1997 +++ linux/drivers/scsi/sr.c Thu Jan 8 20:35:43 1998 @@ -854,8 +854,6 @@ SDp->scsi_request_fn = do_sr_request; scsi_CDs[i].device = SDp; - sr_vendor_init(i); - sr_template.nr_dev++; if(sr_template.nr_dev > sr_template.dev_max) panic ("scsi_devices corrupt (sr)"); @@ -986,13 +984,11 @@ if (-EINVAL == rc) { /* failed, drive has'nt this mode page */ scsi_CDs[i].cdi.speed = 1; - scsi_CDs[i].cdi.capacity = 1; /* disable speed select, drive probably can't do this either */ scsi_CDs[i].cdi.mask |= CDC_SELECT_SPEED; } else { n = buffer[3]+4; scsi_CDs[i].cdi.speed = ((buffer[n+8] << 8) + buffer[n+9])/176; - scsi_CDs[i].cdi.capacity = 1; scsi_CDs[i].readcd_known = 1; scsi_CDs[i].readcd_cdda = buffer[n+5] & 0x01; /* print some capability bits */ @@ -1085,7 +1081,9 @@ scsi_CDs[i].cdi.handle = &scsi_CDs[i]; scsi_CDs[i].cdi.dev = MKDEV(MAJOR_NR,i); scsi_CDs[i].cdi.mask = 0; + scsi_CDs[i].cdi.capacity = 1; get_capabilities(i); + sr_vendor_init(i); sprintf(name, "sr%d", i); strcpy(scsi_CDs[i].cdi.name, name); diff -u --recursive --new-file v2.1.78/linux/drivers/scsi/sr_ioctl.c linux/drivers/scsi/sr_ioctl.c --- v2.1.78/linux/drivers/scsi/sr_ioctl.c Sun Dec 21 22:36:15 1997 +++ linux/drivers/scsi/sr_ioctl.c Thu Jan 8 20:35:43 1998 @@ -30,7 +30,7 @@ #define IOCTL_RETRIES 3 /* The CDROM is fairly slow, so we need a little extra time */ /* In fact, it is very slow if it has to spin up first */ -#define IOCTL_TIMEOUT 3000 +#define IOCTL_TIMEOUT 30*HZ static void sr_ioctl_done(Scsi_Cmnd * SCpnt) { @@ -51,11 +51,15 @@ int sr_do_ioctl(int target, unsigned char * sr_cmd, void * buffer, unsigned buflength, int quiet) { Scsi_Cmnd * SCpnt; + Scsi_Device * SDev; int result, err = 0, retries = 0; + SDev = scsi_CDs[target].device; SCpnt = scsi_allocate_device(NULL, scsi_CDs[target].device, 1); retry: + if( !scsi_block_when_processing_errors(SDev) ) + return -ENODEV; { struct semaphore sem = MUTEX_LOCKED; SCpnt->request.sem = &sem; @@ -69,7 +73,7 @@ result = SCpnt->result; /* Minimal error checking. Ignore cases we know about, and report the rest. */ - if(driver_byte(result) != 0) + if(driver_byte(result) != 0) { switch(SCpnt->sense_buffer[2] & 0xf) { case UNIT_ATTENTION: scsi_CDs[target].device->changed = 1; @@ -86,9 +90,7 @@ printk(KERN_INFO "sr%d: CDROM not ready yet.\n", target); if (retries++ < 10) { /* sleep 2 sec and try again */ - current->state = TASK_INTERRUPTIBLE; - current->timeout = jiffies + 200; - schedule (); + scsi_sleep(2*HZ); goto retry; } else { /* 20 secs are enouth? */ @@ -123,7 +125,8 @@ print_command(sr_cmd); print_sense("sr", SCpnt); err = -EIO; - }; + } + } result = SCpnt->result; /* Wake up a process waiting for device*/ @@ -279,23 +282,10 @@ int sr_audio_ioctl(struct cdrom_device_info *cdi, unsigned int cmd, void* arg) { u_char sr_cmd[10]; - Scsi_Device * SDev; int result, target; target = MINOR(cdi->dev); - SDev = scsi_CDs[target].device; - /* - * If we are in the middle of error recovery, don't let anyone - * else try and use this device. Also, if error recovery fails, it - * may try and take the device offline, in which case all further - * access to the device is prohibited. - */ - if( !scsi_block_when_processing_errors(SDev) ) - { - return -ENODEV; - } - switch (cmd) { /* Sun-compatible */ @@ -718,22 +708,9 @@ unsigned int cmd, unsigned long arg) { int target, err; - Scsi_Device * SDev; target = MINOR(cdi->dev); - SDev = scsi_CDs[target].device; - /* - * If we are in the middle of error recovery, don't let anyone - * else try and use this device. Also, if error recovery fails, it - * may try and take the device offline, in which case all further - * access to the device is prohibited. - */ - if( !scsi_block_when_processing_errors(SDev) ) - { - return -ENODEV; - } - switch (cmd) { case CDROMREADMODE1: case CDROMREADMODE2: diff -u --recursive --new-file v2.1.78/linux/drivers/scsi/sr_vendor.c linux/drivers/scsi/sr_vendor.c --- v2.1.78/linux/drivers/scsi/sr_vendor.c Tue Dec 2 16:45:19 1997 +++ linux/drivers/scsi/sr_vendor.c Thu Jan 8 20:35:43 1998 @@ -56,8 +56,7 @@ #define VENDOR_NEC 2 #define VENDOR_TOSHIBA 3 -#define VENDOR_HP_4020 4 /* HP 4xxx writers, others too ?? */ -#define VENDOR_HP_6020 5 /* HP 6020 writers */ +#define VENDOR_WRITER 4 /* pre-scsi3 writers */ #define VENDOR_ID (scsi_CDs[minor].vendor) @@ -72,13 +71,12 @@ /* default */ VENDOR_ID = VENDOR_SCSI3; + if (scsi_CDs[minor].readcd_known) + /* this is true for scsi3/mmc drives - no more checks */ + return; - if ((!strncmp(vendor,"HP",2) || !strncmp(vendor,"PHILIPS",7)) && - scsi_CDs[minor].device->type == TYPE_WORM) { - if (!strncmp(model,"CD-Writer 6020",14)) - VENDOR_ID = VENDOR_HP_6020; - else - VENDOR_ID = VENDOR_HP_4020; + if (scsi_CDs[minor].device->type == TYPE_WORM) { + VENDOR_ID = VENDOR_WRITER; } else if (!strncmp (vendor, "NEC", 3)) { VENDOR_ID = VENDOR_NEC; @@ -233,16 +231,13 @@ sector -= CD_MSF_OFFSET; break; - case VENDOR_HP_4020: - /* Fallthrough */ - case VENDOR_HP_6020: + case VENDOR_WRITER: + memset(cmd,0,12); cmd[0] = READ_TOC; cmd[1] = (scsi_CDs[minor].device->lun << 5); - cmd[8] = (VENDOR_ID == VENDOR_HP_4020) ? - 0x04 : 0x0c; + cmd[8] = 0x04; cmd[9] = 0x40; - rc = sr_do_ioctl(minor, cmd, buffer, - (VENDOR_ID == VENDOR_HP_4020) ? 0x04 : 0x0c, 0); + rc = sr_do_ioctl(minor, cmd, buffer, 0x04, 0); if (rc != 0) { break; } @@ -252,16 +247,14 @@ break; } - if (VENDOR_ID == VENDOR_HP_4020) { - cmd[0] = READ_TOC; /* Read TOC */ - cmd[1] = (scsi_CDs[minor].device->lun << 5); - cmd[6] = rc & 0x7f; /* number of last session */ - cmd[8] = 0x0c; - cmd[9] = 0x40; - rc = sr_do_ioctl(minor, cmd, buffer, 12, 0); - if (rc != 0) { - break; - } + cmd[0] = READ_TOC; /* Read TOC */ + cmd[1] = (scsi_CDs[minor].device->lun << 5); + cmd[6] = rc & 0x7f; /* number of last session */ + cmd[8] = 0x0c; + cmd[9] = 0x40; + rc = sr_do_ioctl(minor, cmd, buffer, 12, 0); + if (rc != 0) { + break; } sector = buffer[11] + (buffer[10] << 8) + diff -u --recursive --new-file v2.1.78/linux/drivers/sound/Config.in linux/drivers/sound/Config.in --- v2.1.78/linux/drivers/sound/Config.in Tue Jan 6 09:37:35 1998 +++ linux/drivers/sound/Config.in Tue Jan 6 09:47:15 1998 @@ -149,7 +149,7 @@ if [ "$CONFIG_LOWLEVEL_SOUND" = "y" ]; then dep_tristate 'ACI mixer (miroPCM12)' CONFIG_ACI_MIXER $CONFIG_SOUND dep_tristate 'AWE32 synth' CONFIG_AWE32_SYNTH $CONFIG_SOUND - dep_tristate 'Gallant Audio Cards (SC-6000 and SC-6600 based)' CONFIG_AEDSP16 + dep_tristate 'Gallant Audio Cards (SC-6000 and SC-6600 based)' CONFIG_AEDSP16 $CONFIG_SOUND if [ "$CONFIG_AEDSP16" = "y" -o "$CONFIG_AEDSP16" = "m" ]; then hex ' I/O base for Audio Excel DSP 16 220 or 240' AEDSP16_BASE 220 diff -u --recursive --new-file v2.1.78/linux/drivers/sound/ad1848.c linux/drivers/sound/ad1848.c --- v2.1.78/linux/drivers/sound/ad1848.c Tue Jan 6 09:37:35 1998 +++ linux/drivers/sound/ad1848.c Tue Jan 6 19:32:46 1998 @@ -40,24 +40,24 @@ #include "ad1848_mixer.h" typedef struct - { - int base; - int irq; - int dma1, dma2; - int dual_dma; /* 1, when two DMA channels allocated */ - unsigned char MCE_bit; - unsigned char saved_regs[16]; - int debug_flag; - - int audio_flags; - int record_dev, playback_dev; - - int xfer_count; - int audio_mode; - int open_mode; - int intr_active; - char *chip_name, *name; - int model; +{ + int base; + int irq; + int dma1, dma2; + int dual_dma; /* 1, when two DMA channels allocated */ + unsigned char MCE_bit; + unsigned char saved_regs[16]; + int debug_flag; + + int audio_flags; + int record_dev, playback_dev; + + int xfer_count; + int audio_mode; + int open_mode; + int intr_active; + char *chip_name, *name; + int model; #define MD_1848 1 #define MD_4231 2 #define MD_4231A 3 @@ -66,44 +66,47 @@ #define MD_C930 6 #define MD_IWAVE 7 - /* Mixer parameters */ - int recmask; - int supported_devices, orig_devices; - int supported_rec_devices, orig_rec_devices; - int *levels; - short mixer_reroute[32]; - int dev_no; - volatile unsigned long timer_ticks; - int timer_running; - int irq_ok; - mixer_ents *mix_devices; - int mixer_output_port; - int c930_password_port; - } -ad1848_info; + /* Mixer parameters */ + int recmask; + int supported_devices, orig_devices; + int supported_rec_devices, orig_rec_devices; + int *levels; + short mixer_reroute[32]; + int dev_no; + volatile unsigned long timer_ticks; + int timer_running; + int irq_ok; + mixer_ents *mix_devices; + int mixer_output_port; + int c930_password_port; +} ad1848_info; typedef struct ad1848_port_info - { - int open_mode; - int speed; - unsigned char speed_bits; - int channels; - int audio_format; - unsigned char format_bits; - } +{ + int open_mode; + int speed; + unsigned char speed_bits; + int channels; + int audio_format; + unsigned char format_bits; +} ad1848_port_info; -static int nr_ad1848_devs = 0; -static volatile char irq2dev[17] = -{-1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1}; +static int nr_ad1848_devs = 0; +int deskpro_xl = 0; + +static volatile char irq2dev[17] = { + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1 +}; #if defined(CONFIG_SEQUENCER) && !defined(EXCLUDE_TIMERS) -static int timer_installed = -1; + +static int timer_installed = -1; #endif -static int ad_format_mask[8 /*devc->model */ ] = +static int ad_format_mask[8 /*devc->model */ ] = { 0, AFMT_U8 | AFMT_S16_LE | AFMT_MU_LAW | AFMT_A_LAW, @@ -134,13 +137,12 @@ static void ad1848_trigger(int dev, int bits); #if (defined(CONFIG_SEQUENCER) && !defined(EXCLUDE_TIMERS)) || defined(MODULE) -static int ad1848_tmr_install(int dev); -static void ad1848_tmr_reprogram(int dev); +static int ad1848_tmr_install(int dev); +static void ad1848_tmr_reprogram(int dev); #endif -static int -ad_read(ad1848_info * devc, int reg) +static int ad_read(ad1848_info * devc, int reg) { unsigned long flags; int x; @@ -159,8 +161,7 @@ return x; } -static void -ad_write(ad1848_info * devc, int reg, int data) +static void ad_write(ad1848_info * devc, int reg, int data) { unsigned long flags; int timeout = 900000; @@ -177,23 +178,22 @@ restore_flags(flags); } -static void -wait_for_calibration(ad1848_info * devc) +static void wait_for_calibration(ad1848_info * devc) { int timeout = 0; /* - * Wait until the auto calibration process has finished. - * - * 1) Wait until the chip becomes ready (reads don't return 0x80). - * 2) Wait until the ACI bit of I11 gets on and then off. + * Wait until the auto calibration process has finished. + * + * 1) Wait until the chip becomes ready (reads don't return 0x80). + * 2) Wait until the ACI bit of I11 gets on and then off. */ timeout = 100000; while (timeout > 0 && inb(devc->base) == 0x80) timeout--; if (inb(devc->base) & 0x80) - printk("ad1848: Auto calibration timed out(1).\n"); + printk(KERN_WARNING "ad1848: Auto calibration timed out(1).\n"); timeout = 100; while (timeout > 0 && !(ad_read(devc, 11) & 0x20)) @@ -206,36 +206,34 @@ timeout--; if (ad_read(devc, 11) & 0x20) if (devc->model != MD_1845) - printk("ad1848: Auto calibration timed out(3).\n"); + printk(KERN_WARNING "ad1848: Auto calibration timed out(3).\n"); } -static void -ad_mute(ad1848_info * devc) +static void ad_mute(ad1848_info * devc) { - int i; - unsigned char prev; + int i; + unsigned char prev; /* - * Save old register settings and mute output channels + * Save old register settings and mute output channels */ + for (i = 6; i < 8; i++) - { - prev = devc->saved_regs[i] = ad_read(devc, i); - } + { + prev = devc->saved_regs[i] = ad_read(devc, i); + } } -static void -ad_unmute(ad1848_info * devc) +static void ad_unmute(ad1848_info * devc) { } -static void -ad_enter_MCE(ad1848_info * devc) +static void ad_enter_MCE(ad1848_info * devc) { - unsigned long flags; - int timeout = 1000; - unsigned short prev; + unsigned long flags; + int timeout = 1000; + unsigned short prev; while (timeout > 0 && inb(devc->base) == 0x80) /*Are we initializing */ timeout--; @@ -246,20 +244,19 @@ devc->MCE_bit = 0x40; prev = inb(io_Index_Addr(devc)); if (prev & 0x40) - { - restore_flags(flags); - return; - } + { + restore_flags(flags); + return; + } outb((devc->MCE_bit), io_Index_Addr(devc)); restore_flags(flags); } -static void -ad_leave_MCE(ad1848_info * devc) +static void ad_leave_MCE(ad1848_info * devc) { - unsigned long flags; - unsigned char prev, acal; - int timeout = 1000; + unsigned long flags; + unsigned char prev, acal; + int timeout = 1000; while (timeout > 0 && inb(devc->base) == 0x80) /*Are we initializing */ timeout--; @@ -274,18 +271,17 @@ outb((0x00), io_Index_Addr(devc)); /* Clear the MCE bit */ if ((prev & 0x40) == 0) /* Not in MCE mode */ - { - restore_flags(flags); - return; - } + { + restore_flags(flags); + return; + } outb((0x00), io_Index_Addr(devc)); /* Clear the MCE bit */ if (acal & 0x08) /* Auto calibration is enabled */ wait_for_calibration(devc); restore_flags(flags); } -static int -ad1848_set_recmask(ad1848_info * devc, int mask) +static int ad1848_set_recmask(ad1848_info * devc, int mask) { unsigned char recdev; int i, n; @@ -294,12 +290,17 @@ /* Rename the mixer bits if necessary */ for (i = 0; i < 32; i++) + { if (devc->mixer_reroute[i] != i) + { if (mask & (1 << i)) - { - mask &= ~(1 << i); - mask |= (1 << devc->mixer_reroute[i]); - } + { + mask &= ~(1 << i); + mask |= (1 << devc->mixer_reroute[i]); + } + } + } + n = 0; for (i = 0; i < 32; i++) /* Count selected device bits */ if (mask & (1 << i)) @@ -308,41 +309,41 @@ if (n == 0) mask = SOUND_MASK_MIC; else if (n != 1) /* Too many devices selected */ - { + { mask &= ~devc->recmask; /* Filter out active settings */ - n = 0; - for (i = 0; i < 32; i++) /* Count selected device bits */ - if (mask & (1 << i)) - n++; - - if (n != 1) - mask = SOUND_MASK_MIC; - } + n = 0; + for (i = 0; i < 32; i++) /* Count selected device bits */ + if (mask & (1 << i)) + n++; + + if (n != 1) + mask = SOUND_MASK_MIC; + } switch (mask) - { - case SOUND_MASK_MIC: - recdev = 2; - break; - - case SOUND_MASK_LINE: - case SOUND_MASK_LINE3: - recdev = 0; - break; - - case SOUND_MASK_CD: - case SOUND_MASK_LINE1: - recdev = 1; - break; - - case SOUND_MASK_IMIX: - recdev = 3; - break; - - default: - mask = SOUND_MASK_MIC; - recdev = 2; - } + { + case SOUND_MASK_MIC: + recdev = 2; + break; + + case SOUND_MASK_LINE: + case SOUND_MASK_LINE3: + recdev = 0; + break; + + case SOUND_MASK_CD: + case SOUND_MASK_LINE1: + recdev = 1; + break; + + case SOUND_MASK_IMIX: + recdev = 3; + break; + + default: + mask = SOUND_MASK_MIC; + recdev = 2; + } recdev <<= 6; ad_write(devc, 0, (ad_read(devc, 0) & 0x3f) | recdev); @@ -350,24 +351,27 @@ /* Rename the mixer bits back if necessary */ for (i = 0; i < 32; i++) + { if (devc->mixer_reroute[i] != i) + { if (mask & (1 << devc->mixer_reroute[i])) - { - mask &= ~(1 << devc->mixer_reroute[i]); - mask |= (1 << i); - } + { + mask &= ~(1 << devc->mixer_reroute[i]); + mask |= (1 << i); + } + } + } devc->recmask = mask; return mask; } -static void -change_bits(ad1848_info * devc, unsigned char *regval, int dev, int chn, int newval) +static void change_bits(ad1848_info * devc, unsigned char *regval, int dev, int chn, int newval) { - unsigned char mask; - int shift; - int mute; - int mutemask; - int set_mute_bit; + unsigned char mask; + int shift; + int mute; + int mutemask; + int set_mute_bit; set_mute_bit = (newval == 0); @@ -378,22 +382,22 @@ shift = devc->mix_devices[dev][chn].bitpos; if (devc->mix_devices[dev][chn].mutepos == 8) - { /* if there is no mute bit */ - mute = 0; /* No mute bit; do nothing special */ - mutemask = ~0; /* No mute bit; do nothing special */ - } else - { - mute = (set_mute_bit << devc->mix_devices[dev][chn].mutepos); - mutemask = ~(1 << devc->mix_devices[dev][chn].mutepos); - } + { /* if there is no mute bit */ + mute = 0; /* No mute bit; do nothing special */ + mutemask = ~0; /* No mute bit; do nothing special */ + } + else + { + mute = (set_mute_bit << devc->mix_devices[dev][chn].mutepos); + mutemask = ~(1 << devc->mix_devices[dev][chn].mutepos); + } newval = (int) ((newval * mask) + 50) / 100; /* Scale it */ *regval &= (~(mask << shift)) & (mutemask); /* Clear bits */ *regval |= ((newval & mask) << shift) | mute; /* Set new value */ } -static int -ad1848_mixer_get(ad1848_info * devc, int dev) +static int ad1848_mixer_get(ad1848_info * devc, int dev) { if (!((1 << dev) & devc->supported_devices)) return -EINVAL; @@ -403,15 +407,14 @@ return devc->levels[dev]; } -static int -ad1848_mixer_set(ad1848_info * devc, int dev, int value) +static int ad1848_mixer_set(ad1848_info * devc, int dev, int value) { - int left = value & 0x000000ff; - int right = (value & 0x0000ff00) >> 8; - int retvol; + int left = value & 0x000000ff; + int right = (value & 0x0000ff00) >> 8; + int retvol; - int regoffs; - unsigned char val; + int regoffs; + unsigned char val; if (dev > 31) return -EINVAL; @@ -445,7 +448,7 @@ devc->levels[dev] = retvol; /* - * Set the left channel + * Set the left channel */ regoffs = devc->mix_devices[dev][LEFT_CHN].regno; @@ -455,7 +458,7 @@ devc->saved_regs[regoffs] = val; /* - * Set the right channel + * Set the right channel */ if (devc->mix_devices[dev][RIGHT_CHN].nbits == 0) @@ -470,11 +473,10 @@ return retvol; } -static void -ad1848_mixer_reset(ad1848_info * devc) +static void ad1848_mixer_reset(ad1848_info * devc) { - int i; - char name[32]; + int i; + char name[32]; devc->mix_devices = &(ad1848_mix_devices[0]); @@ -484,30 +486,30 @@ devc->mixer_reroute[i] = i; switch (devc->model) - { - case MD_4231: - case MD_4231A: - case MD_1845: - devc->supported_devices = MODE2_MIXER_DEVICES; - break; - - case MD_C930: - devc->supported_devices = C930_MIXER_DEVICES; - devc->mix_devices = &(c930_mix_devices[0]); - break; - - case MD_IWAVE: - devc->supported_devices = MODE3_MIXER_DEVICES; - devc->mix_devices = &(iwave_mix_devices[0]); - break; - - case MD_4232: - devc->supported_devices = MODE3_MIXER_DEVICES; - break; - - default: - devc->supported_devices = MODE1_MIXER_DEVICES; - } + { + case MD_4231: + case MD_4231A: + case MD_1845: + devc->supported_devices = MODE2_MIXER_DEVICES; + break; + + case MD_C930: + devc->supported_devices = C930_MIXER_DEVICES; + devc->mix_devices = &(c930_mix_devices[0]); + break; + + case MD_IWAVE: + devc->supported_devices = MODE3_MIXER_DEVICES; + devc->mix_devices = &(iwave_mix_devices[0]); + break; + + case MD_4232: + devc->supported_devices = MODE3_MIXER_DEVICES; + break; + + default: + devc->supported_devices = MODE1_MIXER_DEVICES; + } devc->supported_rec_devices = MODE1_REC_DEVICES; devc->orig_devices = devc->supported_devices; @@ -516,9 +518,13 @@ devc->levels = load_mixer_volumes(name, default_mixer_levels, 1); for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) + { if (devc->supported_devices & (1 << i)) ad1848_mixer_set(devc, i, devc->levels[i]); + } + ad1848_set_recmask(devc, SOUND_MASK_MIC); + devc->mixer_output_port = devc->levels[31] | AUDIO_HEADPHONE | AUDIO_LINE_OUT; if (devc->mixer_output_port & AUDIO_SPEAKER) ad_write(devc, 26, ad_read(devc, 26) & ~0x40); /* Unmute mono out */ @@ -531,11 +537,13 @@ ad1848_info *devc = mixer_devs[dev]->devc; int val; - if (cmd == SOUND_MIXER_PRIVATE1) { + if (cmd == SOUND_MIXER_PRIVATE1) + { if (get_user(val, (int *)arg)) return -EFAULT; - if (val != 0xffff) { + if (val != 0xffff) + { val &= (AUDIO_SPEAKER | AUDIO_HEADPHONE | AUDIO_LINE_OUT); devc->mixer_output_port = val; val |= AUDIO_HEADPHONE | AUDIO_LINE_OUT; /* Always on */ @@ -548,75 +556,85 @@ val = devc->mixer_output_port; return put_user(val, (int *)arg); } - if (((cmd >> 8) & 0xff) == 'M') { + if (((cmd >> 8) & 0xff) == 'M') + { if (_SIOC_DIR(cmd) & _SIOC_WRITE) - switch (cmd & 0xff) { - case SOUND_MIXER_RECSRC: - if (get_user(val, (int *)arg)) - return -EFAULT; - val = ad1848_set_recmask(devc, val); - return put_user(val, (int *)arg); + { + switch (cmd & 0xff) + { + case SOUND_MIXER_RECSRC: + if (get_user(val, (int *)arg)) + return -EFAULT; + val = ad1848_set_recmask(devc, val); + break; - default: - if (get_user(val, (int *)arg)) + default: + if (get_user(val, (int *)arg)) return -EFAULT; - val = ad1848_mixer_set(devc, cmd & 0xff, val); - return put_user(val, (int *)arg); + val = ad1848_mixer_set(devc, cmd & 0xff, val); + break; } + return put_user(val, (int *)arg); + } else - switch (cmd & 0xff) { + { + switch (cmd & 0xff) + { /* * Return parameters */ - case SOUND_MIXER_RECSRC: - val = devc->recmask; - return put_user(val, (int *)arg); + case SOUND_MIXER_RECSRC: + val = devc->recmask; + break; - case SOUND_MIXER_DEVMASK: - val = devc->supported_devices; - return put_user(val, (int *)arg); + case SOUND_MIXER_DEVMASK: + val = devc->supported_devices; + break; - case SOUND_MIXER_STEREODEVS: - val = devc->supported_devices; - if (devc->model != MD_C930) - val &= ~(SOUND_MASK_SPEAKER | SOUND_MASK_IMIX); - return put_user(val, (int *)arg); + case SOUND_MIXER_STEREODEVS: + val = devc->supported_devices; + if (devc->model != MD_C930) + val &= ~(SOUND_MASK_SPEAKER | SOUND_MASK_IMIX); + break; - case SOUND_MIXER_RECMASK: - val = devc->supported_rec_devices; - return put_user(val, (int *)arg); - - case SOUND_MIXER_CAPS: - return put_user(SOUND_CAP_EXCL_INPUT, (int *)arg); - - default: - val = ad1848_mixer_get(devc, cmd & 0xff); - return put_user(val, (int *)arg); + case SOUND_MIXER_RECMASK: + val = devc->supported_rec_devices; + break; + + case SOUND_MIXER_CAPS: + val=SOUND_CAP_EXCL_INPUT; + break; + + default: + val = ad1848_mixer_get(devc, cmd & 0xff); + break; } - } else + return put_user(val, (int *)arg); + } + } + else return -EINVAL; } -static int -ad1848_set_speed(int dev, int arg) +static int ad1848_set_speed(int dev, int arg) { - ad1848_info *devc = (ad1848_info *) audio_devs[dev]->devc; + ad1848_info *devc = (ad1848_info *) audio_devs[dev]->devc; ad1848_port_info *portc = (ad1848_port_info *) audio_devs[dev]->portc; /* - * The sampling speed is encoded in the least significant nibble of I8. The - * LSB selects the clock source (0=24.576 MHz, 1=16.9344 MHz) and other - * three bits select the divisor (indirectly): - * - * The available speeds are in the following table. Keep the speeds in - * the increasing order. + * The sampling speed is encoded in the least significant nibble of I8. The + * LSB selects the clock source (0=24.576 MHz, 1=16.9344 MHz) and other + * three bits select the divisor (indirectly): + * + * The available speeds are in the following table. Keep the speeds in + * the increasing order. */ typedef struct - { - int speed; - unsigned char bits; - } + { + int speed; + unsigned char bits; + } speed_struct; static speed_struct speed_table[] = @@ -638,7 +656,7 @@ {48000, (6 << 1) | 0} }; - int i, n, selected = -1; + int i, n, selected = -1; n = sizeof(speed_table) / sizeof(speed_struct); @@ -646,48 +664,49 @@ return portc->speed; if (devc->model == MD_1845) /* AD1845 has different timer than others */ - { - if (arg < 4000) - arg = 4000; - if (arg > 50000) - arg = 50000; - - portc->speed = arg; - portc->speed_bits = speed_table[3].bits; - return portc->speed; - } + { + if (arg < 4000) + arg = 4000; + if (arg > 50000) + arg = 50000; + + portc->speed = arg; + portc->speed_bits = speed_table[3].bits; + return portc->speed; + } if (arg < speed_table[0].speed) selected = 0; if (arg > speed_table[n - 1].speed) selected = n - 1; for (i = 1 /*really */ ; selected == -1 && i < n; i++) + { if (speed_table[i].speed == arg) selected = i; else if (speed_table[i].speed > arg) - { - int diff1, diff2; + { + int diff1, diff2; - diff1 = arg - speed_table[i - 1].speed; - diff2 = speed_table[i].speed - arg; + diff1 = arg - speed_table[i - 1].speed; + diff2 = speed_table[i].speed - arg; - if (diff1 < diff2) - selected = i - 1; - else - selected = i; - } + if (diff1 < diff2) + selected = i - 1; + else + selected = i; + } + } if (selected == -1) - { - printk("ad1848: Can't find speed???\n"); - selected = 3; - } + { + printk(KERN_WARNING "ad1848: Can't find speed???\n"); + selected = 3; + } portc->speed = speed_table[selected].speed; portc->speed_bits = speed_table[selected].bits; return portc->speed; } -static short -ad1848_set_channels(int dev, short arg) +static short ad1848_set_channels(int dev, short arg) { ad1848_port_info *portc = (ad1848_port_info *) audio_devs[dev]->portc; @@ -698,17 +717,16 @@ return arg; } -static unsigned int -ad1848_set_bits(int dev, unsigned int arg) +static unsigned int ad1848_set_bits(int dev, unsigned int arg) { ad1848_info *devc = (ad1848_info *) audio_devs[dev]->devc; ad1848_port_info *portc = (ad1848_port_info *) audio_devs[dev]->portc; static struct format_tbl - { + { int format; unsigned char bits; - } + } format2bits[] = { { @@ -751,7 +769,7 @@ AFMT_U16_BE, 0 } }; - int i, n = sizeof(format2bits) / sizeof(struct format_tbl); + int i, n = sizeof(format2bits) / sizeof(struct format_tbl); if (arg == 0) return portc->audio_format; @@ -763,12 +781,12 @@ for (i = 0; i < n; i++) if (format2bits[i].format == arg) - { - if ((portc->format_bits = format2bits[i].bits) == 0) - return portc->audio_format = AFMT_U8; /* Was not supported */ + { + if ((portc->format_bits = format2bits[i].bits) == 0) + return portc->audio_format = AFMT_U8; /* Was not supported */ - return arg; - } + return arg; + } /* Still hanging here. Something must be terribly wrong */ portc->format_bits = 0; return portc->audio_format = AFMT_U8; @@ -801,8 +819,7 @@ ad1848_mixer_ioctl }; -static int -ad1848_open(int dev, int mode) +static int ad1848_open(int dev, int mode) { ad1848_info *devc = NULL; ad1848_port_info *portc; @@ -817,16 +834,16 @@ save_flags(flags); cli(); if (portc->open_mode || (devc->open_mode & mode)) - { - restore_flags(flags); - return -EBUSY; - } + { + restore_flags(flags); + return -EBUSY; + } devc->dual_dma = 0; if (audio_devs[dev]->flags & DMA_DUPLEX) - { - devc->dual_dma = 1; - } + { + devc->dual_dma = 1; + } devc->intr_active = 0; devc->audio_mode = 0; devc->open_mode |= mode; @@ -846,8 +863,7 @@ return 0; } -static void -ad1848_close(int dev) +static void ad1848_close(int dev) { unsigned long flags; ad1848_info *devc = (ad1848_info *) audio_devs[dev]->devc; @@ -869,8 +885,7 @@ restore_flags(flags); } -static void -ad1848_output_block(int dev, unsigned long buf, int count, int intrflag) +static void ad1848_output_block(int dev, unsigned long buf, int count, int intrflag) { unsigned long flags, cnt; ad1848_info *devc = (ad1848_info *) audio_devs[dev]->devc; @@ -879,13 +894,14 @@ cnt = count; if (portc->audio_format == AFMT_IMA_ADPCM) - { - cnt /= 4; - } else - { - if (portc->audio_format & (AFMT_S16_LE | AFMT_S16_BE)) /* 16 bit data */ - cnt >>= 1; - } + { + cnt /= 4; + } + else + { + if (portc->audio_format & (AFMT_S16_LE | AFMT_S16_BE)) /* 16 bit data */ + cnt >>= 1; + } if (portc->channels > 1) cnt >>= 1; cnt--; @@ -893,13 +909,13 @@ if (devc->audio_mode & PCM_ENABLE_OUTPUT && audio_devs[dev]->flags & DMA_AUTOMODE && intrflag && cnt == devc->xfer_count) - { - devc->audio_mode |= PCM_ENABLE_OUTPUT; - devc->intr_active = 1; - return; /* - * Auto DMA mode on. No need to react - */ - } + { + devc->audio_mode |= PCM_ENABLE_OUTPUT; + devc->intr_active = 1; + return; /* + * Auto DMA mode on. No need to react + */ + } save_flags(flags); cli(); @@ -912,8 +928,7 @@ restore_flags(flags); } -static void -ad1848_start_input(int dev, unsigned long buf, int count, int intrflag) +static void ad1848_start_input(int dev, unsigned long buf, int count, int intrflag) { unsigned long flags, cnt; ad1848_info *devc = (ad1848_info *) audio_devs[dev]->devc; @@ -921,39 +936,41 @@ cnt = count; if (portc->audio_format == AFMT_IMA_ADPCM) - { - cnt /= 4; - } else - { - if (portc->audio_format & (AFMT_S16_LE | AFMT_S16_BE)) /* 16 bit data */ - cnt >>= 1; - } + { + cnt /= 4; + } + else + { + if (portc->audio_format & (AFMT_S16_LE | AFMT_S16_BE)) /* 16 bit data */ + cnt >>= 1; + } if (portc->channels > 1) cnt >>= 1; cnt--; if (devc->audio_mode & PCM_ENABLE_INPUT && audio_devs[dev]->flags & DMA_AUTOMODE && - intrflag && - cnt == devc->xfer_count) - { - devc->audio_mode |= PCM_ENABLE_INPUT; - devc->intr_active = 1; - return; /* - * Auto DMA mode on. No need to react - */ - } + intrflag && + cnt == devc->xfer_count) + { + devc->audio_mode |= PCM_ENABLE_INPUT; + devc->intr_active = 1; + return; /* + * Auto DMA mode on. No need to react + */ + } save_flags(flags); cli(); if (devc->model == MD_1848) - { + { ad_write(devc, 15, (unsigned char) (cnt & 0xff)); ad_write(devc, 14, (unsigned char) ((cnt >> 8) & 0xff)); - } else - { + } + else + { ad_write(devc, 31, (unsigned char) (cnt & 0xff)); ad_write(devc, 30, (unsigned char) ((cnt >> 8) & 0xff)); - } + } ad_unmute(devc); @@ -963,8 +980,7 @@ restore_flags(flags); } -static int -ad1848_prepare_for_output(int dev, int bsize, int bcount) +static int ad1848_prepare_for_output(int dev, int bsize, int bcount) { int timeout; unsigned char fs, old_fs, tmp = 0; @@ -984,26 +1000,28 @@ ad_enter_MCE(devc); /* Enables changes to the format select reg */ if (devc->model == MD_1845) /* Use alternate speed select registers */ - { - fs &= 0xf0; /* Mask off the rate select bits */ + { + fs &= 0xf0; /* Mask off the rate select bits */ - ad_write(devc, 22, (portc->speed >> 8) & 0xff); /* Speed MSB */ - ad_write(devc, 23, portc->speed & 0xff); /* Speed LSB */ - } + ad_write(devc, 22, (portc->speed >> 8) & 0xff); /* Speed MSB */ + ad_write(devc, 23, portc->speed & 0xff); /* Speed LSB */ + } old_fs = ad_read(devc, 8); if (devc->model == MD_4232) - { - tmp = ad_read(devc, 16); - ad_write(devc, 16, tmp | 0x30); - } + { + tmp = ad_read(devc, 16); + ad_write(devc, 16, tmp | 0x30); + } if (devc->model == MD_IWAVE) ad_write(devc, 17, 0xc2); /* Disable variable frequency select */ ad_write(devc, 8, fs); + /* * Write to I8 starts resynchronization. Wait until it completes. */ + timeout = 0; while (timeout < 100 && inb(devc->base) != 0x80) timeout++; @@ -1023,21 +1041,20 @@ #if (defined(CONFIG_SEQUENCER) && !defined(EXCLUDE_TIMERS)) || defined(MODULE) if (dev == timer_installed && devc->timer_running) if ((fs & 0x01) != (old_fs & 0x01)) - { - ad1848_tmr_reprogram(dev); - } + { + ad1848_tmr_reprogram(dev); + } #endif ad1848_halt_output(dev); return 0; } -static int -ad1848_prepare_for_input(int dev, int bsize, int bcount) +static int ad1848_prepare_for_input(int dev, int bsize, int bcount) { - int timeout; - unsigned char fs, old_fs, tmp = 0; - unsigned long flags; - ad1848_info *devc = (ad1848_info *) audio_devs[dev]->devc; + int timeout; + unsigned char fs, old_fs, tmp = 0; + unsigned long flags; + ad1848_info *devc = (ad1848_info *) audio_devs[dev]->devc; ad1848_port_info *portc = (ad1848_port_info *) audio_devs[dev]->portc; if (devc->audio_mode) @@ -1053,75 +1070,78 @@ ad_enter_MCE(devc); /* Enables changes to the format select reg */ if (devc->model == MD_1845) /* Use alternate speed select registers */ - { - fs &= 0xf0; /* Mask off the rate select bits */ + { + fs &= 0xf0; /* Mask off the rate select bits */ - ad_write(devc, 22, (portc->speed >> 8) & 0xff); /* Speed MSB */ - ad_write(devc, 23, portc->speed & 0xff); /* Speed LSB */ - } + ad_write(devc, 22, (portc->speed >> 8) & 0xff); /* Speed MSB */ + ad_write(devc, 23, portc->speed & 0xff); /* Speed LSB */ + } if (devc->model == MD_4232) - { - tmp = ad_read(devc, 16); - ad_write(devc, 16, tmp | 0x30); - } + { + tmp = ad_read(devc, 16); + ad_write(devc, 16, tmp | 0x30); + } if (devc->model == MD_IWAVE) ad_write(devc, 17, 0xc2); /* Disable variable frequency select */ /* * If mode >= 2 (CS4231), set I28. It's the capture format register. */ + if (devc->model != MD_1848) - { - old_fs = ad_read(devc, 28); - ad_write(devc, 28, fs); - - /* - * Write to I28 starts resynchronization. Wait until it completes. - */ - timeout = 0; - while (timeout < 100 && inb(devc->base) != 0x80) - timeout++; - - timeout = 0; - while (timeout < 10000 && inb(devc->base) == 0x80) - timeout++; - - if (devc->model != MD_1848 && devc->model != MD_1845) - { - /* - * CS4231 compatible devices don't have separate sampling rate selection - * register for recording an playback. The I8 register is shared so we have to - * set the speed encoding bits of it too. - */ - unsigned char tmp = portc->speed_bits | (ad_read(devc, 8) & 0xf0); - - ad_write(devc, 8, tmp); - /* - * Write to I8 starts resynchronization. Wait until it completes. - */ - timeout = 0; - while (timeout < 100 && inb(devc->base) != 0x80) - timeout++; - - timeout = 0; - while (timeout < 10000 && inb(devc->base) == 0x80) - timeout++; - } - } else - { /* For AD1848 set I8. */ + { + old_fs = ad_read(devc, 28); + ad_write(devc, 28, fs); + + /* + * Write to I28 starts resynchronization. Wait until it completes. + */ + + timeout = 0; + while (timeout < 100 && inb(devc->base) != 0x80) + timeout++; + + timeout = 0; + while (timeout < 10000 && inb(devc->base) == 0x80) + timeout++; - old_fs = ad_read(devc, 8); - ad_write(devc, 8, fs); - /* - * Write to I8 starts resynchronization. Wait until it completes. - */ - timeout = 0; - while (timeout < 100 && inb(devc->base) != 0x80) - timeout++; - timeout = 0; - while (timeout < 10000 && inb(devc->base) == 0x80) - timeout++; - } + if (devc->model != MD_1848 && devc->model != MD_1845) + { + /* + * CS4231 compatible devices don't have separate sampling rate selection + * register for recording an playback. The I8 register is shared so we have to + * set the speed encoding bits of it too. + */ + unsigned char tmp = portc->speed_bits | (ad_read(devc, 8) & 0xf0); + + ad_write(devc, 8, tmp); + /* + * Write to I8 starts resynchronization. Wait until it completes. + */ + timeout = 0; + while (timeout < 100 && inb(devc->base) != 0x80) + timeout++; + + timeout = 0; + while (timeout < 10000 && inb(devc->base) == 0x80) + timeout++; + } + } + else + { /* For AD1848 set I8. */ + + old_fs = ad_read(devc, 8); + ad_write(devc, 8, fs); + /* + * Write to I8 starts resynchronization. Wait until it completes. + */ + timeout = 0; + while (timeout < 100 && inb(devc->base) != 0x80) + timeout++; + timeout = 0; + while (timeout < 10000 && inb(devc->base) == 0x80) + timeout++; + } if (devc->model == MD_4232) ad_write(devc, 16, tmp & ~0x30); @@ -1134,19 +1154,20 @@ #if defined(CONFIG_SEQUENCER) && !defined(EXCLUDE_TIMERS) if (dev == timer_installed && devc->timer_running) + { if ((fs & 0x01) != (old_fs & 0x01)) - { - ad1848_tmr_reprogram(dev); - } + { + ad1848_tmr_reprogram(dev); + } + } #endif ad1848_halt_input(dev); return 0; } -static void -ad1848_halt(int dev) +static void ad1848_halt(int dev) { - ad1848_info *devc = (ad1848_info *) audio_devs[dev]->devc; + ad1848_info *devc = (ad1848_info *) audio_devs[dev]->devc; ad1848_port_info *portc = (ad1848_port_info *) audio_devs[dev]->portc; unsigned char bits = ad_read(devc, 9); @@ -1159,8 +1180,7 @@ devc->audio_mode = 0; } -static void -ad1848_halt_input(int dev) +static void ad1848_halt_input(int dev) { ad1848_info *devc = (ad1848_info *) audio_devs[dev]->devc; unsigned long flags; @@ -1187,19 +1207,18 @@ devc->audio_mode &= ~PCM_ENABLE_INPUT; } - outb((0), io_Status(devc)); /* Clear interrupt status */ - outb((0), io_Status(devc)); /* Clear interrupt status */ + outb(0, io_Status(devc)); /* Clear interrupt status */ + outb(0, io_Status(devc)); /* Clear interrupt status */ devc->audio_mode &= ~PCM_ENABLE_INPUT; restore_flags(flags); } -static void -ad1848_halt_output(int dev) +static void ad1848_halt_output(int dev) { - ad1848_info *devc = (ad1848_info *) audio_devs[dev]->devc; - unsigned long flags; + ad1848_info *devc = (ad1848_info *) audio_devs[dev]->devc; + unsigned long flags; if (!(ad_read(devc, 9) & 0x01)) return; /* Playback not enabled */ @@ -1230,8 +1249,7 @@ restore_flags(flags); } -static void -ad1848_trigger(int dev, int state) +static void ad1848_trigger(int dev, int state) { ad1848_info *devc = (ad1848_info *) audio_devs[dev]->devc; ad1848_port_info *portc = (ad1848_port_info *) audio_devs[dev]->portc; @@ -1245,32 +1263,31 @@ tmp = old = ad_read(devc, 9); if (portc->open_mode & OPEN_READ) - { + { if (state & PCM_ENABLE_INPUT) tmp |= 0x02; else tmp &= ~0x02; - } + } if (portc->open_mode & OPEN_WRITE) - { - if (state & PCM_ENABLE_OUTPUT) - tmp |= 0x01; - else - tmp &= ~0x01; - } + { + if (state & PCM_ENABLE_OUTPUT) + tmp |= 0x01; + else + tmp &= ~0x01; + } /* ad_mute(devc); */ if (tmp != old) - { + { ad_write(devc, 9, tmp); ad_unmute(devc); - } + } restore_flags(flags); } -static void -ad1848_init_hw(ad1848_info * devc) +static void ad1848_init_hw(ad1848_info * devc) { - int i; + int i; /* * Initial values for the indirect registers of CS4248/AD1848. @@ -1294,40 +1311,40 @@ ad_unmute(devc); /* Leave it unmuted now */ if (devc->model > MD_1848) - { - ad_write(devc, 12, ad_read(devc, 12) | 0x40); /* Mode2 = enabled */ - - if (devc->model == MD_IWAVE) - ad_write(devc, 12, 0x6c); /* Select codec mode 3 */ + { + ad_write(devc, 12, ad_read(devc, 12) | 0x40); /* Mode2 = enabled */ - for (i = 16; i < 32; i++) - ad_write(devc, i, init_values[i]); + if (devc->model == MD_IWAVE) + ad_write(devc, 12, 0x6c); /* Select codec mode 3 */ - if (devc->model == MD_IWAVE) - ad_write(devc, 16, 0x30); /* Playback and capture counters enabled */ + for (i = 16; i < 32; i++) + ad_write(devc, i, init_values[i]); - } + if (devc->model == MD_IWAVE) + ad_write(devc, 16, 0x30); /* Playback and capture counters enabled */ + } if (devc->model > MD_1848) - { - if (devc->audio_flags & DMA_DUPLEX) - ad_write(devc, 9, ad_read(devc, 9) & ~0x04); /* Dual DMA mode */ - else - ad_write(devc, 9, ad_read(devc, 9) | 0x04); /* Single DMA mode */ + { + if (devc->audio_flags & DMA_DUPLEX) + ad_write(devc, 9, ad_read(devc, 9) & ~0x04); /* Dual DMA mode */ + else + ad_write(devc, 9, ad_read(devc, 9) | 0x04); /* Single DMA mode */ - if (devc->model == MD_1845) - ad_write(devc, 27, ad_read(devc, 27) | 0x08); /* Alternate freq select enabled */ + if (devc->model == MD_1845) + ad_write(devc, 27, ad_read(devc, 27) | 0x08); /* Alternate freq select enabled */ - if (devc->model == MD_IWAVE) - { /* Some magic Interwave specific initialization */ - ad_write(devc, 12, 0x6c); /* Select codec mode 3 */ - ad_write(devc, 16, 0x30); /* Playback and capture counters enabled */ - ad_write(devc, 17, 0xc2); /* Alternate feature enable */ - } - } else - { + if (devc->model == MD_IWAVE) + { /* Some magic Interwave specific initialization */ + ad_write(devc, 12, 0x6c); /* Select codec mode 3 */ + ad_write(devc, 16, 0x30); /* Playback and capture counters enabled */ + ad_write(devc, 17, 0xc2); /* Alternate feature enable */ + } + } + else + { devc->audio_flags &= ~DMA_DUPLEX; ad_write(devc, 9, ad_read(devc, 9) | 0x04); /* Single DMA mode */ - } + } outb((0), io_Status(devc)); /* Clear pending interrupts */ @@ -1341,45 +1358,43 @@ ad1848_mixer_reset(devc); } -int -ad1848_detect(int io_base, int *ad_flags, int *osp) +int ad1848_detect(int io_base, int *ad_flags, int *osp) { + unsigned char tmp; + ad1848_info *devc = &adev_info[nr_ad1848_devs]; + unsigned char tmp1 = 0xff, tmp2 = 0xff; + int optiC930 = 0; /* OPTi 82C930 flag */ + int interwave = 0; + int ad1847_flag = 0; + int cs4248_flag = 0; - unsigned char tmp; - ad1848_info *devc = &adev_info[nr_ad1848_devs]; - unsigned char tmp1 = 0xff, tmp2 = 0xff; - int optiC930 = 0; /* OPTi 82C930 flag */ - int interwave = 0; - int ad1847_flag = 0; - int cs4248_flag = 0; - - int i; + int i; DDB(printk("ad1848_detect(%x)\n", io_base)); if (ad_flags) - { - if (*ad_flags == 0x12345678) - { - interwave = 1; - *ad_flags = 0; - } - if (*ad_flags == 0x12345677) - { - cs4248_flag = 1; - *ad_flags = 0; - } - } + { + if (*ad_flags == 0x12345678) + { + interwave = 1; + *ad_flags = 0; + } + if (*ad_flags == 0x12345677) + { + cs4248_flag = 1; + *ad_flags = 0; + } + } if (nr_ad1848_devs >= MAX_AUDIO_DEV) - { - printk("ad1848 - Too many audio devices\n"); - return 0; - } + { + printk(KERN_ERR "ad1848 - Too many audio devices\n"); + return 0; + } if (check_region(io_base, 4)) - { - printk("ad1848.c: Port %x not free.\n", io_base); - return 0; - } + { + printk(KERN_ERR "ad1848.c: Port %x not free.\n", io_base); + return 0; + } devc->base = io_base; devc->irq_ok = 0; devc->timer_running = 0; @@ -1393,31 +1408,33 @@ devc->debug_flag = 0; /* - * Check that the I/O address is in use. - * - * The bit 0x80 of the base I/O port is known to be 0 after the - * chip has performed its power on initialization. Just assume - * this has happened before the OS is starting. - * - * If the I/O address is unused, it typically returns 0xff. + * Check that the I/O address is in use. + * + * The bit 0x80 of the base I/O port is known to be 0 after the + * chip has performed its power on initialization. Just assume + * this has happened before the OS is starting. + * + * If the I/O address is unused, it typically returns 0xff. */ if (inb(devc->base) == 0xff) - { - DDB(printk("ad1848_detect: The base I/O address appears to be dead\n")); - } -/* - * Wait for the device to stop initialization - */ + { + DDB(printk("ad1848_detect: The base I/O address appears to be dead\n")); + } + + /* + * Wait for the device to stop initialization + */ + DDB(printk("ad1848_detect() - step 0\n")); for (i = 0; i < 10000000; i++) - { - unsigned char x = inb(devc->base); + { + unsigned char x = inb(devc->base); - if (x == 0xff || !(x & 0x80)) - break; - } + if (x == 0xff || !(x & 0x80)) + break; + } DDB(printk("ad1848_detect() - step A\n")); @@ -1425,14 +1442,15 @@ ad_leave_MCE(devc); if ((inb(devc->base) & 0x80) != 0x00) /* Not a AD1848 */ - { - DDB(printk("ad1848 detect error - step A (%02x)\n", (int) inb(devc->base))); - return 0; - } + { + DDB(printk("ad1848 detect error - step A (%02x)\n", (int) inb(devc->base))); + return 0; + } + /* - * Test if it's possible to change contents of the indirect registers. - * Registers 0 and 1 are ADC volume registers. The bit 0x10 is read only - * so try to avoid using it. + * Test if it's possible to change contents of the indirect registers. + * Registers 0 and 1 are ADC volume registers. The bit 0x10 is read only + * so try to avoid using it. */ DDB(printk("ad1848_detect() - step B\n")); @@ -1440,28 +1458,33 @@ ad_write(devc, 1, 0x45); /* 0x55 with bit 0x10 clear */ if ((tmp1 = ad_read(devc, 0)) != 0xaa || (tmp2 = ad_read(devc, 1)) != 0x45) + { if (tmp2 == 0x65) /* AD1847 has couple of bits hardcoded to 1 */ ad1847_flag = 1; else - { - DDB(printk("ad1848 detect error - step B (%x/%x)\n", tmp1, tmp2)); - return 0; - } + { + DDB(printk("ad1848 detect error - step B (%x/%x)\n", tmp1, tmp2)); + return 0; + } + } DDB(printk("ad1848_detect() - step C\n")); ad_write(devc, 0, 0x45); ad_write(devc, 1, 0xaa); if ((tmp1 = ad_read(devc, 0)) != 0x45 || (tmp2 = ad_read(devc, 1)) != 0xaa) + { if (tmp2 == 0x8a) /* AD1847 has few bits hardcoded to 1 */ ad1847_flag = 1; else - { - DDB(printk("ad1848 detect error - step C (%x/%x)\n", tmp1, tmp2)); - return 0; - } + { + DDB(printk("ad1848 detect error - step C (%x/%x)\n", tmp1, tmp2)); + return 0; + } + } + /* - * The indirect register I12 has some read only bits. Lets - * try to change them. + * The indirect register I12 has some read only bits. Lets + * try to change them. */ DDB(printk("ad1848_detect() - step D\n")); @@ -1469,43 +1492,47 @@ ad_write(devc, 12, (~tmp) & 0x0f); if ((tmp & 0x0f) != ((tmp1 = ad_read(devc, 12)) & 0x0f)) - { - DDB(printk("ad1848 detect error - step D (%x)\n", tmp1)); - return 0; - } + { + DDB(printk("ad1848 detect error - step D (%x)\n", tmp1)); + return 0; + } + /* - * NOTE! Last 4 bits of the reg I12 tell the chip revision. - * 0x01=RevB and 0x0A=RevC. + * NOTE! Last 4 bits of the reg I12 tell the chip revision. + * 0x01=RevB and 0x0A=RevC. */ /* - * The original AD1848/CS4248 has just 15 indirect registers. This means - * that I0 and I16 should return the same value (etc.). - * However this doesn't work with CS4248. Actually it seems to be impossible - * to detect if the chip is a CS4231 or CS4248. - * Ensure that the Mode2 enable bit of I12 is 0. Otherwise this test fails - * with CS4231. + * The original AD1848/CS4248 has just 15 indirect registers. This means + * that I0 and I16 should return the same value (etc.). + * However this doesn't work with CS4248. Actually it seems to be impossible + * to detect if the chip is a CS4231 or CS4248. + * Ensure that the Mode2 enable bit of I12 is 0. Otherwise this test fails + * with CS4231. */ -/* - * OPTi 82C930 has mode2 control bit in another place. This test will fail - * with it. Accept this situation as a possible indication of this chip. - */ + /* + * OPTi 82C930 has mode2 control bit in another place. This test will fail + * with it. Accept this situation as a possible indication of this chip. + */ DDB(printk("ad1848_detect() - step F\n")); ad_write(devc, 12, 0); /* Mode2=disabled */ for (i = 0; i < 16; i++) + { if ((tmp1 = ad_read(devc, i)) != (tmp2 = ad_read(devc, i + 16))) - { - DDB(printk("ad1848 detect step F(%d/%x/%x) - OPTi chip???\n", i, tmp1, tmp2)); - if (!ad1847_flag) - optiC930 = 1; - break; - } + { + DDB(printk("ad1848 detect step F(%d/%x/%x) - OPTi chip???\n", i, tmp1, tmp2)); + if (!ad1847_flag) + optiC930 = 1; + break; + } + } + /* - * Try to switch the chip to mode2 (CS4231) by setting the MODE2 bit (0x40). - * The bit 0x80 is always 1 in CS4248 and CS4231. + * Try to switch the chip to mode2 (CS4231) by setting the MODE2 bit (0x40). + * The bit 0x80 is always 1 in CS4248 and CS4231. */ DDB(printk("ad1848_detect() - step G\n")); @@ -1521,66 +1548,67 @@ tmp1 = ad_read(devc, 12); if (tmp1 & 0x80) - { - if (ad_flags) - *ad_flags |= AD_F_CS4248; + { + if (ad_flags) + *ad_flags |= AD_F_CS4248; - devc->chip_name = "CS4248"; /* Our best knowledge just now */ - } + devc->chip_name = "CS4248"; /* Our best knowledge just now */ + } if (optiC930 || (tmp1 & 0xc0) == (0x80 | 0x40)) - { - /* - * CS4231 detected - is it? - * - * Verify that setting I0 doesn't change I16. - */ - DDB(printk("ad1848_detect() - step H\n")); - ad_write(devc, 16, 0); /* Set I16 to known value */ - - ad_write(devc, 0, 0x45); - if ((tmp1 = ad_read(devc, 16)) != 0x45) /* No change -> CS4231? */ - { - - ad_write(devc, 0, 0xaa); - if ((tmp1 = ad_read(devc, 16)) == 0xaa) /* Rotten bits? */ - { - DDB(printk("ad1848 detect error - step H(%x)\n", tmp1)); - return 0; - } - /* - * Verify that some bits of I25 are read only. - */ - - DDB(printk("ad1848_detect() - step I\n")); - tmp1 = ad_read(devc, 25); /* Original bits */ - ad_write(devc, 25, ~tmp1); /* Invert all bits */ - if ((ad_read(devc, 25) & 0xe7) == (tmp1 & 0xe7)) - { - int id, full_id; - - /* - * It's at least CS4231 - */ - devc->chip_name = "CS4231"; - - devc->model = MD_4231; - - /* - * It could be an AD1845 or CS4231A as well. - * CS4231 and AD1845 report the same revision info in I25 - * while the CS4231A reports different. - */ - - id = ad_read(devc, 25) & 0xe7; - full_id = ad_read(devc, 25); - if (id == 0x80) /* Device busy??? */ - id = ad_read(devc, 25) & 0xe7; - if (id == 0x80) /* Device still busy??? */ - id = ad_read(devc, 25) & 0xe7; - DDB(printk("ad1848_detect() - step J (%02x/%02x)\n", id, ad_read(devc, 25))); + { + /* + * CS4231 detected - is it? + * + * Verify that setting I0 doesn't change I16. + */ + + DDB(printk("ad1848_detect() - step H\n")); + ad_write(devc, 16, 0); /* Set I16 to known value */ + + ad_write(devc, 0, 0x45); + if ((tmp1 = ad_read(devc, 16)) != 0x45) /* No change -> CS4231? */ + { + ad_write(devc, 0, 0xaa); + if ((tmp1 = ad_read(devc, 16)) == 0xaa) /* Rotten bits? */ + { + DDB(printk("ad1848 detect error - step H(%x)\n", tmp1)); + return 0; + } + + /* + * Verify that some bits of I25 are read only. + */ + + DDB(printk("ad1848_detect() - step I\n")); + tmp1 = ad_read(devc, 25); /* Original bits */ + ad_write(devc, 25, ~tmp1); /* Invert all bits */ + if ((ad_read(devc, 25) & 0xe7) == (tmp1 & 0xe7)) + { + int id, full_id; - switch (id) - { + /* + * It's at least CS4231 + */ + + devc->chip_name = "CS4231"; + devc->model = MD_4231; + + /* + * It could be an AD1845 or CS4231A as well. + * CS4231 and AD1845 report the same revision info in I25 + * while the CS4231A reports different. + */ + + id = ad_read(devc, 25) & 0xe7; + full_id = ad_read(devc, 25); + if (id == 0x80) /* Device busy??? */ + id = ad_read(devc, 25) & 0xe7; + if (id == 0x80) /* Device still busy??? */ + id = ad_read(devc, 25) & 0xe7; + DDB(printk("ad1848_detect() - step J (%02x/%02x)\n", id, ad_read(devc, 25))); + + switch (id) + { case 0xa0: devc->chip_name = "CS4231A"; @@ -1618,25 +1646,26 @@ */ unsigned char tmp = ad_read(devc, 23); - ad_write(devc, 23, ~tmp); + if (interwave) - { - devc->model = MD_IWAVE; - devc->chip_name = "IWave"; - } else if (ad_read(devc, 23) != tmp) /* AD1845 ? */ - { - devc->chip_name = "AD1845"; - devc->model = MD_1845; - } else if (cs4248_flag) - { - if (ad_flags) + { + devc->model = MD_IWAVE; + devc->chip_name = "IWave"; + } + else if (ad_read(devc, 23) != tmp) /* AD1845 ? */ + { + devc->chip_name = "AD1845"; + devc->model = MD_1845; + } + else if (cs4248_flag) + { + if (ad_flags) *ad_flags |= AD_F_CS4248; - - devc->chip_name = "CS4248"; - devc->model = MD_1848; - ad_write(devc, 12, ad_read(devc, 12) & ~0x40); /* Mode2 off */ - } + devc->chip_name = "CS4248"; + devc->model = MD_1848; + ad_write(devc, 12, ad_read(devc, 12) & ~0x40); /* Mode2 off */ + } ad_write(devc, 23, tmp); /* Restore */ } break; @@ -1644,27 +1673,27 @@ default: /* Assume CS4231 or OPTi 82C930 */ DDB(printk("ad1848: I25 = %02x/%02x\n", ad_read(devc, 25), ad_read(devc, 25) & 0xe7)); if (optiC930) - { - devc->chip_name = "82C930"; - devc->model = MD_C930; - } else - { - devc->model = MD_4231; - } - - } - } - ad_write(devc, 25, tmp1); /* Restore bits */ - - DDB(printk("ad1848_detect() - step K\n")); - } - } + { + devc->chip_name = "82C930"; + devc->model = MD_C930; + } + else + { + devc->model = MD_4231; + } + } + } + ad_write(devc, 25, tmp1); /* Restore bits */ + + DDB(printk("ad1848_detect() - step K\n")); + } + } DDB(printk("ad1848_detect() - step L\n")); if (ad_flags) - { + { if (devc->model != MD_1848) *ad_flags |= AD_F_CS4231; - } + } DDB(printk("ad1848_detect() - Detected OK\n")); if (devc->model == MD_1848 && ad1847_flag) @@ -1674,19 +1703,18 @@ return 1; } -int -ad1848_init(char *name, int io_base, int irq, int dma_playback, int dma_capture, int share_dma, int *osp) +int ad1848_init(char *name, int io_base, int irq, int dma_playback, int dma_capture, int share_dma, int *osp) { /* - * NOTE! If irq < 0, there is another driver which has allocated the IRQ - * so that this driver doesn't need to allocate/deallocate it. - * The actually used IRQ is ABS(irq). + * NOTE! If irq < 0, there is another driver which has allocated the IRQ + * so that this driver doesn't need to allocate/deallocate it. + * The actually used IRQ is ABS(irq). */ - int my_dev; - char dev_name[100]; - int e; + int my_dev; + char dev_name[100]; + int e; ad1848_info *devc = &adev_info[nr_ad1848_devs]; @@ -1711,19 +1739,19 @@ request_region(devc->base, 4, devc->name); - conf_printf2(dev_name, - devc->base, devc->irq, dma_playback, dma_capture); + conf_printf2(dev_name, devc->base, devc->irq, dma_playback, dma_capture); if (devc->model == MD_1848 || devc->model == MD_C930) devc->audio_flags |= DMA_HARDSTOP; if (devc->model > MD_1848) - { - if (devc->dma1 == devc->dma2 || devc->dma2 == -1 || devc->dma1 == -1) - devc->audio_flags &= ~DMA_DUPLEX; - else - devc->audio_flags |= DMA_DUPLEX; - } + { + if (devc->dma1 == devc->dma2 || devc->dma2 == -1 || devc->dma1 == -1) + devc->audio_flags &= ~DMA_DUPLEX; + else + devc->audio_flags |= DMA_DUPLEX; + } + if ((my_dev = sound_install_audiodrv(AUDIO_DRIVER_VERSION, dev_name, &ad1848_audio_driver, @@ -1733,9 +1761,9 @@ devc, dma_playback, dma_capture)) < 0) - { - return -1; - } + { + return -1; + } portc = (ad1848_port_info *) (sound_mem_blocks[sound_nblocks] = vmalloc(sizeof(ad1848_port_info))); sound_mem_sizes[sound_nblocks] = sizeof(ad1848_port_info); if (sound_nblocks < 1024) @@ -1748,37 +1776,38 @@ ad1848_init_hw(devc); if (irq > 0) - { - irq2dev[irq] = devc->dev_no = my_dev; - if (snd_set_irq_handler(devc->irq, adintr, + { + irq2dev[irq] = devc->dev_no = my_dev; + if (snd_set_irq_handler(devc->irq, adintr, devc->name, NULL) < 0) - { - printk(KERN_WARNING "ad1848: IRQ in use\n"); - } - if (devc->model != MD_1848 && devc->model != MD_C930) - { - int x; - unsigned char tmp = ad_read(devc, 16); - - devc->timer_ticks = 0; - - ad_write(devc, 21, 0x00); /* Timer MSB */ - ad_write(devc, 20, 0x10); /* Timer LSB */ - - ad_write(devc, 16, tmp | 0x40); /* Enable timer */ - for (x = 0; x < 100000 && devc->timer_ticks == 0; x++); - ad_write(devc, 16, tmp & ~0x40); /* Disable timer */ - - if (devc->timer_ticks == 0) - printk(KERN_WARNING "ad1848: Interrupt test failed (IRQ%d)\n", devc->irq); - else - { - DDB(printk("Interrupt test OK\n")); - devc->irq_ok = 1; - } - } else - devc->irq_ok = 1; /* Couldn't test. assume it's OK */ + { + printk(KERN_WARNING "ad1848: IRQ in use\n"); + } + if (devc->model != MD_1848 && devc->model != MD_C930) + { + int x; + unsigned char tmp = ad_read(devc, 16); + + devc->timer_ticks = 0; + + ad_write(devc, 21, 0x00); /* Timer MSB */ + ad_write(devc, 20, 0x10); /* Timer LSB */ + + ad_write(devc, 16, tmp | 0x40); /* Enable timer */ + for (x = 0; x < 100000 && devc->timer_ticks == 0; x++); + ad_write(devc, 16, tmp & ~0x40); /* Disable timer */ + + if (devc->timer_ticks == 0) + printk(KERN_WARNING "ad1848: Interrupt test failed (IRQ%d)\n", devc->irq); + else + { + DDB(printk("Interrupt test OK\n")); + devc->irq_ok = 1; + } + } + else + devc->irq_ok = 1; /* Couldn't test. assume it's OK */ } else if (irq < 0) irq2dev[-irq] = devc->dev_no = my_dev; @@ -1789,22 +1818,22 @@ #endif if (!share_dma) - { - if (sound_alloc_dma(dma_playback, devc->name)) - printk("ad1848.c: Can't allocate DMA%d\n", dma_playback); - - if (dma_capture != dma_playback) - if (sound_alloc_dma(dma_capture, devc->name)) - printk("ad1848.c: Can't allocate DMA%d\n", dma_capture); - } + { + if (sound_alloc_dma(dma_playback, devc->name)) + printk(KERN_WARNING "ad1848.c: Can't allocate DMA%d\n", dma_playback); + + if (dma_capture != dma_playback) + if (sound_alloc_dma(dma_capture, devc->name)) + printk(KERN_WARNING "ad1848.c: Can't allocate DMA%d\n", dma_capture); + } if ((e = sound_install_mixer(MIXER_DRIVER_VERSION, dev_name, &ad1848_mixer_operations, sizeof(struct mixer_operations), devc)) >= 0) - { - audio_devs[my_dev]->mixer_dev = e; - } + { + audio_devs[my_dev]->mixer_dev = e; + } MOD_INC_USE_COUNT; return my_dev; } @@ -1819,76 +1848,79 @@ devc = &adev_info[nr_ad1848_devs - 1]; switch (cmd) - { - case AD1848_SET_XTAL: /* Change clock frequency of AD1845 (only ) */ - if (devc->model != MD_1845) - return; - ad_enter_MCE(devc); - ad_write(devc, 29, (ad_read(devc, 29) & 0x1f) | (arg << 5)); - ad_leave_MCE(devc); - break; - - case AD1848_MIXER_REROUTE: - { - int o = (arg >> 8) & 0xff; - int n = arg & 0xff; - - if (n == SOUND_MIXER_NONE) - { /* Just hide this control */ - ad1848_mixer_set(devc, o, 0); /* Shut up it */ - devc->supported_devices &= ~(1 << o); - devc->supported_rec_devices &= ~(1 << o); - return; - } - /* Make the mixer control identified by o to appear as n */ - - if (o < 0 || o > SOUND_MIXER_NRDEVICES) - return; - if (n < 0 || n > SOUND_MIXER_NRDEVICES) - return; - if (!(devc->supported_devices & (1 << o))) - return; /* Not supported */ - - devc->mixer_reroute[n] = o; /* Rename the control */ - devc->supported_devices &= ~(1 << o); - devc->supported_devices |= (1 << n); - if (devc->supported_rec_devices & (1 << o)) - devc->supported_rec_devices |= (1 << n); - devc->supported_rec_devices &= ~(1 << o); - } - break; - } + { + case AD1848_SET_XTAL: /* Change clock frequency of AD1845 (only ) */ + if (devc->model != MD_1845) + return; + ad_enter_MCE(devc); + ad_write(devc, 29, (ad_read(devc, 29) & 0x1f) | (arg << 5)); + ad_leave_MCE(devc); + break; + + case AD1848_MIXER_REROUTE: + { + int o = (arg >> 8) & 0xff; + int n = arg & 0xff; + + if (n == SOUND_MIXER_NONE) + { /* Just hide this control */ + ad1848_mixer_set(devc, o, 0); /* Shut up it */ + devc->supported_devices &= ~(1 << o); + devc->supported_rec_devices &= ~(1 << o); + return; + } + /* Make the mixer control identified by o to appear as n */ + + if (o < 0 || o > SOUND_MIXER_NRDEVICES) + return; + if (n < 0 || n > SOUND_MIXER_NRDEVICES) + return; + if (!(devc->supported_devices & (1 << o))) + return; /* Not supported */ + + devc->mixer_reroute[n] = o; /* Rename the control */ + devc->supported_devices &= ~(1 << o); + devc->supported_devices |= (1 << n); + if (devc->supported_rec_devices & (1 << o)) + devc->supported_rec_devices |= (1 << n); + devc->supported_rec_devices &= ~(1 << o); + } + break; + } return; } -void -ad1848_unload(int io_base, int irq, int dma_playback, int dma_capture, int share_dma) +void ad1848_unload(int io_base, int irq, int dma_playback, int dma_capture, int share_dma) { - int i, dev = 0; - ad1848_info *devc = NULL; + int i, dev = 0; + ad1848_info *devc = NULL; for (i = 0; devc == NULL && i < nr_ad1848_devs; i++) + { if (adev_info[i].base == io_base) - { - devc = &adev_info[i]; - dev = devc->dev_no; - } + { + devc = &adev_info[i]; + dev = devc->dev_no; + } + } + if (devc != NULL) - { - release_region(devc->base, 4); + { + release_region(devc->base, 4); - if (!share_dma) - { - if (irq > 0) - snd_release_irq(devc->irq); - - sound_free_dma(audio_devs[dev]->dmap_out->dma); - - if (audio_devs[dev]->dmap_in->dma != audio_devs[dev]->dmap_out->dma) - sound_free_dma(audio_devs[dev]->dmap_in->dma); - } - } else - printk("ad1848: Can't find device to be unloaded. Base=%x\n", io_base); + if (!share_dma) + { + if (irq > 0) + snd_release_irq(devc->irq); + + sound_free_dma(audio_devs[dev]->dmap_out->dma); + + if (audio_devs[dev]->dmap_in->dma != audio_devs[dev]->dmap_out->dma) + sound_free_dma(audio_devs[dev]->dmap_in->dma); + } + } + else + printk(KERN_ERR "ad1848: Can't find device to be unloaded. Base=%x\n", io_base); MOD_DEC_USE_COUNT; } @@ -1902,94 +1934,96 @@ int cnt = 0; if (irq < 0 || irq > 15) - { - dev = -1; - } else + { + dev = -1; + } + else dev = irq2dev[irq]; if (dev < 0 || dev >= num_audiodevs) - { - for (irq = 0; irq < 17; irq++) - if (irq2dev[irq] != -1) - break; - - if (irq > 15) - { - /* printk("ad1848.c: Bogus interrupt %d\n", irq); */ - return; - } - dev = irq2dev[irq]; - devc = (ad1848_info *) audio_devs[dev]->devc; + { + for (irq = 0; irq < 17; irq++) + if (irq2dev[irq] != -1) + break; + + if (irq > 15) + { + /* printk("ad1848.c: Bogus interrupt %d\n", irq); */ + return; + } + dev = irq2dev[irq]; + devc = (ad1848_info *) audio_devs[dev]->devc; } else devc = (ad1848_info *) audio_devs[dev]->devc; - interrupt_again: /* Jump back here if int status doesn't reset */ +interrupt_again: /* Jump back here if int status doesn't reset */ status = inb(io_Status(devc)); if (status == 0x80) - printk("adintr: Why?\n"); + printk(KERN_DEBUG "adintr: Why?\n"); if (devc->model == MD_1848) outb((0), io_Status(devc)); /* Clear interrupt status */ if (status & 0x01) - { - if (devc->model == MD_C930) - { /* 82C930 has interrupt status register in MAD16 register MC11 */ - unsigned long flags; - - save_flags(flags); - cli(); - - alt_stat = 0; - - if (devc->c930_password_port) - outb((0xe4), devc->c930_password_port); /* Password */ - outb((11), 0xe0e); - c930_stat = inb(0xe0f); - - if (c930_stat & 0x04) - alt_stat |= 0x10; /* Playback intr */ - if (c930_stat & 0x08) - alt_stat |= 0x20; /* Playback intr */ - restore_flags(flags); - } else if (devc->model != MD_1848) - alt_stat = ad_read(devc, 24); - - /* Acknowledge the intr before proceeding */ - if (devc->model == MD_C930) - { /* 82C930 has interrupt status register in MAD16 register MC11 */ - unsigned long flags; - - save_flags(flags); - cli(); - - if (devc->c930_password_port) - outb((0xe4), devc->c930_password_port); /* Password */ - outb((11), 0xe0e); - outb((~c930_stat), 0xe0f); - restore_flags(flags); - } else if (devc->model != MD_1848) - ad_write(devc, 24, ad_read(devc, 24) & ~alt_stat); /* Selective ack */ - - if (devc->open_mode & OPEN_READ && devc->audio_mode & PCM_ENABLE_INPUT && alt_stat & 0x20) - { - DMAbuf_inputintr(devc->record_dev); - } - if (devc->open_mode & OPEN_WRITE && devc->audio_mode & PCM_ENABLE_OUTPUT && + { + if (devc->model == MD_C930) + { /* 82C930 has interrupt status register in MAD16 register MC11 */ + unsigned long flags; + + save_flags(flags); + cli(); + + alt_stat = 0; + + if (devc->c930_password_port) + outb((0xe4), devc->c930_password_port); /* Password */ + outb(11, 0xe0e); + c930_stat = inb(0xe0f); + + if (c930_stat & 0x04) + alt_stat |= 0x10; /* Playback intr */ + if (c930_stat & 0x08) + alt_stat |= 0x20; /* Playback intr */ + restore_flags(flags); + } else if (devc->model != MD_1848) + alt_stat = ad_read(devc, 24); + + /* Acknowledge the intr before proceeding */ + if (devc->model == MD_C930) + { /* 82C930 has interrupt status register in MAD16 register MC11 */ + unsigned long flags; + + save_flags(flags); + cli(); + + if (devc->c930_password_port) + outb((0xe4), devc->c930_password_port); /* Password */ + outb((11), 0xe0e); + outb((~c930_stat), 0xe0f); + restore_flags(flags); + } + else if (devc->model != MD_1848) + ad_write(devc, 24, ad_read(devc, 24) & ~alt_stat); /* Selective ack */ + + if (devc->open_mode & OPEN_READ && devc->audio_mode & PCM_ENABLE_INPUT && alt_stat & 0x20) + { + DMAbuf_inputintr(devc->record_dev); + } + if (devc->open_mode & OPEN_WRITE && devc->audio_mode & PCM_ENABLE_OUTPUT && alt_stat & 0x10) - { - DMAbuf_outputintr(devc->playback_dev, 1); - } - if (devc->model != MD_1848 && alt_stat & 0x40) /* Timer interrupt */ - { - devc->timer_ticks++; + { + DMAbuf_outputintr(devc->playback_dev, 1); + } + if (devc->model != MD_1848 && alt_stat & 0x40) /* Timer interrupt */ + { + devc->timer_ticks++; #if (defined(CONFIG_SEQUENCER) && !defined(EXCLUDE_TIMERS)) || defined(MODULE) - if (timer_installed == dev && devc->timer_running) - sound_timer_interrupt(); + if (timer_installed == dev && devc->timer_running) + sound_timer_interrupt(); #endif - } - } + } + } /* * Sometimes playback or capture interrupts occur while a timer interrupt * is being handled. The interrupt will not be retriggered if we don't @@ -1997,63 +2031,61 @@ * the handler in this case. */ if (inb(io_Status(devc)) & 0x01 && cnt++ < 4) - { + { goto interrupt_again; - } + } } -#ifdef DESKPROXL /* - * Very experimental initialization sequence for the integrated sound system - * of Compaq Deskpro XL. Will be moved somewhere else in future. + * Experimental initialization sequence for the integrated sound system + * of Compaq Deskpro XL. */ -static int -init_deskpro(struct address_info *hw_config) +static int init_deskpro(struct address_info *hw_config) { unsigned char tmp; if ((tmp = inb(0xc44)) == 0xff) - { - DDB(printk("init_deskpro: Dead port 0xc44\n")); - return 0; - } + { + DDB(printk("init_deskpro: Dead port 0xc44\n")); + return 0; + } outb((tmp | 0x04), 0xc44); /* Select bank 1 */ if (inb(0xc44) != 0x04) - { - DDB(printk("init_deskpro: Invalid bank1 signature in port 0xc44\n")); - return 0; - } -/* - * OK. It looks like a Deskpro so let's proceed. - */ + { + DDB(printk("init_deskpro: Invalid bank1 signature in port 0xc44\n")); + return 0; + } + /* + * OK. It looks like a Deskpro so let's proceed. + */ -/* - * I/O port 0xc44 Audio configuration register. - * - * bits 0xc0: Audio revision bits - * 0x00 = Compaq Business Audio - * 0x40 = MS Sound System Compatible (reset default) - * 0x80 = Reserved - * 0xc0 = Reserved - * bit 0x20: No Wait State Enable - * 0x00 = Disabled (reset default, DMA mode) - * 0x20 = Enabled (programmed I/O mode) - * bit 0x10: MS Sound System Decode Enable - * 0x00 = Decoding disabled (reset default) - * 0x10 = Decoding enabled - * bit 0x08: FM Synthesis Decode Enable - * 0x00 = Decoding Disabled (reset default) - * 0x08 = Decoding enabled - * bit 0x04 Bank select - * 0x00 = Bank 0 - * 0x04 = Bank 1 - * bits 0x03 MSS Base address - * 0x00 = 0x530 (reset default) - * 0x01 = 0x604 - * 0x02 = 0xf40 - * 0x03 = 0xe80 - */ + /* + * I/O port 0xc44 Audio configuration register. + * + * bits 0xc0: Audio revision bits + * 0x00 = Compaq Business Audio + * 0x40 = MS Sound System Compatible (reset default) + * 0x80 = Reserved + * 0xc0 = Reserved + * bit 0x20: No Wait State Enable + * 0x00 = Disabled (reset default, DMA mode) + * 0x20 = Enabled (programmed I/O mode) + * bit 0x10: MS Sound System Decode Enable + * 0x00 = Decoding disabled (reset default) + * 0x10 = Decoding enabled + * bit 0x08: FM Synthesis Decode Enable + * 0x00 = Decoding Disabled (reset default) + * 0x08 = Decoding enabled + * bit 0x04 Bank select + * 0x00 = Bank 0 + * 0x04 = Bank 1 + * bits 0x03 MSS Base address + * 0x00 = 0x530 (reset default) + * 0x01 = 0x604 + * 0x02 = 0xf40 + * 0x03 = 0xe80 + */ #ifdef DEBUGXL /* Debug printing */ @@ -2068,23 +2100,23 @@ tmp = 0x58; /* MSS Mode, MSS&FM decode enabled */ switch (hw_config->io_base) - { - case 0x530: - tmp |= 0x00; - break; - case 0x604: - tmp |= 0x01; - break; - case 0xf40: - tmp |= 0x02; - break; - case 0xe80: - tmp |= 0x03; - break; - default: - DDB(printk("init_deskpro: Invalid MSS port %x\n", hw_config->io_base)); - return 0; - } + { + case 0x530: + tmp |= 0x00; + break; + case 0x604: + tmp |= 0x01; + break; + case 0xf40: + tmp |= 0x02; + break; + case 0xe80: + tmp |= 0x03; + break; + default: + DDB(printk("init_deskpro: Invalid MSS port %x\n", hw_config->io_base)); + return 0; + } outb((tmp & ~0x04), 0xc44); /* Write to bank=0 */ #ifdef DEBUGXL @@ -2096,15 +2128,15 @@ printk("%02x\n", inb(0xc44)); #endif -/* - * I/O port 0xc45 FM Address Decode/MSS ID Register. - * - * bank=0, bits 0xfe: FM synthesis Decode Compare bits 7:1 (default=0x88) - * bank=0, bit 0x01: SBIC Power Control Bit - * 0x00 = Powered up - * 0x01 = Powered down - * bank=1, bits 0xfc: MSS ID (default=0x40) - */ + /* + * I/O port 0xc45 FM Address Decode/MSS ID Register. + * + * bank=0, bits 0xfe: FM synthesis Decode Compare bits 7:1 (default=0x88) + * bank=0, bit 0x01: SBIC Power Control Bit + * 0x00 = Powered up + * 0x01 = Powered down + * bank=1, bits 0xfc: MSS ID (default=0x40) + */ #ifdef DEBUGXL /* Debug printing */ @@ -2130,12 +2162,12 @@ #endif -/* - * I/O port 0xc46 FM Address Decode/Address ASIC Revision Register. - * - * bank=0, bits 0xff: FM synthesis Decode Compare bits 15:8 (default=0x03) - * bank=1, bits 0xff: Audio addressing ASIC id - */ + /* + * I/O port 0xc46 FM Address Decode/Address ASIC Revision Register. + * + * bank=0, bits 0xff: FM synthesis Decode Compare bits 15:8 (default=0x03) + * bank=1, bits 0xff: Audio addressing ASIC id + */ #ifdef DEBUGXL /* Debug printing */ @@ -2160,12 +2192,12 @@ printk("%02x\n", inb(0xc46)); #endif -/* - * I/O port 0xc47 FM Address Decode Register. - * - * bank=0, bits 0xff: Decode enable selection for various FM address bits - * bank=1, bits 0xff: Reserved - */ + /* + * I/O port 0xc47 FM Address Decode Register. + * + * bank=0, bits 0xff: Decode enable selection for various FM address bits + * bank=1, bits 0xff: Reserved + */ #ifdef DEBUGXL /* Debug printing */ @@ -2190,9 +2222,9 @@ printk("%02x\n", inb(0xc47)); #endif -/* - * I/O port 0xc6f = Audio Disable Function Register - */ + /* + * I/O port 0xc6f = Audio Disable Function Register + */ #ifdef DEBUGXL printk("Port 0xc6f (before) = %02x\n", inb(0xc6f)); @@ -2206,32 +2238,29 @@ return 1; } -#endif -int -probe_ms_sound(struct address_info *hw_config) +int probe_ms_sound(struct address_info *hw_config) { unsigned char tmp; DDB(printk("Entered probe_ms_sound(%x, %d)\n", hw_config->io_base, hw_config->card_subtype)); if (check_region(hw_config->io_base, 8)) - { - printk("MSS: I/O port conflict\n"); - return 0; - } + { + printk(KERN_ERR "MSS: I/O port conflict\n"); + return 0; + } if (hw_config->card_subtype == 1) /* Has no IRQ/DMA registers */ - { - /* check_opl3(0x388, hw_config); */ - return ad1848_detect(hw_config->io_base + 4, NULL, hw_config->osp); - } -#ifdef DESKPROXL - if (hw_config->card_subtype == 2) /* Compaq Deskpro XL */ - { - if (!init_deskpro(hw_config)) - return 0; - } -#endif + { + /* check_opl3(0x388, hw_config); */ + return ad1848_detect(hw_config->io_base + 4, NULL, hw_config->osp); + } + + if (deskpro_xl && hw_config->card_subtype == 2) /* Compaq Deskpro XL */ + { + if (!init_deskpro(hw_config)) + return 0; + } /* * Check if the IO port returns valid signature. The original MS Sound @@ -2240,58 +2269,57 @@ */ if ((tmp = inb(hw_config->io_base + 3)) == 0xff) /* Bus float */ - { + { int ret; DDB(printk("I/O address is inactive (%x)\n", tmp)); if (!(ret = ad1848_detect(hw_config->io_base + 4, NULL, hw_config->osp))) return 0; return 1; - } + } DDB(printk("MSS signature = %x\n", tmp & 0x3f)); if ((tmp & 0x3f) != 0x04 && (tmp & 0x3f) != 0x0f && (tmp & 0x3f) != 0x00) - { - int ret; + { + int ret; - MDB(printk("No MSS signature detected on port 0x%x (0x%x)\n", hw_config->io_base, (int) inb(hw_config->io_base + 3))); - DDB(printk("Trying to detect codec anyway but IRQ/DMA may not work\n")); - if (!(ret = ad1848_detect(hw_config->io_base + 4, NULL, hw_config->osp))) - return 0; + MDB(printk(KERN_ERR "No MSS signature detected on port 0x%x (0x%x)\n", hw_config->io_base, (int) inb(hw_config->io_base + 3))); + DDB(printk("Trying to detect codec anyway but IRQ/DMA may not work\n")); + if (!(ret = ad1848_detect(hw_config->io_base + 4, NULL, hw_config->osp))) + return 0; - hw_config->card_subtype = 1; - return 1; - } + hw_config->card_subtype = 1; + return 1; + } if (hw_config->irq > 11) - { - printk("MSS: Bad IRQ %d\n", hw_config->irq); - return 0; - } + { + printk(KERN_ERR "MSS: Bad IRQ %d\n", hw_config->irq); + return 0; + } if (hw_config->dma != 0 && hw_config->dma != 1 && hw_config->dma != 3) - { - printk("MSS: Bad DMA %d\n", hw_config->dma); + { + printk(KERN_ERR "MSS: Bad DMA %d\n", hw_config->dma); return 0; - } + } /* - * Check that DMA0 is not in use with a 8 bit board. + * Check that DMA0 is not in use with a 8 bit board. */ if (hw_config->dma == 0 && inb(hw_config->io_base + 3) & 0x80) - { - printk("MSS: Can't use DMA0 with a 8 bit card/slot\n"); - return 0; - } + { + printk(KERN_ERR "MSS: Can't use DMA0 with a 8 bit card/slot\n"); + return 0; + } if (hw_config->irq > 7 && hw_config->irq != 9 && inb(hw_config->io_base + 3) & 0x80) - { - printk("MSS: Can't use IRQ%d with a 8 bit card/slot\n", hw_config->irq); - return 0; - } + { + printk(KERN_ERR "MSS: Can't use IRQ%d with a 8 bit card/slot\n", hw_config->irq); + return 0; + } return ad1848_detect(hw_config->io_base + 4, NULL, hw_config->osp); } -void -attach_ms_sound(struct address_info *hw_config) +void attach_ms_sound(struct address_info *hw_config) { static char interrupt_bits[12] = { @@ -2304,63 +2332,65 @@ 1, 2, 0, 3 }; - int config_port = hw_config->io_base + 0; - int version_port = hw_config->io_base + 3; - int dma = hw_config->dma; - int dma2 = hw_config->dma2; + int config_port = hw_config->io_base + 0; + int version_port = hw_config->io_base + 3; + int dma = hw_config->dma; + int dma2 = hw_config->dma2; if (hw_config->card_subtype == 1) /* Has no IRQ/DMA registers */ - { - hw_config->slots[0] = ad1848_init("MS Sound System", hw_config->io_base + 4, + { + hw_config->slots[0] = ad1848_init("MS Sound System", hw_config->io_base + 4, hw_config->irq, hw_config->dma, hw_config->dma2, 0, hw_config->osp); - request_region(hw_config->io_base, 4, "WSS config"); - return; - } + request_region(hw_config->io_base, 4, "WSS config"); + return; + } /* - * Set the IRQ and DMA addresses. + * Set the IRQ and DMA addresses. */ bits = interrupt_bits[hw_config->irq]; if (bits == -1) - { - printk("MSS: Bad IRQ %d\n", hw_config->irq); - return; - } + { + printk(KERN_ERR "MSS: Bad IRQ %d\n", hw_config->irq); + return; + } outb((bits | 0x40), config_port); if ((inb(version_port) & 0x40) == 0) - printk("[MSS: IRQ Conflict?]"); + printk(KERN_ERR "[MSS: IRQ Conflict?]\n"); /* * Handle the capture DMA channel */ if (dma2 != -1 && dma2 != dma) - { - if (!((dma == 0 && dma2 == 1) || + { + if (!((dma == 0 && dma2 == 1) || (dma == 1 && dma2 == 0) || (dma == 3 && dma2 == 0))) - { /* Unsupported combination. Try to swap channels */ - int tmp = dma; + { /* Unsupported combination. Try to swap channels */ + int tmp = dma; - dma = dma2; - dma2 = tmp; - } - if ((dma == 0 && dma2 == 1) || - (dma == 1 && dma2 == 0) || - (dma == 3 && dma2 == 0)) - { - dma2_bit = 0x04; /* Enable capture DMA */ - } else - { - printk("MSS: Invalid capture DMA\n"); - dma2 = dma; - } - } else - { - dma2 = dma; - } + dma = dma2; + dma2 = tmp; + } + if ((dma == 0 && dma2 == 1) || + (dma == 1 && dma2 == 0) || + (dma == 3 && dma2 == 0)) + { + dma2_bit = 0x04; /* Enable capture DMA */ + } + else + { + printk(KERN_WARNING "MSS: Invalid capture DMA\n"); + dma2 = dma; + } + } + else + { + dma2 = dma; + } hw_config->dma = dma; hw_config->dma2 = dma2; @@ -2375,8 +2405,7 @@ request_region(hw_config->io_base, 4, "WSS config"); } -void -unload_ms_sound(struct address_info *hw_config) +void unload_ms_sound(struct address_info *hw_config) { int mixer = audio_devs[hw_config->slots[0]]->mixer_dev; ad1848_unload(hw_config->io_base + 4, @@ -2387,18 +2416,17 @@ sound_unload_mixerdev(mixer); sound_unload_audiodev(hw_config->slots[0]); release_region(hw_config->io_base, 4); - } #if (defined(CONFIG_SEQUENCER) && !defined(EXCLUDE_TIMERS)) || defined(MODULE) + /* * Timer stuff (for /dev/music). */ static unsigned int current_interval = 0; -static unsigned int -ad1848_tmr_start(int dev, unsigned int usecs) +static unsigned int ad1848_tmr_start(int dev, unsigned int usecs) { unsigned long flags; ad1848_info *devc = (ad1848_info *) audio_devs[dev]->devc; @@ -2408,16 +2436,16 @@ save_flags(flags); cli(); -/* - * Length of the timer interval (in nanoseconds) depends on the - * selected crystal oscillator. Check this from bit 0x01 of I8. - * - * AD1845 has just one oscillator which has cycle time of 10.050 us - * (when a 24.576 MHz xtal oscillator is used). - * - * Convert requested interval to nanoseconds before computing - * the timer divider. - */ + /* + * Length of the timer interval (in nanoseconds) depends on the + * selected crystal oscillator. Check this from bit 0x01 of I8. + * + * AD1845 has just one oscillator which has cycle time of 10.050 us + * (when a 24.576 MHz xtal oscillator is used). + * + * Convert requested interval to nanoseconds before computing + * the timer divider. + */ if (devc->model == MD_1845) xtal_nsecs = 10050; @@ -2443,20 +2471,18 @@ return current_interval = (divider * xtal_nsecs + 500) / 1000; } -static void -ad1848_tmr_reprogram(int dev) +static void ad1848_tmr_reprogram(int dev) { -/* - * Audio driver has changed sampling rate so that a different xtal - * oscillator was selected. We have to reprogram the timer rate. - */ + /* + * Audio driver has changed sampling rate so that a different xtal + * oscillator was selected. We have to reprogram the timer rate. + */ ad1848_tmr_start(dev, current_interval); sound_timer_syncinterval(current_interval); } -static void -ad1848_tmr_disable(int dev) +static void ad1848_tmr_disable(int dev) { unsigned long flags; ad1848_info *devc = (ad1848_info *) audio_devs[dev]->devc; @@ -2468,8 +2494,7 @@ restore_flags(flags); } -static void -ad1848_tmr_restart(int dev) +static void ad1848_tmr_restart(int dev) { unsigned long flags; ad1848_info *devc = (ad1848_info *) audio_devs[dev]->devc; @@ -2493,10 +2518,8 @@ ad1848_tmr_restart }; -static int -ad1848_tmr_install(int dev) +static int ad1848_tmr_install(int dev) { - if (timer_installed != -1) return 0; /* Don't install another timer */ @@ -2524,6 +2547,7 @@ MODULE_PARM(dma, "i"); MODULE_PARM(dma2, "i"); MODULE_PARM(type, "i"); +MODULE_PARM(deskpro_xl, "i"); int io = -1; int irq = -1; @@ -2538,7 +2562,7 @@ int init_module(void) { - printk("ad1848/cs4248 codec driver Copyright (C) by Hannu Savolainen 1993-1996\n"); + printk(KERN_INFO "ad1848/cs4248 codec driver Copyright (C) by Hannu Savolainen 1993-1996\n"); if(io!=-1) { if(irq == -1 || dma == -1) @@ -2560,8 +2584,7 @@ return 0; } -void -cleanup_module(void) +void cleanup_module(void) { SOUND_LOCK_END; if(loaded) @@ -2570,8 +2593,7 @@ #else -void -export_ad1848_syms(void) +void export_ad1848_syms(void) { } diff -u --recursive --new-file v2.1.78/linux/drivers/sound/pas2_card.c linux/drivers/sound/pas2_card.c --- v2.1.78/linux/drivers/sound/pas2_card.c Sat Nov 29 11:25:11 1997 +++ linux/drivers/sound/pas2_card.c Tue Jan 6 19:29:20 1998 @@ -11,14 +11,22 @@ #if defined(CONFIG_PAS) || defined(MODULE) -static unsigned char dma_bits[] = -{4, 1, 2, 3, 0, 5, 6, 7}; -static unsigned char irq_bits[] = -{0, 0, 1, 2, 3, 4, 5, 6, 0, 1, 7, 8, 9, 0, 10, 11}; -static unsigned char sb_irq_bits[] = -{0x00, 0x00, 0x08, 0x10, 0x00, 0x18, 0x00, 0x20, 0x00, 0x08, 0x28, 0x30, 0x38, 0, 0}; -static unsigned char sb_dma_bits[] = -{0x00, 0x40, 0x80, 0xC0, 0, 0, 0, 0}; +static unsigned char dma_bits[] = { + 4, 1, 2, 3, 0, 5, 6, 7 +}; + +static unsigned char irq_bits[] = { + 0, 0, 1, 2, 3, 4, 5, 6, 0, 1, 7, 8, 9, 0, 10, 11 +}; + +static unsigned char sb_irq_bits[] = { + 0x00, 0x00, 0x08, 0x10, 0x00, 0x18, 0x00, 0x20, + 0x00, 0x08, 0x28, 0x30, 0x38, 0, 0 +}; + +static unsigned char sb_dma_bits[] = { + 0x00, 0x40, 0x80, 0xC0, 0, 0, 0, 0 +}; /* * The Address Translation code is used to convert I/O register addresses to @@ -32,32 +40,35 @@ char pas_model = 0; -static char *pas_model_names[] = -{"", "Pro AudioSpectrum+", "CDPC", "Pro AudioSpectrum 16", "Pro AudioSpectrum 16D"}; +static char *pas_model_names[] = { + "", + "Pro AudioSpectrum+", + "CDPC", + "Pro AudioSpectrum 16", + "Pro AudioSpectrum 16D" +}; /* * pas_read() and pas_write() are equivalents of inb and outb * These routines perform the I/O address translation required * to support other than the default base address */ + extern void mix_write(unsigned char data, int ioaddr); -unsigned char -pas_read(int ioaddr) +unsigned charpas_read(int ioaddr) { return inb(ioaddr ^ translate_code); } -void -pas_write(unsigned char data, int ioaddr) +void pas_write(unsigned char data, int ioaddr) { outb((data), ioaddr ^ translate_code); } /******************* Begin of the Interrupt Handler ********************/ -static void -pasintr(int irq, void *dev_id, struct pt_regs *dummy) +static void pasintr(int irq, void *dev_id, struct pt_regs *dummy) { int status; @@ -65,23 +76,22 @@ pas_write(status, 0x0B89); /* Clear interrupt */ if (status & 0x08) - { + { #ifdef CONFIG_AUDIO pas_pcm_interrupt(status, 1); #endif status &= ~0x08; - } + } if (status & 0x10) - { + { #if defined(CONFIG_MIDI) pas_midi_interrupt(); #endif status &= ~0x10; - } + } } -int -pas_set_intr(int mask) +int pas_set_intr(int mask) { if (!mask) return 0; @@ -92,8 +102,7 @@ return 0; } -int -pas_remove_intr(int mask) +int pas_remove_intr(int mask) { if (!mask) return 0; @@ -110,8 +119,7 @@ extern struct address_info sbhw_config; -static int -config_pas_hw(struct address_info *hw_config) +static int config_pas_hw(struct address_info *hw_config) { char ok = 1; unsigned int_ptrs; /* scsi/sound interrupt pointers */ @@ -129,8 +137,8 @@ pas_write(0x80 | 0x40 | 0x20 | 1, 0x0B8A); pas_write(0x80 | 0x20 | 0x10 | 0x08 | 0x01, 0xF8A); pas_write(0x01 | 0x02 | 0x04 | 0x10 /* - * | - * 0x80 + * | + * 0x80 */ , 0xB88); pas_write(0x80 @@ -140,49 +148,53 @@ ,0xF388); if (pas_irq < 0 || pas_irq > 15) - { - printk("PAS16: Invalid IRQ %d", pas_irq); - ok = 0; - } else - { - int_ptrs = pas_read(0xF38A); - int_ptrs |= irq_bits[pas_irq] & 0xf; - pas_write(int_ptrs, 0xF38A); - if (!irq_bits[pas_irq]) - { - printk("PAS16: Invalid IRQ %d", pas_irq); - ok = 0; - } else - { - if (snd_set_irq_handler(pas_irq, pasintr, "PAS16", hw_config->osp) < 0) - ok = 0; - } - } + { + printk(KERN_ERR "PAS16: Invalid IRQ %d", pas_irq); + ok = 0; + } + else + { + int_ptrs = pas_read(0xF38A); + int_ptrs |= irq_bits[pas_irq] & 0xf; + pas_write(int_ptrs, 0xF38A); + if (!irq_bits[pas_irq]) + { + printk(KERN_ERR "PAS16: Invalid IRQ %d", pas_irq); + ok = 0; + } + else + { + if (snd_set_irq_handler(pas_irq, pasintr, "PAS16", hw_config->osp) < 0) + ok = 0; + } + } if (hw_config->dma < 0 || hw_config->dma > 7) - { - printk("PAS16: Invalid DMA selection %d", hw_config->dma); - ok = 0; - } else - { - pas_write(dma_bits[hw_config->dma], 0xF389); - if (!dma_bits[hw_config->dma]) - { - printk("PAS16: Invalid DMA selection %d", hw_config->dma); - ok = 0; - } else - { - if (sound_alloc_dma(hw_config->dma, "PAS16")) - { - printk("pas2_card.c: Can't allocate DMA channel\n"); - ok = 0; - } - } - } + { + printk(KERN_ERR "PAS16: Invalid DMA selection %d", hw_config->dma); + ok = 0; + } + else + { + pas_write(dma_bits[hw_config->dma], 0xF389); + if (!dma_bits[hw_config->dma]) + { + printk(KERN_ERR "PAS16: Invalid DMA selection %d", hw_config->dma); + ok = 0; + } + else + { + if (sound_alloc_dma(hw_config->dma, "PAS16")) + { + printk(KERN_ERR "pas2_card.c: Can't allocate DMA channel\n"); + ok = 0; + } + } + } /* - * This fixes the timing problems of the PAS due to the Symphony chipset - * as per Media Vision. Only define this if your PAS doesn't work correctly. + * This fixes the timing problems of the PAS due to the Symphony chipset + * as per Media Vision. Only define this if your PAS doesn't work correctly. */ #ifdef SYMPHONY_PAS outb((0x05), 0xa8); @@ -215,33 +227,36 @@ sb_config = &sbhw_config; if (sb_config->io_base) #endif - { - unsigned char irq_dma; - - /* - * Turn on Sound Blaster compatibility - * bit 1 = SB emulation - * bit 0 = MPU401 emulation (CDPC only :-( ) - */ - pas_write(0x02, 0xF788); - - /* - * "Emulation address" - */ - pas_write((sb_config->io_base >> 4) & 0x0f, 0xF789); - pas_sb_base = sb_config->io_base; - - if (!sb_dma_bits[sb_config->dma]) - printk("\n\nPAS16 Warning: Invalid SB DMA %d\n\n", sb_config->dma); - - if (!sb_irq_bits[sb_config->irq]) - printk("\n\nPAS16 Warning: Invalid SB IRQ %d\n\n", sb_config->irq); - - irq_dma = sb_dma_bits[sb_config->dma] | - sb_irq_bits[sb_config->irq]; + { + unsigned char irq_dma; - pas_write(irq_dma, 0xFB8A); - } else + /* + * Turn on Sound Blaster compatibility + * bit 1 = SB emulation + * bit 0 = MPU401 emulation (CDPC only :-( ) + */ + + pas_write(0x02, 0xF788); + + /* + * "Emulation address" + */ + + pas_write((sb_config->io_base >> 4) & 0x0f, 0xF789); + pas_sb_base = sb_config->io_base; + + if (!sb_dma_bits[sb_config->dma]) + printk(KERN_ERR "PAS16 Warning: Invalid SB DMA %d\n\n", sb_config->dma); + + if (!sb_irq_bits[sb_config->irq]) + printk(KERN_ERR "PAS16 Warning: Invalid SB IRQ %d\n\n", sb_config->irq); + + irq_dma = sb_dma_bits[sb_config->dma] | + sb_irq_bits[sb_config->irq]; + + pas_write(irq_dma, 0xFB8A); + } + else pas_write(0x00, 0xF788); } #else @@ -249,13 +264,12 @@ #endif if (!ok) - printk("PAS16: Driver not enabled\n"); + printk(KERN_WARNING "PAS16: Driver not enabled\n"); return ok; } -static int -detect_pas_hw(struct address_info *hw_config) +static int detect_pas_hw(struct address_info *hw_config) { unsigned char board_id, foo; @@ -296,40 +310,39 @@ return pas_model; } -void -attach_pas_card(struct address_info *hw_config) +void attach_pas_card(struct address_info *hw_config) { pas_irq = hw_config->irq; if (detect_pas_hw(hw_config)) - { + { - if ((pas_model = pas_read(0xFF88))) - { - char temp[100]; + if ((pas_model = pas_read(0xFF88))) + { + char temp[100]; - sprintf(temp, + sprintf(temp, "%s rev %d", pas_model_names[(int) pas_model], pas_read(0x2789)); - conf_printf(temp, hw_config); - } - if (config_pas_hw(hw_config)) - { + conf_printf(temp, hw_config); + } + if (config_pas_hw(hw_config)) + { #ifdef CONFIG_AUDIO - pas_pcm_init(hw_config); + pas_pcm_init(hw_config); #endif #if !defined(DISABLE_SB_EMULATION) && (defined(CONFIG_SB) || defined(CONFIG_SB_MODULE)) - sb_dsp_disable_midi(pas_sb_base); /* No MIDI capability */ + sb_dsp_disable_midi(pas_sb_base); /* No MIDI capability */ #endif #if defined(CONFIG_MIDI) - pas_midi_init(); + pas_midi_init(); #endif - pas_init_mixer(); - } - } + pas_init_mixer(); + } + } } int @@ -357,18 +370,28 @@ int sb_dma = -1; int sb_dma16 = -1; +MODULE_PARM(io,"i"); +MODULE_PARM(irq,"i"); +MODULE_PARM(dma,"i"); +MODULE_PARM(dma16,"i"); + +MODULE_PARM(sb_io,"i"); +MODULE_PARM(sb_irq,"i"); +MODULE_PARM(sb_dma,"i"); +MODULE_PARM(sb_dma16,"i"); + struct address_info config; struct address_info sbhw_config; int init_module(void) { - printk("MediaTrix audio driver Copyright (C) by Hannu Savolainen 1993-1996\n"); + printk(KERN_INFO "MediaTrix audio driver Copyright (C) by Hannu Savolainen 1993-1996\n"); if (io == -1 || dma == -1 || irq == -1) - { - printk("I/O, IRQ, DMA and type are mandatory\n"); + { + printk(KERN_INFO "I/O, IRQ, DMA and type are mandatory\n"); return -EINVAL; - } + } config.io_base = io; config.irq = irq; config.dma = dma; @@ -386,8 +409,7 @@ return 0; } -void -cleanup_module(void) +void cleanup_module(void) { unload_pas(&config); SOUND_LOCK_END; diff -u --recursive --new-file v2.1.78/linux/fs/affs/Changes linux/fs/affs/Changes --- v2.1.78/linux/fs/affs/Changes Thu Dec 4 14:53:56 1997 +++ linux/fs/affs/Changes Tue Jan 6 13:33:29 1998 @@ -21,10 +21,31 @@ might leave a trashed file system with the bitmap flag set valid. -- The blocks from deleted directories are - sometimes reclaimed only at umount time. +- When a file is truncated to a size that is not + a multiple of the blocksize, the rest of the + last allocated block is not cleared. Well, + this fs never claimed to be Posix conformant. Please direct bug reports to: hjw@zvw.de + +Version 3.7 +----------- + +- Added dentry callbacks to allow the dcache to + operate case insensitive and length ignorant + like the affs itself. + +- getblock() didn't update the lastblock field in the + inode if the fs was not an OFS. This bug only shows + up if a file was enlarged via truncate() and there + was not enough space. + +- Remove some more superfluous code left over from + the old link days ... + +- Fixed some oversights which were in patch 2.1.78. + +- Fixed a few typos. Version 3.6 ----------- diff -u --recursive --new-file v2.1.78/linux/fs/affs/file.c linux/fs/affs/file.c --- v2.1.78/linux/fs/affs/file.c Thu Dec 4 14:53:56 1997 +++ linux/fs/affs/file.c Tue Jan 6 13:33:29 1998 @@ -12,6 +12,7 @@ * affs regular file handling primitives */ +#define DEBUG 0 #include #include #include @@ -417,6 +418,7 @@ nkey = affs_new_data(inode); if (!nkey) break; + inode->u.affs_i.i_lastblock++; lock_super(inode->i_sb); if (AFFS_BLOCK(bh->b_data,inode,j)) { unlock_super(inode->i_sb); @@ -436,7 +438,6 @@ AFFS_BLOCK(bh->b_data,inode,j) = 0; break; } - inode->u.affs_i.i_lastblock++; DATA_FRONT(ebh)->primary_type = cpu_to_be32(T_DATA); DATA_FRONT(ebh)->header_key = cpu_to_be32(inode->i_ino); DATA_FRONT(ebh)->sequence_number = cpu_to_be32(inode->u.affs_i.i_lastblock + 1); @@ -750,7 +751,7 @@ int rem; int ext; - pr_debug("AFFS: file_truncate(inode=%ld,size=%lu)\n",inode->i_ino,inode->i_size); + pr_debug("AFFS: truncate(inode=%ld,size=%lu)\n",inode->i_ino,inode->i_size); blocksize = AFFS_I2BSIZE(inode) - ((inode->i_sb->u.affs_sb.s_flags & SF_OFS) ? 24 : 0); first = (inode->i_size + blocksize - 1) / blocksize; @@ -777,7 +778,7 @@ unlock_super(inode->i_sb); } if (!bh) { - affs_error(inode->i_sb,"truncate","Cannot extend file"); + affs_warning(inode->i_sb,"truncate","Cannot extend file"); inode->i_size = blocksize * (inode->u.affs_i.i_lastblock + 1); } else if (inode->i_sb->u.affs_sb.s_flags & SF_OFS) { rem = inode->i_size % blocksize; @@ -798,12 +799,6 @@ } ptype = be32_to_cpu(((struct file_front *)bh->b_data)->primary_type); stype = be32_to_cpu(FILE_END(bh->b_data,inode)->secondary_type); - if (ekey == inode->i_ino && ptype == T_SHORT && stype == ST_LINKFILE && - LINK_END(bh->b_data,inode)->original == 0) { - pr_debug("AFFS: truncate(): dumping link\n"); - affs_brelse(bh); - break; - } if (stype != ST_FILE || (ptype != T_SHORT && ptype != T_LIST)) { affs_error(inode->i_sb,"truncate","Bad block (ptype=%d, stype=%d)", ptype,stype); diff -u --recursive --new-file v2.1.78/linux/fs/affs/namei.c linux/fs/affs/namei.c --- v2.1.78/linux/fs/affs/namei.c Thu Dec 4 14:53:56 1997 +++ linux/fs/affs/namei.c Tue Jan 6 13:33:29 1998 @@ -21,7 +21,7 @@ #include -/* Simple toupper() for DOS\1 */ +/* Simple toupper()/tolower() for DOS\1 */ static inline unsigned int affs_toupper(unsigned int ch) @@ -29,7 +29,13 @@ return ch >= 'a' && ch <= 'z' ? ch -= ('a' - 'A') : ch; } -/* International toupper() for DOS\3 */ +static inline unsigned int +affs_tolower(unsigned int ch) +{ + return ch >= 'A' && ch <= 'Z' ? ch + ('a' - 'A') : ch; +} + +/* International toupper()/tolower() for DOS\3 ("international") */ static inline unsigned int affs_intl_toupper(unsigned int ch) @@ -39,6 +45,112 @@ ch - ('a' - 'A') : ch; } +static inline unsigned int +affs_intl_tolower(unsigned int ch) +{ + return (ch >= 'A' && ch <= 'Z') || (ch >= 0xC0 + && ch <= 0xDE && ch != 0xD7) ? + ch + ('a' - 'A') : ch; +} + +/* We need 2 sets of dentry operations, since we cannot + * determine the fs flavour in the callback routines. + */ + +static int affs_hash_dentry(struct dentry *, struct qstr *); +static int affs_compare_dentry(struct dentry *, struct qstr *, struct qstr *); +static int affs_hash_dentry_intl(struct dentry *, struct qstr *); +static int affs_compare_dentry_intl(struct dentry *, struct qstr *, struct qstr *); + +struct dentry_operations affs_dentry_operations = { + NULL, /* d_validate */ + affs_hash_dentry, /* d_hash */ + affs_compare_dentry, /* d_compare */ + NULL /* d_delete */ +}; + +struct dentry_operations affs_dentry_operations_intl = { + NULL, /* d_validate */ + affs_hash_dentry_intl, /* d_hash */ + affs_compare_dentry_intl, /* d_compare */ + NULL /* d_delete */ +}; + +static int +affs_hash_dentry(struct dentry *dentry, struct qstr *qstr) +{ + unsigned long hash; + int i; + + if ((i = affs_check_name(qstr->name,qstr->len))) + return i; + hash = init_name_hash(); + for (i = 0; i < qstr->len && i < 30; i++) + hash = partial_name_hash(affs_tolower(qstr->name[i]),hash); + qstr->hash = end_name_hash(hash); + + return 0; +} + +static int +affs_compare_dentry(struct dentry *dentry, struct qstr *a, struct qstr *b) +{ + int i; + + /* 'a' is the qstr of an already existing dentry, so the name + * must be valid. 'b' must be validated first. + */ + + if (affs_check_name(b->name,b->len)) + return 1; + + /* If the names are longer than the allowed 30 chars, + * the excess is ignored, so their length may differ. + */ + + if ((a->len < 30 || b->len < 30) && a->len != b->len) + return 1; + + for (i = 0; i < a->len && i < 30; i++) + if (affs_tolower(a->name[i]) != affs_tolower(b->name[i])) + return 1; + + return 0; +} + +static int +affs_hash_dentry_intl(struct dentry *dentry, struct qstr *qstr) +{ + unsigned long hash; + int i; + + if ((i = affs_check_name(qstr->name,qstr->len))) + return i; + hash = init_name_hash(); + for (i = 0; i < qstr->len && i < 30; i++) + hash = partial_name_hash(affs_intl_tolower(qstr->name[i]),hash); + qstr->hash = end_name_hash(hash); + + return 0; +} + +static int +affs_compare_dentry_intl(struct dentry *dentry, struct qstr *a, struct qstr *b) +{ + int i; + + if (affs_check_name(b->name,b->len)) + return 1; + if ((a->len < 30 || b->len < 30) && a->len != b->len) + return 1; + + for (i = 0; i < a->len && i < 30; i++) + if (affs_intl_tolower(a->name[i]) != affs_intl_tolower(b->name[i])) + return 1; + + return 0; +} + /* * NOTE! unlike strncmp, affs_match returns 1 for success, 0 for failure. */ @@ -162,6 +274,8 @@ if (!inode) return -EACCES; } + dentry->d_op = AFFS_I2FSTYPE(dir) ? &affs_dentry_operations_intl + : &affs_dentry_operations; d_add(dentry,inode); return 0; } @@ -422,8 +536,9 @@ } int -affs_link(struct inode *oldinode, struct inode *dir, struct dentry *dentry) +affs_link(struct dentry *old_dentry, struct inode *dir, struct dentry *dentry) { + struct inode *oldinode = old_dentry->d_inode; struct inode *inode; struct buffer_head *bh; unsigned long i; diff -u --recursive --new-file v2.1.78/linux/fs/affs/super.c linux/fs/affs/super.c --- v2.1.78/linux/fs/affs/super.c Thu Dec 4 14:53:56 1997 +++ linux/fs/affs/super.c Tue Jan 6 13:33:29 1998 @@ -494,7 +494,7 @@ if (bb) { if (affs_checksum_block(s->s_blocksize,bb->b_data,NULL,NULL) && !(s->s_flags & MS_RDONLY)) { - printk(KERN_WARNING "AFFS: Bitmap (%d,key=%lu) invalid - " + printk(KERN_WARNING "AFFS: Bitmap (%d,key=%u) invalid - " "mounting %s read only.\n",mapidx,be32_to_cpu(bm[i]), kdevname(dev)); s->s_flags |= MS_RDONLY; @@ -572,6 +572,8 @@ MOD_DEC_USE_COUNT; return NULL; } + s->s_root->d_op = (s->u.affs_sb.s_flags & SF_INTL) ? &affs_dentry_operations_intl + : &affs_dentry_operations; /* Record date of last change if the bitmap was truncated and * create data zones if the volume is writable. diff -u --recursive --new-file v2.1.78/linux/fs/affs/symlink.c linux/fs/affs/symlink.c --- v2.1.78/linux/fs/affs/symlink.c Tue Jan 6 09:37:36 1998 +++ linux/fs/affs/symlink.c Tue Jan 6 13:33:29 1998 @@ -44,7 +44,7 @@ }; static int -affs_readlink(struct inode *dentry, char *buffer, int buflen) +affs_readlink(struct dentry *dentry, char *buffer, int buflen) { struct inode *inode = dentry->d_inode; struct buffer_head *bh; diff -u --recursive --new-file v2.1.78/linux/fs/coda/cache.c linux/fs/coda/cache.c --- v2.1.78/linux/fs/coda/cache.c Tue Dec 23 16:31:00 1997 +++ linux/fs/coda/cache.c Tue Jan 6 10:00:21 1998 @@ -236,7 +236,7 @@ if ( cnp ) CHECK_CNODE(cnp); } else { - printk("No inode for dentry_delete!\n"); + CDEBUG(D_CACHE, "No inode for dentry_delete!\n"); return; } @@ -254,6 +254,14 @@ return; } +static void coda_zap_cnode(struct cnode *cnp, int flags) +{ + cnp->c_flags |= flags; + coda_cache_clear_cnp(cnp); +} + + + /* the dache will notice the flags and drop entries (possibly with children) the moment they are no longer in use */ void coda_zapfid(struct ViceFid *fid, struct super_block *sb, int flag) @@ -273,9 +281,22 @@ return; } + if ( coda_fid_is_volroot(fid) ) { + struct list_head *lh, *le; + struct coda_sb_info *sbi = coda_sbp(sb); + le = lh = &sbi->sbi_volroothead; + while ( (le = le->next) != lh ) { + cnp = list_entry(le, struct cnode, c_volrootlist); + if ( cnp->c_fid.Volume == fid->Volume) + coda_zap_cnode(cnp, flag); + } + return; + } + + inode = coda_fid_to_inode(fid, sb); if ( !inode ) { - printk("coda_zapfid: no inode!\n"); + CDEBUG(D_CACHE, "coda_zapfid: no inode!\n"); return; } cnp = ITOC(inode); @@ -284,8 +305,7 @@ printk("coda_zapfid: no cnode!\n"); return; } - cnp->c_flags |= flag; - coda_cache_clear_cnp(cnp); + coda_zap_cnode(cnp, flag); } diff -u --recursive --new-file v2.1.78/linux/fs/coda/cnode.c linux/fs/coda/cnode.c --- v2.1.78/linux/fs/coda/cnode.c Sun Dec 21 22:36:16 1997 +++ linux/fs/coda/cnode.c Tue Jan 6 10:00:21 1998 @@ -7,8 +7,8 @@ #include #include -#include #include +#include extern int coda_debug; extern int coda_print_entry; @@ -29,6 +29,7 @@ memset(result, 0, (int) sizeof(struct cnode)); INIT_LIST_HEAD(&(result->c_cnhead)); + INIT_LIST_HEAD(&(result->c_volrootlist)); return result; } @@ -70,6 +71,7 @@ int coda_cnode_make(struct inode **inode, ViceFid *fid, struct super_block *sb) { struct cnode *cnp; + struct coda_sb_info *sbi= coda_sbp(sb); struct coda_vattr attr; int error; ino_t ino; @@ -119,6 +121,9 @@ CHECK_CNODE(cnp); /* fill in the inode attributes */ + if ( coda_fid_is_volroot(fid) ) + list_add(&cnp->c_volrootlist, &sbi->sbi_volroothead); + coda_fill_inode(*inode, &attr); CDEBUG(D_CNODE, "Done linking: ino %ld, at 0x%x with cnp 0x%x, cnp->c_vnode 0x%x\n", (*inode)->i_ino, (int) (*inode), (int) cnp, (int)cnp->c_vnode); @@ -148,6 +153,7 @@ ENTRY; CDEBUG(D_INODE, "%s\n", coda_f2s(fid, str)); + nr = coda_f2i(fid); inode = iget(sb, nr); diff -u --recursive --new-file v2.1.78/linux/fs/coda/coda_linux.c linux/fs/coda/coda_linux.c --- v2.1.78/linux/fs/coda/coda_linux.c Sun Dec 21 22:36:16 1997 +++ linux/fs/coda/coda_linux.c Tue Jan 6 10:00:21 1998 @@ -97,6 +97,11 @@ } +int coda_fid_is_volroot(struct ViceFid *fid) +{ + return ( (fid->Vnode == 1) && (fid->Unique == 1 ) ); +} + /* utility functions below */ void coda_vattr_to_iattr(struct inode *inode, struct coda_vattr *attr) { @@ -155,7 +160,6 @@ void coda_iattr_to_vattr(struct iattr *iattr, struct coda_vattr *vattr) { - umode_t mode; unsigned int valid; /* clean out */ @@ -170,15 +174,16 @@ vattr->va_mtime.tv_nsec = (time_t) -1; vattr->va_ctime.tv_nsec = (time_t) -1; vattr->va_type = C_VNON; - vattr->va_fileid = (long)-1; - vattr->va_gen = (long)-1; - vattr->va_bytes = (long)-1; - vattr->va_nlink = (short)-1; - vattr->va_blocksize = (long)-1; - vattr->va_rdev = (dev_t)-1; + vattr->va_fileid = -1; + vattr->va_gen = -1; + vattr->va_bytes = -1; + vattr->va_nlink = -1; + vattr->va_blocksize = -1; + vattr->va_rdev = -1; vattr->va_flags = 0; /* determine the type */ +#if 0 mode = iattr->ia_mode; if ( S_ISDIR(mode) ) { vattr->va_type = C_VDIR; @@ -190,6 +195,7 @@ /* don't do others */ vattr->va_type = C_VNON; } +#endif /* set those vattrs that need change */ valid = iattr->ia_valid; @@ -219,7 +225,6 @@ } } - void print_vattr(struct coda_vattr *attr) { diff -u --recursive --new-file v2.1.78/linux/fs/coda/dir.c linux/fs/coda/dir.c --- v2.1.78/linux/fs/coda/dir.c Sun Dec 21 22:36:16 1997 +++ linux/fs/coda/dir.c Tue Jan 6 10:00:21 1998 @@ -27,7 +27,7 @@ /* dir inode-ops */ static int coda_create(struct inode *dir, struct dentry *new, int mode); static int coda_lookup(struct inode *dir, struct dentry *target); -static int coda_link(struct inode *old_inode, struct inode *dir_inode, +static int coda_link(struct dentry *old_dentry, struct inode *dir_inode, struct dentry *entry); static int coda_unlink(struct inode *dir_inode, struct dentry *entry); static int coda_symlink(struct inode *dir_inode, struct dentry *entry, @@ -243,19 +243,19 @@ char str[50]; CDEBUG(D_INODE, "create: %s, result %d\n", coda_f2s(&newfid, str), error); + d_drop(de); return error; } error = coda_cnode_make(&result, &newfid, dir->i_sb); if ( error ) { + d_drop(de); result = NULL; return error; } /* invalidate the directory cnode's attributes */ dircnp->c_flags &= ~C_VATTR; -/* cfsnc_zapfid(&(dircnp->c_fid)); */ - d_instantiate(de, result); return 0; } @@ -276,8 +276,10 @@ printk("coda_mkdir: inode is NULL or not a directory\n"); return -ENOENT; } + if ( len > CFS_MAXNAMLEN ) return -ENAMETOOLONG; + if (coda_isroot(dir) && coda_iscontrol(name, len)) return -EPERM; @@ -294,6 +296,7 @@ if ( error ) { CDEBUG(D_INODE, "mkdir error: %s result %d\n", coda_f2s(&newfid, fidstr), error); + d_drop(de); return error; } @@ -301,21 +304,23 @@ coda_f2s(&newfid, fidstr)); error = coda_cnode_make(&inode, &newfid, dir->i_sb); - if ( error ) - return error; + if ( error ) { + d_drop(de); + return error; + } /* invalidate the directory cnode's attributes */ dircnp->c_flags &= ~C_VATTR; -/* cfsnc_zapfid(&(dircnp->c_fid)); */ - dir->i_nlink++; d_instantiate(de, inode); return 0; } -static int coda_link(struct inode *inode, struct inode *dir_inode, +/* try to make de an entry in dir_inodde linked to source_de */ +static int coda_link(struct dentry *source_de, struct inode *dir_inode, struct dentry *de) { + struct inode *inode = source_de->d_inode; const char * name = de->d_name.name; int len = de->d_name.len; struct cnode *dir_cnp, *cnp; @@ -340,19 +345,17 @@ return -ENAMETOOLONG; } - /* Check for link to/from control object. */ - error = venus_link(dir_inode->i_sb,&(cnp->c_fid), &(dir_cnp->c_fid), (const char *)name, len); if ( ! error ) { - dir_cnp->c_flags &= ~C_VATTR; -/* cfsnc_zapfid(&(dir_cnp->c_fid)); */ -/* cfsnc_zapfid(&(cnp->c_fid)); */ - - inode->i_nlink++; - d_instantiate(de, inode); + dir_cnp->c_flags &= ~C_VATTR; + inode->i_nlink++; + d_instantiate(de, inode); + } else { + d_drop(de); } + CDEBUG(D_INODE, "link result %d\n",error); EXIT; return(error); @@ -382,11 +385,18 @@ CDEBUG(D_INODE, "symname: %s, length: %d\n", symname, symlen); + /* + * This entry is now negative. Since we do not create + * an inode for the entry we have to drop it. + */ + d_drop(de); + error = venus_symlink(dir_inode->i_sb, &(dir_cnp->c_fid), name, len, symname, symlen); - if ( !error ) - d_drop(de); + if ( !error ) { + dir_cnp->c_flags |= C_VATTR; + } CDEBUG(D_INODE, "in symlink result %d\n",error); EXIT; @@ -412,7 +422,6 @@ coda_f2s(&(dircnp->c_fid), fidstr), dir->i_ino); /* this file should no longer be in the namecache! */ -/* cfsnc_zapfile(dircnp, (const char *)name, len); */ error = venus_remove(dir->i_sb, &(dircnp->c_fid), name, len); @@ -423,7 +432,6 @@ /* cache management */ dircnp->c_flags &= ~C_VATTR; -/* cfsnc_zapfid(&(dircnp->c_fid)); */ de->d_inode->i_nlink--; d_delete(de); @@ -436,7 +444,7 @@ struct cnode *dircnp; const char *name = de->d_name.name; int len = de->d_name.len; - int error; + int error, rehash = 0; if (!dir || !S_ISDIR(dir->i_mode)) { printk("coda_rmdir: inode is NULL or not a directory\n"); @@ -456,7 +464,16 @@ return error; } /* Drop the dentry to force a new lookup */ - d_drop(de); + if (!list_empty(&de->d_hash)) { + d_drop(de); + rehash = 1; + } + + /* update i_nlink and free the inode before unlinking; + if rmdir fails a new lookup set i_nlink right.*/ + if (de->d_inode->i_nlink) + de->d_inode->i_nlink --; + d_delete(de); error = venus_rmdir(dir->i_sb, &(dircnp->c_fid), name, len); @@ -465,8 +482,9 @@ return error; } - dir->i_nlink--; - d_delete(de); + if (rehash) + d_add(de, NULL); + /* XXX how can mtime be set? */ return 0; } diff -u --recursive --new-file v2.1.78/linux/fs/coda/file.c linux/fs/coda/file.c --- v2.1.78/linux/fs/coda/file.c Tue Jan 6 09:37:36 1998 +++ linux/fs/coda/file.c Tue Jan 6 10:00:21 1998 @@ -25,10 +25,10 @@ #include /* file operations */ -static int coda_readpage(struct dentry *, struct page *); -static ssize_t coda_file_read(struct file *, char *, size_t, loff_t *); -static ssize_t coda_file_write(struct file *, const char *, size_t, loff_t *); -static int coda_file_mmap(struct file *, struct vm_area_struct *); +static int coda_readpage(struct dentry * dentry, struct page * page); +static ssize_t coda_file_read(struct file *f, char *buf, size_t count, loff_t *off); +static ssize_t coda_file_write(struct file *f, const char *buf, size_t count, loff_t *off); +static int coda_file_mmap(struct file * file, struct vm_area_struct * vma); /* exported from this file */ int coda_fsync(struct file *, struct dentry *dentry); @@ -74,9 +74,11 @@ }; /* File file operations */ -static int coda_readpage(struct dentry *dentry, struct page * page) +static int coda_readpage(struct dentry *de, struct page * page) { - struct inode *open_inode, *inode = dentry->d_inode; + struct inode *inode = de->d_inode; + struct dentry cont_dentry; + struct inode *cont_inode; struct cnode *cnp; ENTRY; @@ -89,12 +91,12 @@ return -ENXIO; } - open_inode = cnp->c_ovp; + cont_inode = cnp->c_ovp; + cont_dentry.d_inode = cont_inode; - CDEBUG(D_INODE, "coda ino: %ld, cached ino %ld, page offset: %lx\n", inode->i_ino, open_inode->i_ino, page->offset); + CDEBUG(D_INODE, "coda ino: %ld, cached ino %ld, page offset: %lx\n", inode->i_ino, cont_inode->i_ino, page->offset); - /* N.B. This needs the dentry for open_inode */ - generic_readpage(open_inode, page); + generic_readpage(&cont_dentry, page); EXIT; return 0; } diff -u --recursive --new-file v2.1.78/linux/fs/coda/inode.c linux/fs/coda/inode.c --- v2.1.78/linux/fs/coda/inode.c Tue Dec 2 16:45:19 1997 +++ linux/fs/coda/inode.c Wed Dec 31 16:00:00 1969 @@ -1,34 +0,0 @@ -/* - * Inode operations for Coda filesystem - * Original version: (C) 1996 P. Braam and M. Callahan - * Rewritten for Linux 2.1. (C) 1997 Carnegie Mellon University - * - * Carnegie Mellon encourages users to contribute improvements to - * the Coda project. Contact Peter Braam (coda@cs.cmu.edu). - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -/* prototypes */ -static int coda_readpage(struct inode *inode, struct page *page); -static int coda_cnode_makectl(struct inode **inode, struct super_block *sb); - - - - - diff -u --recursive --new-file v2.1.78/linux/fs/coda/psdev.c linux/fs/coda/psdev.c --- v2.1.78/linux/fs/coda/psdev.c Sun Dec 21 22:36:16 1997 +++ linux/fs/coda/psdev.c Tue Jan 6 10:00:21 1998 @@ -40,8 +40,8 @@ #include #include -#include #include +#include #include #include diff -u --recursive --new-file v2.1.78/linux/fs/coda/super.c linux/fs/coda/super.c --- v2.1.78/linux/fs/coda/super.c Tue Jan 6 09:37:36 1998 +++ linux/fs/coda/super.c Tue Jan 6 10:00:21 1998 @@ -41,7 +41,7 @@ /* VFS super_block ops */ static struct super_block *coda_read_super(struct super_block *, void *, int); static void coda_read_inode(struct inode *); -static int coda_notify_change(struct dentry *, struct iattr *); +static int coda_notify_change(struct dentry *dentry, struct iattr *attr); static void coda_put_inode(struct inode *); static void coda_delete_inode(struct inode *); static void coda_put_super(struct super_block *); @@ -101,6 +101,7 @@ sbi->sbi_psdev = psdev; sbi->sbi_vcomm = vc; INIT_LIST_HEAD(&(sbi->sbi_cchead)); + INIT_LIST_HEAD(&(sbi->sbi_volroothead)); lock_super(sb); sb->u.generic_sbp = sbi; @@ -133,7 +134,6 @@ printk("coda_read_super: rootinode is %ld dev %d\n", root->i_ino, root->i_dev); sbi->sbi_root = root; - /* N.B. check this for failure */ sb->s_root = d_alloc_root(root, NULL); unlock_super(sb); EXIT; @@ -141,6 +141,7 @@ error: EXIT; + MOD_DEC_USE_COUNT; if (sbi) { sbi->sbi_vcomm = NULL; sbi->sbi_root = NULL; @@ -154,7 +155,6 @@ coda_cnode_free(ITOC(root)); } sb->s_dev = 0; - MOD_DEC_USE_COUNT; return NULL; } @@ -209,6 +209,10 @@ } cnp = ITOC(inode); + + if ( coda_fid_is_volroot(&cnp->c_fid) ) + list_del(&cnp->c_volrootlist); + open_inode = cnp->c_ovp; if ( open_inode ) { CDEBUG(D_SUPER, "DELINO cached file: ino %ld count %d.\n", @@ -225,9 +229,9 @@ EXIT; } -static int coda_notify_change(struct dentry *dentry, struct iattr *iattr) +static int coda_notify_change(struct dentry *de, struct iattr *iattr) { - struct inode *inode = dentry->d_inode; + struct inode *inode = de->d_inode; struct cnode *cnp; struct coda_vattr vattr; int error; diff -u --recursive --new-file v2.1.78/linux/fs/coda/symlink.c linux/fs/coda/symlink.c --- v2.1.78/linux/fs/coda/symlink.c Tue Jan 6 09:37:36 1998 +++ linux/fs/coda/symlink.c Tue Jan 6 10:00:21 1998 @@ -24,7 +24,7 @@ #include #include -static int coda_readlink(struct dentry *dentry, char *buffer, int length); +static int coda_readlink(struct dentry *de, char *buffer, int length); static struct dentry *coda_follow_link(struct dentry *, struct dentry *); struct inode_operations coda_symlink_inode_operations = { @@ -39,41 +39,41 @@ NULL, /* mknod */ NULL, /* rename */ coda_readlink, /* readlink */ - coda_follow_link, /* follow_link */ + coda_follow_link, /* follow_link */ NULL, /* readpage */ NULL, /* writepage */ NULL, /* bmap */ NULL, /* truncate */ - NULL, /* permission */ - NULL, /* smap */ - NULL, /* update page */ - NULL /* revalidate */ + NULL, /* permission */ + NULL, /* smap */ + NULL, /* update page */ + NULL /* revalidate */ }; -static int coda_readlink(struct inode *dentry, char *buffer, int length) +static int coda_readlink(struct dentry *de, char *buffer, int length) { - struct inode *inode = dentry->d_inode; - int len; + struct inode *inode = de->d_inode; + int len; int error; - char *buf; + char *buf; struct cnode *cp; - ENTRY; + ENTRY; - cp = ITOC(inode); - CHECK_CNODE(cp); + cp = ITOC(inode); + CHECK_CNODE(cp); - /* the maximum length we receive is len */ - if ( length > CFS_MAXPATHLEN ) - len = CFS_MAXPATHLEN; + /* the maximum length we receive is len */ + if ( length > CFS_MAXPATHLEN ) + len = CFS_MAXPATHLEN; else - len = length; + len = length; CODA_ALLOC(buf, char *, len); if ( !buf ) - return -ENOMEM; + return -ENOMEM; error = venus_readlink(inode->i_sb, &(cp->c_fid), buf, &len); - CDEBUG(D_INODE, "result %s\n", buf); + CDEBUG(D_INODE, "result %s\n", buf); if (! error) { copy_to_user(buffer, buf, len); put_user('\0', buffer + len); @@ -84,20 +84,20 @@ return error; } -static struct dentry *coda_follow_link(struct dentry *dentry, - struct dentry *base) +static struct dentry *coda_follow_link(struct dentry *de, + struct dentry *base) { - struct inode *inode = dentry->d_inode; + struct inode *inode = de->d_inode; int error; struct cnode *cnp; unsigned int len; + char mem[CFS_MAXPATHLEN]; char *path; - char mem[CFS_MAXPATHLEN]; /* N.B. too big for the stack? */ ENTRY; CDEBUG(D_INODE, "(%x/%ld)\n", inode->i_dev, inode->i_ino); - cnp = ITOC(inode); - CHECK_CNODE(cnp); + cnp = ITOC(inode); + CHECK_CNODE(cnp); len = CFS_MAXPATHLEN; error = venus_readlink(inode->i_sb, &(cnp->c_fid), mem, &len); diff -u --recursive --new-file v2.1.78/linux/fs/dcache.c linux/fs/dcache.c --- v2.1.78/linux/fs/dcache.c Tue Jan 6 09:37:36 1998 +++ linux/fs/dcache.c Tue Jan 6 19:59:16 1998 @@ -146,8 +146,9 @@ int d_invalidate(struct dentry * dentry) { /* Check whether to do a partial shrink_dcache */ - if (dentry->d_count > 1 && !list_empty(&dentry->d_subdirs)) + if (!list_empty(&dentry->d_subdirs)) shrink_dcache_parent(dentry); + if (dentry->d_count != 1) return -EBUSY; diff -u --recursive --new-file v2.1.78/linux/fs/ext2/inode.c linux/fs/ext2/inode.c --- v2.1.78/linux/fs/ext2/inode.c Tue Jan 6 09:37:36 1998 +++ linux/fs/ext2/inode.c Fri Jan 9 16:19:26 1998 @@ -219,6 +219,7 @@ (current->rlim[RLIMIT_FSIZE].rlim_cur >> EXT2_BLOCK_SIZE_BITS(inode->i_sb))) { *err = -EFBIG; + send_sig(SIGXFSZ, current, 0); return NULL; } if (inode->u.ext2_i.i_next_alloc_block == new_block) diff -u --recursive --new-file v2.1.78/linux/fs/fat/Makefile linux/fs/fat/Makefile --- v2.1.78/linux/fs/fat/Makefile Tue Feb 6 23:39:27 1996 +++ linux/fs/fat/Makefile Thu Jan 8 14:02:41 1998 @@ -8,7 +8,7 @@ # Note 2! The CFLAGS definitions are now in the main makefile... O_TARGET := fat.o -O_OBJS := buffer.o cache.o dir.o file.o inode.o misc.o mmap.o tables.o +O_OBJS := buffer.o cache.o dir.o file.o inode.o misc.o mmap.o tables.o cvf.o OX_OBJS := fatfs_syms.o M_OBJS := $(O_TARGET) diff -u --recursive --new-file v2.1.78/linux/fs/fat/buffer.c linux/fs/fat/buffer.c --- v2.1.78/linux/fs/fat/buffer.c Sat Oct 25 02:44:17 1997 +++ linux/fs/fat/buffer.c Thu Jan 8 14:02:41 1998 @@ -9,6 +9,7 @@ #include #include #include +#include #if 0 # define PRINTK(x) printk x @@ -28,6 +29,11 @@ * is always of size 1024 (or 2048). Doing readahead may be * counterproductive or just plain wrong. */ + + if(MSDOS_SB(sb)->cvf_format) + if(MSDOS_SB(sb)->cvf_format->cvf_bread) + return MSDOS_SB(sb)->cvf_format->cvf_bread(sb,block); + if (sb->s_blocksize == 512) { ret = bread (sb->s_dev,block,512); } else { @@ -92,6 +98,11 @@ { struct buffer_head *ret = NULL; PRINTK(("fat_getblk: block=0x%x\n", block)); + + if(MSDOS_SB(sb)->cvf_format) + if(MSDOS_SB(sb)->cvf_format->cvf_getblk) + return MSDOS_SB(sb)->cvf_format->cvf_getblk(sb,block); + if (sb->s_blocksize == 512){ ret = getblk (sb->s_dev,block,512); }else{ @@ -111,6 +122,10 @@ struct buffer_head *bh) { if (bh != NULL){ + if(MSDOS_SB(sb)->cvf_format) + if(MSDOS_SB(sb)->cvf_format->cvf_brelse) + return MSDOS_SB(sb)->cvf_format->cvf_brelse(sb,bh); + if (sb->s_blocksize == 512){ brelse (bh); }else{ @@ -128,6 +143,12 @@ struct buffer_head *bh, int dirty_val) { + if(MSDOS_SB(sb)->cvf_format) + if(MSDOS_SB(sb)->cvf_format->cvf_mark_buffer_dirty) + { MSDOS_SB(sb)->cvf_format->cvf_mark_buffer_dirty(sb,bh,dirty_val); + return; + } + if (sb->s_blocksize != 512){ bh = bh->b_next; } @@ -139,6 +160,12 @@ struct buffer_head *bh, int val) { + if(MSDOS_SB(sb)->cvf_format) + if(MSDOS_SB(sb)->cvf_format->cvf_set_uptodate) + { MSDOS_SB(sb)->cvf_format->cvf_set_uptodate(sb,bh,val); + return; + } + if (sb->s_blocksize != 512){ bh = bh->b_next; } @@ -148,6 +175,10 @@ struct super_block *sb, struct buffer_head *bh) { + if(MSDOS_SB(sb)->cvf_format) + if(MSDOS_SB(sb)->cvf_format->cvf_is_uptodate) + return MSDOS_SB(sb)->cvf_format->cvf_is_uptodate(sb,bh); + if (sb->s_blocksize != 512){ bh = bh->b_next; } @@ -160,6 +191,12 @@ int nbreq, struct buffer_head *bh[32]) { + if(MSDOS_SB(sb)->cvf_format) + if(MSDOS_SB(sb)->cvf_format->cvf_ll_rw_block) + { MSDOS_SB(sb)->cvf_format->cvf_ll_rw_block(sb,opr,nbreq,bh); + return; + } + if (sb->s_blocksize == 512){ ll_rw_block(opr,nbreq,bh); }else{ diff -u --recursive --new-file v2.1.78/linux/fs/fat/cache.c linux/fs/fat/cache.c --- v2.1.78/linux/fs/fat/cache.c Wed Nov 12 13:34:27 1997 +++ linux/fs/fat/cache.c Thu Jan 8 14:02:41 1998 @@ -9,6 +9,7 @@ #include #include #include +#include #include "msbuffer.h" @@ -29,6 +30,10 @@ unsigned char *p_first,*p_last; int copy,first,last,next,b; + if(MSDOS_SB(sb)->cvf_format) + if(MSDOS_SB(sb)->cvf_format->fat_access) + return MSDOS_SB(sb)->cvf_format->fat_access(sb,nr,new_value); + if ((unsigned) (nr-2) >= MSDOS_SB(sb)->clusters) return 0; if (MSDOS_SB(sb)->fat_bits == 32) { @@ -240,7 +245,7 @@ } -int get_cluster(struct inode *inode,int cluster) +int fat_get_cluster(struct inode *inode,int cluster) { int nr,count; @@ -262,6 +267,9 @@ int cluster,offset; sb = MSDOS_SB(inode->i_sb); + if(sb->cvf_format) + if(sb->cvf_format->cvf_smap) + return sb->cvf_format->cvf_smap(inode,sector); if ((sb->fat_bits != 32) && (inode->i_ino == MSDOS_ROOT_INO || (S_ISDIR(inode->i_mode) && !MSDOS_I(inode)->i_start))) { @@ -271,7 +279,7 @@ } cluster = sector/sb->cluster_size; offset = sector % sb->cluster_size; - if (!(cluster = get_cluster(inode,cluster))) return 0; + if (!(cluster = fat_get_cluster(inode,cluster))) return 0; return (cluster-2)*sb->cluster_size+sb->data_start+offset; } diff -u --recursive --new-file v2.1.78/linux/fs/fat/cvf.c linux/fs/fat/cvf.c --- v2.1.78/linux/fs/fat/cvf.c Wed Dec 31 16:00:00 1969 +++ linux/fs/fat/cvf.c Thu Jan 8 14:02:41 1998 @@ -0,0 +1,120 @@ +/* + * CVF extensions for fat-based filesystems + * + * written 1997,1998 by Frank Gockel + * + */ + +#include +#include +#include +#include +#include +#include + +#define MAX_CVF_FORMATS 3 + +struct cvf_format *cvf_formats[MAX_CVF_FORMATS]={NULL,NULL,NULL}; +int cvf_format_use_count[MAX_CVF_FORMATS]={0,0,0}; + +int register_cvf_format(struct cvf_format*cvf_format) +{ int i,j; + + for(i=0;icvf_version==cvf_format->cvf_version) + { printk("register_cvf_format: version %d already registered\n", + cvf_format->cvf_version); + return -1; + } + } + } + cvf_formats[i]=cvf_format; + cvf_format_use_count[i]=0; + printk("CVF format %s (version id %d) successfully registered.\n", + cvf_format->cvf_version_text,cvf_format->cvf_version); + return 0; + } + } + + printk("register_cvf_format: too many formats\n"); + return -1; +} + +int unregister_cvf_format(struct cvf_format*cvf_format) +{ int i; + + for(i=0;icvf_version==cvf_format->cvf_version) + { if(cvf_format_use_count[i]) + { printk("unregister_cvf_format: format %d in use, cannot remove!\n", + cvf_formats[i]->cvf_version); + return -1; + } + + printk("CVF format %s (version id %d) successfully unregistered.\n", + cvf_formats[i]->cvf_version_text,cvf_formats[i]->cvf_version); + cvf_formats[i]=NULL; + return 0; + } + } + } + + printk("unregister_cvf_format: format %d is not registered\n", + cvf_format->cvf_version); + return -1; +} + +void dec_cvf_format_use_count_by_version(int version) +{ int i; + + for(i=0;icvf_version==version) + { --cvf_format_use_count[i]; + if(cvf_format_use_count[i]<0) + { cvf_format_use_count[i]=0; + printk(KERN_EMERG "FAT FS/CVF: This is a bug in cvf_version_use_count\n"); + } + return; + } + } + } + + printk("dec_cvf_format_use_count_by_version: version %d not found ???\n", + version); +} + +int detect_cvf(struct super_block*sb,char*force) +{ int i; + int found=0; + int found_i=-1; + + if(force) + { if(*force) + { for(i=0;icvf_version_text,force)) + return i; + } + } + } + } + + for(i=0;idetect_cvf(sb)) + { ++found; + found_i=i; + } + } + } + + if(found==1)return found_i; + if(found>1)printk("CVF detection ambiguous, use cvf_format=xxx option\n"); + return -1; +} diff -u --recursive --new-file v2.1.78/linux/fs/fat/dir.c linux/fs/fat/dir.c --- v2.1.78/linux/fs/fat/dir.c Wed Nov 12 13:34:27 1997 +++ linux/fs/fat/dir.c Thu Jan 8 14:02:41 1998 @@ -434,6 +434,11 @@ vfat_ioctl_fill, NULL, 1, 0, 1); } default: + /* forward ioctl to CVF extension */ + if(MSDOS_SB(inode->i_sb)->cvf_format + &&MSDOS_SB(inode->i_sb)->cvf_format->cvf_dir_ioctl) + return MSDOS_SB(inode->i_sb)->cvf_format-> + cvf_dir_ioctl(inode,filp,cmd,arg); return -EINVAL; } diff -u --recursive --new-file v2.1.78/linux/fs/fat/fatfs_syms.c linux/fs/fat/fatfs_syms.c --- v2.1.78/linux/fs/fat/fatfs_syms.c Sat Oct 25 02:44:17 1997 +++ linux/fs/fat/fatfs_syms.c Thu Jan 8 14:02:41 1998 @@ -11,6 +11,7 @@ #include #include +#include #include "msbuffer.h" #include "tables.h" @@ -47,6 +48,11 @@ EXPORT_SYMBOL(fat_uni2esc); EXPORT_SYMBOL(fat_unlock_creation); EXPORT_SYMBOL(fat_write_inode); +EXPORT_SYMBOL(register_cvf_format); +EXPORT_SYMBOL(unregister_cvf_format); +EXPORT_SYMBOL(fat_get_cluster); +EXPORT_SYMBOL(lock_fat); +EXPORT_SYMBOL(unlock_fat); int init_fat_fs(void) { diff -u --recursive --new-file v2.1.78/linux/fs/fat/file.c linux/fs/fat/file.c --- v2.1.78/linux/fs/fat/file.c Thu Dec 4 14:53:56 1997 +++ linux/fs/fat/file.c Thu Jan 8 14:02:41 1998 @@ -17,6 +17,7 @@ #include #include #include +#include #include #include @@ -112,6 +113,40 @@ NULL /* smap */ }; +static struct file_operations fat_file_operations_readpage = { + NULL, /* lseek - default */ + fat_file_read, /* read */ + fat_file_write, /* write */ + NULL, /* readdir - bad */ + NULL, /* select v2.0.x/poll v2.1.x - default */ + NULL, /* ioctl - default */ + generic_file_mmap, /* mmap */ + NULL, /* no special open is needed */ + NULL, /* release */ + file_fsync /* fsync */ +}; + +struct inode_operations fat_file_inode_operations_readpage = { + &fat_file_operations_readpage, /* 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 */ + fat_readpage, /* readpage */ + NULL, /* writepage */ + NULL, /* bmap */ + fat_truncate, /* truncate */ + NULL, /* permission */ + NULL /* smap */ +}; + #define MSDOS_PREFETCH 32 struct fat_pre { int file_sector;/* Next sector to read in the prefetch table */ @@ -277,6 +312,10 @@ loff_t *ppos) { struct inode *inode = filp->f_dentry->d_inode; + if(MSDOS_SB(inode->i_sb)->cvf_format) + if(MSDOS_SB(inode->i_sb)->cvf_format->cvf_file_read) + return MSDOS_SB(inode->i_sb)->cvf_format->cvf_file_read(filp,buf,count,ppos); + if (!MSDOS_I(inode)->i_binary) return fat_file_read_text(filp, buf, count, ppos); return generic_file_read(filp, buf, count, ppos); @@ -303,6 +342,10 @@ printk("fat_file_write: inode = NULL\n"); return -EINVAL; } + if(MSDOS_SB(sb)->cvf_format) + if(MSDOS_SB(sb)->cvf_format->cvf_file_write) + return MSDOS_SB(sb)->cvf_format->cvf_file_write(filp,buf,count,ppos); + /* S_ISLNK allows for UMSDOS. Should never happen for normal MSDOS */ if (!S_ISREG(inode->i_mode) && !S_ISLNK(inode->i_mode)) { printk("fat_file_write: mode = %07o\n",inode->i_mode); diff -u --recursive --new-file v2.1.78/linux/fs/fat/inode.c linux/fs/fat/inode.c --- v2.1.78/linux/fs/fat/inode.c Tue Jan 6 09:37:36 1998 +++ linux/fs/fat/inode.c Thu Jan 8 14:02:41 1998 @@ -20,6 +20,7 @@ #include #include #include +#include #include #include "msbuffer.h" @@ -139,6 +140,10 @@ void fat_put_super(struct super_block *sb) { lock_super(sb); + if(MSDOS_SB(sb)->cvf_format) + { MSDOS_SB(sb)->cvf_format->unmount_cvf(sb); + dec_cvf_format_use_count_by_version(MSDOS_SB(sb)->cvf_format->cvf_version); + } if (MSDOS_SB(sb)->fat_bits == 32) { fat_clusters_flush(sb); } @@ -169,7 +174,8 @@ static int parse_options(char *options,int *fat, int *blksize, int *debug, - struct fat_mount_options *opts) + struct fat_mount_options *opts, + char* cvf_format, char*cvf_options) { char *this_char,*value,save,*savep; char *p; @@ -306,6 +312,16 @@ ret = 0; } } + else if (!strcmp(this_char,"cvf_format")) { + if (!value) + return 0; + strncpy(cvf_format,value,20); + } + else if (!strcmp(this_char,"cvf_options")) { + if (!value) + return 0; + strncpy(cvf_options,value,100); + } if (this_char != options) *(this_char-1) = ','; if (value) *savep = save; @@ -335,6 +351,14 @@ int fat32; struct fat_mount_options opts; char buf[50]; + int i; + char cvf_format[21]; + char cvf_options[101]; + + cvf_format[0]='\0'; + cvf_options[0]='\0'; + MSDOS_SB(sb)->cvf_format=NULL; + MSDOS_SB(sb)->private_data=NULL; MOD_INC_USE_COUNT; if (hardsect_size[MAJOR(sb->s_dev)] != NULL){ @@ -342,10 +366,12 @@ if (blksize != 512){ printk ("MSDOS: Hardware sector size is %d\n",blksize); } + } opts.isvfat = MSDOS_SB(sb)->options.isvfat; - if (!parse_options((char *) data, &fat, &blksize, &debug, &opts) + if (!parse_options((char *) data, &fat, &blksize, &debug, &opts, + cvf_format, cvf_options) || (blksize != 512 && blksize != 1024 && blksize != 2048)) goto out_fail; /* N.B. we should parse directly into the sb structure */ @@ -458,6 +484,9 @@ /* because clusters (DOS) are often aligned */ /* on odd sectors. */ sb->s_blocksize_bits = blksize == 512 ? 9 : (blksize == 1024 ? 10 : 11); + if(!strcmp(cvf_format,"none"))i=-1; + else i=detect_cvf(sb,cvf_format); + if(i>=0)error=cvf_formats[i]->mount_cvf(sb,cvf_options); if (error || debug) { /* The MSDOS_CAN_BMAP is obsolete, but left just to remember */ printk("[MS-DOS FS Rel. 12,FAT %d,check=%c,conv=%c," @@ -477,7 +506,7 @@ MSDOS_SB(sb)->root_cluster,MSDOS_SB(sb)->free_clusters); printk ("Transaction block size = %d\n",blksize); } - if (MSDOS_SB(sb)->clusters+2 > fat_clusters) + if (i<0) if (MSDOS_SB(sb)->clusters+2 > fat_clusters) MSDOS_SB(sb)->clusters = fat_clusters-2; if (error) goto out_invalid; @@ -517,6 +546,10 @@ sb->s_root = d_alloc_root(root_inode, NULL); if (!sb->s_root) goto out_no_root; + if(i>=0) + { MSDOS_SB(sb)->cvf_format=cvf_formats[i]; + ++cvf_format_use_count[i]; + } return sb; out_no_root: @@ -540,6 +573,9 @@ kfree(opts.iocharset); } sb->s_dev = 0; + if(MSDOS_SB(sb)->private_data)kfree(MSDOS_SB(sb)->private_data); + MSDOS_SB(sb)->private_data=NULL; + MOD_DEC_USE_COUNT; return NULL; } @@ -548,7 +584,11 @@ { int free,nr; struct statfs tmp; - + + if(MSDOS_SB(sb)->cvf_format) + if(MSDOS_SB(sb)->cvf_format->cvf_statfs) + return MSDOS_SB(sb)->cvf_format->cvf_statfs(sb,buf,bufsiz); + lock_fat(sb); if (MSDOS_SB(sb)->free_clusters != -1) free = MSDOS_SB(sb)->free_clusters; @@ -577,12 +617,15 @@ int cluster,offset; sb = MSDOS_SB(inode->i_sb); + if(sb->cvf_format) + if(sb->cvf_format->cvf_bmap) + return sb->cvf_format->cvf_bmap(inode,block); if ((inode->i_ino == MSDOS_ROOT_INO) && (sb->fat_bits != 32)) { return sb->dir_start + block; } cluster = block/sb->cluster_size; offset = block % sb->cluster_size; - if (!(cluster = get_cluster(inode,cluster))) return 0; + if (!(cluster = fat_get_cluster(inode,cluster))) return 0; return (cluster-2)*sb->cluster_size+sb->data_start+offset; } @@ -689,7 +732,12 @@ !is_exec(raw_entry->ext))) ? S_IRUGO|S_IWUGO : S_IRWXUGO) & ~MSDOS_SB(sb)->options.fs_umask) | S_IFREG; - inode->i_op = (sb->s_blocksize == 1024 || sb->s_blocksize == 2048) + if(MSDOS_SB(sb)->cvf_format) + inode->i_op = (MSDOS_SB(sb)->cvf_format->flags&CVF_USE_READPAGE) + ? &fat_file_inode_operations_readpage + : &fat_file_inode_operations_1024; + else + inode->i_op = (sb->s_blocksize == 1024 || sb->s_blocksize == 2048) ? &fat_file_inode_operations_1024 : &fat_file_inode_operations; MSDOS_I(inode)->i_start = CF_LE_W(raw_entry->start); diff -u --recursive --new-file v2.1.78/linux/fs/fat/misc.c linux/fs/fat/misc.c --- v2.1.78/linux/fs/fat/misc.c Sat Oct 25 02:44:17 1997 +++ linux/fs/fat/misc.c Thu Jan 8 14:02:41 1998 @@ -221,6 +221,10 @@ #endif sector = MSDOS_SB(sb)->data_start+(nr-2)*cluster_size; last_sector = sector + cluster_size; + if(MSDOS_SB(sb)->cvf_format&& + MSDOS_SB(sb)->cvf_format->zero_out_cluster) + MSDOS_SB(sb)->cvf_format->zero_out_cluster(inode,nr); + else for ( ; sector < last_sector; sector++) { #ifdef DEBUG printk("zeroing sector %d\n",sector); @@ -279,9 +283,7 @@ month < 2 ? 1 : 0)+3653); /* days since 1.1.70 plus 80's leap day */ secs += sys_tz.tz_minuteswest*60; - if (sys_tz.tz_dsttime) { - secs -= 3600; - } + if (sys_tz.tz_dsttime) secs -= 3600; return secs; } @@ -293,9 +295,6 @@ { int day,year,nl_day,month; - if (sys_tz.tz_dsttime) { - unix_date += 3600; - } unix_date -= sys_tz.tz_minuteswest*60; if (sys_tz.tz_dsttime) unix_date += 3600; diff -u --recursive --new-file v2.1.78/linux/fs/fat/mmap.c linux/fs/fat/mmap.c --- v2.1.78/linux/fs/fat/mmap.c Tue Dec 2 09:49:40 1997 +++ linux/fs/fat/mmap.c Thu Jan 8 14:02:41 1998 @@ -97,7 +97,10 @@ int fat_mmap(struct file * file, struct vm_area_struct * vma) { struct inode *inode = file->f_dentry->d_inode; - + if(MSDOS_SB(inode->i_sb)->cvf_format) + if(MSDOS_SB(inode->i_sb)->cvf_format->cvf_mmap) + return MSDOS_SB(inode->i_sb)->cvf_format->cvf_mmap(file,vma); + if (vma->vm_flags & VM_SHARED) /* only PAGE_COW or read-only supported now */ return -EINVAL; if (vma->vm_offset & (inode->i_sb->s_blocksize - 1)) @@ -114,4 +117,14 @@ return 0; } + +int fat_readpage(struct inode * inode, struct page * page) +{ + if(MSDOS_SB(inode->i_sb)->cvf_format) + if(MSDOS_SB(inode->i_sb)->cvf_format->cvf_readpage) + return MSDOS_SB(inode->i_sb)->cvf_format->cvf_readpage(inode,page); + + printk("fat_readpage called with no handler (shouldn't happen)\n"); + return -1; +} diff -u --recursive --new-file v2.1.78/linux/fs/minix/namei.c linux/fs/minix/namei.c --- v2.1.78/linux/fs/minix/namei.c Sun Dec 21 22:36:16 1997 +++ linux/fs/minix/namei.c Tue Jan 6 12:26:59 1998 @@ -562,10 +562,11 @@ return 0; } -int minix_link(struct inode * inode, struct inode * dir, +int minix_link(struct dentry * old_dentry, struct inode * dir, struct dentry *dentry) { int error; + struct inode *inode = old_dentry->d_inode; struct minix_dir_entry * de; struct buffer_head * bh; diff -u --recursive --new-file v2.1.78/linux/fs/namei.c linux/fs/namei.c --- v2.1.78/linux/fs/namei.c Tue Jan 6 09:37:37 1998 +++ linux/fs/namei.c Tue Jan 6 20:00:49 1998 @@ -247,20 +247,13 @@ /* * Internal lookup() using the new generic dcache. - * - * Note the revalidation: we have to drop the dcache - * lock when we revalidate, so we need to update the - * counts around it. */ static struct dentry * cached_lookup(struct dentry * parent, struct qstr * name) { struct dentry * dentry = d_lookup(parent, name); if (dentry && dentry->d_op && dentry->d_op->d_revalidate) { - int validated, (*revalidate)(struct dentry *) = dentry->d_op->d_revalidate; - - validated = revalidate(dentry) || d_invalidate(dentry); - if (!validated) { + if (!dentry->d_op->d_revalidate(dentry) && !d_invalidate(dentry)) { dput(dentry); dentry = NULL; } @@ -840,7 +833,7 @@ /* Disallow removals of mountpoints. */ error = -EBUSY; - if (dentry == dir) + if (dentry->d_mounts != dentry->d_covers) goto exit_lock; error = -EPERM; diff -u --recursive --new-file v2.1.78/linux/fs/nfs/nfsroot.c linux/fs/nfs/nfsroot.c --- v2.1.78/linux/fs/nfs/nfsroot.c Sun Dec 21 22:36:16 1997 +++ linux/fs/nfs/nfsroot.c Fri Jan 9 09:28:06 1998 @@ -58,6 +58,7 @@ * Martin Mares : Default path now contains host name instead of * host IP address (but host name defaults to IP * address anyway). + * Martin Mares : Use root_server_addr appropriately during setup. */ #include @@ -86,6 +87,7 @@ /* Parameters passed from the kernel command line */ static char nfs_root_name[NFS_ROOT_NAME_LEN] __initdata = "default"; +static int nfs_params_parsed = 0; /* Address of NFS server */ static __u32 servaddr __initdata = 0; @@ -157,6 +159,9 @@ char *cp, *cq, *options, *val; int octets = 0; + if (nfs_params_parsed) + return nfs_params_parsed; + /* It is possible to override the server IP number here */ cp = cq = name; while (octets < 4) { @@ -173,17 +178,12 @@ if (octets == 4 && (*cp == ':' || *cp == '\0')) { if (*cp == ':') *cp++ = '\0'; - servaddr = in_aton(name); + root_server_addr = in_aton(name); name = cp; - } else if ((servaddr = root_server_addr) == INADDR_NONE) { - printk(KERN_ERR "Root-NFS: No NFS server available, giving up.\n"); - return -1; } /* Clear the nfs_data structure and setup the server hostname */ memset(&nfs_data, 0, sizeof(nfs_data)); - strncpy(nfs_data.hostname, in_ntoa(servaddr), sizeof(nfs_data.hostname)-1); - nfs_data.namlen = strlen(nfs_data.hostname); /* Set the name of the directory to mount */ if (root_server_path[0] && !strcmp(name, "default")) @@ -239,11 +239,26 @@ cp = strtok(NULL, ","); } } - return 0; + return 1; } /* + * Get NFS server address. + */ +__initfunc(static int root_nfs_addr(void)) +{ + if ((servaddr = root_server_addr) == INADDR_NONE) { + printk(KERN_ERR "Root-NFS: No NFS server available, giving up.\n"); + return -1; + } + + strncpy(nfs_data.hostname, in_ntoa(servaddr), sizeof(nfs_data.hostname)-1); + nfs_data.namlen = strlen(nfs_data.hostname); + return 0; +} + +/* * Tell the user what's going on. */ #ifdef NFSROOT_DEBUG @@ -274,7 +289,8 @@ * be able to use the client IP address for the remote root * directory (necessary for pure RARP booting). */ - if (root_nfs_name(nfs_root_name) < 0) + if (root_nfs_name(nfs_root_name) < 0 || + root_nfs_addr() < 0) return -1; #ifdef NFSROOT_DEBUG @@ -301,6 +317,7 @@ line[sizeof(nfs_root_name) - strlen(NFS_ROOT) - 1] = '\0'; sprintf(nfs_root_name, NFS_ROOT, line); } + nfs_params_parsed = root_nfs_name(nfs_root_name); } diff -u --recursive --new-file v2.1.78/linux/fs/nfs/proc.c linux/fs/nfs/proc.c --- v2.1.78/linux/fs/nfs/proc.c Wed Oct 15 16:04:23 1997 +++ linux/fs/nfs/proc.c Fri Jan 9 13:52:01 1998 @@ -45,8 +45,8 @@ /* * If NFS_DEBUG is defined, you can toggle NFS debugging by causing - * a lookup of "xyzzy". Just cd to an NFS-mounted filesystem and type - * 'ls xyzzy' to turn on debugging. + * a lookup of "__xyzzy__". Just cd to an NFS-mounted filesystem and type + * 'ls __xyzzy__' to turn on debugging. */ #ifdef NFS_DEBUG # define NFSDBG_FACILITY NFSDBG_PROC @@ -91,7 +91,7 @@ dprintk("NFS call lookup %s\n", name); #ifdef RPC_DEBUG - if (!strcmp(name, "xyzzy")) + if (!strcmp(name, "__xyzzy__")) nfs_debug = ~nfs_debug; #endif status = rpc_call(server->client, NFSPROC_LOOKUP, &arg, &res, 0); diff -u --recursive --new-file v2.1.78/linux/fs/proc/link.c linux/fs/proc/link.c --- v2.1.78/linux/fs/proc/link.c Tue Jan 6 09:37:37 1998 +++ linux/fs/proc/link.c Tue Jan 6 12:33:11 1998 @@ -146,9 +146,9 @@ pattern = NULL; inode = dentry->d_inode; if (inode && dentry->d_parent == dentry) { - if (inode->i_sock) + if (S_ISSOCK(inode->i_mode)) pattern = "socket:[%lu]"; - if (inode->i_pipe) + if (S_ISFIFO(inode->i_mode)) pattern = "pipe:[%lu]"; } diff -u --recursive --new-file v2.1.78/linux/fs/proc/root.c linux/fs/proc/root.c --- v2.1.78/linux/fs/proc/root.c Tue Jan 6 09:37:37 1998 +++ linux/fs/proc/root.c Sat Jan 10 10:43:43 1998 @@ -50,6 +50,9 @@ NULL /* can't fsync */ }; +int proc_readlink(struct dentry * dentry, char * buffer, int buflen); +struct dentry * proc_follow_link(struct dentry *dentry, struct dentry *base); + /* * proc directories can do almost nothing.. */ @@ -332,6 +335,9 @@ if (dp->ops == NULL) dp->ops = &proc_dir_inode_operations; dir->nlink++; + } else if (S_ISLNK(dp->mode)) { + if (dp->ops == NULL) + dp->ops = &proc_link_inode_operations; } else { if (dp->ops == NULL) dp->ops = &proc_file_inode_operations; @@ -389,6 +395,50 @@ return lookup_dentry(tmp, base, 1); } +int proc_readlink(struct dentry * dentry, char * buffer, int buflen) +{ + struct inode *inode = dentry->d_inode; + struct proc_dir_entry * de; + char *page; + int len = 0; + + de = (struct proc_dir_entry *) inode->u.generic_ip; + if (!de) + return -ENOENT; + if (!(page = (char*) __get_free_page(GFP_KERNEL))) + return -ENOMEM; + + if (de->readlink_proc) + len = de->readlink_proc(de, page); + + if (len > buflen) + len = buflen; + + copy_to_user(buffer, page, len); + free_page((unsigned long) page); + return len; +} + +struct dentry * proc_follow_link(struct dentry * dentry, struct dentry *base) +{ + struct inode *inode = dentry->d_inode; + struct proc_dir_entry * de; + char *page; + struct dentry *d; + int len = 0; + + de = (struct proc_dir_entry *) inode->u.generic_ip; + if (!(page = (char*) __get_free_page(GFP_KERNEL))) + return NULL; + + if (de->readlink_proc) + len = de->readlink_proc(de, page); + + d = lookup_dentry(page, base, 1); + free_page((unsigned long) page); + return d; +} + static struct inode_operations proc_self_inode_operations = { NULL, /* no file-ops */ NULL, /* create */ @@ -402,6 +452,26 @@ NULL, /* rename */ proc_self_readlink, /* readlink */ proc_self_follow_link, /* follow_link */ + NULL, /* readpage */ + NULL, /* writepage */ + NULL, /* bmap */ + NULL, /* truncate */ + NULL /* permission */ +}; + +static struct inode_operations proc_link_inode_operations = { + NULL, /* no file-ops */ + NULL, /* create */ + NULL, /* lookup */ + NULL, /* link */ + NULL, /* unlink */ + NULL, /* symlink */ + NULL, /* mkdir */ + NULL, /* rmdir */ + NULL, /* mknod */ + NULL, /* rename */ + proc_readlink, /* readlink */ + proc_follow_link, /* follow_link */ NULL, /* readpage */ NULL, /* writepage */ NULL, /* bmap */ diff -u --recursive --new-file v2.1.78/linux/fs/sysv/inode.c linux/fs/sysv/inode.c --- v2.1.78/linux/fs/sysv/inode.c Tue Jan 6 09:37:38 1998 +++ linux/fs/sysv/inode.c Tue Jan 6 09:48:03 1998 @@ -873,7 +873,7 @@ } /* To avoid inconsistencies between inodes in memory and inodes on disk. */ -extern int sysv_notify_change(struct dentry *dentry, struct iattr *attr) +int sysv_notify_change(struct dentry *dentry, struct iattr *attr) { struct inode *inode = dentry->d_inode; int error; diff -u --recursive --new-file v2.1.78/linux/fs/sysv/namei.c linux/fs/sysv/namei.c --- v2.1.78/linux/fs/sysv/namei.c Sun Dec 21 22:36:16 1997 +++ linux/fs/sysv/namei.c Tue Jan 6 09:48:04 1998 @@ -571,9 +571,10 @@ return 0; } -int sysv_link(struct inode * oldinode, struct inode * dir, +int sysv_link(struct dentry * old_dentry, struct inode * dir, struct dentry * dentry) { + struct inode *oldinode = old_dentry->d_inode; int error; struct sysv_dir_entry * de; struct buffer_head * bh; diff -u --recursive --new-file v2.1.78/linux/include/asm-i386/uaccess.h linux/include/asm-i386/uaccess.h --- v2.1.78/linux/include/asm-i386/uaccess.h Fri Jan 2 14:37:02 1998 +++ linux/include/asm-i386/uaccess.h Sat Jan 10 18:11:36 1998 @@ -97,15 +97,50 @@ * with a separate "access_ok()" call (this is used when we do multiple * accesses to the same area of user memory). */ + +extern void __get_user_1(void); +extern void __get_user_2(void); +extern void __get_user_4(void); + +#define __get_user_x(size,ret,x,ptr) \ + __asm__ __volatile__("call __get_user_" #size \ + :"=a" (ret),"=d" (x) \ + :"0" (ptr)) + #define get_user(x,ptr) \ - __get_user_check((x),(ptr),sizeof(*(ptr))) +({ int __ret_gu; \ + switch(sizeof (*(ptr))) { \ + case 1: __get_user_x(1,__ret_gu,x,ptr); break; \ + case 2: __get_user_x(2,__ret_gu,x,ptr); break; \ + case 4: __get_user_x(4,__ret_gu,x,ptr); break; \ + default: __get_user_x(X,__ret_gu,x,ptr); break; \ + } \ + __ret_gu; \ +}) + +extern void __put_user_1(void); +extern void __put_user_2(void); +extern void __put_user_4(void); + +#define __put_user_x(size,ret,x,ptr) \ + __asm__ __volatile__("call __put_user_" #size \ + :"=a" (ret) \ + :"0" (ptr),"d" (x) \ + :"cx") + #define put_user(x,ptr) \ - __put_user_check((__typeof__(*(ptr)))(x),(ptr),sizeof(*(ptr))) +({ int __ret_pu; \ + switch(sizeof (*(ptr))) { \ + case 1: __put_user_x(1,__ret_pu,(char)(x),ptr); break; \ + case 2: __put_user_x(2,__ret_pu,(short)(x),ptr); break; \ + case 4: __put_user_x(4,__ret_pu,(int)(x),ptr); break; \ + default: __put_user_x(X,__ret_pu,x,ptr); break; \ + } \ + __ret_pu; \ +}) -#define __get_user(x,ptr) \ - __get_user_nocheck((x),(ptr),sizeof(*(ptr))) -#define __put_user(x,ptr) \ - __put_user_nocheck((__typeof__(*(ptr)))(x),(ptr),sizeof(*(ptr))) +#define __get_user(x,ptr) get_user(x,ptr) +#define __put_user(x,ptr) put_user(x,ptr) /* * The "xxx_ret" versions return constant specified in third argument, if @@ -113,119 +148,13 @@ * case of just returning from the function xxx_ret is used. */ -#define put_user_ret(x,ptr,ret) ({ \ -if (put_user(x,ptr)) return ret; }) +#define put_user_ret(x,ptr,ret) ({ if (put_user(x,ptr)) return ret; }) -#define get_user_ret(x,ptr,ret) ({ \ -if (get_user(x,ptr)) return ret; }) +#define get_user_ret(x,ptr,ret) ({ if (get_user(x,ptr)) return ret; }) -#define __put_user_ret(x,ptr,ret) ({ \ -if (__put_user(x,ptr)) return ret; }) +#define __put_user_ret(x,ptr,ret) ({ if (__put_user(x,ptr)) return ret; }) -#define __get_user_ret(x,ptr,ret) ({ \ -if (__get_user(x,ptr)) return ret; }) - - - -extern long __put_user_bad(void); - -#define __put_user_nocheck(x,ptr,size) \ -({ \ - long __pu_err; \ - __put_user_size((x),(ptr),(size),__pu_err); \ - __pu_err; \ -}) - -#define __put_user_check(x,ptr,size) \ -({ \ - long __pu_err = -EFAULT; \ - __typeof__(*(ptr)) *__pu_addr = (ptr); \ - if (access_ok(VERIFY_WRITE,__pu_addr,size)) \ - __put_user_size((x),__pu_addr,(size),__pu_err); \ - __pu_err; \ -}) - -#define __put_user_size(x,ptr,size,retval) \ -do { \ - retval = 0; \ - switch (size) { \ - case 1: __put_user_asm(x,ptr,retval,"b","b","iq"); break; \ - case 2: __put_user_asm(x,ptr,retval,"w","w","ir"); break; \ - case 4: __put_user_asm(x,ptr,retval,"l","","ir"); break; \ - default: __put_user_bad(); \ - } \ -} while (0) - -struct __large_struct { unsigned long buf[100]; }; -#define __m(x) (*(struct __large_struct *)(x)) - -/* - * Tell gcc we read from memory instead of writing: this is because - * we do not write to any memory gcc knows about, so there are no - * aliasing issues. - */ -#define __put_user_asm(x, addr, err, itype, rtype, ltype) \ - __asm__ __volatile__( \ - "1: mov"itype" %"rtype"1,%2\n" \ - "2:\n" \ - ".section .fixup,\"ax\"\n" \ - "3: movl %3,%0\n" \ - " jmp 2b\n" \ - ".previous\n" \ - ".section __ex_table,\"a\"\n" \ - " .align 4\n" \ - " .long 1b,3b\n" \ - ".previous" \ - : "=r"(err) \ - : ltype (x), "m"(__m(addr)), "i"(-EFAULT), "0"(err)) - - -#define __get_user_nocheck(x,ptr,size) \ -({ \ - long __gu_err, __gu_val; \ - __get_user_size(__gu_val,(ptr),(size),__gu_err); \ - (x) = (__typeof__(*(ptr)))__gu_val; \ - __gu_err; \ -}) - -#define __get_user_check(x,ptr,size) \ -({ \ - long __gu_err = -EFAULT, __gu_val = 0; \ - const __typeof__(*(ptr)) *__gu_addr = (ptr); \ - if (access_ok(VERIFY_READ,__gu_addr,size)) \ - __get_user_size(__gu_val,__gu_addr,(size),__gu_err); \ - (x) = (__typeof__(*(ptr)))__gu_val; \ - __gu_err; \ -}) - -extern long __get_user_bad(void); - -#define __get_user_size(x,ptr,size,retval) \ -do { \ - retval = 0; \ - switch (size) { \ - case 1: __get_user_asm(x,ptr,retval,"b","b","=q"); break; \ - case 2: __get_user_asm(x,ptr,retval,"w","w","=r"); break; \ - case 4: __get_user_asm(x,ptr,retval,"l","","=r"); break; \ - default: (x) = __get_user_bad(); \ - } \ -} while (0) - -#define __get_user_asm(x, addr, err, itype, rtype, ltype) \ - __asm__ __volatile__( \ - "1: mov"itype" %2,%"rtype"1\n" \ - "2:\n" \ - ".section .fixup,\"ax\"\n" \ - "3: movl %3,%0\n" \ - " xor"itype" %"rtype"1,%"rtype"1\n" \ - " jmp 2b\n" \ - ".previous\n" \ - ".section __ex_table,\"a\"\n" \ - " .align 4\n" \ - " .long 1b,3b\n" \ - ".previous" \ - : "=r"(err), ltype (x) \ - : "m"(__m(addr)), "i"(-EFAULT), "0"(err)) +#define __get_user_ret(x,ptr,ret) ({ if (__get_user(x,ptr)) return ret; }) /* @@ -252,6 +181,24 @@ : "r"(size & 3), "0"(size / 4), "D"(to), "S"(from) \ : "di", "si", "memory") +/* We let the __ versions of copy_from/to_user inline, because they're often + * used in fast paths and have only a small space overhead. + */ +static inline unsigned long +__generic_copy_from_user_nocheck(void *to, const void *from, unsigned long n) +{ + __copy_user(to,from,n); + return n; +} + +static inline unsigned long +__generic_copy_to_user_nocheck(void *to, const void *from, unsigned long n) +{ + __copy_user(to,from,n); + return n; +} + + /* Optimize just a little bit when we know the size of the move. */ #define __constant_copy_user(to, from, size) \ do { \ @@ -335,13 +282,8 @@ } \ } while (0) -static inline unsigned long -__generic_copy_to_user(void *to, const void *from, unsigned long n) -{ - if (access_ok(VERIFY_WRITE, to, n)) - __copy_user(to,from,n); - return n; -} +unsigned long __generic_copy_to_user(void *, const void *, unsigned long); +unsigned long __generic_copy_from_user(void *, const void *, unsigned long); static inline unsigned long __constant_copy_to_user(void *to, const void *from, unsigned long n) @@ -352,14 +294,6 @@ } static inline unsigned long -__generic_copy_from_user(void *to, const void *from, unsigned long n) -{ - if (access_ok(VERIFY_READ, from, n)) - __copy_user(to,from,n); - return n; -} - -static inline unsigned long __constant_copy_from_user(void *to, const void *from, unsigned long n) { if (access_ok(VERIFY_READ, from, n)) @@ -368,13 +302,6 @@ } static inline unsigned long -__generic_copy_to_user_nocheck(void *to, const void *from, unsigned long n) -{ - __copy_user(to,from,n); - return n; -} - -static inline unsigned long __constant_copy_to_user_nocheck(void *to, const void *from, unsigned long n) { __constant_copy_user(to,from,n); @@ -382,13 +309,6 @@ } static inline unsigned long -__generic_copy_from_user_nocheck(void *to, const void *from, unsigned long n) -{ - __copy_user(to,from,n); - return n; -} - -static inline unsigned long __constant_copy_from_user_nocheck(void *to, const void *from, unsigned long n) { __constant_copy_user(to,from,n); @@ -405,15 +325,9 @@ __constant_copy_from_user((to),(from),(n)) : \ __generic_copy_from_user((to),(from),(n))) -#define copy_to_user_ret(to,from,n,retval) ({ \ -if (copy_to_user(to,from,n)) \ - return retval; \ -}) +#define copy_to_user_ret(to,from,n,retval) ({ if (copy_to_user(to,from,n)) return retval; }) -#define copy_from_user_ret(to,from,n,retval) ({ \ -if (copy_from_user(to,from,n)) \ - return retval; \ -}) +#define copy_from_user_ret(to,from,n,retval) ({ if (copy_from_user(to,from,n)) return retval; }) #define __copy_to_user(to,from,n) \ (__builtin_constant_p(n) ? \ @@ -425,116 +339,10 @@ __constant_copy_from_user_nocheck((to),(from),(n)) : \ __generic_copy_from_user_nocheck((to),(from),(n))) - -/* - * Zero Userspace - */ - -#define __do_clear_user(addr,size) \ - __asm__ __volatile__( \ - "0: rep; stosl\n" \ - " movl %1,%0\n" \ - "1: rep; stosb\n" \ - "2:\n" \ - ".section .fixup,\"ax\"\n" \ - "3: lea 0(%1,%0,4),%0\n" \ - " jmp 2b\n" \ - ".previous\n" \ - ".section __ex_table,\"a\"\n" \ - " .align 4\n" \ - " .long 0b,3b\n" \ - " .long 1b,2b\n" \ - ".previous" \ - : "=c"(size) \ - : "r"(size & 3), "0"(size / 4), "D"(addr), "a"(0) \ - : "di") - -static inline unsigned long -clear_user(void *to, unsigned long n) -{ - if (access_ok(VERIFY_WRITE, to, n)) - __do_clear_user(to, n); - return n; -} - -static inline unsigned long -__clear_user(void *to, unsigned long n) -{ - __do_clear_user(to, n); - return n; -} - - -/* - * Copy a null terminated string from userspace. - */ - -#define __do_strncpy_from_user(dst,src,count,res) \ - __asm__ __volatile__( \ - " testl %1,%1\n" \ - " jz 2f\n" \ - "0: lodsb\n" \ - " stosb\n" \ - " testb %%al,%%al\n" \ - " jz 1f\n" \ - " decl %1\n" \ - " jnz 0b\n" \ - "1: subl %1,%0\n" \ - "2:\n" \ - ".section .fixup,\"ax\"\n" \ - "3: movl %2,%0\n" \ - " jmp 2b\n" \ - ".previous\n" \ - ".section __ex_table,\"a\"\n" \ - " .align 4\n" \ - " .long 0b,3b\n" \ - ".previous" \ - : "=d"(res), "=c"(count) \ - : "i"(-EFAULT), "0"(count), "1"(count), "S"(src), "D"(dst) \ - : "si", "di", "ax", "memory") - -static inline long -__strncpy_from_user(char *dst, const char *src, long count) -{ - long res; - __do_strncpy_from_user(dst, src, count, res); - return res; -} - -static inline long -strncpy_from_user(char *dst, const char *src, long count) -{ - long res = -EFAULT; - if (access_ok(VERIFY_READ, src, 1)) - __do_strncpy_from_user(dst, src, count, res); - return res; -} - -/* - * Return the size of a string (including the ending 0) - * - * Return 0 for error - */ - -extern inline long strlen_user(const char *s) -{ - unsigned long res; - - __asm__ __volatile__( - "0: repne; scasb\n" - " notl %0\n" - "1:\n" - ".section .fixup,\"ax\"\n" - "2: xorl %0,%0\n" - " jmp 1b\n" - ".previous\n" - ".section __ex_table,\"a\"\n" - " .align 4\n" - " .long 0b,2b\n" - ".previous" - :"=c" (res), "=D" (s) - :"1" (s), "a" (0), "0" (-__addr_ok(s))); - return res & -__addr_ok(s); -} +long strncpy_from_user(char *dst, const char *src, long count); +long __strncpy_from_user(char *dst, const char *src, long count); +long strlen_user(const char *str); +unsigned long clear_user(void *mem, unsigned long len); +unsigned long __clear_user(void *mem, unsigned long len); #endif /* __i386_UACCESS_H */ diff -u --recursive --new-file v2.1.78/linux/include/linux/affs_fs.h linux/include/linux/affs_fs.h --- v2.1.78/linux/include/linux/affs_fs.h Thu Dec 4 14:53:57 1997 +++ linux/include/linux/affs_fs.h Tue Jan 6 13:33:29 1998 @@ -65,7 +65,7 @@ extern int affs_create(struct inode *dir, struct dentry *dentry, int mode); extern int affs_mkdir(struct inode *dir, struct dentry *dentry, int mode); extern int affs_rmdir(struct inode *dir, struct dentry *dentry); -extern int affs_link(struct inode *oldinode, struct inode *dir, +extern int affs_link(struct dentry *olddentry, struct inode *dir, struct dentry *dentry); extern int affs_symlink(struct inode *dir, struct dentry *dentry, const char *symname); @@ -78,7 +78,7 @@ extern void affs_brelse(struct buffer_head *buf); extern unsigned long affs_parent_ino(struct inode *dir); extern struct inode *affs_new_inode(const struct inode *dir); -extern int affs_notify_change(struct inode *inode, struct iattr *attr); +extern int affs_notify_change(struct dentry *dentry, struct iattr *attr); extern int affs_add_entry(struct inode *dir, struct inode *link, struct inode *inode, struct dentry *dentry, s32 type); extern void affs_put_inode(struct inode *inode); @@ -106,5 +106,8 @@ extern struct inode_operations affs_symlink_inode_operations; extern struct inode_operations affs_chrdev_inode_operations; extern struct inode_operations affs_blkdev_inode_operations; + +extern struct dentry_operations affs_dentry_operations; +extern struct dentry_operations affs_dentry_operations_intl; #endif diff -u --recursive --new-file v2.1.78/linux/include/linux/coda.h linux/include/linux/coda.h --- v2.1.78/linux/include/linux/coda.h Sun Dec 21 22:36:17 1997 +++ linux/include/linux/coda.h Tue Jan 6 10:00:22 1998 @@ -16,10 +16,13 @@ #endif #ifdef __linux__ +#define cdev_t u_quad_t #if !defined(_UQUAD_T_) && (!defined(__GLIBC__) || __GLIBC__ < 2) #define _UQUAD_T_ 1 typedef unsigned long long u_quad_t; #endif +#else +#define cdev_t dev_t #endif @@ -146,7 +149,7 @@ struct timespec va_ctime; /* time file changed */ u_long va_gen; /* generation number of file */ u_long va_flags; /* flags defined for file */ - dev_t va_rdev; /* device the special file represents */ + cdev_t va_rdev; /* device special file represents */ u_quad_t va_bytes; /* bytes of disk space held by file */ u_quad_t va_filerev; /* file modification number */ }; @@ -237,7 +240,7 @@ struct cfs_open_out { struct cfs_out_hdr oh; - dev_t dev; + cdev_t dev; ino_t inode; }; diff -u --recursive --new-file v2.1.78/linux/include/linux/coda_cnode.h linux/include/linux/coda_cnode.h --- v2.1.78/linux/include/linux/coda_cnode.h Sun Dec 21 22:36:17 1997 +++ linux/include/linux/coda_cnode.h Tue Jan 6 10:00:22 1998 @@ -26,6 +26,7 @@ u_short c_mmcount; /* count of mmappers */ struct inode *c_ovp; /* open vnode pointer */ struct list_head c_cnhead; /* head of cache entries */ + struct list_head c_volrootlist; /* list of volroot cnoddes */ }; /* flags */ @@ -36,7 +37,6 @@ #define C_ZAPDIR 0x10 void coda_cnode_free(struct cnode *); -struct cnode *coda_cnode_alloc(void); int coda_cnode_make(struct inode **, struct ViceFid *, struct super_block *); int coda_cnode_makectl(struct inode **inode, struct super_block *sb); struct inode *coda_fid_to_inode(ViceFid *fid, struct super_block *sb); diff -u --recursive --new-file v2.1.78/linux/include/linux/coda_linux.h linux/include/linux/coda_linux.h --- v2.1.78/linux/include/linux/coda_linux.h Sun Dec 21 22:36:17 1997 +++ linux/include/linux/coda_linux.h Tue Jan 6 10:00:22 1998 @@ -45,6 +45,7 @@ /* this file: heloers */ char *coda_f2s(ViceFid *f, char *s); int coda_isroot(struct inode *i); +int coda_fid_is_volroot(struct ViceFid *); int coda_iscontrol(const char *name, size_t length); void coda_load_creds(struct coda_cred *cred); int coda_mycred(struct coda_cred *); diff -u --recursive --new-file v2.1.78/linux/include/linux/coda_psdev.h linux/include/linux/coda_psdev.h --- v2.1.78/linux/include/linux/coda_psdev.h Sun Dec 21 22:36:17 1997 +++ linux/include/linux/coda_psdev.h Tue Jan 6 10:00:22 1998 @@ -26,6 +26,7 @@ struct vcomm * sbi_vcomm; struct inode * sbi_root; struct list_head sbi_cchead; + struct list_head sbi_volroothead; }; /* communication pending/processing queues queues */ diff -u --recursive --new-file v2.1.78/linux/include/linux/fat_cvf.h linux/include/linux/fat_cvf.h --- v2.1.78/linux/include/linux/fat_cvf.h Wed Dec 31 16:00:00 1969 +++ linux/include/linux/fat_cvf.h Thu Jan 8 14:02:41 1998 @@ -0,0 +1,49 @@ +#ifndef _FAT_CVF +#define _FAT_CVF + +#define CVF_USE_READPAGE 0x0001 + +struct cvf_format +{ int cvf_version; + char* cvf_version_text; + unsigned long flags; + int (*detect_cvf) (struct super_block*sb); + int (*mount_cvf) (struct super_block*sb,char*options); + int (*unmount_cvf) (struct super_block*sb); + struct buffer_head* (*cvf_bread) (struct super_block*sb,int block); + struct buffer_head* (*cvf_getblk) (struct super_block*sb,int block); + void (*cvf_brelse) (struct super_block *sb,struct buffer_head *bh); + void (*cvf_mark_buffer_dirty) (struct super_block *sb, + struct buffer_head *bh, + int dirty_val); + void (*cvf_set_uptodate) (struct super_block *sb, + struct buffer_head *bh, + int val); + int (*cvf_is_uptodate) (struct super_block *sb,struct buffer_head *bh); + void (*cvf_ll_rw_block) (struct super_block *sb, + int opr, + int nbreq, + struct buffer_head *bh[32]); + int (*fat_access) (struct super_block *sb,int nr,int new_value); + int (*cvf_statfs) (struct super_block *sb,struct statfs *buf, int bufsiz); + int (*cvf_bmap) (struct inode *inode,int block); + int (*cvf_smap) (struct inode *inode,int sector); + ssize_t (*cvf_file_read) ( struct file *, char *, size_t, loff_t *); + ssize_t (*cvf_file_write) ( struct file *, const char *, size_t, loff_t *); + int (*cvf_mmap) (struct file *, struct vm_area_struct *); + int (*cvf_readpage) (struct inode *, struct page *); + int (*cvf_writepage) (struct inode *, struct page *); + int (*cvf_dir_ioctl) (struct inode * inode, struct file * filp, + unsigned int cmd, unsigned long arg); + void (*zero_out_cluster) (struct inode*, int clusternr); +}; + +int register_cvf_format(struct cvf_format*cvf_format); +int unregister_cvf_format(struct cvf_format*cvf_format); +void dec_cvf_format_use_count_by_version(int version); +int detect_cvf(struct super_block*sb,char*force); + +extern struct cvf_format *cvf_formats[]; +extern int cvf_format_use_count[]; + +#endif diff -u --recursive --new-file v2.1.78/linux/include/linux/hdreg.h linux/include/linux/hdreg.h --- v2.1.78/linux/include/linux/hdreg.h Fri Dec 19 15:53:04 1997 +++ linux/include/linux/hdreg.h Sat Jan 10 18:11:34 1998 @@ -62,10 +62,24 @@ #define WIN_READDMA 0xc8 /* read sectors using DMA transfers */ #define WIN_WRITEDMA 0xca /* write sectors using DMA transfers */ +#define WIN_SMART 0xb0 /* self-monitoring and reporting */ + /* Additional drive command codes used by ATAPI devices. */ #define WIN_PIDENTIFY 0xA1 /* identify ATAPI device */ #define WIN_SRST 0x08 /* ATAPI soft reset command */ #define WIN_PACKETCMD 0xa0 /* Send a packet command. */ + +/* WIN_SMART sub-commands */ + +#define SMART_READ_VALUES 0xd0 +#define SMART_READ_THRESHOLDS 0xd1 +#define SMART_AUTOSAVE 0xd2 +#define SMART_SAVE 0xd3 +#define SMART_IMMEDIATE_OFFLINE 0xd4 +#define SMART_ENABLE 0xd8 +#define SMART_DISABLE 0xd9 +#define SMART_STATUS 0xda +#define SMART_AUTO_OFFLINE 0xdb /* Bits for HD_ERROR */ #define MARK_ERR 0x01 /* Bad address mark */ diff -u --recursive --new-file v2.1.78/linux/include/linux/minix_fs.h linux/include/linux/minix_fs.h --- v2.1.78/linux/include/linux/minix_fs.h Tue Sep 23 16:48:50 1997 +++ linux/include/linux/minix_fs.h Tue Jan 6 12:26:59 1998 @@ -95,7 +95,7 @@ extern int minix_unlink(struct inode * dir, struct dentry *dentry); extern int minix_symlink(struct inode * inode, struct dentry *dentry, const char * symname); -extern int minix_link(struct inode * oldinode, struct inode * dir, struct dentry *dentry); +extern int minix_link(struct dentry * old_dentry, struct inode * dir, struct dentry *dentry); extern int minix_mknod(struct inode * dir, struct dentry *dentry, int mode, int rdev); extern int minix_rename(struct inode * old_dir, struct dentry *old_dentry, struct inode * new_dir, struct dentry *new_dentry); diff -u --recursive --new-file v2.1.78/linux/include/linux/msdos_fs.h linux/include/linux/msdos_fs.h --- v2.1.78/linux/include/linux/msdos_fs.h Tue Jan 6 09:37:38 1998 +++ linux/include/linux/msdos_fs.h Sat Jan 10 18:14:50 1998 @@ -161,8 +161,9 @@ __u8 name11_12[4]; /* last 2 characters in name */ }; -struct slot_info { +struct vfat_slot_info { int is_long; /* was the found entry long */ + int is_alias; /* was the found entry an alias */ int long_slots; /* number of long slots in filename */ int total_slots; /* total slots (long and short) */ loff_t longname_offset; /* dir offset for longname start */ @@ -248,12 +249,14 @@ /* file.c */ extern struct inode_operations fat_file_inode_operations; extern struct inode_operations fat_file_inode_operations_1024; +extern struct inode_operations fat_file_inode_operations_readpage; extern ssize_t fat_file_read(struct file *, char *, size_t, loff_t *); extern ssize_t fat_file_write(struct file *, const char *, size_t, loff_t *); extern void fat_truncate(struct inode *inode); /* mmap.c */ extern int fat_mmap(struct file *, struct vm_area_struct *); +extern int fat_readpage(struct inode *, struct page *); /* vfat.c */ diff -u --recursive --new-file v2.1.78/linux/include/linux/msdos_fs_sb.h linux/include/linux/msdos_fs_sb.h --- v2.1.78/linux/include/linux/msdos_fs_sb.h Sat Oct 25 02:44:18 1997 +++ linux/include/linux/msdos_fs_sb.h Thu Jan 8 14:02:41 1998 @@ -1,5 +1,6 @@ #ifndef _MSDOS_FS_SB #define _MSDOS_FS_SB +#include /* * MS-DOS file system in-core superblock data @@ -47,6 +48,8 @@ struct fat_mount_options options; struct nls_table *nls_disk; /* Codepage used on disk */ struct nls_table *nls_io; /* Charset used for input and display */ + struct cvf_format* cvf_format; + void* private_data; }; #endif diff -u --recursive --new-file v2.1.78/linux/include/linux/proc_fs.h linux/include/linux/proc_fs.h --- v2.1.78/linux/include/linux/proc_fs.h Fri Jan 2 14:37:02 1998 +++ linux/include/linux/proc_fs.h Sat Jan 10 18:11:34 1998 @@ -244,6 +244,7 @@ int count, int *eof, void *data); int (*write_proc)(struct file *file, const char *buffer, unsigned long count, void *data); + int (*readlink_proc)(struct proc_dir_entry *de, char *page); unsigned int count; /* use count */ int deleted; /* delete flag */ }; diff -u --recursive --new-file v2.1.78/linux/include/linux/sched.h linux/include/linux/sched.h --- v2.1.78/linux/include/linux/sched.h Tue Jan 6 09:37:38 1998 +++ linux/include/linux/sched.h Sat Jan 10 18:11:34 1998 @@ -179,17 +179,18 @@ struct task_struct { /* these are hardcoded - don't touch */ volatile long state; /* -1 unrunnable, 0 runnable, >0 stopped */ - long counter; - long priority; unsigned long flags; /* per process flags, defined below */ int sigpending; - long debugreg[8]; /* Hardware debugging registers */ - struct exec_domain *exec_domain; -/* various fields */ mm_segment_t addr_limit; /* thread address space: 0-0xBFFFFFFF for user-thead 0-0xFFFFFFFF for kernel-thread */ + struct exec_domain *exec_domain; + +/* various fields */ + long debugreg[8]; /* Hardware debugging registers */ + long counter; + long priority; struct linux_binfmt *binfmt; struct task_struct *next_task, *prev_task; struct task_struct *next_run, *prev_run; @@ -311,10 +312,9 @@ * your own risk!. Base=0, limit=0x1fffff (=2MB) */ #define INIT_TASK \ -/* state etc */ { 0,DEF_PRIORITY,DEF_PRIORITY,0,0, \ +/* state etc */ { 0,0,0,KERNEL_DS,&default_exec_domain, \ /* debugregs */ { 0, }, \ -/* exec domain */&default_exec_domain, \ -/* mm_seg */ KERNEL_DS, \ +/* counter */ DEF_PRIORITY,DEF_PRIORITY, \ /* binfmt */ NULL, \ /* schedlink */ &init_task,&init_task, &init_task, &init_task, \ /* ec,brk... */ 0,0,0,0,0,0, \ diff -u --recursive --new-file v2.1.78/linux/include/linux/sysv_fs.h linux/include/linux/sysv_fs.h --- v2.1.78/linux/include/linux/sysv_fs.h Wed Dec 10 11:12:46 1997 +++ linux/include/linux/sysv_fs.h Sat Jan 10 18:14:50 1998 @@ -367,7 +367,7 @@ extern int sysv_rmdir(struct inode * dir, struct dentry * dentry); extern int sysv_unlink(struct inode * dir, struct dentry * dentry); extern int sysv_symlink(struct inode * inode, struct dentry * dentry, const char * symname); -extern int sysv_link(struct inode * oldinode, struct inode * dir, struct dentry * dentry); +extern int sysv_link(struct dentry * old_dentry, struct inode * dir, struct dentry * dentry); extern int sysv_mknod(struct inode * dir, struct dentry * dentry, int mode, int rdev); extern int sysv_rename(struct inode * old_dir, struct dentry * old_dentry, struct inode * new_dir, struct dentry * new_dentry); @@ -390,7 +390,7 @@ extern int init_sysv_fs(void); extern void sysv_write_super(struct super_block *); extern void sysv_read_inode(struct inode *); -extern int sysv_notify_change(struct inode *, struct iattr *); +extern int sysv_notify_change(struct dentry *, struct iattr *); extern void sysv_write_inode(struct inode *); extern void sysv_put_inode(struct inode *); extern int sysv_statfs(struct super_block *, struct statfs *, int); diff -u --recursive --new-file v2.1.78/linux/include/linux/umsdos_fs.h linux/include/linux/umsdos_fs.h --- v2.1.78/linux/include/linux/umsdos_fs.h Mon Jul 7 16:03:54 1997 +++ linux/include/linux/umsdos_fs.h Sat Jan 10 18:14:50 1998 @@ -135,6 +135,7 @@ extern struct file_operations umsdos_file_operations; extern struct inode_operations umsdos_file_inode_operations; extern struct inode_operations umsdos_file_inode_operations_no_bmap; +extern struct inode_operations umsdos_file_inode_operations_readpage; extern struct inode_operations umsdos_symlink_inode_operations; extern int init_umsdos_fs(void); diff -u --recursive --new-file v2.1.78/linux/kernel/exit.c linux/kernel/exit.c --- v2.1.78/linux/kernel/exit.c Mon Dec 1 12:04:15 1997 +++ linux/kernel/exit.c Sat Jan 10 15:21:42 1998 @@ -418,8 +418,7 @@ if (ru != NULL) getrusage(p, RUSAGE_BOTH, ru); if (stat_addr) - __put_user((p->exit_code << 8) | 0x7f, - stat_addr); + __put_user((p->exit_code << 8) | 0x7f, stat_addr); p->exit_code = 0; retval = p->pid; goto end_wait4; diff -u --recursive --new-file v2.1.78/linux/kernel/sysctl.c linux/kernel/sysctl.c --- v2.1.78/linux/kernel/sysctl.c Sun Dec 21 22:36:17 1997 +++ linux/kernel/sysctl.c Sat Jan 10 15:15:21 1998 @@ -435,12 +435,16 @@ return tmp; } -void unregister_sysctl_table(struct ctl_table_header * table) +/* + * Unlink and free a ctl_table. + */ +void unregister_sysctl_table(struct ctl_table_header * header) { - DLIST_DELETE(table, ctl_entry); + DLIST_DELETE(header, ctl_entry); #ifdef CONFIG_PROC_FS - unregister_proc_table(table->ctl_table, &proc_sys_root); + unregister_proc_table(header->ctl_table, &proc_sys_root); #endif + kfree(header); } /* @@ -457,18 +461,20 @@ mode_t mode; for (; table->ctl_name; table++) { - de = 0; /* Can't do anything without a proc name. */ if (!table->procname) continue; /* Maybe we can't do anything with it... */ - if (!table->proc_handler && - !table->child) + if (!table->proc_handler && !table->child) { + printk(KERN_WARNING "SYSCTL: Can't register %s\n", + table->procname); continue; + } len = strlen(table->procname); mode = table->mode; + de = NULL; if (table->proc_handler) mode |= S_IFREG; else { @@ -495,6 +501,9 @@ } } +/* + * Unregister a /proc sysctl table and any subdirectories. + */ static void unregister_proc_table(ctl_table * table, struct proc_dir_entry *root) { struct proc_dir_entry *de; @@ -512,8 +521,11 @@ entries... */ if (!((de->mode & S_IFDIR) && de->subdir)) { proc_unregister(root, de->low_ino); + table->de = NULL; kfree(de); - } + } else + printk("unregister_proc_table: %s not empty!\n", + table->procname); } } diff -u --recursive --new-file v2.1.78/linux/net/ipv4/ipconfig.c linux/net/ipv4/ipconfig.c --- v2.1.78/linux/net/ipv4/ipconfig.c Mon Dec 1 12:04:16 1997 +++ linux/net/ipv4/ipconfig.c Fri Jan 9 09:28:06 1998 @@ -868,6 +868,9 @@ } } } + + if (ic_gateway == INADDR_NONE && b->relay_ip) + ic_gateway = b->relay_ip; } #endif