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
--- /dev/null
+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
+
VERSION = 2
PATCHLEVEL = 1
-SUBLEVEL = 78
+SUBLEVEL = 79
ARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/)
/*
* 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):
* 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
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 */
EXPORT_SYMBOL(mca_isenabled);
EXPORT_SYMBOL(mca_isadapter);
#endif
+
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
--- /dev/null
+/*
+ * __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
--- /dev/null
+/*
+ * __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
--- /dev/null
+/*
+ * User address space access functions.
+ * The non inlined parts of asm-i386/uaccess.h are here.
+ *
+ * Copyright 1997 Andi Kleen <ak@muc.de>
+ * Copyright 1997 Linus Torvalds
+ */
+#include <asm/uaccess.h>
+
+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);
+}
/* 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;
}
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)
{
info->devinfo.handle = NULL;
return 1;
}
+ ide_cdrom_add_settings(drive);
return 0;
}
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 */
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)
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++;
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);
/*
- * 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)
*/
* 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 */
{
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;
}
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;
}
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
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);
struct hd_driveid *id = drive->id;
unsigned long capacity, check;
+ idedisk_add_settings(drive);
+
if (id == NULL)
return;
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;
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++;
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.
*/
}
(void) idefloppy_get_capacity (drive);
+ idefloppy_add_settings(drive);
}
static int idefloppy_cleanup (ide_drive_t *drive)
{ 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
*/
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.
*/
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;
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++;
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)
/*
- * 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
*/
* 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.
*
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];
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)
{
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
(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;
-
- 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);
+ int len, rc, mul_factor, div_factor;
+
+ 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)
{
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)
{
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 }
};
}
}
-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];
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;
}
}
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;
}
/*
- * 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 <gadio@netvision.net.il>
+ * Copyright (C) 1995 - 1998 Gadi Oxman <gadio@netvision.net.il>
*
* This driver was constructed as a student project in the software laboratory
* of the faculty of electrical engineering in the Technion - Israel's
* 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:
* sharing a (fast) ATA-2 disk with any (slow) new ATAPI device.
*/
-#define IDETAPE_VERSION "1.12"
+#define IDETAPE_VERSION "1.13"
#include <linux/config.h>
#include <linux/module.h>
*/
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 */
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);
}
/*
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;
}
/*
* 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");
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
#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:
*
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);
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)
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)
{
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
*/
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.
*/
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;
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
/*
- * 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)
*/
* 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
*
/*
* 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:
{
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]) {
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 */
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;
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;
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:
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;
#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;
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:
{
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 */
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;
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;
}
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;
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);
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 */
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 */
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;
/*
int active; /* set when servicing requests */
} 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 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;
typedef struct ide_module_s {
int type;
ide_module_init_proc *init;
+ void *info;
struct ide_module_s *next;
} ide_module_t;
*/
#ifndef _IDE_C
extern ide_hwif_t ide_hwifs[]; /* master data repository */
+extern ide_module_t *ide_modules;
#endif
/*
*/
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.
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;
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
+ <redhat@cococo.net>.
+ Fix bug in pci_probe() for 64 bit systems reported
+ by <belliott@accessone.com>.
+ 0.533 9-Jan-98 Fix more 64 bit bugs reported by <jal@cs.brown.edu>.
=========================================================================
*/
-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 <linux/module.h>
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 */
{
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;
/* 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
{
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;
/* 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
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);
/*
- * 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 <gadio@netvision.net.il>
+ * Copyright (C) 1996 - 1998 Gadi Oxman <gadio@netvision.net.il>
*/
/*
* 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 <linux/module.h>
#include <linux/types.h>
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;
/*
}
/*
- * 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)
{
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;
}
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;
}
*/
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;
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];
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;
}
}
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.
*/
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)
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
*/
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};
/*
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;
{
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;
}
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++;
#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 *);
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;
}
#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 $";
*/
EXPORT_SYMBOL(scsi_logging_level);
#endif
+EXPORT_SYMBOL(scsi_sleep);
+
#if defined(CONFIG_PROC_FS)
EXPORT_SYMBOL(proc_print_scsidevice);
#endif
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 &&
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)");
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 */
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);
#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)
{
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;
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;
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? */
print_command(sr_cmd);
print_sense("sr", SCpnt);
err = -EIO;
- };
+ }
+ }
result = SCpnt->result;
/* Wake up a process waiting for device*/
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 */
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:
#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)
/* 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;
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;
}
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) +
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
#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
#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,
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;
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;
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))
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--;
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--;
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;
/* 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))
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++;
+ n = 0;
+ for (i = 0; i < 32; i++) /* Count selected device bits */
+ if (mask & (1 << i))
+ n++;
- if (n != 1)
- mask = SOUND_MASK_MIC;
- }
+ 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);
/* 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);
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;
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;
devc->levels[dev] = retvol;
/*
- * Set the left channel
+ * Set the left channel
*/
regoffs = devc->mix_devices[dev][LEFT_CHN].regno;
devc->saved_regs[regoffs] = val;
/*
- * Set the right channel
+ * Set the right channel
*/
if (devc->mix_devices[dev][RIGHT_CHN].nbits == 0)
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]);
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;
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 */
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 */
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_RECMASK:
+ val = devc->supported_rec_devices;
+ break;
- case SOUND_MIXER_CAPS:
- return put_user(SOUND_CAP_EXCL_INPUT, (int *)arg);
+ case SOUND_MIXER_CAPS:
+ val=SOUND_CAP_EXCL_INPUT;
+ break;
- default:
- val = ad1848_mixer_get(devc, cmd & 0xff);
- return put_user(val, (int *)arg);
+ 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[] =
{48000, (6 << 1) | 0}
};
- int i, n, selected = -1;
+ int i, n, selected = -1;
n = sizeof(speed_table) / sizeof(speed_struct);
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;
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[] =
{
{
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;
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;
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;
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;
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;
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;
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_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();
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;
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);
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;
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++;
#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)
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, 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++;
- }
+ {
+ 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, 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);
#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);
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;
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 */
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;
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.
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 */
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;
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"));
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"));
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"));
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"));
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)));
-
- switch (id)
- {
+ {
+ /*
+ * 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)));
+
+ switch (id)
+ {
case 0xa0:
devc->chip_name = "CS4231A";
*/
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;
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)
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];
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,
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)
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;
#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;
}
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);
+ if (!share_dma)
+ {
+ if (irq > 0)
+ snd_release_irq(devc->irq);
- sound_free_dma(audio_devs[dev]->dmap_out->dma);
+ 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 (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;
}
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
* 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 */
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
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 */
#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 */
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 */
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));
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
*/
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] =
{
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;
-
- 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;
- }
+ { /* 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(KERN_WARNING "MSS: Invalid capture DMA\n");
+ dma2 = dma;
+ }
+ }
+ else
+ {
+ dma2 = dma;
+ }
hw_config->dma = dma;
hw_config->dma2 = dma2;
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,
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;
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;
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;
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;
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 */
MODULE_PARM(dma, "i");
MODULE_PARM(dma2, "i");
MODULE_PARM(type, "i");
+MODULE_PARM(deskpro_xl, "i");
int io = -1;
int irq = -1;
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)
return 0;
}
-void
-cleanup_module(void)
+void cleanup_module(void)
{
SOUND_LOCK_END;
if(loaded)
#else
-void
-export_ad1848_syms(void)
+void export_ad1848_syms(void)
{
}
#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
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;
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;
return 0;
}
-int
-pas_remove_intr(int mask)
+int pas_remove_intr(int mask)
{
if (!mask)
return 0;
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 */
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
,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);
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];
-
- pas_write(irq_dma, 0xFB8A);
- } else
+ {
+ 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(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
#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;
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
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;
return 0;
}
-void
-cleanup_module(void)
+void cleanup_module(void)
{
unload_pas(&config);
SOUND_LOCK_END;
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
-----------
* affs regular file handling primitives
*/
+#define DEBUG 0
#include <asm/uaccess.h>
#include <asm/system.h>
#include <linux/sched.h>
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);
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);
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;
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;
}
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);
#include <linux/errno.h>
-/* Simple toupper() for DOS\1 */
+/* Simple toupper()/tolower() for DOS\1 */
static inline unsigned int
affs_toupper(unsigned int ch)
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)
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.
*/
if (!inode)
return -EACCES;
}
+ dentry->d_op = AFFS_I2FSTYPE(dir) ? &affs_dentry_operations_intl
+ : &affs_dentry_operations;
d_add(dentry,inode);
return 0;
}
}
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;
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;
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.
};
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;
if ( cnp )
CHECK_CNODE(cnp);
} else {
- printk("No inode for dentry_delete!\n");
+ CDEBUG(D_CACHE, "No inode for dentry_delete!\n");
return;
}
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)
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);
printk("coda_zapfid: no cnode!\n");
return;
}
- cnp->c_flags |= flag;
- coda_cache_clear_cnp(cnp);
+ coda_zap_cnode(cnp, flag);
}
#include <linux/coda.h>
#include <linux/coda_linux.h>
-#include <linux/coda_psdev.h>
#include <linux/coda_cnode.h>
+#include <linux/coda_psdev.h>
extern int coda_debug;
extern int coda_print_entry;
memset(result, 0, (int) sizeof(struct cnode));
INIT_LIST_HEAD(&(result->c_cnhead));
+ INIT_LIST_HEAD(&(result->c_volrootlist));
return result;
}
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;
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);
ENTRY;
CDEBUG(D_INODE, "%s\n", coda_f2s(fid, str));
+
nr = coda_f2i(fid);
inode = iget(sb, nr);
}
+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)
{
void coda_iattr_to_vattr(struct iattr *iattr, struct coda_vattr *vattr)
{
- umode_t mode;
unsigned int valid;
/* clean out */
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;
/* don't do others */
vattr->va_type = C_VNON;
}
+#endif
/* set those vattrs that need change */
valid = iattr->ia_valid;
}
}
-
void print_vattr(struct coda_vattr *attr)
{
/* 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,
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;
}
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;
if ( error ) {
CDEBUG(D_INODE, "mkdir error: %s result %d\n",
coda_f2s(&newfid, fidstr), error);
+ d_drop(de);
return error;
}
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;
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);
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;
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);
/* cache management */
dircnp->c_flags &= ~C_VATTR;
-/* cfsnc_zapfid(&(dircnp->c_fid)); */
de->d_inode->i_nlink--;
d_delete(de);
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");
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);
return error;
}
- dir->i_nlink--;
- d_delete(de);
+ if (rehash)
+ d_add(de, NULL);
+ /* XXX how can mtime be set? */
return 0;
}
#include <linux/coda_cache.h>
/* 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);
};
/* 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;
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;
}
+++ /dev/null
-/*
- * 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 <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/fs.h>
-#include <linux/stat.h>
-#include <linux/errno.h>
-#include <linux/locks.h>
-#include <asm/segment.h>
-#include <asm/uaccess.h>
-#include <linux/string.h>
-
-#include <linux/coda.h>
-#include <linux/coda_linux.h>
-#include <linux/coda_psdev.h>
-#include <linux/coda_cnode.h>
-#include <linux/coda_namecache.h>
-
-/* prototypes */
-static int coda_readpage(struct inode *inode, struct page *page);
-static int coda_cnode_makectl(struct inode **inode, struct super_block *sb);
-
-
-
-
-
#include <linux/coda.h>
#include <linux/coda_linux.h>
-#include <linux/coda_psdev.h>
#include <linux/coda_cnode.h>
+#include <linux/coda_psdev.h>
#include <linux/coda_cache.h>
#include <linux/coda_sysctl.h>
/* 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 *);
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;
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;
error:
EXIT;
+ MOD_DEC_USE_COUNT;
if (sbi) {
sbi->sbi_vcomm = NULL;
sbi->sbi_root = NULL;
coda_cnode_free(ITOC(root));
}
sb->s_dev = 0;
- MOD_DEC_USE_COUNT;
return NULL;
}
}
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",
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;
#include <linux/coda_cnode.h>
#include <linux/coda_cache.h>
-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 = {
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);
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);
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;
(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)
# 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)
#include <linux/string.h>
#include <linux/fs.h>
#include <linux/msdos_fs.h>
+#include <linux/fat_cvf.h>
#if 0
# define PRINTK(x) printk x
* 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 {
{
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{
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{
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;
}
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;
}
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;
}
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{
#include <linux/errno.h>
#include <linux/string.h>
#include <linux/stat.h>
+#include <linux/fat_cvf.h>
#include "msbuffer.h"
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) {
}
-int get_cluster(struct inode *inode,int cluster)
+int fat_get_cluster(struct inode *inode,int cluster)
{
int nr,count;
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))) {
}
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;
}
--- /dev/null
+/*
+ * CVF extensions for fat-based filesystems
+ *
+ * written 1997,1998 by Frank Gockel <gockel@sent13.uni-duisburg.de>
+ *
+ */
+
+#include<linux/sched.h>
+#include<linux/fs.h>
+#include<linux/msdos_fs.h>
+#include<linux/msdos_fs_sb.h>
+#include<linux/string.h>
+#include<linux/fat_cvf.h>
+
+#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;i<MAX_CVF_FORMATS;++i)
+ { if(cvf_formats[i]==NULL)
+ { /* free slot found, now check version */
+ for(j=0;j<MAX_CVF_FORMATS;++j)
+ { if(cvf_formats[j])
+ { if(cvf_formats[j]->cvf_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;i<MAX_CVF_FORMATS;++i)
+ { if(cvf_formats[i])
+ { if(cvf_formats[i]->cvf_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;i<MAX_CVF_FORMATS;++i)
+ { if(cvf_formats[i])
+ { if(cvf_formats[i]->cvf_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;i<MAX_CVF_FORMATS;++i)
+ { if(cvf_formats[i])
+ { if(!strcmp(cvf_formats[i]->cvf_version_text,force))
+ return i;
+ }
+ }
+ }
+ }
+
+ for(i=0;i<MAX_CVF_FORMATS;++i)
+ { if(cvf_formats[i])
+ { if(cvf_formats[i]->detect_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;
+}
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;
}
#include <linux/mm.h>
#include <linux/msdos_fs.h>
+#include <linux/fat_cvf.h>
#include "msbuffer.h"
#include "tables.h"
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)
{
#include <linux/stat.h>
#include <linux/string.h>
#include <linux/pagemap.h>
+#include <linux/fat_cvf.h>
#include <asm/uaccess.h>
#include <asm/system.h>
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 */
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);
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);
#include <linux/fs.h>
#include <linux/stat.h>
#include <linux/locks.h>
+#include <linux/fat_cvf.h>
#include <linux/malloc.h>
#include "msbuffer.h"
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);
}
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;
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;
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){
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 */
/* 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,"
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;
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:
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;
}
{
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;
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;
}
!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);
#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);
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;
}
{
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;
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))
}
+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;
+}
+
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;
/*
* 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;
}
/* Disallow removals of mountpoints. */
error = -EBUSY;
- if (dentry == dir)
+ if (dentry->d_mounts != dentry->d_covers)
goto exit_lock;
error = -EPERM;
* 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 <linux/types.h>
/* 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;
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) {
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"))
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.
*/
* 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
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);
}
/*
* 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
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);
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]";
}
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..
*/
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;
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 */
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 */
+ NULL, /* truncate */
+ NULL /* permission */
+};
+
static struct proc_dir_entry proc_root_loadavg = {
PROC_LOADAVG, 7, "loadavg",
S_IFREG | S_IRUGO, 1, 0, 0,
}
/* 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;
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;
* with a separate "access_ok()" call (this is used when we do multiple
* accesses to the same area of user memory).
*/
-#define get_user(x,ptr) \
- __get_user_check((x),(ptr),sizeof(*(ptr)))
-#define put_user(x,ptr) \
- __put_user_check((__typeof__(*(ptr)))(x),(ptr),sizeof(*(ptr)))
-#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)))
-
-/*
- * The "xxx_ret" versions return constant specified in third argument, if
- * something bad happens. These macros can be optimized for the
- * 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 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 __get_user_ret(x,ptr,ret) ({ \
-if (__get_user(x,ptr)) return ret; })
+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) \
+({ 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 long __put_user_bad(void);
+extern void __put_user_1(void);
+extern void __put_user_2(void);
+extern void __put_user_4(void);
-#define __put_user_nocheck(x,ptr,size) \
-({ \
- long __pu_err; \
- __put_user_size((x),(ptr),(size),__pu_err); \
- __pu_err; \
-})
+#define __put_user_x(size,ret,x,ptr) \
+ __asm__ __volatile__("call __put_user_" #size \
+ :"=a" (ret) \
+ :"0" (ptr),"d" (x) \
+ :"cx")
-#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(x,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 __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))
+#define __get_user(x,ptr) get_user(x,ptr)
+#define __put_user(x,ptr) put_user(x,ptr)
/*
- * 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.
+ * The "xxx_ret" versions return constant specified in third argument, if
+ * something bad happens. These macros can be optimized for the
+ * case of just returning from the function xxx_ret is used.
*/
-#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; \
-})
+#define put_user_ret(x,ptr,ret) ({ if (put_user(x,ptr)) return ret; })
-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_ret(x,ptr,ret) ({ if (get_user(x,ptr)) return ret; })
-#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 __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; })
/*
: "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 { \
} \
} 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)
return n;
}
-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)
{
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;
-}
-
static inline unsigned long
__constant_copy_to_user_nocheck(void *to, const void *from, unsigned long n)
{
return n;
}
-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_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) ? \
__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 */
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);
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);
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
#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
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 */
};
struct cfs_open_out {
struct cfs_out_hdr oh;
- dev_t dev;
+ cdev_t dev;
ino_t inode;
};
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 */
#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);
/* 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 *);
struct vcomm * sbi_vcomm;
struct inode * sbi_root;
struct list_head sbi_cchead;
+ struct list_head sbi_volroothead;
};
/* communication pending/processing queues queues */
--- /dev/null
+#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
#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 */
#define TRK0_ERR 0x02 /* couldn't find track 0 */
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);
__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 */
/* 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 */
#ifndef _MSDOS_FS_SB
#define _MSDOS_FS_SB
+#include<linux/fat_cvf.h>
/*
* MS-DOS file system in-core superblock data
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
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 */
};
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;
* 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, \
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);
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);
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);
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;
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);
}
/*
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 {
}
}
+/*
+ * 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;
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);
}
}
}
}
}
+
+ if (ic_gateway == INADDR_NONE && b->relay_ip)
+ ic_gateway = b->relay_ip;
}
#endif