diff options
439 files changed, 10433 insertions, 15637 deletions
diff --git a/Documentation/BUG-HUNTING b/Documentation/BUG-HUNTING index 6c816751b868..65022a87bf17 100644 --- a/Documentation/BUG-HUNTING +++ b/Documentation/BUG-HUNTING @@ -214,6 +214,23 @@ And recompile the kernel with CONFIG_DEBUG_INFO enabled: gdb vmlinux (gdb) p vt_ioctl (gdb) l *(0x<address of vt_ioctl> + 0xda8) +or, as one command + (gdb) l *(vt_ioctl + 0xda8) + +If you have a call trace, such as :- +>Call Trace: +> [<ffffffff8802c8e9>] :jbd:log_wait_commit+0xa3/0xf5 +> [<ffffffff810482d9>] autoremove_wake_function+0x0/0x2e +> [<ffffffff8802770b>] :jbd:journal_stop+0x1be/0x1ee +> ... +this shows the problem in the :jbd: module. You can load that module in gdb +and list the relevant code. + gdb fs/jbd/jbd.ko + (gdb) p log_wait_commit + (gdb) l *(0x<address> + 0xa3) +or + (gdb) l *(log_wait_commit + 0xa3) + Another very useful option of the Kernel Hacking section in menuconfig is Debug memory allocations. This will help you see whether data has been diff --git a/Documentation/DocBook/kernel-locking.tmpl b/Documentation/DocBook/kernel-locking.tmpl index 01825ee7db64..2e9d6b41f034 100644 --- a/Documentation/DocBook/kernel-locking.tmpl +++ b/Documentation/DocBook/kernel-locking.tmpl @@ -717,7 +717,7 @@ used, and when it gets full, throws out the least used one. <para> For our first example, we assume that all operations are in user context (ie. from system calls), so we can sleep. This means we can -use a semaphore to protect the cache and all the objects within +use a mutex to protect the cache and all the objects within it. Here's the code: </para> @@ -725,7 +725,7 @@ it. Here's the code: #include <linux/list.h> #include <linux/slab.h> #include <linux/string.h> -#include <asm/semaphore.h> +#include <linux/mutex.h> #include <asm/errno.h> struct object @@ -737,7 +737,7 @@ struct object }; /* Protects the cache, cache_num, and the objects within it */ -static DECLARE_MUTEX(cache_lock); +static DEFINE_MUTEX(cache_lock); static LIST_HEAD(cache); static unsigned int cache_num = 0; #define MAX_CACHE_SIZE 10 @@ -789,17 +789,17 @@ int cache_add(int id, const char *name) obj->id = id; obj->popularity = 0; - down(&cache_lock); + mutex_lock(&cache_lock); __cache_add(obj); - up(&cache_lock); + mutex_unlock(&cache_lock); return 0; } void cache_delete(int id) { - down(&cache_lock); + mutex_lock(&cache_lock); __cache_delete(__cache_find(id)); - up(&cache_lock); + mutex_unlock(&cache_lock); } int cache_find(int id, char *name) @@ -807,13 +807,13 @@ int cache_find(int id, char *name) struct object *obj; int ret = -ENOENT; - down(&cache_lock); + mutex_lock(&cache_lock); obj = __cache_find(id); if (obj) { ret = 0; strcpy(name, obj->name); } - up(&cache_lock); + mutex_unlock(&cache_lock); return ret; } </programlisting> @@ -853,7 +853,7 @@ The change is shown below, in standard patch format: the int popularity; }; --static DECLARE_MUTEX(cache_lock); +-static DEFINE_MUTEX(cache_lock); +static spinlock_t cache_lock = SPIN_LOCK_UNLOCKED; static LIST_HEAD(cache); static unsigned int cache_num = 0; @@ -870,22 +870,22 @@ The change is shown below, in standard patch format: the obj->id = id; obj->popularity = 0; -- down(&cache_lock); +- mutex_lock(&cache_lock); + spin_lock_irqsave(&cache_lock, flags); __cache_add(obj); -- up(&cache_lock); +- mutex_unlock(&cache_lock); + spin_unlock_irqrestore(&cache_lock, flags); return 0; } void cache_delete(int id) { -- down(&cache_lock); +- mutex_lock(&cache_lock); + unsigned long flags; + + spin_lock_irqsave(&cache_lock, flags); __cache_delete(__cache_find(id)); -- up(&cache_lock); +- mutex_unlock(&cache_lock); + spin_unlock_irqrestore(&cache_lock, flags); } @@ -895,14 +895,14 @@ The change is shown below, in standard patch format: the int ret = -ENOENT; + unsigned long flags; -- down(&cache_lock); +- mutex_lock(&cache_lock); + spin_lock_irqsave(&cache_lock, flags); obj = __cache_find(id); if (obj) { ret = 0; strcpy(name, obj->name); } -- up(&cache_lock); +- mutex_unlock(&cache_lock); + spin_unlock_irqrestore(&cache_lock, flags); return ret; } diff --git a/Documentation/fb/deferred_io.txt b/Documentation/fb/deferred_io.txt index 63883a892120..748328370250 100644 --- a/Documentation/fb/deferred_io.txt +++ b/Documentation/fb/deferred_io.txt @@ -7,10 +7,10 @@ IO. The following example may be a useful explanation of how one such setup works: - userspace app like Xfbdev mmaps framebuffer -- deferred IO and driver sets up nopage and page_mkwrite handlers +- deferred IO and driver sets up fault and page_mkwrite handlers - userspace app tries to write to mmaped vaddress -- we get pagefault and reach nopage handler -- nopage handler finds and returns physical page +- we get pagefault and reach fault handler +- fault handler finds and returns physical page - we get page_mkwrite where we add this page to a list - schedule a workqueue task to be run after a delay - app continues writing to that page with no additional cost. this is diff --git a/Documentation/feature-removal-schedule.txt b/Documentation/feature-removal-schedule.txt index a7d9d179131a..68ce1300a360 100644 --- a/Documentation/feature-removal-schedule.txt +++ b/Documentation/feature-removal-schedule.txt @@ -208,13 +208,6 @@ Who: Randy Dunlap <randy.dunlap@oracle.com> --------------------------- -What: drivers depending on OSS_OBSOLETE -When: options in 2.6.23, code in 2.6.25 -Why: obsolete OSS drivers -Who: Adrian Bunk <bunk@stusta.de> - ---------------------------- - What: libata spindown skipping and warning When: Dec 2008 Why: Some halt(8) implementations synchronize caches for and spin diff --git a/Documentation/filesystems/proc.txt b/Documentation/filesystems/proc.txt index e2799b5fafea..5681e2fa1496 100644 --- a/Documentation/filesystems/proc.txt +++ b/Documentation/filesystems/proc.txt @@ -1029,6 +1029,14 @@ nr_inodes Denotes the number of inodes the system has allocated. This number will grow and shrink dynamically. +nr_open +------- + +Denotes the maximum number of file-handles a process can +allocate. Default value is 1024*1024 (1048576) which should be +enough for most machines. Actual limit depends on RLIMIT_NOFILE +resource limit. + nr_free_inodes -------------- diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt index 9ad4e6fc56fd..8fd5aa40585f 100644 --- a/Documentation/kernel-parameters.txt +++ b/Documentation/kernel-parameters.txt @@ -780,6 +780,9 @@ and is between 256 and 4096 characters. It is defined in the file loop use the MONITOR/MWAIT idle loop anyways. Performance should be the same as idle=poll. + ide-pci-generic.all-generic-ide [HW] (E)IDE subsystem + Claim all unknown PCI IDE storage controllers. + ignore_loglevel [KNL] Ignore loglevel setting - this will print /all/ kernel messages to the console. Useful for debugging. diff --git a/Documentation/kprobes.txt b/Documentation/kprobes.txt index 53a63890aea4..30c101761d0d 100644 --- a/Documentation/kprobes.txt +++ b/Documentation/kprobes.txt @@ -96,7 +96,9 @@ or in registers (e.g., for x86_64 or for an i386 fastcall function). The jprobe will work in either case, so long as the handler's prototype matches that of the probed function. -1.3 How Does a Return Probe Work? +1.3 Return Probes + +1.3.1 How Does a Return Probe Work? When you call register_kretprobe(), Kprobes establishes a kprobe at the entry to the function. When the probed function is called and this @@ -107,9 +109,9 @@ At boot time, Kprobes registers a kprobe at the trampoline. When the probed function executes its return instruction, control passes to the trampoline and that probe is hit. Kprobes' trampoline -handler calls the user-specified handler associated with the kretprobe, -then sets the saved instruction pointer to the saved return address, -and that's where execution resumes upon return from the trap. +handler calls the user-specified return handler associated with the +kretprobe, then sets the saved instruction pointer to the saved return +address, and that's where execution resumes upon return from the trap. While the probed function is executing, its return address is stored in an object of type kretprobe_instance. Before calling @@ -131,6 +133,30 @@ zero when the return probe is registered, and is incremented every time the probed function is entered but there is no kretprobe_instance object available for establishing the return probe. +1.3.2 Kretprobe entry-handler + +Kretprobes also provides an optional user-specified handler which runs +on function entry. This handler is specified by setting the entry_handler +field of the kretprobe struct. Whenever the kprobe placed by kretprobe at the +function entry is hit, the user-defined entry_handler, if any, is invoked. +If the entry_handler returns 0 (success) then a corresponding return handler +is guaranteed to be called upon function return. If the entry_handler +returns a non-zero error then Kprobes leaves the return address as is, and +the kretprobe has no further effect for that particular function instance. + +Multiple entry and return handler invocations are matched using the unique +kretprobe_instance object associated with them. Additionally, a user +may also specify per return-instance private data to be part of each +kretprobe_instance object. This is especially useful when sharing private +data between corresponding user entry and return handlers. The size of each +private data object can be specified at kretprobe registration time by +setting the data_size field of the kretprobe struct. This data can be +accessed through the data field of each kretprobe_instance object. + +In case probed function is entered but there is no kretprobe_instance +object available, then in addition to incrementing the nmissed count, +the user entry_handler invocation is also skipped. + 2. Architectures Supported Kprobes, jprobes, and return probes are implemented on the following @@ -274,6 +300,8 @@ of interest: - ret_addr: the return address - rp: points to the corresponding kretprobe object - task: points to the corresponding task struct +- data: points to per return-instance private data; see "Kretprobe + entry-handler" for details. The regs_return_value(regs) macro provides a simple abstraction to extract the return value from the appropriate register as defined by @@ -556,23 +584,52 @@ report failed calls to sys_open(). #include <linux/kernel.h> #include <linux/module.h> #include <linux/kprobes.h> +#include <linux/ktime.h> + +/* per-instance private data */ +struct my_data { + ktime_t entry_stamp; +}; static const char *probed_func = "sys_open"; -/* Return-probe handler: If the probed function fails, log the return value. */ -static int ret_handler(struct kretprobe_instance *ri, struct pt_regs *regs) +/* Timestamp function entry. */ +static int entry_handler(struct kretprobe_instance *ri, struct pt_regs *regs) +{ + struct my_data *data; + + if(!current->mm) + return 1; /* skip kernel threads */ + + data = (struct my_data *)ri->data; + data->entry_stamp = ktime_get(); + return 0; +} + +/* If the probed function failed, log the return value and duration. + * Duration may turn out to be zero consistently, depending upon the + * granularity of time accounting on the platform. */ +static int return_handler(struct kretprobe_instance *ri, struct pt_regs *regs) { int retval = regs_return_value(regs); + struct my_data *data = (struct my_data *)ri->data; + s64 delta; + ktime_t now; + if (retval < 0) { - printk("%s returns %d\n", probed_func, retval); + now = ktime_get(); + delta = ktime_to_ns(ktime_sub(now, data->entry_stamp)); + printk("%s: return val = %d (duration = %lld ns)\n", + probed_func, retval, delta); } return 0; } static struct kretprobe my_kretprobe = { - .handler = ret_handler, - /* Probe up to 20 instances concurrently. */ - .maxactive = 20 + .handler = return_handler, + .entry_handler = entry_handler, + .data_size = sizeof(struct my_data), + .maxactive = 20, /* probe up to 20 instances concurrently */ }; static int __init kretprobe_init(void) @@ -584,7 +641,7 @@ static int __init kretprobe_init(void) printk("register_kretprobe failed, returned %d\n", ret); return -1; } - printk("Planted return probe at %p\n", my_kretprobe.kp.addr); + printk("Kretprobe active on %s\n", my_kretprobe.kp.symbol_name); return 0; } @@ -594,7 +651,7 @@ static void __exit kretprobe_exit(void) printk("kretprobe unregistered\n"); /* nmissed > 0 suggests that maxactive was set too low. */ printk("Missed probing %d instances of %s\n", - my_kretprobe.nmissed, probed_func); + my_kretprobe.nmissed, probed_func); } module_init(kretprobe_init) diff --git a/Documentation/kref.txt b/Documentation/kref.txt index f38b59d00c63..130b6e87aa7e 100644 --- a/Documentation/kref.txt +++ b/Documentation/kref.txt @@ -141,10 +141,10 @@ The last rule (rule 3) is the nastiest one to handle. Say, for instance, you have a list of items that are each kref-ed, and you wish to get the first one. You can't just pull the first item off the list and kref_get() it. That violates rule 3 because you are not already -holding a valid pointer. You must add locks or semaphores. For -instance: +holding a valid pointer. You must add a mutex (or some other lock). +For instance: -static DECLARE_MUTEX(sem); +static DEFINE_MUTEX(mutex); static LIST_HEAD(q); struct my_data { @@ -155,12 +155,12 @@ struct my_data static struct my_data *get_entry() { struct my_data *entry = NULL; - down(&sem); + mutex_lock(&mutex); if (!list_empty(&q)) { entry = container_of(q.next, struct my_q_entry, link); kref_get(&entry->refcount); } - up(&sem); + mutex_unlock(&mutex); return entry; } @@ -174,9 +174,9 @@ static void release_entry(struct kref *ref) static void put_entry(struct my_data *entry) { - down(&sem); + mutex_lock(&mutex); kref_put(&entry->refcount, release_entry); - up(&sem); + mutex_unlock(&mutex); } The kref_put() return value is useful if you do not want to hold the @@ -191,13 +191,13 @@ static void release_entry(struct kref *ref) static void put_entry(struct my_data *entry) { - down(&sem); + mutex_lock(&mutex); if (kref_put(&entry->refcount, release_entry)) { list_del(&entry->link); - up(&sem); + mutex_unlock(&mutex); kfree(entry); } else - up(&sem); + mutex_unlock(&mutex); } This is really more useful if you have to call other routines as part diff --git a/Documentation/md.txt b/Documentation/md.txt index 5818628207b5..396cdd982c26 100644 --- a/Documentation/md.txt +++ b/Documentation/md.txt @@ -416,6 +416,16 @@ also have sectors in total that could need to be processed. The two numbers are separated by a '/' thus effectively showing one value, a fraction of the process that is complete. + A 'select' on this attribute will return when resync completes, + when it reaches the current sync_max (below) and possibly at + other times. + + sync_max + This is a number of sectors at which point a resync/recovery + process will pause. When a resync is active, the value can + only ever be increased, never decreased. The value of 'max' + effectively disables the limit. + sync_speed This shows the current actual speed, in K/sec, of the current diff --git a/Documentation/rtc.txt b/Documentation/rtc.txt index e20b19c1b60d..8deffcd68cb8 100644 --- a/Documentation/rtc.txt +++ b/Documentation/rtc.txt @@ -182,8 +182,8 @@ driver returns ENOIOCTLCMD. Some common examples: since the frequency is stored in the irq_freq member of the rtc_device structure. Your driver needs to initialize the irq_freq member during init. Make sure you check the requested frequency is in range of your - hardware in the irq_set_freq function. If you cannot actually change - the frequency, just return -ENOTTY. + hardware in the irq_set_freq function. If it isn't, return -EINVAL. If + you cannot actually change the frequency, do not define irq_set_freq. If all else fails, check out the rtc-test.c driver! @@ -268,8 +268,8 @@ int main(int argc, char **argv) /* This read will block */ retval = read(fd, &data, sizeof(unsigned long)); if (retval == -1) { - perror("read"); - exit(errno); + perror("read"); + exit(errno); } fprintf(stderr, " %d",i); fflush(stderr); @@ -326,11 +326,11 @@ test_READ: rtc_tm.tm_sec %= 60; rtc_tm.tm_min++; } - if (rtc_tm.tm_min == 60) { + if (rtc_tm.tm_min == 60) { rtc_tm.tm_min = 0; rtc_tm.tm_hour++; } - if (rtc_tm.tm_hour == 24) + if (rtc_tm.tm_hour == 24) rtc_tm.tm_hour = 0; retval = ioctl(fd, RTC_ALM_SET, &rtc_tm); @@ -407,8 +407,8 @@ test_PIE: "\n...Periodic IRQ rate is fixed\n"); goto done; } - perror("RTC_IRQP_SET ioctl"); - exit(errno); + perror("RTC_IRQP_SET ioctl"); + exit(errno); } fprintf(stderr, "\n%ldHz:\t", tmp); @@ -417,27 +417,27 @@ test_PIE: /* Enable periodic interrupts */ retval = ioctl(fd, RTC_PIE_ON, 0); if (retval == -1) { - perror("RTC_PIE_ON ioctl"); - exit(errno); + perror("RTC_PIE_ON ioctl"); + exit(errno); } for (i=1; i<21; i++) { - /* This blocks */ - retval = read(fd, &data, sizeof(unsigned long)); - if (retval == -1) { - perror("read"); - exit(errno); - } - fprintf(stderr, " %d",i); - fflush(stderr); - irqcount++; + /* This blocks */ + retval = read(fd, &data, sizeof(unsigned long)); + if (retval == -1) { + perror("read"); + exit(errno); + } + fprintf(stderr, " %d",i); + fflush(stderr); + irqcount++; } /* Disable periodic interrupts */ retval = ioctl(fd, RTC_PIE_OFF, 0); if (retval == -1) { - perror("RTC_PIE_OFF ioctl"); - exit(errno); + perror("RTC_PIE_OFF ioctl"); + exit(errno); } } diff --git a/Documentation/sysctl/fs.txt b/Documentation/sysctl/fs.txt index aa986a35e994..f99254327ae5 100644 --- a/Documentation/sysctl/fs.txt +++ b/Documentation/sysctl/fs.txt @@ -23,6 +23,7 @@ Currently, these files are in /proc/sys/fs: - inode-max - inode-nr - inode-state +- nr_open - overflowuid - overflowgid - suid_dumpable @@ -91,6 +92,15 @@ usage of file handles and you don't need to increase the maximum. ============================================================== +nr_open: + +This denotes the maximum number of file-handles a process can +allocate. Default value is 1024*1024 (1048576) which should be +enough for most machines. Actual limit depends on RLIMIT_NOFILE +resource limit. + +============================================================== + inode-max, inode-nr & inode-state: As with file handles, the kernel allocates the inode structures diff --git a/Documentation/unaligned-memory-access.txt b/Documentation/unaligned-memory-access.txt new file mode 100644 index 000000000000..6223eace3c09 --- /dev/null +++ b/Documentation/unaligned-memory-access.txt @@ -0,0 +1,226 @@ +UNALIGNED MEMORY ACCESSES +========================= + +Linux runs on a wide variety of architectures which have varying behaviour +when it comes to memory access. This document presents some details about +unaligned accesses, why you need to write code that doesn't cause them, +and how to write such code! + + +The definition of an unaligned access +===================================== + +Unaligned memory accesses occur when you try to read N bytes of data starting +from an address that is not evenly divisible by N (i.e. addr % N != 0). +For example, reading 4 bytes of data from address 0x10004 is fine, but +reading 4 bytes of data from address 0x10005 would be an unaligned memory +access. + +The above may seem a little vague, as memory access can happen in different +ways. The context here is at the machine code level: certain instructions read +or write a number of bytes to or from memory (e.g. movb, movw, movl in x86 +assembly). As will become clear, it is relatively easy to spot C statements +which will compile to multiple-byte memory access instructions, namely when +dealing with types such as u16, u32 and u64. + + +Natural alignment +================= + +The rule mentioned above forms what we refer to as natural alignment: +When accessing N bytes of memory, the base memory address must be evenly +divisible by N, i.e. addr % N == 0. + +When writing code, assume the target architecture has natural alignment +requirements. + +In reality, only a few architectures require natural alignment on all sizes +of memory access. However, we must consider ALL supported architectures; +writing code that satisfies natural alignment requirements is the easiest way +to achieve full portability. + + +Why unaligned access is bad +=========================== + +The effects of performing an unaligned memory access vary from architecture +to architecture. It would be easy to write a whole document on the differences +here; a summary of the common scenarios is presented below: + + - Some architectures are able to perform unaligned memory accesses + transparently, but there is usually a significant performance cost. + - Some architectures raise processor exceptions when unaligned accesses + happen. The exception handler is able to correct the unaligned access, + at significant cost to performance. + - Some architectures raise processor exceptions when unaligned accesses + happen, but the exceptions do not contain enough information for the + unaligned access to be corrected. + - Some architectures are not capable of unaligned memory access, but will + silently perform a different memory access to the one that was requested, + resulting a a subtle code bug that is hard to detect! + +It should be obvious from the above that if your code causes unaligned +memory accesses to happen, your code will not work correctly on certain +platforms and will cause performance problems on others. + + +Code that does not cause unaligned access +========================================= + +At first, the concepts above may seem a little hard to relate to actual +coding practice. After all, you don't have a great deal of control over +memory addresses of certain variables, etc. + +Fortunately things are not too complex, as in most cases, the compiler +ensures that things will work for you. For example, take the following +structure: + + struct foo { + u16 field1; + u32 field2; + u8 field3; + }; + +Let us assume that an instance of the above structure resides in memory +starting at address 0x10000. With a basic level of understanding, it would +not be unreasonable to expect that accessing field2 would cause an unaligned +access. You'd be expecting field2 to be located at offset 2 bytes into the +structure, i.e. address 0x10002, but that address is not evenly divisible +by 4 (remember, we're reading a 4 byte value here). + +Fortunately, the compiler understands the alignment constraints, so in the +above case it would insert 2 bytes of padding in between field1 and field2. +Therefore, for standard structure types you can always rely on the compiler +to pad structures so that accesses to fields are suitably aligned (assuming +you do not cast the field to a type of different length). + +Similarly, you can also rely on the compiler to align variables and function +parameters to a naturally aligned scheme, based on the size of the type of +the variable. + +At this point, it should be clear that accessing a single byte (u8 or char) +will never cause an unaligned access, because all memory addresses are evenly +divisible by one. + +On a related topic, with the above considerations in mind you may observe +that you could reorder the fields in the structure in order to place fields +where padding would otherwise be inserted, and hence reduce the overall +resident memory size of structure instances. The optimal layout of the +above example is: + + struct foo { + u32 field2; + u16 field1; + u8 field3; + }; + +For a natural alignment scheme, the compiler would only have to add a single +byte of padding at the end of the structure. This padding is added in order +to satisfy alignment constraints for arrays of these structures. + +Another point worth mentioning is the use of __attribute__((packed)) on a +structure type. This GCC-specific attribute tells the compiler never to +insert any padding within structures, useful when you want to use a C struct +to represent some data that comes in a fixed arrangement 'off the wire'. + +You might be inclined to believe that usage of this attribute can easily +lead to unaligned accesses when accessing fields that do not satisfy +architectural alignment requirements. However, again, the compiler is aware +of the alignment constraints and will generate extra instructions to perform +the memory access in a way that does not cause unaligned access. Of course, +the extra instructions obviously cause a loss in performance compared to the +non-packed case, so the packed attribute should only be used when avoiding +structure padding is of importance. + + +Code that causes unaligned access +================================= + +With the above in mind, let's move onto a real life example of a function +that can cause an unaligned memory access. The following function adapted +from include/linux/etherdevice.h is an optimized routine to compare two +ethernet MAC addresses for equality. + +unsigned int compare_ether_addr(const u8 *addr1, const u8 *addr2) +{ + const u16 *a = (const u16 *) addr1; + const u16 *b = (const u16 *) addr2; + return ((a[0] ^ b[0]) | (a[1] ^ b[1]) | (a[2] ^ b[2])) != 0; +} + +In the above function, the reference to a[0] causes 2 bytes (16 bits) to +be read from memory starting at address addr1. Think about what would happen +if addr1 was an odd address such as 0x10003. (Hint: it'd be an unaligned +access.) + +Despite the potential unaligned access problems with the above function, it +is included in the kernel anyway but is understood to only work on +16-bit-aligned addresses. It is up to the caller to ensure this alignment or +not use this function at all. This alignment-unsafe function is still useful +as it is a decent optimization for the cases when you can ensure alignment, +which is true almost all of the time in ethernet networking context. + + +Here is another example of some code that could cause unaligned accesses: + void myfunc(u8 *data, u32 value) + { + [...] + *((u32 *) data) = cpu_to_le32(value); + [...] + } + +This code will cause unaligned accesses every time the data parameter points +to an address that is not evenly divisible by 4. + +In summary, the 2 main scenarios where you may run into unaligned access +problems involve: + 1. Casting variables to types of different lengths + 2. Pointer arithmetic followed by access to at least 2 bytes of data + + +Avoiding unaligned accesses +=========================== + +The easiest way to avoid unaligned access is to use the get_unaligned() and +put_unaligned() macros provided by the <asm/unaligned.h> header file. + +Going back to an earlier example of code that potentially causes unaligned +access: + + void myfunc(u8 *data, u32 value) + { + [...] + *((u32 *) data) = cpu_to_le32(value); + [...] + } + +To avoid the unaligned memory access, you would rewrite it as follows: + + void myfunc(u8 *data, u32 value) + { + [...] + value = cpu_to_le32(value); + put_unaligned(value, (u32 *) data); + [...] + } + +The get_unaligned() macro works similarly. Assuming 'data' is a pointer to +memory and you wish to avoid unaligned access, its usage is as follows: + + u32 value = get_unaligned((u32 *) data); + +These macros work work for memory accesses of any length (not just 32 bits as +in the examples above). Be aware that when compared to standard access of +aligned memory, using these macros to access unaligned memory can be costly in +terms of performance. + +If use of such macros is not convenient, another option is to use memcpy(), +where the source or destination (or both) are of type u8* or unsigned char*. +Due to the byte-wise nature of this operation, unaligned accesses are avoided. + +-- +Author: Daniel Drake <dsd@gentoo.org> +With help from: Alan Cox, Avuton Olrich, Heikki Orsila, Jan Engelhardt, +Johannes Berg, Kyle McMartin, Kyle Moffett, Randy Dunlap, Robert Hancock, +Uli Kunitz, Vadim Lobanov + diff --git a/Documentation/w1/masters/00-INDEX b/Documentation/w1/masters/00-INDEX index 752613c4cea2..7b0ceaaad7af 100644 --- a/Documentation/w1/masters/00-INDEX +++ b/Documentation/w1/masters/00-INDEX @@ -4,3 +4,5 @@ ds2482 - The Maxim/Dallas Semiconductor DS2482 provides 1-wire busses. ds2490 - The Maxim/Dallas Semiconductor DS2490 builds USB <-> W1 bridges. +w1-gpio + - GPIO 1-wire bus master driver. diff --git a/Documentation/w1/masters/w1-gpio b/Documentation/w1/masters/w1-gpio new file mode 100644 index 000000000000..af5d3b4aa851 --- /dev/null +++ b/Documentation/w1/masters/w1-gpio @@ -0,0 +1,33 @@ +Kernel driver w1-gpio +===================== + +Author: Ville Syrjala <syrjala@sci.fi> + + +Description +----------- + +GPIO 1-wire bus master driver. The driver uses the GPIO API to control the +wire and the GPIO pin can be specified using platform data. + + +Example (mach-at91) +------------------- + +#include <linux/w1-gpio.h> + +static struct w1_gpio_platform_data foo_w1_gpio_pdata = { + .pin = AT91_PIN_PB20, + .is_open_drain = 1, +}; + +static struct platform_device foo_w1_device = { + .name = "w1-gpio", + .id = -1, + .dev.platform_data = &foo_w1_gpio_pdata, +}; + +... + at91_set_GPIO_periph(foo_w1_gpio_pdata.pin, 1); + at91_set_multi_drive(foo_w1_gpio_pdata.pin, 1); + platform_device_register(&foo_w1_device); diff --git a/MAINTAINERS b/MAINTAINERS index 4f3da8b56979..c5325d2bb86d 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -338,13 +338,12 @@ S: Maintained for 2.4; PCI support for 2.6. AMD GEODE CS5536 USB DEVICE CONTROLLER DRIVER P: Thomas Dahlmann M: thomas.dahlmann@amd.com -L: info-linux@geode.amd.com +L: info-linux@geode.amd.com (subscribers-only) S: Supported AMD GEODE PROCESSOR/CHIPSET SUPPORT P: Jordan Crouse -M: info-linux@geode.amd.com -L: info-linux@geode.amd.com +L: info-linux@geode.amd.com (subscribers-only) W: http://www.amd.com/us-en/ConnectivitySolutions/TechnicalResources/0,,50_2334_2452_11363,00.html S: Supported @@ -841,6 +840,12 @@ L: linux-kernel@vger.kernel.org T: git kernel.org:/pub/scm/linux/kernel/git/axboe/linux-2.6-block.git S: Maintained +BLOCK2MTD DRIVER +P: Joern Engel +M: joern@lazybastard.org +L: linux-mtd@lists.infradead.org +S: Maintained + BLUETOOTH SUBSYSTEM P: Marcel Holtmann M: marcel@holtmann.org @@ -3031,8 +3036,8 @@ L: linux-abi-devel@lists.sourceforge.net S: Maintained PHRAM MTD DRIVER -P: Jörn Engel -M: joern@wh.fh-wedel.de +P: Joern Engel +M: joern@lazybastard.org L: linux-mtd@lists.infradead.org S: Maintained @@ -3856,6 +3861,12 @@ M: oliver@neukum.name L: linux-usb@vger.kernel.org S: Maintained +USB AUERSWALD DRIVER +P: Wolfgang Muees +M: wolfgang@iksw-muees.de +L: linux-usb@vger.kernel.org +S: Maintained + USB BLOCK DRIVER (UB ub) P: Pete Zaitcev M: zaitcev@redhat.com @@ -4006,12 +4017,6 @@ S: Maintained W: http://geocities.com/i0xox0i W: http://firstlight.net/cvs -USB AUERSWALD DRIVER -P: Wolfgang Muees -M: wolfgang@iksw-muees.de -L: linux-usb@vger.kernel.org -S: Maintained - USB SERIAL EMPEG EMPEG-CAR MARK I/II DRIVER P: Gary Brubaker M: xavyer@ix.netcom.com diff --git a/arch/alpha/Kconfig.debug b/arch/alpha/Kconfig.debug index f45f28cc10da..3f6265f2d9d4 100644 --- a/arch/alpha/Kconfig.debug +++ b/arch/alpha/Kconfig.debug @@ -7,15 +7,6 @@ config EARLY_PRINTK depends on ALPHA_GENERIC || ALPHA_SRM default y -config DEBUG_RWLOCK - bool "Read-write spinlock debugging" - depends on DEBUG_KERNEL - help - If you say Y here then read-write lock processing will count how many - times it has tried to get the lock and issue an error message after - too many attempts. If you suspect a rwlock problem or a kernel - hacker asks for this option then say Y. Otherwise say N. - config ALPHA_LEGACY_START_ADDRESS bool "Legacy kernel start address" depends on ALPHA_GENERIC diff --git a/arch/alpha/defconfig b/arch/alpha/defconfig index 6da9c3dbde44..e43f68fd66b0 100644 --- a/arch/alpha/defconfig +++ b/arch/alpha/defconfig @@ -882,7 +882,6 @@ CONFIG_MAGIC_SYSRQ=y # CONFIG_DEBUG_SPINLOCK is not set CONFIG_DEBUG_INFO=y CONFIG_EARLY_PRINTK=y -# CONFIG_DEBUG_RWLOCK is not set # CONFIG_DEBUG_SEMAPHORE is not set CONFIG_ALPHA_LEGACY_START_ADDRESS=y CONFIG_MATHEMU=y diff --git a/arch/alpha/kernel/osf_sys.c b/arch/alpha/kernel/osf_sys.c index 6413c5f23226..72f9a619a66d 100644 --- a/arch/alpha/kernel/osf_sys.c +++ b/arch/alpha/kernel/osf_sys.c @@ -430,7 +430,7 @@ sys_getpagesize(void) asmlinkage unsigned long sys_getdtablesize(void) { - return NR_OPEN; + return sysctl_nr_open; } /* diff --git a/arch/alpha/kernel/smp.c b/arch/alpha/kernel/smp.c index f4ab233201b2..63c2073401ee 100644 --- a/arch/alpha/kernel/smp.c +++ b/arch/alpha/kernel/smp.c @@ -77,10 +77,6 @@ int smp_num_probed; /* Internal processor count */ int smp_num_cpus = 1; /* Number that came online. */ EXPORT_SYMBOL(smp_num_cpus); -extern void calibrate_delay(void); - - - /* * Called by both boot and secondaries to move global data into * per-processor storage. diff --git a/arch/arm/mach-at91/board-sam9261ek.c b/arch/arm/mach-at91/board-sam9261ek.c index aa29ea58ca09..0ce38dfa6ebe 100644 --- a/arch/arm/mach-at91/board-sam9261ek.c +++ b/arch/arm/mach-at91/board-sam9261ek.c @@ -383,6 +383,7 @@ static void at91_lcdc_tft_power_control(int on) } static struct atmel_lcdfb_info __initdata ek_lcdc_data = { + .lcdcon_is_backlight = true, .default_bpp = 16, .default_dmacon = ATMEL_LCDC_DMAEN, .default_lcdcon2 = AT91SAM9261_DEFAULT_TFT_LCDCON2, diff --git a/arch/arm/mach-at91/board-sam9263ek.c b/arch/arm/mach-at91/board-sam9263ek.c index f09347a86e71..38313abef657 100644 --- a/arch/arm/mach-at91/board-sam9263ek.c +++ b/arch/arm/mach-at91/board-sam9263ek.c @@ -253,6 +253,7 @@ static void at91_lcdc_power_control(int on) /* Driver datas */ static struct atmel_lcdfb_info __initdata ek_lcdc_data = { + .lcdcon_is_backlight = true, .default_bpp = 16, .default_dmacon = ATMEL_LCDC_DMAEN, .default_lcdcon2 = AT91SAM9263_DEFAULT_LCDCON2, diff --git a/arch/avr32/kernel/syscall_table.S b/arch/avr32/kernel/syscall_table.S index 75c81f2dd0b3..478bda4c4a09 100644 --- a/arch/avr32/kernel/syscall_table.S +++ b/arch/avr32/kernel/syscall_table.S @@ -293,6 +293,6 @@ sys_call_table: .long sys_shmctl .long sys_utimensat .long sys_signalfd - .long sys_timerfd /* 280 */ + .long sys_ni_syscall /* 280, was sys_timerfd */ .long sys_eventfd .long sys_ni_syscall /* r8 is saturated at nr_syscalls */ diff --git a/arch/avr32/lib/delay.c b/arch/avr32/lib/delay.c index b3bc0b56e2c6..9aa8800830f3 100644 --- a/arch/avr32/lib/delay.c +++ b/arch/avr32/lib/delay.c @@ -12,13 +12,15 @@ #include <linux/delay.h> #include <linux/module.h> +#include <linux/timex.h> #include <linux/param.h> #include <linux/types.h> +#include <linux/init.h> #include <asm/processor.h> #include <asm/sysreg.h> -int read_current_timer(unsigned long *timer_value) +int __devinit read_current_timer(unsigned long *timer_value) { *timer_value = sysreg_read(COUNT); return 0; diff --git a/arch/frv/kernel/entry.S b/arch/frv/kernel/entry.S index 99046b1f51c8..ca6a345b87e4 100644 --- a/arch/frv/kernel/entry.S +++ b/arch/frv/kernel/entry.S @@ -1494,7 +1494,7 @@ sys_call_table: .long sys_epoll_pwait .long sys_utimensat /* 320 */ .long sys_signalfd - .long sys_timerfd + .long sys_ni_syscall .long sys_eventfd .long sys_fallocate diff --git a/arch/frv/kernel/setup.c b/arch/frv/kernel/setup.c index a74c08786b21..b38ae1fc15fd 100644 --- a/arch/frv/kernel/setup.c +++ b/arch/frv/kernel/setup.c @@ -708,7 +708,7 @@ static void __init reserve_dma_coherent(void) /* * calibrate the delay loop */ -void __init calibrate_delay(void) +void __cpuinit calibrate_delay(void) { loops_per_jiffy = __delay_loops_MHz * (1000000 / HZ); diff --git a/arch/h8300/kernel/irq.c b/arch/h8300/kernel/irq.c index 8dec4dd57b4e..5a1b4cfea05b 100644 --- a/arch/h8300/kernel/irq.c +++ b/arch/h8300/kernel/irq.c @@ -14,6 +14,7 @@ #include <linux/random.h> #include <linux/bootmem.h> #include <linux/irq.h> +#include <linux/interrupt.h> #include <asm/system.h> #include <asm/traps.h> diff --git a/arch/ia64/kernel/smpboot.c b/arch/ia64/kernel/smpboot.c index 480b1a5085d5..32ee5979a042 100644 --- a/arch/ia64/kernel/smpboot.c +++ b/arch/ia64/kernel/smpboot.c @@ -120,7 +120,6 @@ static volatile unsigned long go[SLAVE + 1]; #define DEBUG_ITC_SYNC 0 -extern void __devinit calibrate_delay (void); extern void start_ap (void); extern unsigned long ia64_iobase; @@ -477,7 +476,7 @@ start_secondary (void *unused) return 0; } -struct pt_regs * __devinit idle_regs(struct pt_regs *regs) +struct pt_regs * __cpuinit idle_regs(struct pt_regs *regs) { return NULL; } diff --git a/arch/ia64/sn/pci/pcibr/pcibr_provider.c b/arch/ia64/sn/pci/pcibr/pcibr_provider.c index ab3eaf85fe4d..2c676cc05418 100644 --- a/arch/ia64/sn/pci/pcibr/pcibr_provider.c +++ b/arch/ia64/sn/pci/pcibr/pcibr_provider.c @@ -100,11 +100,11 @@ u16 sn_ioboard_to_pci_bus(struct pci_bus *pci_bus) static irqreturn_t pcibr_error_intr_handler(int irq, void *arg) { - struct pcibus_info *soft = (struct pcibus_info *)arg; + struct pcibus_info *soft = arg; - if (sal_pcibr_error_interrupt(soft) < 0) { + if (sal_pcibr_error_interrupt(soft) < 0) panic("pcibr_error_intr_handler(): Fatal Bridge Error"); - } + return IRQ_HANDLED; } diff --git a/arch/m32r/kernel/syscall_table.S b/arch/m32r/kernel/syscall_table.S index 95aa79874847..aa3bf4cfab37 100644 --- a/arch/m32r/kernel/syscall_table.S +++ b/arch/m32r/kernel/syscall_table.S @@ -321,6 +321,6 @@ ENTRY(sys_call_table) .long sys_epoll_pwait .long sys_utimensat /* 320 */ .long sys_signalfd - .long sys_timerfd + .long sys_ni_syscall .long sys_eventfd .long sys_fallocate diff --git a/arch/m68k/amiga/chipram.c b/arch/m68k/amiga/chipram.c index d10726f9038b..cbe36538af47 100644 --- a/arch/m68k/amiga/chipram.c +++ b/arch/m68k/amiga/chipram.c @@ -32,12 +32,10 @@ void __init amiga_chip_init(void) if (!AMIGAHW_PRESENT(CHIP_RAM)) return; -#ifndef CONFIG_APUS_FAST_EXCEPT /* * Remove the first 4 pages where PPC exception handlers will be located */ amiga_chip_size -= 0x4000; -#endif chipram_res.end = amiga_chip_size-1; request_resource(&iomem_resource, &chipram_res); diff --git a/arch/m68k/amiga/cia.c b/arch/m68k/amiga/cia.c index c4a4ffd45bc0..343fab49bd9a 100644 --- a/arch/m68k/amiga/cia.c +++ b/arch/m68k/amiga/cia.c @@ -84,7 +84,7 @@ unsigned char cia_able_irq(struct ciabase *base, unsigned char mask) static irqreturn_t cia_handler(int irq, void *dev_id) { - struct ciabase *base = (struct ciabase *)dev_id; + struct ciabase *base = dev_id; int mach_irq; unsigned char ints; diff --git a/arch/m68knommu/lib/memcpy.c b/arch/m68knommu/lib/memcpy.c index 0d5577569e4c..b50dbcad4746 100644 --- a/arch/m68knommu/lib/memcpy.c +++ b/arch/m68knommu/lib/memcpy.c @@ -1,6 +1,5 @@ #include <linux/types.h> -#include <linux/autoconf.h> void * memcpy(void * to, const void * from, size_t n) { diff --git a/arch/mips/au1000/common/gpio.c b/arch/mips/au1000/common/gpio.c index 8527856aec45..0b658f1db4ce 100644 --- a/arch/mips/au1000/common/gpio.c +++ b/arch/mips/au1000/common/gpio.c @@ -27,7 +27,6 @@ * others have a second one : GPIO2 */ -#include <linux/autoconf.h> #include <linux/init.h> #include <linux/io.h> #include <linux/types.h> diff --git a/arch/mips/kernel/smp.c b/arch/mips/kernel/smp.c index 1e5dfc28294a..9d41dab90a80 100644 --- a/arch/mips/kernel/smp.c +++ b/arch/mips/kernel/smp.c @@ -52,7 +52,6 @@ int __cpu_logical_map[NR_CPUS]; /* Map logical to physical */ EXPORT_SYMBOL(phys_cpu_present_map); EXPORT_SYMBOL(cpu_online_map); -extern void __init calibrate_delay(void); extern void cpu_idle(void); /* Number of TCs (or siblings in Intel speak) per CPU core */ diff --git a/arch/mips/kernel/sysirix.c b/arch/mips/kernel/sysirix.c index 4c477c7ff74a..22fd41e946b2 100644 --- a/arch/mips/kernel/sysirix.c +++ b/arch/mips/kernel/sysirix.c @@ -356,7 +356,7 @@ asmlinkage int irix_syssgi(struct pt_regs *regs) retval = NGROUPS_MAX; goto out; case 5: - retval = NR_OPEN; + retval = sysctl_nr_open; goto out; case 6: retval = 1; diff --git a/arch/parisc/Kconfig.debug b/arch/parisc/Kconfig.debug index 9166bd117267..bc989e522a04 100644 --- a/arch/parisc/Kconfig.debug +++ b/arch/parisc/Kconfig.debug @@ -2,15 +2,6 @@ menu "Kernel hacking" source "lib/Kconfig.debug" -config DEBUG_RWLOCK - bool "Read-write spinlock debugging" - depends on DEBUG_KERNEL && SMP - help - If you say Y here then read-write lock processing will count how many - times it has tried to get the lock and issue an error message after - too many attempts. If you suspect a rwlock problem or a kernel - hacker asks for this option then say Y. Otherwise say N. - config DEBUG_RODATA bool "Write protect kernel read-only data structures" depends on DEBUG_KERNEL diff --git a/arch/parisc/configs/a500_defconfig b/arch/parisc/configs/a500_defconfig index ea071218a3ed..ddacc72e38fb 100644 --- a/arch/parisc/configs/a500_defconfig +++ b/arch/parisc/configs/a500_defconfig @@ -1050,7 +1050,6 @@ CONFIG_SCHED_DEBUG=y CONFIG_FORCED_INLINING=y # CONFIG_RCU_TORTURE_TEST is not set # CONFIG_FAULT_INJECTION is not set -# CONFIG_DEBUG_RWLOCK is not set # CONFIG_DEBUG_RODATA is not set # diff --git a/arch/powerpc/kernel/time.c b/arch/powerpc/kernel/time.c index 5cd3db5cae41..3b26fbd6bec9 100644 --- a/arch/powerpc/kernel/time.c +++ b/arch/powerpc/kernel/time.c @@ -66,6 +66,7 @@ #include <asm/smp.h> #include <asm/vdso_datapage.h> #include <asm/firmware.h> +#include <asm/cputime.h> #ifdef CONFIG_PPC_ISERIES #include <asm/iseries/it_lp_queue.h> #include <asm/iseries/hv_call_xm.h> @@ -189,6 +190,8 @@ u64 __cputime_sec_factor; EXPORT_SYMBOL(__cputime_sec_factor); u64 __cputime_clockt_factor; EXPORT_SYMBOL(__cputime_clockt_factor); +DEFINE_PER_CPU(unsigned long, cputime_last_delta); +DEFINE_PER_CPU(unsigned long, cputime_scaled_last_delta); static void calc_cputime_factors(void) { @@ -257,8 +260,8 @@ void account_system_vtime(struct task_struct *tsk) } account_system_time(tsk, 0, delta); account_system_time_scaled(tsk, deltascaled); - get_paca()->purrdelta = delta; - get_paca()->spurrdelta = deltascaled; + per_cpu(cputime_last_delta, smp_processor_id()) = delta; + per_cpu(cputime_scaled_last_delta, smp_processor_id()) = deltascaled; local_irq_restore(flags); } @@ -276,10 +279,7 @@ void account_process_tick(struct task_struct *tsk, int user_tick) get_paca()->user_time = 0; account_user_time(tsk, utime); - /* Estimate the scaled utime by scaling the real utime based - * on the last spurr to purr ratio */ - utimescaled = utime * get_paca()->spurrdelta / get_paca()->purrdelta; - get_paca()->spurrdelta = get_paca()->purrdelta = 0; + utimescaled = cputime_to_scaled(utime); account_user_time_scaled(tsk, utimescaled); } diff --git a/arch/powerpc/platforms/powermac/cpufreq_32.c b/arch/powerpc/platforms/powermac/cpufreq_32.c index c04abcc28a7a..792d3ce8112e 100644 --- a/arch/powerpc/platforms/powermac/cpufreq_32.c +++ b/arch/powerpc/platforms/powermac/cpufreq_32.c @@ -113,8 +113,6 @@ static inline void debug_calc_bogomips(void) * result. We backup/restore the value to avoid affecting the * core cpufreq framework's own calculation. */ - extern void calibrate_delay(void); - unsigned long save_lpj = loops_per_jiffy; calibrate_delay(); loops_per_jiffy = save_lpj; diff --git a/arch/ppc/8260_io/enet.c b/arch/ppc/8260_io/enet.c index 25ef55bacd99..ec1defea9c1e 100644 --- a/arch/ppc/8260_io/enet.c +++ b/arch/ppc/8260_io/enet.c @@ -418,7 +418,7 @@ scc_enet_rx(struct net_device *dev) struct sk_buff *skb; ushort pkt_len; - cep = (struct scc_enet_private *)dev->priv; + cep = dev->priv; /* First, grab all of the stats for the incoming packet. * These get messed up if we get called due to a busy condition. diff --git a/arch/ppc/8260_io/fcc_enet.c b/arch/ppc/8260_io/fcc_enet.c index a3a27dafff1f..bcc3aa9d04f3 100644 --- a/arch/ppc/8260_io/fcc_enet.c +++ b/arch/ppc/8260_io/fcc_enet.c @@ -682,7 +682,7 @@ fcc_enet_rx(struct net_device *dev) struct sk_buff *skb; ushort pkt_len; - cep = (struct fcc_enet_private *)dev->priv; + cep = dev->priv; /* First, grab all of the stats for the incoming packet. * These get messed up if we get called due to a busy condition. diff --git a/arch/ppc/kernel/vmlinux.lds.S b/arch/ppc/kernel/vmlinux.lds.S index 52b64fcbdfc5..8a24bc47eb6c 100644 --- a/arch/ppc/kernel/vmlinux.lds.S +++ b/arch/ppc/kernel/vmlinux.lds.S @@ -143,11 +143,6 @@ SECTIONS . = ALIGN(4096); __init_end = .; - - . = ALIGN(4096); - _sextratext = .; - _eextratext = .; - __bss_start = .; .bss : { diff --git a/arch/ppc/platforms/prep_setup.c b/arch/ppc/platforms/prep_setup.c index 3c56654bfc6f..38449855d5ff 100644 --- a/arch/ppc/platforms/prep_setup.c +++ b/arch/ppc/platforms/prep_setup.c @@ -91,20 +91,11 @@ extern void prep_tiger1_setup_pci(char *irq_edge_mask_lo, char *irq_edge_mask_hi #define cached_21 (((char *)(ppc_cached_irq_mask))[3]) #define cached_A1 (((char *)(ppc_cached_irq_mask))[2]) -#ifdef CONFIG_SOUND_CS4232 -long ppc_cs4232_dma, ppc_cs4232_dma2; -#endif - extern PTE *Hash, *Hash_end; extern unsigned long Hash_size, Hash_mask; extern int probingmem; extern unsigned long loops_per_jiffy; -#ifdef CONFIG_SOUND_CS4232 -EXPORT_SYMBOL(ppc_cs4232_dma); -EXPORT_SYMBOL(ppc_cs4232_dma2); -#endif - /* useful ISA ports */ #define PREP_SYSCTL 0x81c /* present in the IBM reference design; possibly identical in Mot boxes: */ @@ -569,74 +560,6 @@ prep_show_percpuinfo(struct seq_file *m, int i) return 0; } -#ifdef CONFIG_SOUND_CS4232 -static long __init masktoint(unsigned int i) -{ - int t = -1; - while (i >> ++t) - ; - return (t-1); -} - -/* - * ppc_cs4232_dma and ppc_cs4232_dma2 are used in include/asm/dma.h - * to distinguish sound dma-channels from others. This is because - * blocksize on 16 bit dma-channels 5,6,7 is 128k, but - * the cs4232.c uses 64k like on 8 bit dma-channels 0,1,2,3 - */ - -static void __init prep_init_sound(void) -{ - PPC_DEVICE *audiodevice = NULL; - - /* - * Get the needed resource information from residual data. - * - */ - if (have_residual_data) - audiodevice = residual_find_device(~0, NULL, - MultimediaController, AudioController, -1, 0); - - if (audiodevice != NULL) { - PnP_TAG_PACKET *pkt; - - pkt = PnP_find_packet((unsigned char *)&res->DevicePnPHeap[audiodevice->AllocatedOffset], - S5_Packet, 0); - if (pkt != NULL) - ppc_cs4232_dma = masktoint(pkt->S5_Pack.DMAMask); - pkt = PnP_find_packet((unsigned char*)&res->DevicePnPHeap[audiodevice->AllocatedOffset], - S5_Packet, 1); - if (pkt != NULL) - ppc_cs4232_dma2 = masktoint(pkt->S5_Pack.DMAMask); - } - - /* - * These are the PReP specs' defaults for the cs4231. We use these - * as fallback incase we don't have residual data. - * At least the IBM Thinkpad 850 with IDE DMA Channels at 6 and 7 - * will use the other values. - */ - if (audiodevice == NULL) { - switch (_prep_type) { - case _PREP_IBM: - ppc_cs4232_dma = 1; - ppc_cs4232_dma2 = -1; - break; - default: - ppc_cs4232_dma = 6; - ppc_cs4232_dma2 = 7; - } - } - - /* - * Find a way to push this information to the cs4232 driver - * Give it out with printk, when not in cmd_line? - * Append it to cmd_line and boot_command_line? - * Format is cs4232=io,irq,dma,dma2 - */ -} -#endif /* CONFIG_SOUND_CS4232 */ - /* * Fill out screen_info according to the residual data. This allows us to use * at least vesafb. @@ -898,10 +821,6 @@ prep_setup_arch(void) } } -#ifdef CONFIG_SOUND_CS4232 - prep_init_sound(); -#endif /* CONFIG_SOUND_CS4232 */ - prep_init_vesa(); switch (_prep_type) { diff --git a/arch/sh/kernel/syscalls_32.S b/arch/sh/kernel/syscalls_32.S index 10bec45415ba..719e127a7c05 100644 --- a/arch/sh/kernel/syscalls_32.S +++ b/arch/sh/kernel/syscalls_32.S @@ -338,6 +338,6 @@ ENTRY(sys_call_table) .long sys_epoll_pwait .long sys_utimensat /* 320 */ .long sys_signalfd - .long sys_timerfd + .long sys_ni_syscall .long sys_eventfd .long sys_fallocate diff --git a/arch/sh/kernel/syscalls_64.S b/arch/sh/kernel/syscalls_64.S index 98a93efe3691..12c7340356ae 100644 --- a/arch/sh/kernel/syscalls_64.S +++ b/arch/sh/kernel/syscalls_64.S @@ -376,6 +376,6 @@ sys_call_table: .long sys_epoll_pwait .long sys_utimensat .long sys_signalfd - .long sys_timerfd /* 350 */ + .long sys_ni_syscall /* 350 */ .long sys_eventfd .long sys_fallocate diff --git a/arch/sparc/kernel/sun4d_smp.c b/arch/sparc/kernel/sun4d_smp.c index 89a6de95070c..0def48158c7d 100644 --- a/arch/sparc/kernel/sun4d_smp.c +++ b/arch/sparc/kernel/sun4d_smp.c @@ -19,12 +19,12 @@ #include <linux/mm.h> #include <linux/swap.h> #include <linux/profile.h> +#include <linux/delay.h> #include <asm/ptrace.h> #include <asm/atomic.h> #include <asm/irq_regs.h> -#include <asm/delay.h> #include <asm/irq.h> #include <asm/page.h> #include <asm/pgalloc.h> @@ -41,8 +41,6 @@ extern ctxd_t *srmmu_ctx_table_phys; -extern void calibrate_delay(void); - static volatile int smp_processors_ready = 0; static int smp_highest_cpu; extern volatile unsigned long cpu_callin_map[NR_CPUS]; diff --git a/arch/sparc/kernel/sun4m_smp.c b/arch/sparc/kernel/sun4m_smp.c index 730eb5796f8e..0b9407267162 100644 --- a/arch/sparc/kernel/sun4m_smp.c +++ b/arch/sparc/kernel/sun4m_smp.c @@ -16,6 +16,8 @@ #include <linux/mm.h> #include <linux/swap.h> #include <linux/profile.h> +#include <linux/delay.h> + #include <asm/cacheflush.h> #include <asm/tlbflush.h> #include <asm/irq_regs.h> @@ -23,7 +25,6 @@ #include <asm/ptrace.h> #include <asm/atomic.h> -#include <asm/delay.h> #include <asm/irq.h> #include <asm/page.h> #include <asm/pgalloc.h> @@ -39,8 +40,6 @@ extern ctxd_t *srmmu_ctx_table_phys; -extern void calibrate_delay(void); - extern volatile unsigned long cpu_callin_map[NR_CPUS]; extern unsigned char boot_cpu_id; diff --git a/arch/sparc/kernel/systbls.S b/arch/sparc/kernel/systbls.S index ee010f4532a0..9064485dc40b 100644 --- a/arch/sparc/kernel/systbls.S +++ b/arch/sparc/kernel/systbls.S @@ -79,7 +79,8 @@ sys_call_table: /*295*/ .long sys_fchmodat, sys_faccessat, sys_pselect6, sys_ppoll, sys_unshare /*300*/ .long sys_set_robust_list, sys_get_robust_list, sys_migrate_pages, sys_mbind, sys_get_mempolicy /*305*/ .long sys_set_mempolicy, sys_kexec_load, sys_move_pages, sys_getcpu, sys_epoll_pwait -/*310*/ .long sys_utimensat, sys_signalfd, sys_ni_syscall, sys_eventfd, sys_fallocate +/*310*/ .long sys_utimensat, sys_signalfd, sys_timerfd_create, sys_eventfd, sys_fallocate +/*315*/ .long sys_timerfd_settime, sys_timerfd_gettime #ifdef CONFIG_SUNOS_EMUL /* Now the SunOS syscall table. */ @@ -197,6 +198,7 @@ sunos_sys_table: .long sunos_nosys, sunos_nosys, sunos_nosys .long sunos_nosys /*310*/ .long sunos_nosys, sunos_nosys, sunos_nosys - .long sunos_nosys, sunos_nosys + .long sunos_nosys, sunos_nosys, sunos_nosys + .long sunos_nosys #endif diff --git a/arch/sparc64/defconfig b/arch/sparc64/defconfig index f62d9f6c5e2a..833d74b2b192 100644 --- a/arch/sparc64/defconfig +++ b/arch/sparc64/defconfig @@ -1,7 +1,7 @@ # # Automatically generated make config: don't edit -# Linux kernel version: 2.6.24-rc4 -# Tue Dec 4 00:37:59 2007 +# Linux kernel version: 2.6.24 +# Tue Feb 5 17:28:19 2008 # CONFIG_SPARC=y CONFIG_SPARC64=y @@ -17,6 +17,7 @@ CONFIG_ARCH_MAY_HAVE_PC_FDC=y # CONFIG_ARCH_HAS_ILOG2_U32 is not set # CONFIG_ARCH_HAS_ILOG2_U64 is not set CONFIG_AUDIT_ARCH=y +CONFIG_HAVE_SETUP_PER_CPU_AREA=y CONFIG_ARCH_NO_VIRT_TO_BUS=y CONFIG_OF=y CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y @@ -30,13 +31,15 @@ CONFIG_HZ_100=y # CONFIG_HZ_300 is not set # CONFIG_HZ_1000 is not set CONFIG_HZ=100 +# CONFIG_SCHED_HRTICK is not set +CONFIG_HOTPLUG_CPU=y CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" # # General setup # CONFIG_EXPERIMENTAL=y -CONFIG_BROKEN_ON_SMP=y +CONFIG_LOCK_KERNEL=y CONFIG_INIT_ENV_ARG_LIMIT=32 CONFIG_LOCALVERSION="" # CONFIG_LOCALVERSION_AUTO is not set @@ -76,6 +79,7 @@ CONFIG_FUTEX=y CONFIG_ANON_INODES=y CONFIG_EPOLL=y CONFIG_SIGNALFD=y +CONFIG_TIMERFD=y CONFIG_EVENTFD=y CONFIG_SHMEM=y CONFIG_VM_EVENT_COUNTERS=y @@ -83,6 +87,14 @@ CONFIG_SLUB_DEBUG=y # CONFIG_SLAB is not set CONFIG_SLUB=y # CONFIG_SLOB is not set +CONFIG_PROFILING=y +# CONFIG_MARKERS is not set +CONFIG_OPROFILE=m +CONFIG_HAVE_OPROFILE=y +CONFIG_KPROBES=y +CONFIG_HAVE_KPROBES=y +CONFIG_PROC_PAGE_MONITOR=y +CONFIG_SLABINFO=y CONFIG_RT_MUTEXES=y # CONFIG_TINY_SHMEM is not set CONFIG_BASE_SMALL=0 @@ -92,6 +104,7 @@ CONFIG_MODULE_FORCE_UNLOAD=y CONFIG_MODVERSIONS=y CONFIG_MODULE_SRCVERSION_ALL=y CONFIG_KMOD=y +CONFIG_STOP_MACHINE=y CONFIG_BLOCK=y CONFIG_BLK_DEV_IO_TRACE=y CONFIG_BLK_DEV_BSG=y @@ -109,6 +122,8 @@ CONFIG_DEFAULT_AS=y # CONFIG_DEFAULT_CFQ is not set # CONFIG_DEFAULT_NOOP is not set CONFIG_DEFAULT_IOSCHED="anticipatory" +CONFIG_CLASSIC_RCU=y +# CONFIG_PREEMPT_RCU is not set CONFIG_SYSVIPC_COMPAT=y CONFIG_GENERIC_HARDIRQS=y @@ -119,7 +134,8 @@ CONFIG_TICK_ONESHOT=y CONFIG_NO_HZ=y CONFIG_HIGH_RES_TIMERS=y CONFIG_GENERIC_CLOCKEVENTS_BUILD=y -# CONFIG_SMP is not set +CONFIG_SMP=y +CONFIG_NR_CPUS=64 # CONFIG_CPU_FREQ is not set CONFIG_RWSEM_XCHGADD_ALGORITHM=y CONFIG_GENERIC_FIND_NEXT_BIT=y @@ -169,9 +185,12 @@ CONFIG_BINFMT_ELF32=y CONFIG_BINFMT_ELF=y CONFIG_BINFMT_MISC=m CONFIG_SOLARIS_EMUL=y +CONFIG_SCHED_SMT=y +CONFIG_SCHED_MC=y # CONFIG_PREEMPT_NONE is not set CONFIG_PREEMPT_VOLUNTARY=y # CONFIG_PREEMPT is not set +# CONFIG_RCU_TRACE is not set # CONFIG_CMDLINE_BOOL is not set # @@ -189,6 +208,7 @@ CONFIG_XFRM=y CONFIG_XFRM_USER=m # CONFIG_XFRM_SUB_POLICY is not set CONFIG_XFRM_MIGRATE=y +# CONFIG_XFRM_STATISTICS is not set CONFIG_NET_KEY=m CONFIG_NET_KEY_MIGRATE=y CONFIG_INET=y @@ -249,9 +269,9 @@ CONFIG_IP_DCCP_ACKVEC=y CONFIG_IP_DCCP_CCID2=m # CONFIG_IP_DCCP_CCID2_DEBUG is not set CONFIG_IP_DCCP_CCID3=m -CONFIG_IP_DCCP_TFRC_LIB=m # CONFIG_IP_DCCP_CCID3_DEBUG is not set CONFIG_IP_DCCP_CCID3_RTO=100 +CONFIG_IP_DCCP_TFRC_LIB=m # # DCCP Kernel Hacking @@ -279,6 +299,7 @@ CONFIG_VLAN_8021Q=m CONFIG_NET_PKTGEN=m CONFIG_NET_TCPPROBE=m # CONFIG_HAMRADIO is not set +# CONFIG_CAN is not set # CONFIG_IRDA is not set # CONFIG_BT is not set # CONFIG_AF_RXRPC is not set @@ -343,6 +364,7 @@ CONFIG_BLK_DEV_IDE=y CONFIG_BLK_DEV_IDEDISK=y # CONFIG_IDEDISK_MULTI_MODE is not set CONFIG_BLK_DEV_IDECD=y +CONFIG_BLK_DEV_IDECD_VERBOSE_ERRORS=y # CONFIG_BLK_DEV_IDETAPE is not set # CONFIG_BLK_DEV_IDEFLOPPY is not set # CONFIG_BLK_DEV_IDESCSI is not set @@ -359,7 +381,6 @@ CONFIG_IDE_GENERIC=y # PCI IDE chipsets support # CONFIG_BLK_DEV_IDEPCI=y -# CONFIG_IDEPCI_SHARE_IRQ is not set CONFIG_IDEPCI_PCIBUS_ORDER=y # CONFIG_BLK_DEV_GENERIC is not set # CONFIG_BLK_DEV_OPTI621 is not set @@ -389,7 +410,6 @@ CONFIG_BLK_DEV_ALI15X3=y # CONFIG_BLK_DEV_TRM290 is not set # CONFIG_BLK_DEV_VIA82CXXX is not set # CONFIG_BLK_DEV_TC86C001 is not set -# CONFIG_IDE_ARM is not set CONFIG_BLK_DEV_IDEDMA=y CONFIG_IDE_ARCH_OBSOLETE_INIT=y # CONFIG_BLK_DEV_HD is not set @@ -501,7 +521,6 @@ CONFIG_NETDEVICES=y # CONFIG_EQUALIZER is not set # CONFIG_TUN is not set # CONFIG_VETH is not set -# CONFIG_IP1000 is not set # CONFIG_ARCNET is not set # CONFIG_PHYLIB is not set CONFIG_NET_ETHERNET=y @@ -533,6 +552,7 @@ CONFIG_NET_PCI=y # CONFIG_NE2K_PCI is not set # CONFIG_8139CP is not set # CONFIG_8139TOO is not set +# CONFIG_R6040 is not set # CONFIG_SIS900 is not set # CONFIG_EPIC100 is not set # CONFIG_SUNDANCE is not set @@ -545,6 +565,9 @@ CONFIG_E1000=m CONFIG_E1000_NAPI=y # CONFIG_E1000_DISABLE_PACKET_SPLIT is not set # CONFIG_E1000E is not set +# CONFIG_E1000E_ENABLED is not set +# CONFIG_IP1000 is not set +# CONFIG_IGB is not set # CONFIG_MYRI_SBUS is not set # CONFIG_NS83820 is not set # CONFIG_HAMACHI is not set @@ -570,6 +593,7 @@ CONFIG_NETDEV_10000=y CONFIG_NIU=m # CONFIG_MLX4_CORE is not set # CONFIG_TEHUTI is not set +# CONFIG_BNX2X is not set # CONFIG_TR is not set # @@ -602,7 +626,6 @@ CONFIG_PPPOE=m # CONFIG_SLIP is not set CONFIG_SLHC=m # CONFIG_NET_FC is not set -# CONFIG_SHAPER is not set # CONFIG_NETCONSOLE is not set # CONFIG_NETPOLL is not set # CONFIG_NET_POLL_CONTROLLER is not set @@ -679,6 +702,7 @@ CONFIG_VT_CONSOLE=y CONFIG_HW_CONSOLE=y # CONFIG_VT_HW_CONSOLE_BINDING is not set # CONFIG_SERIAL_NONSTANDARD is not set +# CONFIG_NOZOMI is not set # # Serial drivers @@ -747,13 +771,13 @@ CONFIG_I2C_ALGOBIT=y # # Miscellaneous I2C Chip support # -# CONFIG_SENSORS_DS1337 is not set -# CONFIG_SENSORS_DS1374 is not set # CONFIG_DS1682 is not set # CONFIG_SENSORS_EEPROM is not set # CONFIG_SENSORS_PCF8574 is not set +# CONFIG_PCF8575 is not set # CONFIG_SENSORS_PCA9539 is not set # CONFIG_SENSORS_PCF8591 is not set +# CONFIG_TPS65010 is not set # CONFIG_SENSORS_MAX6875 is not set # CONFIG_SENSORS_TSL2550 is not set # CONFIG_I2C_DEBUG_CORE is not set @@ -990,6 +1014,7 @@ CONFIG_SND_ALI5451=m # CONFIG_SND_BT87X is not set # CONFIG_SND_CA0106 is not set # CONFIG_SND_CMIPCI is not set +# CONFIG_SND_OXYGEN is not set # CONFIG_SND_CS4281 is not set # CONFIG_SND_CS46XX is not set # CONFIG_SND_DARLA20 is not set @@ -1014,6 +1039,7 @@ CONFIG_SND_ALI5451=m # CONFIG_SND_HDA_INTEL is not set # CONFIG_SND_HDSP is not set # CONFIG_SND_HDSPM is not set +# CONFIG_SND_HIFIER is not set # CONFIG_SND_ICE1712 is not set # CONFIG_SND_ICE1724 is not set # CONFIG_SND_INTEL8X0 is not set @@ -1031,6 +1057,7 @@ CONFIG_SND_ALI5451=m # CONFIG_SND_TRIDENT is not set # CONFIG_SND_VIA82XX is not set # CONFIG_SND_VIA82XX_MODEM is not set +# CONFIG_SND_VIRTUOSO is not set # CONFIG_SND_VX222 is not set # CONFIG_SND_YMFPCI is not set # CONFIG_SND_AC97_POWER_SAVE is not set @@ -1058,6 +1085,10 @@ CONFIG_SND_SUN_CS4231=m # # +# ALSA SoC audio for Freescale SOCs +# + +# # Open Sound System # # CONFIG_SOUND_PRIME is not set @@ -1080,6 +1111,7 @@ CONFIG_USB_ARCH_HAS_OHCI=y CONFIG_USB_ARCH_HAS_EHCI=y CONFIG_USB=y # CONFIG_USB_DEBUG is not set +# CONFIG_USB_ANNOUNCE_NEW_DEVICES is not set # # Miscellaneous USB options @@ -1093,7 +1125,6 @@ CONFIG_USB_DEVICEFS=y # USB Host Controller Drivers # CONFIG_USB_EHCI_HCD=m -# CONFIG_USB_EHCI_SPLIT_ISO is not set # CONFIG_USB_EHCI_ROOT_HUB_TT is not set # CONFIG_USB_EHCI_TT_NEWSCHED is not set # CONFIG_USB_ISP116X_HCD is not set @@ -1143,10 +1174,6 @@ CONFIG_USB_STORAGE=m # # USB port drivers # - -# -# USB Serial Converter support -# # CONFIG_USB_SERIAL is not set # @@ -1172,14 +1199,6 @@ CONFIG_USB_STORAGE=m # CONFIG_USB_TRANCEVIBRATOR is not set # CONFIG_USB_IOWARRIOR is not set # CONFIG_USB_TEST is not set - -# -# USB DSL modem support -# - -# -# USB Gadget Support -# # CONFIG_USB_GADGET is not set # CONFIG_MMC is not set # CONFIG_NEW_LEDS is not set @@ -1332,11 +1351,6 @@ CONFIG_NLS_DEFAULT="iso8859-1" # CONFIG_NLS_KOI8_U is not set # CONFIG_NLS_UTF8 is not set # CONFIG_DLM is not set -CONFIG_INSTRUMENTATION=y -CONFIG_PROFILING=y -CONFIG_OPROFILE=m -CONFIG_KPROBES=y -# CONFIG_MARKERS is not set # # Kernel hacking @@ -1374,6 +1388,8 @@ CONFIG_DEBUG_BUGVERBOSE=y CONFIG_FORCED_INLINING=y # CONFIG_BOOT_PRINTK_DELAY is not set # CONFIG_RCU_TORTURE_TEST is not set +# CONFIG_KPROBES_SANITY_TEST is not set +# CONFIG_BACKTRACE_SELF_TEST is not set # CONFIG_LKDTM is not set # CONFIG_FAULT_INJECTION is not set # CONFIG_SAMPLES is not set @@ -1396,8 +1412,9 @@ CONFIG_ASYNC_MEMCPY=m CONFIG_ASYNC_XOR=m CONFIG_CRYPTO=y CONFIG_CRYPTO_ALGAPI=y -CONFIG_CRYPTO_AEAD=m +CONFIG_CRYPTO_AEAD=y CONFIG_CRYPTO_BLKCIPHER=y +# CONFIG_CRYPTO_SEQIV is not set CONFIG_CRYPTO_HASH=y CONFIG_CRYPTO_MANAGER=y CONFIG_CRYPTO_HMAC=y @@ -1416,6 +1433,9 @@ CONFIG_CRYPTO_CBC=y CONFIG_CRYPTO_PCBC=m CONFIG_CRYPTO_LRW=m CONFIG_CRYPTO_XTS=m +# CONFIG_CRYPTO_CTR is not set +# CONFIG_CRYPTO_GCM is not set +# CONFIG_CRYPTO_CCM is not set # CONFIG_CRYPTO_CRYPTD is not set CONFIG_CRYPTO_DES=y CONFIG_CRYPTO_FCRYPT=m @@ -1431,13 +1451,16 @@ CONFIG_CRYPTO_ARC4=m CONFIG_CRYPTO_KHAZAD=m CONFIG_CRYPTO_ANUBIS=m CONFIG_CRYPTO_SEED=m +# CONFIG_CRYPTO_SALSA20 is not set CONFIG_CRYPTO_DEFLATE=y CONFIG_CRYPTO_MICHAEL_MIC=m CONFIG_CRYPTO_CRC32C=m CONFIG_CRYPTO_CAMELLIA=m CONFIG_CRYPTO_TEST=m CONFIG_CRYPTO_AUTHENC=m +# CONFIG_CRYPTO_LZO is not set CONFIG_CRYPTO_HW=y +# CONFIG_CRYPTO_DEV_HIFN_795X is not set # # Library routines diff --git a/arch/sparc64/kernel/Makefile b/arch/sparc64/kernel/Makefile index ef50d217432f..4b78b24ef413 100644 --- a/arch/sparc64/kernel/Makefile +++ b/arch/sparc64/kernel/Makefile @@ -11,7 +11,7 @@ obj-y := process.o setup.o cpu.o idprom.o \ traps.o auxio.o una_asm.o sysfs.o iommu.o \ irq.o ptrace.o time.o sys_sparc.o signal.o \ unaligned.o central.o pci.o starfire.o semaphore.o \ - power.o sbus.o iommu_common.o sparc64_ksyms.o chmc.o \ + power.o sbus.o sparc64_ksyms.o chmc.o \ visemul.o prom.o of_device.o hvapi.o sstate.o mdesc.o obj-$(CONFIG_STACKTRACE) += stacktrace.o diff --git a/arch/sparc64/kernel/iommu.c b/arch/sparc64/kernel/iommu.c index 4b9115a4d92e..5623a4d59dff 100644 --- a/arch/sparc64/kernel/iommu.c +++ b/arch/sparc64/kernel/iommu.c @@ -472,94 +472,15 @@ static void dma_4u_unmap_single(struct device *dev, dma_addr_t bus_addr, spin_unlock_irqrestore(&iommu->lock, flags); } -#define SG_ENT_PHYS_ADDRESS(SG) (__pa(sg_virt((SG)))) - -static void fill_sg(iopte_t *iopte, struct scatterlist *sg, - int nused, int nelems, - unsigned long iopte_protection) -{ - struct scatterlist *dma_sg = sg; - int i; - - for (i = 0; i < nused; i++) { - unsigned long pteval = ~0UL; - u32 dma_npages; - - dma_npages = ((dma_sg->dma_address & (IO_PAGE_SIZE - 1UL)) + - dma_sg->dma_length + - ((IO_PAGE_SIZE - 1UL))) >> IO_PAGE_SHIFT; - do { - unsigned long offset; - signed int len; - - /* If we are here, we know we have at least one - * more page to map. So walk forward until we - * hit a page crossing, and begin creating new - * mappings from that spot. - */ - for (;;) { - unsigned long tmp; - - tmp = SG_ENT_PHYS_ADDRESS(sg); - len = sg->length; - if (((tmp ^ pteval) >> IO_PAGE_SHIFT) != 0UL) { - pteval = tmp & IO_PAGE_MASK; - offset = tmp & (IO_PAGE_SIZE - 1UL); - break; - } - if (((tmp ^ (tmp + len - 1UL)) >> IO_PAGE_SHIFT) != 0UL) { - pteval = (tmp + IO_PAGE_SIZE) & IO_PAGE_MASK; - offset = 0UL; - len -= (IO_PAGE_SIZE - (tmp & (IO_PAGE_SIZE - 1UL))); - break; - } - sg = sg_next(sg); - nelems--; - } - - pteval = iopte_protection | (pteval & IOPTE_PAGE); - while (len > 0) { - *iopte++ = __iopte(pteval); - pteval += IO_PAGE_SIZE; - len -= (IO_PAGE_SIZE - offset); - offset = 0; - dma_npages--; - } - - pteval = (pteval & IOPTE_PAGE) + len; - sg = sg_next(sg); - nelems--; - - /* Skip over any tail mappings we've fully mapped, - * adjusting pteval along the way. Stop when we - * detect a page crossing event. - */ - while (nelems && - (pteval << (64 - IO_PAGE_SHIFT)) != 0UL && - (pteval == SG_ENT_PHYS_ADDRESS(sg)) && - ((pteval ^ - (SG_ENT_PHYS_ADDRESS(sg) + sg->length - 1UL)) >> IO_PAGE_SHIFT) == 0UL) { - pteval += sg->length; - sg = sg_next(sg); - nelems--; - } - if ((pteval << (64 - IO_PAGE_SHIFT)) == 0UL) - pteval = ~0UL; - } while (dma_npages != 0); - dma_sg = sg_next(dma_sg); - } -} - static int dma_4u_map_sg(struct device *dev, struct scatterlist *sglist, int nelems, enum dma_data_direction direction) { - struct iommu *iommu; + unsigned long flags, ctx, i, npages, iopte_protection; + struct scatterlist *sg; struct strbuf *strbuf; - unsigned long flags, ctx, npages, iopte_protection; + struct iommu *iommu; iopte_t *base; u32 dma_base; - struct scatterlist *sgtmp; - int used; /* Fast path single entry scatterlists. */ if (nelems == 1) { @@ -578,11 +499,7 @@ static int dma_4u_map_sg(struct device *dev, struct scatterlist *sglist, if (unlikely(direction == DMA_NONE)) goto bad_no_ctx; - /* Step 1: Prepare scatter list. */ - - npages = prepare_sg(dev, sglist, nelems); - - /* Step 2: Allocate a cluster and context, if necessary. */ + npages = calc_npages(sglist, nelems); spin_lock_irqsave(&iommu->lock, flags); @@ -599,18 +516,6 @@ static int dma_4u_map_sg(struct device *dev, struct scatterlist *sglist, dma_base = iommu->page_table_map_base + ((base - iommu->page_table) << IO_PAGE_SHIFT); - /* Step 3: Normalize DMA addresses. */ - used = nelems; - - sgtmp = sglist; - while (used && sgtmp->dma_length) { - sgtmp->dma_address += dma_base; - sgtmp = sg_next(sgtmp); - used--; - } - used = nelems - used; - - /* Step 4: Create the mappings. */ if (strbuf->strbuf_enabled) iopte_protection = IOPTE_STREAMING(ctx); else @@ -618,13 +523,27 @@ static int dma_4u_map_sg(struct device *dev, struct scatterlist *sglist, if (direction != DMA_TO_DEVICE) iopte_protection |= IOPTE_WRITE; - fill_sg(base, sglist, used, nelems, iopte_protection); + for_each_sg(sglist, sg, nelems, i) { + unsigned long paddr = SG_ENT_PHYS_ADDRESS(sg); + unsigned long slen = sg->length; + unsigned long this_npages; -#ifdef VERIFY_SG - verify_sglist(sglist, nelems, base, npages); -#endif + this_npages = iommu_num_pages(paddr, slen); - return used; + sg->dma_address = dma_base | (paddr & ~IO_PAGE_MASK); + sg->dma_length = slen; + + paddr &= IO_PAGE_MASK; + while (this_npages--) { + iopte_val(*base) = iopte_protection | paddr; + + base++; + paddr += IO_PAGE_SIZE; + dma_base += IO_PAGE_SIZE; + } + } + + return nelems; bad: iommu_free_ctx(iommu, ctx); @@ -637,11 +556,10 @@ bad_no_ctx: static void dma_4u_unmap_sg(struct device *dev, struct scatterlist *sglist, int nelems, enum dma_data_direction direction) { - struct iommu *iommu; + unsigned long flags, ctx, i, npages; struct strbuf *strbuf; + struct iommu *iommu; iopte_t *base; - unsigned long flags, ctx, i, npages; - struct scatterlist *sg, *sgprv; u32 bus_addr; if (unlikely(direction == DMA_NONE)) { @@ -654,15 +572,7 @@ static void dma_4u_unmap_sg(struct device *dev, struct scatterlist *sglist, bus_addr = sglist->dma_address & IO_PAGE_MASK; - sgprv = NULL; - for_each_sg(sglist, sg, nelems, i) { - if (sg->dma_length == 0) - break; - sgprv = sg; - } - - npages = (IO_PAGE_ALIGN(sgprv->dma_address + sgprv->dma_length) - - bus_addr) >> IO_PAGE_SHIFT; + npages = calc_npages(sglist, nelems); base = iommu->page_table + ((bus_addr - iommu->page_table_map_base) >> IO_PAGE_SHIFT); diff --git a/arch/sparc64/kernel/iommu_common.c b/arch/sparc64/kernel/iommu_common.c deleted file mode 100644 index 72a4acfe8c7b..000000000000 --- a/arch/sparc64/kernel/iommu_common.c +++ /dev/null @@ -1,248 +0,0 @@ -/* $Id: iommu_common.c,v 1.9 2001/12/17 07:05:09 davem Exp $ - * iommu_common.c: UltraSparc SBUS/PCI common iommu code. - * - * Copyright (C) 1999 David S. Miller (davem@redhat.com) - */ - -#include <linux/dma-mapping.h> -#include "iommu_common.h" - -/* You are _strongly_ advised to enable the following debugging code - * any time you make changes to the sg code below, run it for a while - * with filesystems mounted read-only before buying the farm... -DaveM - */ - -#ifdef VERIFY_SG -static int verify_lengths(struct scatterlist *sglist, int nents, int npages) -{ - int sg_len, dma_len; - int i, pgcount; - struct scatterlist *sg; - - sg_len = 0; - for_each_sg(sglist, sg, nents, i) - sg_len += sg->length; - - dma_len = 0; - for_each_sg(sglist, sg, nents, i) { - if (!sg->dma_length) - break; - dma_len += sg->dma_length; - } - - if (sg_len != dma_len) { - printk("verify_lengths: Error, different, sg[%d] dma[%d]\n", - sg_len, dma_len); - return -1; - } - - pgcount = 0; - for_each_sg(sglist, sg, nents, i) { - unsigned long start, end; - - if (!sg->dma_length) - break; - - start = sg->dma_address; - start = start & IO_PAGE_MASK; - - end = sg->dma_address + sg->dma_length; - end = (end + (IO_PAGE_SIZE - 1)) & IO_PAGE_MASK; - - pgcount += ((end - start) >> IO_PAGE_SHIFT); - } - - if (pgcount != npages) { - printk("verify_lengths: Error, page count wrong, " - "npages[%d] pgcount[%d]\n", - npages, pgcount); - return -1; - } - - /* This test passes... */ - return 0; -} - -static int verify_one_map(struct scatterlist *dma_sg, struct scatterlist **__sg, int nents, iopte_t **__iopte) -{ - struct scatterlist *sg = *__sg; - iopte_t *iopte = *__iopte; - u32 dlen = dma_sg->dma_length; - u32 daddr; - unsigned int sglen; - unsigned long sgaddr; - - daddr = dma_sg->dma_address; - sglen = sg->length; - sgaddr = (unsigned long) sg_virt(sg); - while (dlen > 0) { - unsigned long paddr; - - /* SG and DMA_SG must begin at the same sub-page boundary. */ - if ((sgaddr & ~IO_PAGE_MASK) != (daddr & ~IO_PAGE_MASK)) { - printk("verify_one_map: Wrong start offset " - "sg[%08lx] dma[%08x]\n", - sgaddr, daddr); - nents = -1; - goto out; - } - - /* Verify the IOPTE points to the right page. */ - paddr = iopte_val(*iopte) & IOPTE_PAGE; - if ((paddr + PAGE_OFFSET) != (sgaddr & IO_PAGE_MASK)) { - printk("verify_one_map: IOPTE[%08lx] maps the " - "wrong page, should be [%08lx]\n", - iopte_val(*iopte), (sgaddr & IO_PAGE_MASK) - PAGE_OFFSET); - nents = -1; - goto out; - } - - /* If this SG crosses a page, adjust to that next page - * boundary and loop. - */ - if ((sgaddr & IO_PAGE_MASK) ^ ((sgaddr + sglen - 1) & IO_PAGE_MASK)) { - unsigned long next_page, diff; - - next_page = (sgaddr + IO_PAGE_SIZE) & IO_PAGE_MASK; - diff = next_page - sgaddr; - sgaddr += diff; - daddr += diff; - sglen -= diff; - dlen -= diff; - if (dlen > 0) - iopte++; - continue; - } - - /* SG wholly consumed within this page. */ - daddr += sglen; - dlen -= sglen; - - if (dlen > 0 && ((daddr & ~IO_PAGE_MASK) == 0)) - iopte++; - - sg = sg_next(sg); - if (--nents <= 0) - break; - sgaddr = (unsigned long) sg_virt(sg); - sglen = sg->length; - } - if (dlen < 0) { - /* Transfer overrun, big problems. */ - printk("verify_one_map: Transfer overrun by %d bytes.\n", - -dlen); - nents = -1; - } else { - /* Advance to next dma_sg implies that the next iopte will - * begin it. - */ - iopte++; - } - -out: - *__sg = sg; - *__iopte = iopte; - return nents; -} - -static int verify_maps(struct scatterlist *sg, int nents, iopte_t *iopte) -{ - struct scatterlist *dma_sg = sg; - struct scatterlist *orig_dma_sg = dma_sg; - int orig_nents = nents; - - for (;;) { - nents = verify_one_map(dma_sg, &sg, nents, &iopte); - if (nents <= 0) - break; - dma_sg = sg_next(dma_sg); - if (dma_sg->dma_length == 0) - break; - } - - if (nents > 0) { - printk("verify_maps: dma maps consumed by some sgs remain (%d)\n", - nents); - return -1; - } - - if (nents < 0) { - printk("verify_maps: Error, messed up mappings, " - "at sg %d dma_sg %d\n", - (int) (orig_nents + nents), (int) (dma_sg - orig_dma_sg)); - return -1; - } - - /* This test passes... */ - return 0; -} - -void verify_sglist(struct scatterlist *sglist, int nents, iopte_t *iopte, int npages) -{ - struct scatterlist *sg; - - if (verify_lengths(sglist, nents, npages) < 0 || - verify_maps(sglist, nents, iopte) < 0) { - int i; - - printk("verify_sglist: Crap, messed up mappings, dumping, iodma at "); - printk("%016lx.\n", sglist->dma_address & IO_PAGE_MASK); - - for_each_sg(sglist, sg, nents, i) { - printk("sg(%d): page_addr(%p) off(%x) length(%x) " - "dma_address[%016x] dma_length[%016x]\n", - i, - page_address(sg_page(sg)), sg->offset, - sg->length, - sg->dma_address, sg->dma_length); - } - } - - /* Seems to be ok */ -} -#endif - -unsigned long prepare_sg(struct device *dev, struct scatterlist *sg, int nents) -{ - struct scatterlist *dma_sg = sg; - unsigned long prev; - u32 dent_addr, dent_len; - unsigned int max_seg_size; - - prev = (unsigned long) sg_virt(sg); - prev += (unsigned long) (dent_len = sg->length); - dent_addr = (u32) ((unsigned long)(sg_virt(sg)) & (IO_PAGE_SIZE - 1UL)); - max_seg_size = dma_get_max_seg_size(dev); - while (--nents) { - unsigned long addr; - - sg = sg_next(sg); - addr = (unsigned long) sg_virt(sg); - if (! VCONTIG(prev, addr) || - dent_len + sg->length > max_seg_size) { - dma_sg->dma_address = dent_addr; - dma_sg->dma_length = dent_len; - dma_sg = sg_next(dma_sg); - - dent_addr = ((dent_addr + - dent_len + - (IO_PAGE_SIZE - 1UL)) >> IO_PAGE_SHIFT); - dent_addr <<= IO_PAGE_SHIFT; - dent_addr += addr & (IO_PAGE_SIZE - 1UL); - dent_len = 0; - } - dent_len += sg->length; - prev = addr + sg->length; - } - dma_sg->dma_address = dent_addr; - dma_sg->dma_length = dent_len; - - if (dma_sg != sg) { - dma_sg = sg_next(dma_sg); - dma_sg->dma_length = 0; - } - - return ((unsigned long) dent_addr + - (unsigned long) dent_len + - (IO_PAGE_SIZE - 1UL)) >> IO_PAGE_SHIFT; -} diff --git a/arch/sparc64/kernel/iommu_common.h b/arch/sparc64/kernel/iommu_common.h index a90d046e8024..4b5cafa2877a 100644 --- a/arch/sparc64/kernel/iommu_common.h +++ b/arch/sparc64/kernel/iommu_common.h @@ -30,6 +30,32 @@ */ #define IOMMU_PAGE_SHIFT 13 +#define SG_ENT_PHYS_ADDRESS(SG) (__pa(sg_virt((SG)))) + +static inline unsigned long iommu_num_pages(unsigned long vaddr, + unsigned long slen) +{ + unsigned long npages; + + npages = IO_PAGE_ALIGN(vaddr + slen) - (vaddr & IO_PAGE_MASK); + npages >>= IO_PAGE_SHIFT; + + return npages; +} + +static inline unsigned long calc_npages(struct scatterlist *sglist, int nelems) +{ + unsigned long i, npages = 0; + struct scatterlist *sg; + + for_each_sg(sglist, sg, nelems, i) { + unsigned long paddr = SG_ENT_PHYS_ADDRESS(sg); + npages += iommu_num_pages(paddr, sg->length); + } + + return npages; +} + /* You are _strongly_ advised to enable the following debugging code * any time you make changes to the sg code below, run it for a while * with filesystems mounted read-only before buying the farm... -DaveM diff --git a/arch/sparc64/kernel/pci_sun4v.c b/arch/sparc64/kernel/pci_sun4v.c index 5ea2eab1ccda..61baf8dc095e 100644 --- a/arch/sparc64/kernel/pci_sun4v.c +++ b/arch/sparc64/kernel/pci_sun4v.c @@ -365,113 +365,14 @@ static void dma_4v_unmap_single(struct device *dev, dma_addr_t bus_addr, spin_unlock_irqrestore(&iommu->lock, flags); } -#define SG_ENT_PHYS_ADDRESS(SG) (__pa(sg_virt((SG)))) - -static long fill_sg(long entry, struct device *dev, - struct scatterlist *sg, - int nused, int nelems, unsigned long prot) -{ - struct scatterlist *dma_sg = sg; - unsigned long flags; - int i; - - local_irq_save(flags); - - iommu_batch_start(dev, prot, entry); - - for (i = 0; i < nused; i++) { - unsigned long pteval = ~0UL; - u32 dma_npages; - - dma_npages = ((dma_sg->dma_address & (IO_PAGE_SIZE - 1UL)) + - dma_sg->dma_length + - ((IO_PAGE_SIZE - 1UL))) >> IO_PAGE_SHIFT; - do { - unsigned long offset; - signed int len; - - /* If we are here, we know we have at least one - * more page to map. So walk forward until we - * hit a page crossing, and begin creating new - * mappings from that spot. - */ - for (;;) { - unsigned long tmp; - - tmp = SG_ENT_PHYS_ADDRESS(sg); - len = sg->length; - if (((tmp ^ pteval) >> IO_PAGE_SHIFT) != 0UL) { - pteval = tmp & IO_PAGE_MASK; - offset = tmp & (IO_PAGE_SIZE - 1UL); - break; - } - if (((tmp ^ (tmp + len - 1UL)) >> IO_PAGE_SHIFT) != 0UL) { - pteval = (tmp + IO_PAGE_SIZE) & IO_PAGE_MASK; - offset = 0UL; - len -= (IO_PAGE_SIZE - (tmp & (IO_PAGE_SIZE - 1UL))); - break; - } - sg = sg_next(sg); - nelems--; - } - - pteval = (pteval & IOPTE_PAGE); - while (len > 0) { - long err; - - err = iommu_batch_add(pteval); - if (unlikely(err < 0L)) - goto iommu_map_failed; - - pteval += IO_PAGE_SIZE; - len -= (IO_PAGE_SIZE - offset); - offset = 0; - dma_npages--; - } - - pteval = (pteval & IOPTE_PAGE) + len; - sg = sg_next(sg); - nelems--; - - /* Skip over any tail mappings we've fully mapped, - * adjusting pteval along the way. Stop when we - * detect a page crossing event. - */ - while (nelems && - (pteval << (64 - IO_PAGE_SHIFT)) != 0UL && - (pteval == SG_ENT_PHYS_ADDRESS(sg)) && - ((pteval ^ - (SG_ENT_PHYS_ADDRESS(sg) + sg->length - 1UL)) >> IO_PAGE_SHIFT) == 0UL) { - pteval += sg->length; - sg = sg_next(sg); - nelems--; - } - if ((pteval << (64 - IO_PAGE_SHIFT)) == 0UL) - pteval = ~0UL; - } while (dma_npages != 0); - dma_sg = sg_next(dma_sg); - } - - if (unlikely(iommu_batch_end() < 0L)) - goto iommu_map_failed; - - local_irq_restore(flags); - return 0; - -iommu_map_failed: - local_irq_restore(flags); - return -1L; -} - static int dma_4v_map_sg(struct device *dev, struct scatterlist *sglist, int nelems, enum dma_data_direction direction) { + unsigned long flags, npages, i, prot; + struct scatterlist *sg; struct iommu *iommu; - unsigned long flags, npages, prot; - u32 dma_base; - struct scatterlist *sgtmp; long entry, err; - int used; + u32 dma_base; /* Fast path single entry scatterlists. */ if (nelems == 1) { @@ -489,10 +390,8 @@ static int dma_4v_map_sg(struct device *dev, struct scatterlist *sglist, if (unlikely(direction == DMA_NONE)) goto bad; - /* Step 1: Prepare scatter list. */ - npages = prepare_sg(dev, sglist, nelems); + npages = calc_npages(sglist, nelems); - /* Step 2: Allocate a cluster and context, if necessary. */ spin_lock_irqsave(&iommu->lock, flags); entry = arena_alloc(&iommu->arena, npages); spin_unlock_irqrestore(&iommu->lock, flags); @@ -503,27 +402,45 @@ static int dma_4v_map_sg(struct device *dev, struct scatterlist *sglist, dma_base = iommu->page_table_map_base + (entry << IO_PAGE_SHIFT); - /* Step 3: Normalize DMA addresses. */ - used = nelems; - - sgtmp = sglist; - while (used && sgtmp->dma_length) { - sgtmp->dma_address += dma_base; - sgtmp = sg_next(sgtmp); - used--; - } - used = nelems - used; - - /* Step 4: Create the mappings. */ prot = HV_PCI_MAP_ATTR_READ; if (direction != DMA_TO_DEVICE) prot |= HV_PCI_MAP_ATTR_WRITE; - err = fill_sg(entry, dev, sglist, used, nelems, prot); + local_irq_save(flags); + + iommu_batch_start(dev, prot, entry); + + for_each_sg(sglist, sg, nelems, i) { + unsigned long paddr = SG_ENT_PHYS_ADDRESS(sg); + unsigned long slen = sg->length; + unsigned long this_npages; + + this_npages = iommu_num_pages(paddr, slen); + + sg->dma_address = dma_base | (paddr & ~IO_PAGE_MASK); + sg->dma_length = slen; + + paddr &= IO_PAGE_MASK; + while (this_npages--) { + err = iommu_batch_add(paddr); + if (unlikely(err < 0L)) { + local_irq_restore(flags); + goto iommu_map_failed; + } + + paddr += IO_PAGE_SIZE; + dma_base += IO_PAGE_SIZE; + } + } + + err = iommu_batch_end(); + + local_irq_restore(flags); + if (unlikely(err < 0L)) goto iommu_map_failed; - return used; + return nelems; bad: if (printk_ratelimit()) @@ -541,12 +458,11 @@ iommu_map_failed: static void dma_4v_unmap_sg(struct device *dev, struct scatterlist *sglist, int nelems, enum dma_data_direction direction) { + unsigned long flags, npages; struct pci_pbm_info *pbm; + u32 devhandle, bus_addr; struct iommu *iommu; - unsigned long flags, i, npages; - struct scatterlist *sg, *sgprv; long entry; - u32 devhandle, bus_addr; if (unlikely(direction == DMA_NONE)) { if (printk_ratelimit()) @@ -558,16 +474,8 @@ static void dma_4v_unmap_sg(struct device *dev, struct scatterlist *sglist, devhandle = pbm->devhandle; bus_addr = sglist->dma_address & IO_PAGE_MASK; - sgprv = NULL; - for_each_sg(sglist, sg, nelems, i) { - if (sg->dma_length == 0) - break; - - sgprv = sg; - } - npages = (IO_PAGE_ALIGN(sgprv->dma_address + sgprv->dma_length) - - bus_addr) >> IO_PAGE_SHIFT; + npages = calc_npages(sglist, nelems); entry = ((bus_addr - iommu->page_table_map_base) >> IO_PAGE_SHIFT); diff --git a/arch/sparc64/kernel/smp.c b/arch/sparc64/kernel/smp.c index c39944927f1a..a8052b76df41 100644 --- a/arch/sparc64/kernel/smp.c +++ b/arch/sparc64/kernel/smp.c @@ -46,8 +46,6 @@ #include <asm/ldc.h> #include <asm/hypervisor.h> -extern void calibrate_delay(void); - int sparc64_multi_core __read_mostly; cpumask_t cpu_possible_map __read_mostly = CPU_MASK_NONE; diff --git a/arch/sparc64/kernel/sparc64_ksyms.c b/arch/sparc64/kernel/sparc64_ksyms.c index 60765e314bd8..8649635d6d74 100644 --- a/arch/sparc64/kernel/sparc64_ksyms.c +++ b/arch/sparc64/kernel/sparc64_ksyms.c @@ -277,6 +277,7 @@ EXPORT_SYMBOL(sys_getpid); EXPORT_SYMBOL(sys_geteuid); EXPORT_SYMBOL(sys_getuid); EXPORT_SYMBOL(sys_getegid); +EXPORT_SYMBOL(sysctl_nr_open); EXPORT_SYMBOL(sys_getgid); EXPORT_SYMBOL(svr4_getcontext); EXPORT_SYMBOL(svr4_setcontext); diff --git a/arch/sparc64/kernel/systbls.S b/arch/sparc64/kernel/systbls.S index b8058906e727..adc62f490f36 100644 --- a/arch/sparc64/kernel/systbls.S +++ b/arch/sparc64/kernel/systbls.S @@ -80,7 +80,8 @@ sys_call_table32: .word sys_fchmodat, sys_faccessat, compat_sys_pselect6, compat_sys_ppoll, sys_unshare /*300*/ .word compat_sys_set_robust_list, compat_sys_get_robust_list, compat_sys_migrate_pages, compat_sys_mbind, compat_sys_get_mempolicy .word compat_sys_set_mempolicy, compat_sys_kexec_load, compat_sys_move_pages, sys_getcpu, compat_sys_epoll_pwait -/*310*/ .word compat_sys_utimensat, compat_sys_signalfd, sys_ni_syscall, sys_eventfd, compat_sys_fallocate +/*310*/ .word compat_sys_utimensat, compat_sys_signalfd, sys_timerfd_create, sys_eventfd, compat_sys_fallocate + .word compat_sys_timerfd_settime, compat_sys_timerfd_gettime #endif /* CONFIG_COMPAT */ @@ -152,7 +153,8 @@ sys_call_table: .word sys_fchmodat, sys_faccessat, sys_pselect6, sys_ppoll, sys_unshare /*300*/ .word sys_set_robust_list, sys_get_robust_list, sys_migrate_pages, sys_mbind, sys_get_mempolicy .word sys_set_mempolicy, sys_kexec_load, sys_move_pages, sys_getcpu, sys_epoll_pwait -/*310*/ .word sys_utimensat, sys_signalfd, sys_ni_syscall, sys_eventfd, sys_fallocate +/*310*/ .word sys_utimensat, sys_signalfd, sys_timerfd_create, sys_eventfd, sys_fallocate + .word sys_timerfd_settime, sys_timerfd_gettime #if defined(CONFIG_SUNOS_EMUL) || defined(CONFIG_SOLARIS_EMUL) || \ defined(CONFIG_SOLARIS_EMUL_MODULE) @@ -271,6 +273,7 @@ sunos_sys_table: .word sunos_nosys, sunos_nosys, sunos_nosys .word sunos_nosys /*310*/ .word sunos_nosys, sunos_nosys, sunos_nosys - .word sunos_nosys, sunos_nosys + .word sunos_nosys, sunos_nosys, sunos_nosys + .word sunos_nosys #endif diff --git a/arch/sparc64/kernel/time.c b/arch/sparc64/kernel/time.c index 4352ee4d8dac..d204f1ab1d4c 100644 --- a/arch/sparc64/kernel/time.c +++ b/arch/sparc64/kernel/time.c @@ -1707,6 +1707,11 @@ static void __exit rtc_mini_exit(void) misc_deregister(&rtc_mini_dev); } +int __devinit read_current_timer(unsigned long *timer_val) +{ + *timer_val = tick_ops->get_tick(); + return 0; +} module_init(rtc_mini_init); module_exit(rtc_mini_exit); diff --git a/arch/sparc64/solaris/fs.c b/arch/sparc64/solaris/fs.c index 61be597bf430..9311bfe4f2f7 100644 --- a/arch/sparc64/solaris/fs.c +++ b/arch/sparc64/solaris/fs.c @@ -624,7 +624,7 @@ asmlinkage int solaris_ulimit(int cmd, int val) case 3: /* UL_GMEMLIM */ return current->signal->rlim[RLIMIT_DATA].rlim_cur; case 4: /* UL_GDESLIM */ - return NR_OPEN; + return sysctl_nr_open; } return -EINVAL; } diff --git a/arch/sparc64/solaris/timod.c b/arch/sparc64/solaris/timod.c index a9d32ceabf26..f53123c02c2b 100644 --- a/arch/sparc64/solaris/timod.c +++ b/arch/sparc64/solaris/timod.c @@ -859,7 +859,8 @@ asmlinkage int solaris_getmsg(unsigned int fd, u32 arg1, u32 arg2, u32 arg3) SOLD("entry"); lock_kernel(); - if(fd >= NR_OPEN) goto out; + if (fd >= sysctl_nr_open) + goto out; fdt = files_fdtable(current->files); filp = fdt->fd[fd]; @@ -927,7 +928,8 @@ asmlinkage int solaris_putmsg(unsigned int fd, u32 arg1, u32 arg2, u32 arg3) SOLD("entry"); lock_kernel(); - if(fd >= NR_OPEN) goto out; + if (fd >= sysctl_nr_open) + goto out; fdt = files_fdtable(current->files); filp = fdt->fd[fd]; diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index 434821187cfc..e6728bd61cc1 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig @@ -415,7 +415,7 @@ config HPET_TIMER config HPET_EMULATE_RTC def_bool y - depends on HPET_TIMER && (RTC=y || RTC=m) + depends on HPET_TIMER && (RTC=y || RTC=m || RTC_DRV_CMOS=m || RTC_DRV_CMOS=y) # Mark as embedded because too many people got it wrong. # The code disables itself when not needed. diff --git a/arch/x86/kernel/cpu/common.c b/arch/x86/kernel/cpu/common.c index d9313d9adced..f86a3c4a2669 100644 --- a/arch/x86/kernel/cpu/common.c +++ b/arch/x86/kernel/cpu/common.c @@ -637,7 +637,7 @@ void __init early_cpu_init(void) } /* Make sure %fs is initialized properly in idle threads */ -struct pt_regs * __devinit idle_regs(struct pt_regs *regs) +struct pt_regs * __cpuinit idle_regs(struct pt_regs *regs) { memset(regs, 0, sizeof(struct pt_regs)); regs->fs = __KERNEL_PERCPU; diff --git a/arch/x86/kernel/cpu/cyrix.c b/arch/x86/kernel/cpu/cyrix.c index 404a6a2d4016..7139b0262703 100644 --- a/arch/x86/kernel/cpu/cyrix.c +++ b/arch/x86/kernel/cpu/cyrix.c @@ -83,8 +83,6 @@ static char cyrix_model_mult2[] __cpuinitdata = "12233445"; * FIXME: our newer udelay uses the tsc. We don't need to frob with SLOP */ -extern void calibrate_delay(void) __init; - static void __cpuinit check_cx686_slop(struct cpuinfo_x86 *c) { unsigned long flags; diff --git a/arch/x86/kernel/smpboot_32.c b/arch/x86/kernel/smpboot_32.c index 5787a0c3e296..579b9b740c7c 100644 --- a/arch/x86/kernel/smpboot_32.c +++ b/arch/x86/kernel/smpboot_32.c @@ -202,8 +202,6 @@ valid_k7: ; } -extern void calibrate_delay(void); - static atomic_t init_deasserted; static void __cpuinit smp_callin(void) diff --git a/arch/x86/lib/delay_32.c b/arch/x86/lib/delay_32.c index aad9d95469dc..4535e6d147ad 100644 --- a/arch/x86/lib/delay_32.c +++ b/arch/x86/lib/delay_32.c @@ -12,8 +12,10 @@ #include <linux/module.h> #include <linux/sched.h> +#include <linux/timex.h> #include <linux/preempt.h> #include <linux/delay.h> +#include <linux/init.h> #include <asm/processor.h> #include <asm/delay.h> @@ -63,7 +65,7 @@ void use_tsc_delay(void) delay_fn = delay_tsc; } -int read_current_timer(unsigned long *timer_val) +int __devinit read_current_timer(unsigned long *timer_val) { if (delay_fn == delay_tsc) { rdtscl(*timer_val); diff --git a/arch/x86/lib/delay_64.c b/arch/x86/lib/delay_64.c index 45cdd3fbd91c..bbc610518516 100644 --- a/arch/x86/lib/delay_64.c +++ b/arch/x86/lib/delay_64.c @@ -10,8 +10,10 @@ #include <linux/module.h> #include <linux/sched.h> +#include <linux/timex.h> #include <linux/preempt.h> #include <linux/delay.h> +#include <linux/init.h> #include <asm/delay.h> #include <asm/msr.h> @@ -20,7 +22,7 @@ #include <asm/smp.h> #endif -int read_current_timer(unsigned long *timer_value) +int __devinit read_current_timer(unsigned long *timer_value) { rdtscll(*timer_value); return 0; diff --git a/arch/x86/mach-voyager/voyager_smp.c b/arch/x86/mach-voyager/voyager_smp.c index dffa786f61fe..3cc8eb2f36a9 100644 --- a/arch/x86/mach-voyager/voyager_smp.c +++ b/arch/x86/mach-voyager/voyager_smp.c @@ -444,8 +444,6 @@ static __u32 __init setup_trampoline(void) static void __init start_secondary(void *unused) { __u8 cpuid = hard_smp_processor_id(); - /* external functions not defined in the headers */ - extern void calibrate_delay(void); cpu_init(); diff --git a/arch/x86/mm/pageattr.c b/arch/x86/mm/pageattr.c index bb55a78dcd62..16ce841f08d6 100644 --- a/arch/x86/mm/pageattr.c +++ b/arch/x86/mm/pageattr.c @@ -237,7 +237,6 @@ static void __set_pmd_pte(pte_t *kpte, unsigned long address, pte_t pte) if (!SHARED_KERNEL_PMD) { struct page *page; - address = __pa(address); list_for_each_entry(page, &pgd_list, lru) { pgd_t *pgd; pud_t *pud; diff --git a/arch/xtensa/kernel/time.c b/arch/xtensa/kernel/time.c index 60d29fe0b1bd..8df1e842f6d4 100644 --- a/arch/xtensa/kernel/time.c +++ b/arch/xtensa/kernel/time.c @@ -204,7 +204,7 @@ again: } #ifndef CONFIG_GENERIC_CALIBRATE_DELAY -void __devinit calibrate_delay(void) +void __cpuinit calibrate_delay(void) { loops_per_jiffy = CCOUNT_PER_JIFFY; printk("Calibrating delay loop (skipped)... " diff --git a/drivers/base/Makefile b/drivers/base/Makefile index 63e09c015ca0..c66637392bbc 100644 --- a/drivers/base/Makefile +++ b/drivers/base/Makefile @@ -5,7 +5,7 @@ obj-y := core.o sys.o bus.o dd.o \ cpu.o firmware.o init.o map.o devres.o \ attribute_container.o transport_class.o obj-y += power/ -obj-$(CONFIG_HAS_DMA) += dma-mapping.o dmapool.o +obj-$(CONFIG_HAS_DMA) += dma-mapping.o obj-$(CONFIG_ISA) += isa.o obj-$(CONFIG_FW_LOADER) += firmware_class.o obj-$(CONFIG_NUMA) += node.o diff --git a/drivers/base/cpu.c b/drivers/base/cpu.c index c5885f5ce0ac..499b003f9278 100644 --- a/drivers/base/cpu.c +++ b/drivers/base/cpu.c @@ -110,7 +110,7 @@ static SYSDEV_ATTR(crash_notes, 0400, show_crash_notes, NULL); * * Initialize and register the CPU device. */ -int __devinit register_cpu(struct cpu *cpu, int num) +int __cpuinit register_cpu(struct cpu *cpu, int num) { int error; cpu->node_id = cpu_to_node(num); diff --git a/drivers/base/dmapool.c b/drivers/base/dmapool.c deleted file mode 100644 index b5034dc72a05..000000000000 --- a/drivers/base/dmapool.c +++ /dev/null @@ -1,481 +0,0 @@ - -#include <linux/device.h> -#include <linux/mm.h> -#include <asm/io.h> /* Needed for i386 to build */ -#include <linux/dma-mapping.h> -#include <linux/dmapool.h> -#include <linux/slab.h> -#include <linux/module.h> -#include <linux/poison.h> -#include <linux/sched.h> - -/* - * Pool allocator ... wraps the dma_alloc_coherent page allocator, so - * small blocks are easily used by drivers for bus mastering controllers. - * This should probably be sharing the guts of the slab allocator. - */ - -struct dma_pool { /* the pool */ - struct list_head page_list; - spinlock_t lock; - size_t blocks_per_page; - size_t size; - struct device *dev; - size_t allocation; - char name [32]; - wait_queue_head_t waitq; - struct list_head pools; -}; - -struct dma_page { /* cacheable header for 'allocation' bytes */ - struct list_head page_list; - void *vaddr; - dma_addr_t dma; - unsigned in_use; - unsigned long bitmap [0]; -}; - -#define POOL_TIMEOUT_JIFFIES ((100 /* msec */ * HZ) / 1000) - -static DEFINE_MUTEX (pools_lock); - -static ssize_t -show_pools (struct device *dev, struct device_attribute *attr, char *buf) -{ - unsigned temp; - unsigned size; - char *next; - struct dma_page *page; - struct dma_pool *pool; - - next = buf; - size = PAGE_SIZE; - - temp = scnprintf(next, size, "poolinfo - 0.1\n"); - size -= temp; - next += temp; - - mutex_lock(&pools_lock); - list_for_each_entry(pool, &dev->dma_pools, pools) { - unsigned pages = 0; - unsigned blocks = 0; - - list_for_each_entry(page, &pool->page_list, page_list) { - pages++; - blocks += page->in_use; - } - - /* per-pool info, no real statistics yet */ - temp = scnprintf(next, size, "%-16s %4u %4Zu %4Zu %2u\n", - pool->name, - blocks, pages * pool->blocks_per_page, - pool->size, pages); - size -= temp; - next += temp; - } - mutex_unlock(&pools_lock); - - return PAGE_SIZE - size; -} -static DEVICE_ATTR (pools, S_IRUGO, show_pools, NULL); - -/** - * dma_pool_create - Creates a pool of consistent memory blocks, for dma. - * @name: name of pool, for diagnostics - * @dev: device that will be doing the DMA - * @size: size of the blocks in this pool. - * @align: alignment requirement for blocks; must be a power of two - * @allocation: returned blocks won't cross this boundary (or zero) - * Context: !in_interrupt() - * - * Returns a dma allocation pool with the requested characteristics, or - * null if one can't be created. Given one of these pools, dma_pool_alloc() - * may be used to allocate memory. Such memory will all have "consistent" - * DMA mappings, accessible by the device and its driver without using - * cache flushing primitives. The actual size of blocks allocated may be - * larger than requested because of alignment. - * - * If allocation is nonzero, objects returned from dma_pool_alloc() won't - * cross that size boundary. This is useful for devices which have - * addressing restrictions on individual DMA transfers, such as not crossing - * boundaries of 4KBytes. - */ -struct dma_pool * -dma_pool_create (const char *name, struct device *dev, - size_t size, size_t align, size_t allocation) -{ - struct dma_pool *retval; - - if (align == 0) - align = 1; - if (size == 0) - return NULL; - else if (size < align) - size = align; - else if ((size % align) != 0) { - size += align + 1; - size &= ~(align - 1); - } - - if (allocation == 0) { - if (PAGE_SIZE < size) - allocation = size; - else - allocation = PAGE_SIZE; - // FIXME: round up for less fragmentation - } else if (allocation < size) - return NULL; - - if (!(retval = kmalloc_node (sizeof *retval, GFP_KERNEL, dev_to_node(dev)))) - return retval; - - strlcpy (retval->name, name, sizeof retval->name); - - retval->dev = dev; - - INIT_LIST_HEAD (&retval->page_list); - spin_lock_init (&retval->lock); - retval->size = size; - retval->allocation = allocation; - retval->blocks_per_page = allocation / size; - init_waitqueue_head (&retval->waitq); - - if (dev) { - int ret; - - mutex_lock(&pools_lock); - if (list_empty (&dev->dma_pools)) - ret = device_create_file (dev, &dev_attr_pools); - else - ret = 0; - /* note: not currently insisting "name" be unique */ - if (!ret) - list_add (&retval->pools, &dev->dma_pools); - else { - kfree(retval); - retval = NULL; - } - mutex_unlock(&pools_lock); - } else - INIT_LIST_HEAD (&retval->pools); - - return retval; -} - - -static struct dma_page * -pool_alloc_page (struct dma_pool *pool, gfp_t mem_flags) -{ - struct dma_page *page; - int mapsize; - - mapsize = pool->blocks_per_page; - mapsize = (mapsize + BITS_PER_LONG - 1) / BITS_PER_LONG; - mapsize *= sizeof (long); - - page = kmalloc(mapsize + sizeof *page, mem_flags); - if (!page) - return NULL; - page->vaddr = dma_alloc_coherent (pool->dev, - pool->allocation, - &page->dma, - mem_flags); - if (page->vaddr) { - memset (page->bitmap, 0xff, mapsize); // bit set == free -#ifdef CONFIG_DEBUG_SLAB - memset (page->vaddr, POOL_POISON_FREED, pool->allocation); -#endif - list_add (&page->page_list, &pool->page_list); - page->in_use = 0; - } else { - kfree (page); - page = NULL; - } - return page; -} - - -static inline int -is_page_busy (int blocks, unsigned long *bitmap) -{ - while (blocks > 0) { - if (*bitmap++ != ~0UL) - return 1; - blocks -= BITS_PER_LONG; - } - return 0; -} - -static void -pool_free_page (struct dma_pool *pool, struct dma_page *page) -{ - dma_addr_t dma = page->dma; - -#ifdef CONFIG_DEBUG_SLAB - memset (page->vaddr, POOL_POISON_FREED, pool->allocation); -#endif - dma_free_coherent (pool->dev, pool->allocation, page->vaddr, dma); - list_del (&page->page_list); - kfree (page); -} - - -/** - * dma_pool_destroy - destroys a pool of dma memory blocks. - * @pool: dma pool that will be destroyed - * Context: !in_interrupt() - * - * Caller guarantees that no more memory from the pool is in use, - * and that nothing will try to use the pool after this call. - */ -void -dma_pool_destroy (struct dma_pool *pool) -{ - mutex_lock(&pools_lock); - list_del (&pool->pools); - if (pool->dev && list_empty (&pool->dev->dma_pools)) - device_remove_file (pool->dev, &dev_attr_pools); - mutex_unlock(&pools_lock); - - while (!list_empty (&pool->page_list)) { - struct dma_page *page; - page = list_entry (pool->page_list.next, - struct dma_page, page_list); - if (is_page_busy (pool->blocks_per_page, page->bitmap)) { - if (pool->dev) - dev_err(pool->dev, "dma_pool_destroy %s, %p busy\n", - pool->name, page->vaddr); - else - printk (KERN_ERR "dma_pool_destroy %s, %p busy\n", - pool->name, page->vaddr); - /* leak the still-in-use consistent memory */ - list_del (&page->page_list); - kfree (page); - } else - pool_free_page (pool, page); - } - - kfree (pool); -} - - -/** - * dma_pool_alloc - get a block of consistent memory - * @pool: dma pool that will produce the block - * @mem_flags: GFP_* bitmask - * @handle: pointer to dma address of block - * - * This returns the kernel virtual address of a currently unused block, - * and reports its dma address through the handle. - * If such a memory block can't be allocated, null is returned. - */ -void * -dma_pool_alloc (struct dma_pool *pool, gfp_t mem_flags, dma_addr_t *handle) -{ - unsigned long flags; - struct dma_page *page; - int map, block; - size_t offset; - void *retval; - -restart: - spin_lock_irqsave (&pool->lock, flags); - list_for_each_entry(page, &pool->page_list, page_list) { - int i; - /* only cachable accesses here ... */ - for (map = 0, i = 0; - i < pool->blocks_per_page; - i += BITS_PER_LONG, map++) { - if (page->bitmap [map] == 0) - continue; - block = ffz (~ page->bitmap [map]); - if ((i + block) < pool->blocks_per_page) { - clear_bit (block, &page->bitmap [map]); - offset = (BITS_PER_LONG * map) + block; - offset *= pool->size; - goto ready; - } - } - } - if (!(page = pool_alloc_page (pool, GFP_ATOMIC))) { - if (mem_flags & __GFP_WAIT) { - DECLARE_WAITQUEUE (wait, current); - - __set_current_state(TASK_INTERRUPTIBLE); - add_wait_queue (&pool->waitq, &wait); - spin_unlock_irqrestore (&pool->lock, flags); - - schedule_timeout (POOL_TIMEOUT_JIFFIES); - - remove_wait_queue (&pool->waitq, &wait); - goto restart; - } - retval = NULL; - goto done; - } - - clear_bit (0, &page->bitmap [0]); - offset = 0; -ready: - page->in_use++; - retval = offset + page->vaddr; - *handle = offset + page->dma; -#ifdef CONFIG_DEBUG_SLAB - memset (retval, POOL_POISON_ALLOCATED, pool->size); -#endif -done: - spin_unlock_irqrestore (&pool->lock, flags); - return retval; -} - - -static struct dma_page * -pool_find_page (struct dma_pool *pool, dma_addr_t dma) -{ - unsigned long flags; - struct dma_page *page; - - spin_lock_irqsave (&pool->lock, flags); - list_for_each_entry(page, &pool->page_list, page_list) { - if (dma < page->dma) - continue; - if (dma < (page->dma + pool->allocation)) - goto done; - } - page = NULL; -done: - spin_unlock_irqrestore (&pool->lock, flags); - return page; -} - - -/** - * dma_pool_free - put block back into dma pool - * @pool: the dma pool holding the block - * @vaddr: virtual address of block - * @dma: dma address of block - * - * Caller promises neither device nor driver will again touch this block - * unless it is first re-allocated. - */ -void -dma_pool_free (struct dma_pool *pool, void *vaddr, dma_addr_t dma) -{ - struct dma_page *page; - unsigned long flags; - int map, block; - - if ((page = pool_find_page(pool, dma)) == NULL) { - if (pool->dev) - dev_err(pool->dev, "dma_pool_free %s, %p/%lx (bad dma)\n", - pool->name, vaddr, (unsigned long) dma); - else - printk (KERN_ERR "dma_pool_free %s, %p/%lx (bad dma)\n", - pool->name, vaddr, (unsigned long) dma); - return; - } - - block = dma - page->dma; - block /= pool->size; - map = block / BITS_PER_LONG; - block %= BITS_PER_LONG; - -#ifdef CONFIG_DEBUG_SLAB - if (((dma - page->dma) + (void *)page->vaddr) != vaddr) { - if (pool->dev) - dev_err(pool->dev, "dma_pool_free %s, %p (bad vaddr)/%Lx\n", - pool->name, vaddr, (unsigned long long) dma); - else - printk (KERN_ERR "dma_pool_free %s, %p (bad vaddr)/%Lx\n", - pool->name, vaddr, (unsigned long long) dma); - return; - } - if (page->bitmap [map] & (1UL << block)) { - if (pool->dev) - dev_err(pool->dev, "dma_pool_free %s, dma %Lx already free\n", - pool->name, (unsigned long long)dma); - else - printk (KERN_ERR "dma_pool_free %s, dma %Lx already free\n", - pool->name, (unsigned long long)dma); - return; - } - memset (vaddr, POOL_POISON_FREED, pool->size); -#endif - - spin_lock_irqsave (&pool->lock, flags); - page->in_use--; - set_bit (block, &page->bitmap [map]); - if (waitqueue_active (&pool->waitq)) - wake_up (&pool->waitq); - /* - * Resist a temptation to do - * if (!is_page_busy(bpp, page->bitmap)) pool_free_page(pool, page); - * Better have a few empty pages hang around. - */ - spin_unlock_irqrestore (&pool->lock, flags); -} - -/* - * Managed DMA pool - */ -static void dmam_pool_release(struct device *dev, void *res) -{ - struct dma_pool *pool = *(struct dma_pool **)res; - - dma_pool_destroy(pool); -} - -static int dmam_pool_match(struct device *dev, void *res, void *match_data) -{ - return *(struct dma_pool **)res == match_data; -} - -/** - * dmam_pool_create - Managed dma_pool_create() - * @name: name of pool, for diagnostics - * @dev: device that will be doing the DMA - * @size: size of the blocks in this pool. - * @align: alignment requirement for blocks; must be a power of two - * @allocation: returned blocks won't cross this boundary (or zero) - * - * Managed dma_pool_create(). DMA pool created with this function is - * automatically destroyed on driver detach. - */ -struct dma_pool *dmam_pool_create(const char *name, struct device *dev, - size_t size, size_t align, size_t allocation) -{ - struct dma_pool **ptr, *pool; - - ptr = devres_alloc(dmam_pool_release, sizeof(*ptr), GFP_KERNEL); - if (!ptr) - return NULL; - - pool = *ptr = dma_pool_create(name, dev, size, align, allocation); - if (pool) - devres_add(dev, ptr); - else - devres_free(ptr); - - return pool; -} - -/** - * dmam_pool_destroy - Managed dma_pool_destroy() - * @pool: dma pool that will be destroyed - * - * Managed dma_pool_destroy(). - */ -void dmam_pool_destroy(struct dma_pool *pool) -{ - struct device *dev = pool->dev; - - dma_pool_destroy(pool); - WARN_ON(devres_destroy(dev, dmam_pool_release, dmam_pool_match, pool)); -} - -EXPORT_SYMBOL (dma_pool_create); -EXPORT_SYMBOL (dma_pool_destroy); -EXPORT_SYMBOL (dma_pool_alloc); -EXPORT_SYMBOL (dma_pool_free); -EXPORT_SYMBOL (dmam_pool_create); -EXPORT_SYMBOL (dmam_pool_destroy); diff --git a/drivers/block/ataflop.c b/drivers/block/ataflop.c index 94268c75d04f..424995073c6b 100644 --- a/drivers/block/ataflop.c +++ b/drivers/block/ataflop.c @@ -90,7 +90,7 @@ static struct atari_disk_type { unsigned blocks; /* total number of blocks */ unsigned fdc_speed; /* fdc_speed setting */ unsigned stretch; /* track doubling ? */ -} disk_type[] = { +} atari_disk_type[] = { { "d360", 9, 720, 0, 0}, /* 0: 360kB diskette */ { "D360", 9, 720, 0, 1}, /* 1: 360kb in 720k or 1.2MB drive */ { "D720", 9,1440, 0, 0}, /* 2: 720kb in 720k or 1.2MB drive */ @@ -658,7 +658,7 @@ static int do_format(int drive, int type, struct atari_format_descr *desc) return -EINVAL; } type = minor2disktype[type].index; - UDT = &disk_type[type]; + UDT = &atari_disk_type[type]; } if (!UDT || desc->track >= UDT->blocks/UDT->spt/2 || desc->head >= 2) { @@ -1064,7 +1064,7 @@ static void fd_rwsec_done1(int status) searched for a non-existent sector! */ !(read_track && FDC_READ(FDCREG_SECTOR) > SUDT->spt)) { if (Probing) { - if (SUDT > disk_type) { + if (SUDT > atari_disk_type) { if (SUDT[-1].blocks > ReqBlock) { /* try another disk type */ SUDT--; @@ -1082,7 +1082,7 @@ static void fd_rwsec_done1(int status) } else { /* record not found, but not probing. Maybe stretch wrong ? Restart probing */ if (SUD.autoprobe) { - SUDT = disk_type + StartDiskType[DriveType]; + SUDT = atari_disk_type + StartDiskType[DriveType]; set_capacity(unit[SelectedDrive].disk, SUDT->blocks); Probing = 1; @@ -1421,7 +1421,7 @@ repeat: if (type == 0) { if (!UDT) { Probing = 1; - UDT = disk_type + StartDiskType[DriveType]; + UDT = atari_disk_type + StartDiskType[DriveType]; set_capacity(floppy->disk, UDT->blocks); UD.autoprobe = 1; } @@ -1439,7 +1439,7 @@ repeat: goto repeat; } type = minor2disktype[type].index; - UDT = &disk_type[type]; + UDT = &atari_disk_type[type]; set_capacity(floppy->disk, UDT->blocks); UD.autoprobe = 0; } @@ -1505,7 +1505,7 @@ static int fd_ioctl(struct inode *inode, struct file *filp, if (minor2disktype[type].drive_types > DriveType) return -ENODEV; type = minor2disktype[type].index; - dtp = &disk_type[type]; + dtp = &atari_disk_type[type]; if (UD.flags & FTD_MSG) printk (KERN_ERR "floppy%d: found dtp %p name %s!\n", drive, dtp, dtp->name); @@ -1576,7 +1576,7 @@ static int fd_ioctl(struct inode *inode, struct file *filp, continue; } setidx = minor2disktype[settype].index; - dtp = &disk_type[setidx]; + dtp = &atari_disk_type[setidx]; /* found matching entry ?? */ if ( dtp->blocks == setprm.size diff --git a/drivers/block/cciss.c b/drivers/block/cciss.c index 855ce8e5efba..9715be3f2487 100644 --- a/drivers/block/cciss.c +++ b/drivers/block/cciss.c @@ -2630,12 +2630,14 @@ static void do_cciss_request(struct request_queue *q) c->Request.CDB[8] = creq->nr_sectors & 0xff; c->Request.CDB[9] = c->Request.CDB[11] = c->Request.CDB[12] = 0; } else { + u32 upper32 = upper_32_bits(start_blk); + c->Request.CDBLen = 16; c->Request.CDB[1]= 0; - c->Request.CDB[2]= (start_blk >> 56) & 0xff; //MSB - c->Request.CDB[3]= (start_blk >> 48) & 0xff; - c->Request.CDB[4]= (start_blk >> 40) & 0xff; - c->Request.CDB[5]= (start_blk >> 32) & 0xff; + c->Request.CDB[2]= (upper32 >> 24) & 0xff; //MSB + c->Request.CDB[3]= (upper32 >> 16) & 0xff; + c->Request.CDB[4]= (upper32 >> 8) & 0xff; + c->Request.CDB[5]= upper32 & 0xff; c->Request.CDB[6]= (start_blk >> 24) & 0xff; c->Request.CDB[7]= (start_blk >> 16) & 0xff; c->Request.CDB[8]= (start_blk >> 8) & 0xff; diff --git a/drivers/block/loop.c b/drivers/block/loop.c index b8af22e610df..91ebb007416c 100644 --- a/drivers/block/loop.c +++ b/drivers/block/loop.c @@ -973,6 +973,10 @@ loop_set_status(struct loop_device *lo, const struct loop_info64 *info) lo->transfer = xfer->transfer; lo->ioctl = xfer->ioctl; + if ((lo->lo_flags & LO_FLAGS_AUTOCLEAR) != + (info->lo_flags & LO_FLAGS_AUTOCLEAR)) + lo->lo_flags ^= LO_FLAGS_AUTOCLEAR; + lo->lo_encrypt_key_size = info->lo_encrypt_key_size; lo->lo_init[0] = info->lo_init[0]; lo->lo_init[1] = info->lo_init[1]; @@ -1331,6 +1335,10 @@ static int lo_release(struct inode *inode, struct file *file) mutex_lock(&lo->lo_ctl_mutex); --lo->lo_refcnt; + + if ((lo->lo_flags & LO_FLAGS_AUTOCLEAR) && !lo->lo_refcnt) + loop_clr_fd(lo, inode->i_bdev); + mutex_unlock(&lo->lo_ctl_mutex); return 0; diff --git a/drivers/block/paride/pt.c b/drivers/block/paride/pt.c index 76096cad798f..8b9549ab4a4e 100644 --- a/drivers/block/paride/pt.c +++ b/drivers/block/paride/pt.c @@ -660,7 +660,7 @@ static int pt_open(struct inode *inode, struct file *file) pt_identify(tape); err = -ENODEV; - if (!tape->flags & PT_MEDIA) + if (!(tape->flags & PT_MEDIA)) goto out; err = -EROFS; diff --git a/drivers/block/pktcdvd.c b/drivers/block/pktcdvd.c index e9de1712e5a0..674cd66dcaba 100644 --- a/drivers/block/pktcdvd.c +++ b/drivers/block/pktcdvd.c @@ -2212,11 +2212,11 @@ static int pkt_media_speed(struct pktcdvd_device *pd, unsigned *speed) return ret; } - if (!buf[6] & 0x40) { + if (!(buf[6] & 0x40)) { printk(DRIVER_NAME": Disc type is not CD-RW\n"); return 1; } - if (!buf[6] & 0x4) { + if (!(buf[6] & 0x4)) { printk(DRIVER_NAME": A1 values on media are not valid, maybe not CDRW?\n"); return 1; } diff --git a/drivers/block/rd.c b/drivers/block/rd.c index 82f4eecc8699..06e23be70904 100644 --- a/drivers/block/rd.c +++ b/drivers/block/rd.c @@ -56,6 +56,7 @@ #include <linux/backing-dev.h> #include <linux/blkpg.h> #include <linux/writeback.h> +#include <linux/log2.h> #include <asm/uaccess.h> @@ -450,7 +451,7 @@ static int __init rd_init(void) err = -ENOMEM; if (rd_blocksize > PAGE_SIZE || rd_blocksize < 512 || - (rd_blocksize & (rd_blocksize-1))) { + !is_power_of_2(rd_blocksize)) { printk("RAMDISK: wrong blocksize %d, reverting to defaults\n", rd_blocksize); rd_blocksize = BLOCK_SIZE; diff --git a/drivers/cdrom/cdrom.c b/drivers/cdrom/cdrom.c index 47e5b40510cb..db259e60289b 100644 --- a/drivers/cdrom/cdrom.c +++ b/drivers/cdrom/cdrom.c @@ -1206,25 +1206,26 @@ int check_for_audio_disc(struct cdrom_device_info * cdi, return 0; } -/* Admittedly, the logic below could be performed in a nicer way. */ int cdrom_release(struct cdrom_device_info *cdi, struct file *fp) { struct cdrom_device_ops *cdo = cdi->ops; int opened_for_data; - cdinfo(CD_CLOSE, "entering cdrom_release\n"); + cdinfo(CD_CLOSE, "entering cdrom_release\n"); if (cdi->use_count > 0) cdi->use_count--; - if (cdi->use_count == 0) + + if (cdi->use_count == 0) { cdinfo(CD_CLOSE, "Use count for \"/dev/%s\" now zero\n", cdi->name); - if (cdi->use_count == 0) cdrom_dvd_rw_close_write(cdi); - if (cdi->use_count == 0 && - (cdo->capability & CDC_LOCK) && !keeplocked) { - cdinfo(CD_CLOSE, "Unlocking door!\n"); - cdo->lock_door(cdi, 0); + + if ((cdo->capability & CDC_LOCK) && !keeplocked) { + cdinfo(CD_CLOSE, "Unlocking door!\n"); + cdo->lock_door(cdi, 0); + } } + opened_for_data = !(cdi->options & CDO_USE_FFLAGS) || !(fp && fp->f_flags & O_NONBLOCK); diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig index 466629594776..85bf9b2aa74a 100644 --- a/drivers/char/Kconfig +++ b/drivers/char/Kconfig @@ -276,7 +276,7 @@ config N_HDLC config RISCOM8 tristate "SDL RISCom/8 card support" - depends on SERIAL_NONSTANDARD && BROKEN_ON_SMP + depends on SERIAL_NONSTANDARD help This is a driver for the SDL Communications RISCom/8 multiport card, which gives you many serial ports. You would need something like @@ -765,7 +765,7 @@ config JS_RTC config SGI_DS1286 tristate "SGI DS1286 RTC support" - depends on SGI_IP22 + depends on SGI_HAS_DS1286 help If you say Y here and create a character special file /dev/rtc with major number 10 and minor number 135 using mknod ("man mknod"), you diff --git a/drivers/char/hvc_console.c b/drivers/char/hvc_console.c index 480fae29c9b2..44160d5ebca0 100644 --- a/drivers/char/hvc_console.c +++ b/drivers/char/hvc_console.c @@ -93,7 +93,7 @@ struct hvc_struct { }; /* dynamic list of hvc_struct instances */ -static struct list_head hvc_structs = LIST_HEAD_INIT(hvc_structs); +static LIST_HEAD(hvc_structs); /* * Protect the list of hvc_struct instances from inserts and removals during diff --git a/drivers/char/hvcs.c b/drivers/char/hvcs.c index 3402def22007..786d518e9477 100644 --- a/drivers/char/hvcs.c +++ b/drivers/char/hvcs.c @@ -306,7 +306,7 @@ struct hvcs_struct { /* Required to back map a kref to its containing object */ #define from_kref(k) container_of(k, struct hvcs_struct, kref) -static struct list_head hvcs_structs = LIST_HEAD_INIT(hvcs_structs); +static LIST_HEAD(hvcs_structs); static DEFINE_SPINLOCK(hvcs_structs_lock); static void hvcs_unthrottle(struct tty_struct *tty); diff --git a/drivers/char/hw_random/via-rng.c b/drivers/char/hw_random/via-rng.c index 868e39fd42e4..f7feae4ebb5e 100644 --- a/drivers/char/hw_random/via-rng.c +++ b/drivers/char/hw_random/via-rng.c @@ -42,6 +42,8 @@ enum { VIA_STRFILT_ENABLE = (1 << 14), VIA_RAWBITS_ENABLE = (1 << 13), VIA_RNG_ENABLE = (1 << 6), + VIA_NOISESRC1 = (1 << 8), + VIA_NOISESRC2 = (1 << 9), VIA_XSTORE_CNT_MASK = 0x0F, VIA_RNG_CHUNK_8 = 0x00, /* 64 rand bits, 64 stored bits */ @@ -119,6 +121,7 @@ static int via_rng_data_read(struct hwrng *rng, u32 *data) static int via_rng_init(struct hwrng *rng) { + struct cpuinfo_x86 *c = &cpu_data(0); u32 lo, hi, old_lo; /* Control the RNG via MSR. Tread lightly and pay very close @@ -134,6 +137,17 @@ static int via_rng_init(struct hwrng *rng) lo &= ~VIA_XSTORE_CNT_MASK; lo &= ~(VIA_STRFILT_ENABLE | VIA_STRFILT_FAIL | VIA_RAWBITS_ENABLE); lo |= VIA_RNG_ENABLE; + lo |= VIA_NOISESRC1; + + /* Enable secondary noise source on CPUs where it is present. */ + + /* Nehemiah stepping 8 and higher */ + if ((c->x86_model == 9) && (c->x86_mask > 7)) + lo |= VIA_NOISESRC2; + + /* Esther */ + if (c->x86_model >= 10) + lo |= VIA_NOISESRC2; if (lo != old_lo) wrmsr(MSR_VIA_RNG, lo, hi); diff --git a/drivers/char/i8k.c b/drivers/char/i8k.c index 30e564516422..179223a17414 100644 --- a/drivers/char/i8k.c +++ b/drivers/char/i8k.c @@ -439,6 +439,13 @@ static struct dmi_system_id __initdata i8k_dmi_table[] = { DMI_MATCH(DMI_PRODUCT_NAME, "Latitude"), }, }, + { /* UK Inspiron 6400 */ + .ident = "Dell Inspiron 3", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), + DMI_MATCH(DMI_PRODUCT_NAME, "MM061"), + }, + }, { } }; diff --git a/drivers/char/ip27-rtc.c b/drivers/char/ip27-rtc.c index 932264a657d0..86e6538a77b0 100644 --- a/drivers/char/ip27-rtc.c +++ b/drivers/char/ip27-rtc.c @@ -46,8 +46,8 @@ #include <asm/sn/sn0/hub.h> #include <asm/sn/sn_private.h> -static int rtc_ioctl(struct inode *inode, struct file *file, - unsigned int cmd, unsigned long arg); +static long rtc_ioctl(struct file *filp, unsigned int cmd, + unsigned long arg); static int rtc_read_proc(char *page, char **start, off_t off, int count, int *eof, void *data); @@ -75,8 +75,7 @@ static unsigned long epoch = 1970; /* year corresponding to 0x00 */ static const unsigned char days_in_mo[] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; -static int rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd, - unsigned long arg) +static long rtc_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) { struct rtc_time wtime; @@ -197,7 +196,7 @@ static int rtc_release(struct inode *inode, struct file *file) static const struct file_operations rtc_fops = { .owner = THIS_MODULE, - .ioctl = rtc_ioctl, + .unlocked_ioctl = rtc_ioctl, .open = rtc_open, .release = rtc_release, }; diff --git a/drivers/char/ipmi/ipmi_msghandler.c b/drivers/char/ipmi/ipmi_msghandler.c index 5dc1265ce1d5..32b2b22996dc 100644 --- a/drivers/char/ipmi/ipmi_msghandler.c +++ b/drivers/char/ipmi/ipmi_msghandler.c @@ -365,12 +365,12 @@ static struct device_driver ipmidriver = { }; static DEFINE_MUTEX(ipmidriver_mutex); -static struct list_head ipmi_interfaces = LIST_HEAD_INIT(ipmi_interfaces); +static LIST_HEAD(ipmi_interfaces); static DEFINE_MUTEX(ipmi_interfaces_mutex); /* List of watchers that want to know when smi's are added and deleted. */ -static struct list_head smi_watchers = LIST_HEAD_INIT(smi_watchers); +static LIST_HEAD(smi_watchers); static DEFINE_MUTEX(smi_watchers_mutex); @@ -441,7 +441,7 @@ struct watcher_entry { int ipmi_smi_watcher_register(struct ipmi_smi_watcher *watcher) { ipmi_smi_t intf; - struct list_head to_deliver = LIST_HEAD_INIT(to_deliver); + LIST_HEAD(to_deliver); struct watcher_entry *e, *e2; mutex_lock(&smi_watchers_mutex); diff --git a/drivers/char/lp.c b/drivers/char/lp.c index 81674d7c56c7..60ac642752be 100644 --- a/drivers/char/lp.c +++ b/drivers/char/lp.c @@ -312,7 +312,7 @@ static ssize_t lp_write(struct file * file, const char __user * buf, if (copy_size > LP_BUFFER_SIZE) copy_size = LP_BUFFER_SIZE; - if (down_interruptible (&lp_table[minor].port_mutex)) + if (mutex_lock_interruptible(&lp_table[minor].port_mutex)) return -EINTR; if (copy_from_user (kbuf, buf, copy_size)) { @@ -399,7 +399,7 @@ static ssize_t lp_write(struct file * file, const char __user * buf, lp_release_parport (&lp_table[minor]); } out_unlock: - up (&lp_table[minor].port_mutex); + mutex_unlock(&lp_table[minor].port_mutex); return retv; } @@ -421,7 +421,7 @@ static ssize_t lp_read(struct file * file, char __user * buf, if (count > LP_BUFFER_SIZE) count = LP_BUFFER_SIZE; - if (down_interruptible (&lp_table[minor].port_mutex)) + if (mutex_lock_interruptible(&lp_table[minor].port_mutex)) return -EINTR; lp_claim_parport_or_block (&lp_table[minor]); @@ -479,7 +479,7 @@ static ssize_t lp_read(struct file * file, char __user * buf, if (retval > 0 && copy_to_user (buf, kbuf, retval)) retval = -EFAULT; - up (&lp_table[minor].port_mutex); + mutex_unlock(&lp_table[minor].port_mutex); return retval; } @@ -888,7 +888,7 @@ static int __init lp_init (void) lp_table[i].last_error = 0; init_waitqueue_head (&lp_table[i].waitq); init_waitqueue_head (&lp_table[i].dataq); - init_MUTEX (&lp_table[i].port_mutex); + mutex_init(&lp_table[i].port_mutex); lp_table[i].timeout = 10 * HZ; } diff --git a/drivers/char/mxser.c b/drivers/char/mxser.c index fd0abef7ee08..47420787a017 100644 --- a/drivers/char/mxser.c +++ b/drivers/char/mxser.c @@ -37,7 +37,6 @@ #include <linux/module.h> -#include <linux/autoconf.h> #include <linux/errno.h> #include <linux/signal.h> #include <linux/sched.h> diff --git a/drivers/char/mxser_new.c b/drivers/char/mxser_new.c index 081c84c7b548..bf1bee4e1f5e 100644 --- a/drivers/char/mxser_new.c +++ b/drivers/char/mxser_new.c @@ -20,7 +20,6 @@ */ #include <linux/module.h> -#include <linux/autoconf.h> #include <linux/errno.h> #include <linux/signal.h> #include <linux/sched.h> diff --git a/drivers/char/n_tty.c b/drivers/char/n_tty.c index 596c7173997b..90c3969012a3 100644 --- a/drivers/char/n_tty.c +++ b/drivers/char/n_tty.c @@ -695,17 +695,16 @@ static inline void n_tty_receive_char(struct tty_struct *tty, unsigned char c) return; } - if (tty->stopped && !tty->flow_stopped && - I_IXON(tty) && I_IXANY(tty)) { - start_tty(tty); - return; - } - if (I_ISTRIP(tty)) c &= 0x7f; if (I_IUCLC(tty) && L_IEXTEN(tty)) c=tolower(c); + if (tty->stopped && !tty->flow_stopped && I_IXON(tty) && + ((I_IXANY(tty) && c != START_CHAR(tty) && c != STOP_CHAR(tty)) || + c == INTR_CHAR(tty) || c == QUIT_CHAR(tty))) + start_tty(tty); + if (tty->closing) { if (I_IXON(tty)) { if (c == START_CHAR(tty)) @@ -769,7 +768,21 @@ static inline void n_tty_receive_char(struct tty_struct *tty, unsigned char c) signal = SIGTSTP; if (c == SUSP_CHAR(tty)) { send_signal: - isig(signal, tty, 0); + /* + * Echo character, and then send the signal. + * Note that we do not use isig() here because we want + * the order to be: + * 1) flush, 2) echo, 3) signal + */ + if (!L_NOFLSH(tty)) { + n_tty_flush_buffer(tty); + if (tty->driver->flush_buffer) + tty->driver->flush_buffer(tty); + } + if (L_ECHO(tty)) + echo_char(c, tty); + if (tty->pgrp) + kill_pgrp(tty->pgrp, signal, 1); return; } } diff --git a/drivers/char/pcmcia/synclink_cs.c b/drivers/char/pcmcia/synclink_cs.c index 8caff0ca80ff..279ff5005cec 100644 --- a/drivers/char/pcmcia/synclink_cs.c +++ b/drivers/char/pcmcia/synclink_cs.c @@ -57,6 +57,7 @@ #include <linux/init.h> #include <linux/delay.h> #include <linux/ioctl.h> +#include <linux/synclink.h> #include <asm/system.h> #include <asm/io.h> @@ -87,8 +88,6 @@ #include <asm/uaccess.h> -#include "linux/synclink.h" - static MGSL_PARAMS default_params = { MGSL_MODE_HDLC, /* unsigned long mode */ 0, /* unsigned char loopback; */ diff --git a/drivers/char/random.c b/drivers/char/random.c index c511a831f0c0..f43c89f7c449 100644 --- a/drivers/char/random.c +++ b/drivers/char/random.c @@ -1039,6 +1039,7 @@ write_pool(struct entropy_store *r, const char __user *buffer, size_t count) p += bytes; add_entropy_words(r, buf, (bytes + 3) / 4); + cond_resched(); } return 0; diff --git a/drivers/char/riscom8.c b/drivers/char/riscom8.c index 102ece4c4e0e..d130b87d8ed7 100644 --- a/drivers/char/riscom8.c +++ b/drivers/char/riscom8.c @@ -47,6 +47,7 @@ #include <linux/init.h> #include <linux/delay.h> #include <linux/tty_flip.h> +#include <linux/spinlock.h> #include <asm/uaccess.h> @@ -81,6 +82,8 @@ static struct tty_driver *riscom_driver; +static DEFINE_SPINLOCK(riscom_lock); + static struct riscom_board rc_board[RC_NBOARD] = { { .base = RC_IOBASE1, @@ -217,13 +220,14 @@ static void __init rc_init_CD180(struct riscom_board const * bp) { unsigned long flags; - save_flags(flags); cli(); + spin_lock_irqsave(&riscom_lock, flags); + rc_out(bp, RC_CTOUT, 0); /* Clear timeout */ rc_wait_CCR(bp); /* Wait for CCR ready */ rc_out(bp, CD180_CCR, CCR_HARDRESET); /* Reset CD180 chip */ - sti(); + spin_unlock_irqrestore(&riscom_lock, flags); msleep(50); /* Delay 0.05 sec */ - cli(); + spin_lock_irqsave(&riscom_lock, flags); rc_out(bp, CD180_GIVR, RC_ID); /* Set ID for this chip */ rc_out(bp, CD180_GICR, 0); /* Clear all bits */ rc_out(bp, CD180_PILR1, RC_ACK_MINT); /* Prio for modem intr */ @@ -234,7 +238,7 @@ static void __init rc_init_CD180(struct riscom_board const * bp) rc_out(bp, CD180_PPRH, (RC_OSCFREQ/(1000000/RISCOM_TPS)) >> 8); rc_out(bp, CD180_PPRL, (RC_OSCFREQ/(1000000/RISCOM_TPS)) & 0xff); - restore_flags(flags); + spin_unlock_irqrestore(&riscom_lock, flags); } /* Main probing routine, also sets irq. */ @@ -812,9 +816,9 @@ static int rc_setup_port(struct riscom_board *bp, struct riscom_port *port) } port->xmit_buf = (unsigned char *) tmp; } - - save_flags(flags); cli(); - + + spin_lock_irqsave(&riscom_lock, flags); + if (port->tty) clear_bit(TTY_IO_ERROR, &port->tty->flags); @@ -825,7 +829,7 @@ static int rc_setup_port(struct riscom_board *bp, struct riscom_port *port) rc_change_speed(bp, port); port->flags |= ASYNC_INITIALIZED; - restore_flags(flags); + spin_unlock_irqrestore(&riscom_lock, flags); return 0; } @@ -901,6 +905,7 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp, int retval; int do_clocal = 0; int CD; + unsigned long flags; /* * If the device is in the middle of being closed, then block @@ -936,19 +941,26 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp, */ retval = 0; add_wait_queue(&port->open_wait, &wait); - cli(); + + spin_lock_irqsave(&riscom_lock, flags); + if (!tty_hung_up_p(filp)) port->count--; - sti(); + + spin_unlock_irqrestore(&riscom_lock, flags); + port->blocked_open++; while (1) { - cli(); + spin_lock_irqsave(&riscom_lock, flags); + rc_out(bp, CD180_CAR, port_No(port)); CD = rc_in(bp, CD180_MSVR) & MSVR_CD; rc_out(bp, CD180_MSVR, MSVR_RTS); bp->DTR &= ~(1u << port_No(port)); rc_out(bp, RC_DTR, bp->DTR); - sti(); + + spin_unlock_irqrestore(&riscom_lock, flags); + set_current_state(TASK_INTERRUPTIBLE); if (tty_hung_up_p(filp) || !(port->flags & ASYNC_INITIALIZED)) { @@ -1020,8 +1032,9 @@ static void rc_close(struct tty_struct * tty, struct file * filp) if (!port || rc_paranoia_check(port, tty->name, "close")) return; - - save_flags(flags); cli(); + + spin_lock_irqsave(&riscom_lock, flags); + if (tty_hung_up_p(filp)) goto out; @@ -1088,7 +1101,9 @@ static void rc_close(struct tty_struct * tty, struct file * filp) } port->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING); wake_up_interruptible(&port->close_wait); -out: restore_flags(flags); + +out: + spin_unlock_irqrestore(&riscom_lock, flags); } static int rc_write(struct tty_struct * tty, @@ -1107,34 +1122,33 @@ static int rc_write(struct tty_struct * tty, if (!tty || !port->xmit_buf) return 0; - save_flags(flags); while (1) { - cli(); + spin_lock_irqsave(&riscom_lock, flags); + c = min_t(int, count, min(SERIAL_XMIT_SIZE - port->xmit_cnt - 1, SERIAL_XMIT_SIZE - port->xmit_head)); - if (c <= 0) { - restore_flags(flags); - break; - } + if (c <= 0) + break; /* lock continues to be held */ memcpy(port->xmit_buf + port->xmit_head, buf, c); port->xmit_head = (port->xmit_head + c) & (SERIAL_XMIT_SIZE-1); port->xmit_cnt += c; - restore_flags(flags); + + spin_unlock_irqrestore(&riscom_lock, flags); buf += c; count -= c; total += c; } - cli(); if (port->xmit_cnt && !tty->stopped && !tty->hw_stopped && !(port->IER & IER_TXRDY)) { port->IER |= IER_TXRDY; rc_out(bp, CD180_CAR, port_No(port)); rc_out(bp, CD180_IER, port->IER); } - restore_flags(flags); + + spin_unlock_irqrestore(&riscom_lock, flags); return total; } @@ -1150,7 +1164,7 @@ static void rc_put_char(struct tty_struct * tty, unsigned char ch) if (!tty || !port->xmit_buf) return; - save_flags(flags); cli(); + spin_lock_irqsave(&riscom_lock, flags); if (port->xmit_cnt >= SERIAL_XMIT_SIZE - 1) goto out; @@ -1158,7 +1172,9 @@ static void rc_put_char(struct tty_struct * tty, unsigned char ch) port->xmit_buf[port->xmit_head++] = ch; port->xmit_head &= SERIAL_XMIT_SIZE - 1; port->xmit_cnt++; -out: restore_flags(flags); + +out: + spin_unlock_irqrestore(&riscom_lock, flags); } static void rc_flush_chars(struct tty_struct * tty) @@ -1173,11 +1189,13 @@ static void rc_flush_chars(struct tty_struct * tty) !port->xmit_buf) return; - save_flags(flags); cli(); + spin_lock_irqsave(&riscom_lock, flags); + port->IER |= IER_TXRDY; rc_out(port_Board(port), CD180_CAR, port_No(port)); rc_out(port_Board(port), CD180_IER, port->IER); - restore_flags(flags); + + spin_unlock_irqrestore(&riscom_lock, flags); } static int rc_write_room(struct tty_struct * tty) @@ -1212,9 +1230,11 @@ static void rc_flush_buffer(struct tty_struct *tty) if (rc_paranoia_check(port, tty->name, "rc_flush_buffer")) return; - save_flags(flags); cli(); + spin_lock_irqsave(&riscom_lock, flags); + port->xmit_cnt = port->xmit_head = port->xmit_tail = 0; - restore_flags(flags); + + spin_unlock_irqrestore(&riscom_lock, flags); tty_wakeup(tty); } @@ -1231,11 +1251,15 @@ static int rc_tiocmget(struct tty_struct *tty, struct file *file) return -ENODEV; bp = port_Board(port); - save_flags(flags); cli(); + + spin_lock_irqsave(&riscom_lock, flags); + rc_out(bp, CD180_CAR, port_No(port)); status = rc_in(bp, CD180_MSVR); result = rc_in(bp, RC_RI) & (1u << port_No(port)) ? 0 : TIOCM_RNG; - restore_flags(flags); + + spin_unlock_irqrestore(&riscom_lock, flags); + result |= ((status & MSVR_RTS) ? TIOCM_RTS : 0) | ((status & MSVR_DTR) ? TIOCM_DTR : 0) | ((status & MSVR_CD) ? TIOCM_CAR : 0) @@ -1256,7 +1280,8 @@ static int rc_tiocmset(struct tty_struct *tty, struct file *file, bp = port_Board(port); - save_flags(flags); cli(); + spin_lock_irqsave(&riscom_lock, flags); + if (set & TIOCM_RTS) port->MSVR |= MSVR_RTS; if (set & TIOCM_DTR) @@ -1270,7 +1295,9 @@ static int rc_tiocmset(struct tty_struct *tty, struct file *file, rc_out(bp, CD180_CAR, port_No(port)); rc_out(bp, CD180_MSVR, port->MSVR); rc_out(bp, RC_DTR, bp->DTR); - restore_flags(flags); + + spin_unlock_irqrestore(&riscom_lock, flags); + return 0; } @@ -1279,7 +1306,8 @@ static inline void rc_send_break(struct riscom_port * port, unsigned long length struct riscom_board *bp = port_Board(port); unsigned long flags; - save_flags(flags); cli(); + spin_lock_irqsave(&riscom_lock, flags); + port->break_length = RISCOM_TPS / HZ * length; port->COR2 |= COR2_ETC; port->IER |= IER_TXRDY; @@ -1289,7 +1317,8 @@ static inline void rc_send_break(struct riscom_port * port, unsigned long length rc_wait_CCR(bp); rc_out(bp, CD180_CCR, CCR_CORCHG2); rc_wait_CCR(bp); - restore_flags(flags); + + spin_unlock_irqrestore(&riscom_lock, flags); } static inline int rc_set_serial_info(struct riscom_port * port, @@ -1298,7 +1327,6 @@ static inline int rc_set_serial_info(struct riscom_port * port, struct serial_struct tmp; struct riscom_board *bp = port_Board(port); int change_speed; - unsigned long flags; if (copy_from_user(&tmp, newinfo, sizeof(tmp))) return -EFAULT; @@ -1332,9 +1360,11 @@ static inline int rc_set_serial_info(struct riscom_port * port, port->closing_wait = tmp.closing_wait; } if (change_speed) { - save_flags(flags); cli(); + unsigned long flags; + + spin_lock_irqsave(&riscom_lock, flags); rc_change_speed(bp, port); - restore_flags(flags); + spin_unlock_irqrestore(&riscom_lock, flags); } return 0; } @@ -1414,17 +1444,19 @@ static void rc_throttle(struct tty_struct * tty) return; bp = port_Board(port); - - save_flags(flags); cli(); + + spin_lock_irqsave(&riscom_lock, flags); + port->MSVR &= ~MSVR_RTS; rc_out(bp, CD180_CAR, port_No(port)); - if (I_IXOFF(tty)) { + if (I_IXOFF(tty)) { rc_wait_CCR(bp); rc_out(bp, CD180_CCR, CCR_SSCH2); rc_wait_CCR(bp); } rc_out(bp, CD180_MSVR, port->MSVR); - restore_flags(flags); + + spin_unlock_irqrestore(&riscom_lock, flags); } static void rc_unthrottle(struct tty_struct * tty) @@ -1438,7 +1470,8 @@ static void rc_unthrottle(struct tty_struct * tty) bp = port_Board(port); - save_flags(flags); cli(); + spin_lock_irqsave(&riscom_lock, flags); + port->MSVR |= MSVR_RTS; rc_out(bp, CD180_CAR, port_No(port)); if (I_IXOFF(tty)) { @@ -1447,7 +1480,8 @@ static void rc_unthrottle(struct tty_struct * tty) rc_wait_CCR(bp); } rc_out(bp, CD180_MSVR, port->MSVR); - restore_flags(flags); + + spin_unlock_irqrestore(&riscom_lock, flags); } static void rc_stop(struct tty_struct * tty) @@ -1461,11 +1495,13 @@ static void rc_stop(struct tty_struct * tty) bp = port_Board(port); - save_flags(flags); cli(); + spin_lock_irqsave(&riscom_lock, flags); + port->IER &= ~IER_TXRDY; rc_out(bp, CD180_CAR, port_No(port)); rc_out(bp, CD180_IER, port->IER); - restore_flags(flags); + + spin_unlock_irqrestore(&riscom_lock, flags); } static void rc_start(struct tty_struct * tty) @@ -1479,13 +1515,15 @@ static void rc_start(struct tty_struct * tty) bp = port_Board(port); - save_flags(flags); cli(); + spin_lock_irqsave(&riscom_lock, flags); + if (port->xmit_cnt && port->xmit_buf && !(port->IER & IER_TXRDY)) { port->IER |= IER_TXRDY; rc_out(bp, CD180_CAR, port_No(port)); rc_out(bp, CD180_IER, port->IER); } - restore_flags(flags); + + spin_unlock_irqrestore(&riscom_lock, flags); } /* @@ -1537,9 +1575,9 @@ static void rc_set_termios(struct tty_struct * tty, struct ktermios * old_termio tty->termios->c_iflag == old_termios->c_iflag) return; - save_flags(flags); cli(); + spin_lock_irqsave(&riscom_lock, flags); rc_change_speed(port_Board(port), port); - restore_flags(flags); + spin_unlock_irqrestore(&riscom_lock, flags); if ((old_termios->c_cflag & CRTSCTS) && !(tty->termios->c_cflag & CRTSCTS)) { @@ -1627,11 +1665,12 @@ static void rc_release_drivers(void) { unsigned long flags; - save_flags(flags); - cli(); + spin_lock_irqsave(&riscom_lock, flags); + tty_unregister_driver(riscom_driver); put_tty_driver(riscom_driver); - restore_flags(flags); + + spin_unlock_irqrestore(&riscom_lock, flags); } #ifndef MODULE diff --git a/drivers/char/ser_a2232.c b/drivers/char/ser_a2232.c index 3c869145bfdc..4ba3aec9e1cd 100644 --- a/drivers/char/ser_a2232.c +++ b/drivers/char/ser_a2232.c @@ -653,7 +653,7 @@ static void a2232_init_portstructs(void) port->gs.closing_wait = 30 * HZ; port->gs.rd = &a2232_real_driver; #ifdef NEW_WRITE_LOCKING - init_MUTEX(&(port->gs.port_write_mutex)); + mutex_init(&(port->gs.port_write_mutex)); #endif init_waitqueue_head(&port->gs.open_wait); init_waitqueue_head(&port->gs.close_wait); diff --git a/drivers/char/synclink.c b/drivers/char/synclink.c index d010ed95ed3b..ddc74d1f4f1b 100644 --- a/drivers/char/synclink.c +++ b/drivers/char/synclink.c @@ -85,6 +85,7 @@ #include <linux/vmalloc.h> #include <linux/init.h> #include <linux/ioctl.h> +#include <linux/synclink.h> #include <asm/system.h> #include <asm/io.h> @@ -110,8 +111,6 @@ #include <asm/uaccess.h> -#include "linux/synclink.h" - #define RCLRVALUE 0xffff static MGSL_PARAMS default_params = { diff --git a/drivers/char/synclink_gt.c b/drivers/char/synclink_gt.c index 64e835f62438..1f954acf2bac 100644 --- a/drivers/char/synclink_gt.c +++ b/drivers/char/synclink_gt.c @@ -73,6 +73,7 @@ #include <linux/bitops.h> #include <linux/workqueue.h> #include <linux/hdlc.h> +#include <linux/synclink.h> #include <asm/system.h> #include <asm/io.h> @@ -81,8 +82,6 @@ #include <asm/types.h> #include <asm/uaccess.h> -#include "linux/synclink.h" - #if defined(CONFIG_HDLC) || (defined(CONFIG_HDLC_MODULE) && defined(CONFIG_SYNCLINK_GT_MODULE)) #define SYNCLINK_GENERIC_HDLC 1 #else @@ -2040,37 +2039,41 @@ static void bh_transmit(struct slgt_info *info) tty_wakeup(tty); } -static void dsr_change(struct slgt_info *info) +static void dsr_change(struct slgt_info *info, unsigned short status) { - get_signals(info); + if (status & BIT3) { + info->signals |= SerialSignal_DSR; + info->input_signal_events.dsr_up++; + } else { + info->signals &= ~SerialSignal_DSR; + info->input_signal_events.dsr_down++; + } DBGISR(("dsr_change %s signals=%04X\n", info->device_name, info->signals)); if ((info->dsr_chkcount)++ == IO_PIN_SHUTDOWN_LIMIT) { slgt_irq_off(info, IRQ_DSR); return; } info->icount.dsr++; - if (info->signals & SerialSignal_DSR) - info->input_signal_events.dsr_up++; - else - info->input_signal_events.dsr_down++; wake_up_interruptible(&info->status_event_wait_q); wake_up_interruptible(&info->event_wait_q); info->pending_bh |= BH_STATUS; } -static void cts_change(struct slgt_info *info) +static void cts_change(struct slgt_info *info, unsigned short status) { - get_signals(info); + if (status & BIT2) { + info->signals |= SerialSignal_CTS; + info->input_signal_events.cts_up++; + } else { + info->signals &= ~SerialSignal_CTS; + info->input_signal_events.cts_down++; + } DBGISR(("cts_change %s signals=%04X\n", info->device_name, info->signals)); if ((info->cts_chkcount)++ == IO_PIN_SHUTDOWN_LIMIT) { slgt_irq_off(info, IRQ_CTS); return; } info->icount.cts++; - if (info->signals & SerialSignal_CTS) - info->input_signal_events.cts_up++; - else - info->input_signal_events.cts_down++; wake_up_interruptible(&info->status_event_wait_q); wake_up_interruptible(&info->event_wait_q); info->pending_bh |= BH_STATUS; @@ -2091,20 +2094,21 @@ static void cts_change(struct slgt_info *info) } } -static void dcd_change(struct slgt_info *info) +static void dcd_change(struct slgt_info *info, unsigned short status) { - get_signals(info); + if (status & BIT1) { + info->signals |= SerialSignal_DCD; + info->input_signal_events.dcd_up++; + } else { + info->signals &= ~SerialSignal_DCD; + info->input_signal_events.dcd_down++; + } DBGISR(("dcd_change %s signals=%04X\n", info->device_name, info->signals)); if ((info->dcd_chkcount)++ == IO_PIN_SHUTDOWN_LIMIT) { slgt_irq_off(info, IRQ_DCD); return; } info->icount.dcd++; - if (info->signals & SerialSignal_DCD) { - info->input_signal_events.dcd_up++; - } else { - info->input_signal_events.dcd_down++; - } #if SYNCLINK_GENERIC_HDLC if (info->netcount) { if (info->signals & SerialSignal_DCD) @@ -2127,20 +2131,21 @@ static void dcd_change(struct slgt_info *info) } } -static void ri_change(struct slgt_info *info) +static void ri_change(struct slgt_info *info, unsigned short status) { - get_signals(info); + if (status & BIT0) { + info->signals |= SerialSignal_RI; + info->input_signal_events.ri_up++; + } else { + info->signals &= ~SerialSignal_RI; + info->input_signal_events.ri_down++; + } DBGISR(("ri_change %s signals=%04X\n", info->device_name, info->signals)); if ((info->ri_chkcount)++ == IO_PIN_SHUTDOWN_LIMIT) { slgt_irq_off(info, IRQ_RI); return; } - info->icount.dcd++; - if (info->signals & SerialSignal_RI) { - info->input_signal_events.ri_up++; - } else { - info->input_signal_events.ri_down++; - } + info->icount.rng++; wake_up_interruptible(&info->status_event_wait_q); wake_up_interruptible(&info->event_wait_q); info->pending_bh |= BH_STATUS; @@ -2191,13 +2196,13 @@ static void isr_serial(struct slgt_info *info) } if (status & IRQ_DSR) - dsr_change(info); + dsr_change(info, status); if (status & IRQ_CTS) - cts_change(info); + cts_change(info, status); if (status & IRQ_DCD) - dcd_change(info); + dcd_change(info, status); if (status & IRQ_RI) - ri_change(info); + ri_change(info, status); } static void isr_rdma(struct slgt_info *info) diff --git a/drivers/char/synclinkmp.c b/drivers/char/synclinkmp.c index c63013b2fc36..f3e7807f78d9 100644 --- a/drivers/char/synclinkmp.c +++ b/drivers/char/synclinkmp.c @@ -66,6 +66,7 @@ #include <linux/termios.h> #include <linux/workqueue.h> #include <linux/hdlc.h> +#include <linux/synclink.h> #if defined(CONFIG_HDLC) || (defined(CONFIG_HDLC_MODULE) && defined(CONFIG_SYNCLINKMP_MODULE)) #define SYNCLINK_GENERIC_HDLC 1 @@ -80,8 +81,6 @@ #include <asm/uaccess.h> -#include "linux/synclink.h" - static MGSL_PARAMS default_params = { MGSL_MODE_HDLC, /* unsigned long mode */ 0, /* unsigned char loopback; */ diff --git a/drivers/char/tpm/tpm.c b/drivers/char/tpm/tpm.c index c88424a0c89b..a5d8bcb40000 100644 --- a/drivers/char/tpm/tpm.c +++ b/drivers/char/tpm/tpm.c @@ -1031,18 +1031,13 @@ void tpm_remove_hardware(struct device *dev) spin_unlock(&driver_lock); - dev_set_drvdata(dev, NULL); misc_deregister(&chip->vendor.miscdev); - kfree(chip->vendor.miscdev.name); sysfs_remove_group(&dev->kobj, chip->vendor.attr_group); tpm_bios_log_teardown(chip->bios_dir); - clear_bit(chip->dev_num, dev_mask); - - kfree(chip); - - put_device(dev); + /* write it this way to be explicit (chip->dev == dev) */ + put_device(chip->dev); } EXPORT_SYMBOL_GPL(tpm_remove_hardware); @@ -1083,6 +1078,26 @@ int tpm_pm_resume(struct device *dev) EXPORT_SYMBOL_GPL(tpm_pm_resume); /* + * Once all references to platform device are down to 0, + * release all allocated structures. + * In case vendor provided release function, + * call it too. + */ +static void tpm_dev_release(struct device *dev) +{ + struct tpm_chip *chip = dev_get_drvdata(dev); + + if (chip->vendor.release) + chip->vendor.release(dev); + + chip->release(dev); + + clear_bit(chip->dev_num, dev_mask); + kfree(chip->vendor.miscdev.name); + kfree(chip); +} + +/* * Called from tpm_<specific>.c probe function only for devices * the driver has determined it should claim. Prior to calling * this function the specific probe function has called pci_enable_device @@ -1136,23 +1151,21 @@ struct tpm_chip *tpm_register_hardware(struct device *dev, const struct tpm_vend chip->vendor.miscdev.parent = dev; chip->dev = get_device(dev); + chip->release = dev->release; + dev->release = tpm_dev_release; + dev_set_drvdata(dev, chip); if (misc_register(&chip->vendor.miscdev)) { dev_err(chip->dev, "unable to misc_register %s, minor %d\n", chip->vendor.miscdev.name, chip->vendor.miscdev.minor); - put_device(dev); - clear_bit(chip->dev_num, dev_mask); - kfree(chip); - kfree(devname); + put_device(chip->dev); return NULL; } spin_lock(&driver_lock); - dev_set_drvdata(dev, chip); - list_add(&chip->list, &tpm_chip_list); spin_unlock(&driver_lock); @@ -1160,10 +1173,7 @@ struct tpm_chip *tpm_register_hardware(struct device *dev, const struct tpm_vend if (sysfs_create_group(&dev->kobj, chip->vendor.attr_group)) { list_del(&chip->list); misc_deregister(&chip->vendor.miscdev); - put_device(dev); - clear_bit(chip->dev_num, dev_mask); - kfree(chip); - kfree(devname); + put_device(chip->dev); return NULL; } diff --git a/drivers/char/tpm/tpm.h b/drivers/char/tpm/tpm.h index d15ccddc92eb..e885148b4cfb 100644 --- a/drivers/char/tpm/tpm.h +++ b/drivers/char/tpm/tpm.h @@ -74,6 +74,7 @@ struct tpm_vendor_specific { int (*send) (struct tpm_chip *, u8 *, size_t); void (*cancel) (struct tpm_chip *); u8 (*status) (struct tpm_chip *); + void (*release) (struct device *); struct miscdevice miscdev; struct attribute_group *attr_group; struct list_head list; @@ -106,6 +107,7 @@ struct tpm_chip { struct dentry **bios_dir; struct list_head list; + void (*release) (struct device *); }; #define to_tpm_chip(n) container_of(n, struct tpm_chip, vendor) diff --git a/drivers/char/tpm/tpm_infineon.c b/drivers/char/tpm/tpm_infineon.c index 967002a5a1e5..726ee8a0277f 100644 --- a/drivers/char/tpm/tpm_infineon.c +++ b/drivers/char/tpm/tpm_infineon.c @@ -611,7 +611,7 @@ static __devexit void tpm_inf_pnp_remove(struct pnp_dev *dev) } } -static struct pnp_driver tpm_inf_pnp = { +static struct pnp_driver tpm_inf_pnp_driver = { .name = "tpm_inf_pnp", .driver = { .owner = THIS_MODULE, @@ -625,12 +625,12 @@ static struct pnp_driver tpm_inf_pnp = { static int __init init_inf(void) { - return pnp_register_driver(&tpm_inf_pnp); + return pnp_register_driver(&tpm_inf_pnp_driver); } static void __exit cleanup_inf(void) { - pnp_unregister_driver(&tpm_inf_pnp); + pnp_unregister_driver(&tpm_inf_pnp_driver); } module_init(init_inf); diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c index f36fecd3fd26..79c86c47947f 100644 --- a/drivers/char/tty_io.c +++ b/drivers/char/tty_io.c @@ -138,7 +138,7 @@ EXPORT_SYMBOL(tty_mutex); extern struct tty_driver *ptm_driver; /* Unix98 pty masters; for /dev/ptmx */ extern int pty_limit; /* Config limit on Unix98 ptys */ static DEFINE_IDR(allocated_ptys); -static DECLARE_MUTEX(allocated_ptys_lock); +static DEFINE_MUTEX(allocated_ptys_lock); static int ptmx_open(struct inode *, struct file *); #endif @@ -2571,9 +2571,9 @@ static void release_dev(struct file * filp) #ifdef CONFIG_UNIX98_PTYS /* Make this pty number available for reallocation */ if (devpts) { - down(&allocated_ptys_lock); + mutex_lock(&allocated_ptys_lock); idr_remove(&allocated_ptys, idx); - up(&allocated_ptys_lock); + mutex_unlock(&allocated_ptys_lock); } #endif @@ -2737,24 +2737,24 @@ static int ptmx_open(struct inode * inode, struct file * filp) nonseekable_open(inode, filp); /* find a device that is not in use. */ - down(&allocated_ptys_lock); + mutex_lock(&allocated_ptys_lock); if (!idr_pre_get(&allocated_ptys, GFP_KERNEL)) { - up(&allocated_ptys_lock); + mutex_unlock(&allocated_ptys_lock); return -ENOMEM; } idr_ret = idr_get_new(&allocated_ptys, NULL, &index); if (idr_ret < 0) { - up(&allocated_ptys_lock); + mutex_unlock(&allocated_ptys_lock); if (idr_ret == -EAGAIN) return -ENOMEM; return -EIO; } if (index >= pty_limit) { idr_remove(&allocated_ptys, index); - up(&allocated_ptys_lock); + mutex_unlock(&allocated_ptys_lock); return -EIO; } - up(&allocated_ptys_lock); + mutex_unlock(&allocated_ptys_lock); mutex_lock(&tty_mutex); retval = init_dev(ptm_driver, index, &tty); @@ -2781,9 +2781,9 @@ out1: release_dev(filp); return retval; out: - down(&allocated_ptys_lock); + mutex_lock(&allocated_ptys_lock); idr_remove(&allocated_ptys, index); - up(&allocated_ptys_lock); + mutex_unlock(&allocated_ptys_lock); return retval; } #endif @@ -3721,7 +3721,6 @@ static void initialize_tty_struct(struct tty_struct *tty) tty->buf.head = tty->buf.tail = NULL; tty_buffer_init(tty); INIT_DELAYED_WORK(&tty->buf.work, flush_to_ldisc); - init_MUTEX(&tty->buf.pty_sem); mutex_init(&tty->termios_mutex); init_waitqueue_head(&tty->write_wait); init_waitqueue_head(&tty->read_wait); @@ -4048,10 +4047,6 @@ void __init console_init(void) } } -#ifdef CONFIG_VT -extern int vty_init(void); -#endif - static int __init tty_class_init(void) { tty_class = class_create(THIS_MODULE, "tty"); diff --git a/drivers/char/vt.c b/drivers/char/vt.c index 7a5badfb7d84..367be9175061 100644 --- a/drivers/char/vt.c +++ b/drivers/char/vt.c @@ -2400,13 +2400,15 @@ static void vt_console_print(struct console *co, const char *b, unsigned count) { struct vc_data *vc = vc_cons[fg_console].d; unsigned char c; - static unsigned long printing; + static DEFINE_SPINLOCK(printing_lock); const ushort *start; ushort cnt = 0; ushort myx; /* console busy or not yet initialized */ - if (!printable || test_and_set_bit(0, &printing)) + if (!printable) + return; + if (!spin_trylock(&printing_lock)) return; if (kmsg_redirect && vc_cons_allocated(kmsg_redirect - 1)) @@ -2481,7 +2483,7 @@ static void vt_console_print(struct console *co, const char *b, unsigned count) notify_update(vc); quit: - clear_bit(0, &printing); + spin_unlock(&printing_lock); } static struct tty_driver *vt_console_device(struct console *c, int *index) diff --git a/drivers/firmware/dcdbas.c b/drivers/firmware/dcdbas.c index 18cdcb3ae1ca..1636806ec55e 100644 --- a/drivers/firmware/dcdbas.c +++ b/drivers/firmware/dcdbas.c @@ -658,4 +658,5 @@ MODULE_DESCRIPTION(DRIVER_DESCRIPTION " (version " DRIVER_VERSION ")"); MODULE_VERSION(DRIVER_VERSION); MODULE_AUTHOR("Dell Inc."); MODULE_LICENSE("GPL"); - +/* Any System or BIOS claiming to be by Dell */ +MODULE_ALIAS("dmi:*:[bs]vnD[Ee][Ll][Ll]*:*"); diff --git a/drivers/firmware/dmi-id.c b/drivers/firmware/dmi-id.c index 313c99cbdc62..e880d6c8d896 100644 --- a/drivers/firmware/dmi-id.c +++ b/drivers/firmware/dmi-id.c @@ -11,7 +11,6 @@ #include <linux/init.h> #include <linux/dmi.h> #include <linux/device.h> -#include <linux/autoconf.h> struct dmi_device_attribute{ struct device_attribute dev_attr; diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index 74fac0f5c348..bbd28342e771 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -27,15 +27,16 @@ config DEBUG_GPIO comment "I2C GPIO expanders:" -config GPIO_PCA9539 - tristate "PCA9539 16-bit I/O port" +config GPIO_PCA953X + tristate "PCA953x I/O ports" depends on I2C help - Say yes here to support the PCA9539 16-bit I/O port. These - parts are made by NXP and TI. + Say yes here to support the PCA9534 (8-bit), PCA9535 (16-bit), + PCA9536 (4-bit), PCA9537 (4-bit), PCA9538 (8-bit), and PCA9539 + (16-bit) I/O ports. These parts are made by NXP and TI. This driver can also be built as a module. If so, the module - will be called pca9539. + will be called pca953x. config GPIO_PCF857X tristate "PCF857x, PCA857x, and PCA967x I2C GPIO expanders" diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile index 470ecd6aa778..fdde9923cf33 100644 --- a/drivers/gpio/Makefile +++ b/drivers/gpio/Makefile @@ -5,5 +5,5 @@ ccflags-$(CONFIG_DEBUG_GPIO) += -DDEBUG obj-$(CONFIG_HAVE_GPIO_LIB) += gpiolib.o obj-$(CONFIG_GPIO_MCP23S08) += mcp23s08.o -obj-$(CONFIG_GPIO_PCA9539) += pca9539.o +obj-$(CONFIG_GPIO_PCA953X) += pca953x.o obj-$(CONFIG_GPIO_PCF857X) += pcf857x.o diff --git a/drivers/gpio/pca9539.c b/drivers/gpio/pca9539.c deleted file mode 100644 index 3e85c92a7d59..000000000000 --- a/drivers/gpio/pca9539.c +++ /dev/null @@ -1,271 +0,0 @@ -/* - * pca9539.c - 16-bit I/O port with interrupt and reset - * - * Copyright (C) 2005 Ben Gardner <bgardner@wabtec.com> - * Copyright (C) 2007 Marvell International Ltd. - * - * Derived from drivers/i2c/chips/pca9539.c - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - */ - -#include <linux/module.h> -#include <linux/init.h> -#include <linux/i2c.h> -#include <linux/i2c/pca9539.h> - -#include <asm/gpio.h> - - -#define NR_PCA9539_GPIOS 16 - -#define PCA9539_INPUT 0 -#define PCA9539_OUTPUT 2 -#define PCA9539_INVERT 4 -#define PCA9539_DIRECTION 6 - -struct pca9539_chip { - unsigned gpio_start; - uint16_t reg_output; - uint16_t reg_direction; - - struct i2c_client *client; - struct gpio_chip gpio_chip; -}; - -/* NOTE: we can't currently rely on fault codes to come from SMBus - * calls, so we map all errors to EIO here and return zero otherwise. - */ -static int pca9539_write_reg(struct pca9539_chip *chip, int reg, uint16_t val) -{ - if (i2c_smbus_write_word_data(chip->client, reg, val) < 0) - return -EIO; - else - return 0; -} - -static int pca9539_read_reg(struct pca9539_chip *chip, int reg, uint16_t *val) -{ - int ret; - - ret = i2c_smbus_read_word_data(chip->client, reg); - if (ret < 0) { - dev_err(&chip->client->dev, "failed reading register\n"); - return -EIO; - } - - *val = (uint16_t)ret; - return 0; -} - -static int pca9539_gpio_direction_input(struct gpio_chip *gc, unsigned off) -{ - struct pca9539_chip *chip; - uint16_t reg_val; - int ret; - - chip = container_of(gc, struct pca9539_chip, gpio_chip); - - reg_val = chip->reg_direction | (1u << off); - ret = pca9539_write_reg(chip, PCA9539_DIRECTION, reg_val); - if (ret) - return ret; - - chip->reg_direction = reg_val; - return 0; -} - -static int pca9539_gpio_direction_output(struct gpio_chip *gc, - unsigned off, int val) -{ - struct pca9539_chip *chip; - uint16_t reg_val; - int ret; - - chip = container_of(gc, struct pca9539_chip, gpio_chip); - - /* set output level */ - if (val) - reg_val = chip->reg_output | (1u << off); - else - reg_val = chip->reg_output & ~(1u << off); - - ret = pca9539_write_reg(chip, PCA9539_OUTPUT, reg_val); - if (ret) - return ret; - - chip->reg_output = reg_val; - - /* then direction */ - reg_val = chip->reg_direction & ~(1u << off); - ret = pca9539_write_reg(chip, PCA9539_DIRECTION, reg_val); - if (ret) - return ret; - - chip->reg_direction = reg_val; - return 0; -} - -static int pca9539_gpio_get_value(struct gpio_chip *gc, unsigned off) -{ - struct pca9539_chip *chip; - uint16_t reg_val; - int ret; - - chip = container_of(gc, struct pca9539_chip, gpio_chip); - - ret = pca9539_read_reg(chip, PCA9539_INPUT, ®_val); - if (ret < 0) { - /* NOTE: diagnostic already emitted; that's all we should - * do unless gpio_*_value_cansleep() calls become different - * from their nonsleeping siblings (and report faults). - */ - return 0; - } - - return (reg_val & (1u << off)) ? 1 : 0; -} - -static void pca9539_gpio_set_value(struct gpio_chip *gc, unsigned off, int val) -{ - struct pca9539_chip *chip; - uint16_t reg_val; - int ret; - - chip = container_of(gc, struct pca9539_chip, gpio_chip); - - if (val) - reg_val = chip->reg_output | (1u << off); - else - reg_val = chip->reg_output & ~(1u << off); - - ret = pca9539_write_reg(chip, PCA9539_OUTPUT, reg_val); - if (ret) - return; - - chip->reg_output = reg_val; -} - -static int pca9539_init_gpio(struct pca9539_chip *chip) -{ - struct gpio_chip *gc; - - gc = &chip->gpio_chip; - - gc->direction_input = pca9539_gpio_direction_input; - gc->direction_output = pca9539_gpio_direction_output; - gc->get = pca9539_gpio_get_value; - gc->set = pca9539_gpio_set_value; - - gc->base = chip->gpio_start; - gc->ngpio = NR_PCA9539_GPIOS; - gc->label = "pca9539"; - - return gpiochip_add(gc); -} - -static int __devinit pca9539_probe(struct i2c_client *client) -{ - struct pca9539_platform_data *pdata; - struct pca9539_chip *chip; - int ret; - - pdata = client->dev.platform_data; - if (pdata == NULL) - return -ENODEV; - - chip = kzalloc(sizeof(struct pca9539_chip), GFP_KERNEL); - if (chip == NULL) - return -ENOMEM; - - chip->client = client; - - chip->gpio_start = pdata->gpio_base; - - /* initialize cached registers from their original values. - * we can't share this chip with another i2c master. - */ - ret = pca9539_read_reg(chip, PCA9539_OUTPUT, &chip->reg_output); - if (ret) - goto out_failed; - - ret = pca9539_read_reg(chip, PCA9539_DIRECTION, &chip->reg_direction); - if (ret) - goto out_failed; - - /* set platform specific polarity inversion */ - ret = pca9539_write_reg(chip, PCA9539_INVERT, pdata->invert); - if (ret) - goto out_failed; - - ret = pca9539_init_gpio(chip); - if (ret) - goto out_failed; - - if (pdata->setup) { - ret = pdata->setup(client, chip->gpio_chip.base, - chip->gpio_chip.ngpio, pdata->context); - if (ret < 0) - dev_warn(&client->dev, "setup failed, %d\n", ret); - } - - i2c_set_clientdata(client, chip); - return 0; - -out_failed: - kfree(chip); - return ret; -} - -static int pca9539_remove(struct i2c_client *client) -{ - struct pca9539_platform_data *pdata = client->dev.platform_data; - struct pca9539_chip *chip = i2c_get_clientdata(client); - int ret = 0; - - if (pdata->teardown) { - ret = pdata->teardown(client, chip->gpio_chip.base, - chip->gpio_chip.ngpio, pdata->context); - if (ret < 0) { - dev_err(&client->dev, "%s failed, %d\n", - "teardown", ret); - return ret; - } - } - - ret = gpiochip_remove(&chip->gpio_chip); - if (ret) { - dev_err(&client->dev, "%s failed, %d\n", - "gpiochip_remove()", ret); - return ret; - } - - kfree(chip); - return 0; -} - -static struct i2c_driver pca9539_driver = { - .driver = { - .name = "pca9539", - }, - .probe = pca9539_probe, - .remove = pca9539_remove, -}; - -static int __init pca9539_init(void) -{ - return i2c_add_driver(&pca9539_driver); -} -module_init(pca9539_init); - -static void __exit pca9539_exit(void) -{ - i2c_del_driver(&pca9539_driver); -} -module_exit(pca9539_exit); - -MODULE_AUTHOR("eric miao <eric.miao@marvell.com>"); -MODULE_DESCRIPTION("GPIO expander driver for PCA9539"); -MODULE_LICENSE("GPL"); diff --git a/drivers/gpio/pca953x.c b/drivers/gpio/pca953x.c new file mode 100644 index 000000000000..92583cd4bffd --- /dev/null +++ b/drivers/gpio/pca953x.c @@ -0,0 +1,308 @@ +/* + * pca953x.c - 4/8/16 bit I/O ports + * + * Copyright (C) 2005 Ben Gardner <bgardner@wabtec.com> + * Copyright (C) 2007 Marvell International Ltd. + * + * Derived from drivers/i2c/chips/pca9539.c + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + */ + +#include <linux/module.h> +#include <linux/init.h> +#include <linux/i2c.h> +#include <linux/i2c/pca953x.h> + +#include <asm/gpio.h> + +#define PCA953X_INPUT 0 +#define PCA953X_OUTPUT 1 +#define PCA953X_INVERT 2 +#define PCA953X_DIRECTION 3 + +/* This is temporary - in 2.6.26 i2c_driver_data should replace it. */ +struct pca953x_desc { + char name[I2C_NAME_SIZE]; + unsigned long driver_data; +}; + +static const struct pca953x_desc pca953x_descs[] = { + { "pca9534", 8, }, + { "pca9535", 16, }, + { "pca9536", 4, }, + { "pca9537", 4, }, + { "pca9538", 8, }, + { "pca9539", 16, }, + /* REVISIT several pca955x parts should work here too */ +}; + +struct pca953x_chip { + unsigned gpio_start; + uint16_t reg_output; + uint16_t reg_direction; + + struct i2c_client *client; + struct gpio_chip gpio_chip; +}; + +/* NOTE: we can't currently rely on fault codes to come from SMBus + * calls, so we map all errors to EIO here and return zero otherwise. + */ +static int pca953x_write_reg(struct pca953x_chip *chip, int reg, uint16_t val) +{ + int ret; + + if (chip->gpio_chip.ngpio <= 8) + ret = i2c_smbus_write_byte_data(chip->client, reg, val); + else + ret = i2c_smbus_write_word_data(chip->client, reg << 1, val); + + if (ret < 0) { + dev_err(&chip->client->dev, "failed writing register\n"); + return -EIO; + } + + return 0; +} + +static int pca953x_read_reg(struct pca953x_chip *chip, int reg, uint16_t *val) +{ + int ret; + + if (chip->gpio_chip.ngpio <= 8) + ret = i2c_smbus_read_byte_data(chip->client, reg); + else + ret = i2c_smbus_read_word_data(chip->client, reg << 1); + + if (ret < 0) { + dev_err(&chip->client->dev, "failed reading register\n"); + return -EIO; + } + + *val = (uint16_t)ret; + return 0; +} + +static int pca953x_gpio_direction_input(struct gpio_chip *gc, unsigned off) +{ + struct pca953x_chip *chip; + uint16_t reg_val; + int ret; + + chip = container_of(gc, struct pca953x_chip, gpio_chip); + + reg_val = chip->reg_direction | (1u << off); + ret = pca953x_write_reg(chip, PCA953X_DIRECTION, reg_val); + if (ret) + return ret; + + chip->reg_direction = reg_val; + return 0; +} + +static int pca953x_gpio_direction_output(struct gpio_chip *gc, + unsigned off, int val) +{ + struct pca953x_chip *chip; + uint16_t reg_val; + int ret; + + chip = container_of(gc, struct pca953x_chip, gpio_chip); + + /* set output level */ + if (val) + reg_val = chip->reg_output | (1u << off); + else + reg_val = chip->reg_output & ~(1u << off); + + ret = pca953x_write_reg(chip, PCA953X_OUTPUT, reg_val); + if (ret) + return ret; + + chip->reg_output = reg_val; + + /* then direction */ + reg_val = chip->reg_direction & ~(1u << off); + ret = pca953x_write_reg(chip, PCA953X_DIRECTION, reg_val); + if (ret) + return ret; + + chip->reg_direction = reg_val; + return 0; +} + +static int pca953x_gpio_get_value(struct gpio_chip *gc, unsigned off) +{ + struct pca953x_chip *chip; + uint16_t reg_val; + int ret; + + chip = container_of(gc, struct pca953x_chip, gpio_chip); + + ret = pca953x_read_reg(chip, PCA953X_INPUT, ®_val); + if (ret < 0) { + /* NOTE: diagnostic already emitted; that's all we should + * do unless gpio_*_value_cansleep() calls become different + * from their nonsleeping siblings (and report faults). + */ + return 0; + } + + return (reg_val & (1u << off)) ? 1 : 0; +} + +static void pca953x_gpio_set_value(struct gpio_chip *gc, unsigned off, int val) +{ + struct pca953x_chip *chip; + uint16_t reg_val; + int ret; + + chip = container_of(gc, struct pca953x_chip, gpio_chip); + + if (val) + reg_val = chip->reg_output | (1u << off); + else + reg_val = chip->reg_output & ~(1u << off); + + ret = pca953x_write_reg(chip, PCA953X_OUTPUT, reg_val); + if (ret) + return; + + chip->reg_output = reg_val; +} + +static void pca953x_setup_gpio(struct pca953x_chip *chip, int gpios) +{ + struct gpio_chip *gc; + + gc = &chip->gpio_chip; + + gc->direction_input = pca953x_gpio_direction_input; + gc->direction_output = pca953x_gpio_direction_output; + gc->get = pca953x_gpio_get_value; + gc->set = pca953x_gpio_set_value; + + gc->base = chip->gpio_start; + gc->ngpio = gpios; + gc->label = chip->client->name; +} + +static int __devinit pca953x_probe(struct i2c_client *client) +{ + struct pca953x_platform_data *pdata; + struct pca953x_chip *chip; + int ret, i; + const struct pca953x_desc *id = NULL; + + pdata = client->dev.platform_data; + if (pdata == NULL) + return -ENODEV; + + /* this loop vanishes when we get i2c_device_id */ + for (i = 0; i < ARRAY_SIZE(pca953x_descs); i++) + if (!strcmp(pca953x_descs[i].name, client->name)) { + id = pca953x_descs + i; + break; + } + if (!id) + return -ENODEV; + + chip = kzalloc(sizeof(struct pca953x_chip), GFP_KERNEL); + if (chip == NULL) + return -ENOMEM; + + chip->client = client; + + chip->gpio_start = pdata->gpio_base; + + /* initialize cached registers from their original values. + * we can't share this chip with another i2c master. + */ + pca953x_setup_gpio(chip, id->driver_data); + + ret = pca953x_read_reg(chip, PCA953X_OUTPUT, &chip->reg_output); + if (ret) + goto out_failed; + + ret = pca953x_read_reg(chip, PCA953X_DIRECTION, &chip->reg_direction); + if (ret) + goto out_failed; + + /* set platform specific polarity inversion */ + ret = pca953x_write_reg(chip, PCA953X_INVERT, pdata->invert); + if (ret) + goto out_failed; + + + ret = gpiochip_add(&chip->gpio_chip); + if (ret) + goto out_failed; + + if (pdata->setup) { + ret = pdata->setup(client, chip->gpio_chip.base, + chip->gpio_chip.ngpio, pdata->context); + if (ret < 0) + dev_warn(&client->dev, "setup failed, %d\n", ret); + } + + i2c_set_clientdata(client, chip); + return 0; + +out_failed: + kfree(chip); + return ret; +} + +static int pca953x_remove(struct i2c_client *client) +{ + struct pca953x_platform_data *pdata = client->dev.platform_data; + struct pca953x_chip *chip = i2c_get_clientdata(client); + int ret = 0; + + if (pdata->teardown) { + ret = pdata->teardown(client, chip->gpio_chip.base, + chip->gpio_chip.ngpio, pdata->context); + if (ret < 0) { + dev_err(&client->dev, "%s failed, %d\n", + "teardown", ret); + return ret; + } + } + + ret = gpiochip_remove(&chip->gpio_chip); + if (ret) { + dev_err(&client->dev, "%s failed, %d\n", + "gpiochip_remove()", ret); + return ret; + } + + kfree(chip); + return 0; +} + +static struct i2c_driver pca953x_driver = { + .driver = { + .name = "pca953x", + }, + .probe = pca953x_probe, + .remove = pca953x_remove, +}; + +static int __init pca953x_init(void) +{ + return i2c_add_driver(&pca953x_driver); +} +module_init(pca953x_init); + +static void __exit pca953x_exit(void) +{ + i2c_del_driver(&pca953x_driver); +} +module_exit(pca953x_exit); + +MODULE_AUTHOR("eric miao <eric.miao@marvell.com>"); +MODULE_DESCRIPTION("GPIO expander driver for PCA953x"); +MODULE_LICENSE("GPL"); diff --git a/drivers/ide/Kconfig b/drivers/ide/Kconfig index 45b26ed351cf..ab8fb257528e 100644 --- a/drivers/ide/Kconfig +++ b/drivers/ide/Kconfig @@ -1009,6 +1009,15 @@ config BLK_DEV_Q40IDE normally be on; disable it only if you are running a custom hard drive subsystem through an expansion card. +config BLK_DEV_PALMCHIP_BK3710 + tristate "Palmchip bk3710 IDE controller support" + depends on ARCH_DAVINCI + select BLK_DEV_IDEDMA_PCI + help + Say Y here if you want to support the onchip IDE controller on the + TI DaVinci SoC + + config BLK_DEV_MPC8xx_IDE tristate "MPC8xx IDE support" depends on 8xx && (LWMON || IVMS8 || IVML24 || TQM8xxL) && IDE=y && BLK_DEV_IDE=y && !PPC_MERGE diff --git a/drivers/ide/arm/Makefile b/drivers/ide/arm/Makefile index 5f63ad216862..936e7b0237f5 100644 --- a/drivers/ide/arm/Makefile +++ b/drivers/ide/arm/Makefile @@ -2,6 +2,7 @@ obj-$(CONFIG_BLK_DEV_IDE_ICSIDE) += icside.o obj-$(CONFIG_BLK_DEV_IDE_RAPIDE) += rapide.o obj-$(CONFIG_BLK_DEV_IDE_BAST) += bast-ide.o +obj-$(CONFIG_BLK_DEV_PALMCHIP_BK3710) += palm_bk3710.o ifeq ($(CONFIG_IDE_ARM), m) obj-m += ide_arm.o diff --git a/drivers/ide/arm/icside.c b/drivers/ide/arm/icside.c index fb00f3827ecd..e816b0ffcfe6 100644 --- a/drivers/ide/arm/icside.c +++ b/drivers/ide/arm/icside.c @@ -365,7 +365,7 @@ static void icside_dma_timeout(ide_drive_t *drive) if (icside_dma_test_irq(drive)) return; - ide_dump_status(drive, "DMA timeout", HWIF(drive)->INB(IDE_STATUS_REG)); + ide_dump_status(drive, "DMA timeout", ide_read_status(drive)); icside_dma_end(drive); } diff --git a/drivers/ide/arm/palm_bk3710.c b/drivers/ide/arm/palm_bk3710.c new file mode 100644 index 000000000000..c3069970a012 --- /dev/null +++ b/drivers/ide/arm/palm_bk3710.c @@ -0,0 +1,395 @@ +/* + * Palmchip bk3710 IDE controller + * + * Copyright (C) 2006 Texas Instruments. + * Copyright (C) 2007 MontaVista Software, Inc., <source@mvista.com> + * + * ---------------------------------------------------------------------------- + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * ---------------------------------------------------------------------------- + * + */ + +#include <linux/types.h> +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/ioport.h> +#include <linux/hdreg.h> +#include <linux/ide.h> +#include <linux/delay.h> +#include <linux/init.h> +#include <linux/clk.h> +#include <linux/platform_device.h> + +/* Offset of the primary interface registers */ +#define IDE_PALM_ATA_PRI_REG_OFFSET 0x1F0 + +/* Primary Control Offset */ +#define IDE_PALM_ATA_PRI_CTL_OFFSET 0x3F6 + +/* + * PalmChip 3710 IDE Controller UDMA timing structure Definition + */ +struct palm_bk3710_udmatiming { + unsigned int rptime; /* Ready to pause time */ + unsigned int cycletime; /* Cycle Time */ +}; + +#define BK3710_BMICP 0x00 +#define BK3710_BMISP 0x02 +#define BK3710_BMIDTP 0x04 +#define BK3710_BMICS 0x08 +#define BK3710_BMISS 0x0A +#define BK3710_BMIDTS 0x0C +#define BK3710_IDETIMP 0x40 +#define BK3710_IDETIMS 0x42 +#define BK3710_SIDETIM 0x44 +#define BK3710_SLEWCTL 0x45 +#define BK3710_IDESTATUS 0x47 +#define BK3710_UDMACTL 0x48 +#define BK3710_UDMATIM 0x4A +#define BK3710_MISCCTL 0x50 +#define BK3710_REGSTB 0x54 +#define BK3710_REGRCVR 0x58 +#define BK3710_DATSTB 0x5C +#define BK3710_DATRCVR 0x60 +#define BK3710_DMASTB 0x64 +#define BK3710_DMARCVR 0x68 +#define BK3710_UDMASTB 0x6C +#define BK3710_UDMATRP 0x70 +#define BK3710_UDMAENV 0x74 +#define BK3710_IORDYTMP 0x78 +#define BK3710_IORDYTMS 0x7C + +#include "../ide-timing.h" + +static long ide_palm_clk; + +static const struct palm_bk3710_udmatiming palm_bk3710_udmatimings[6] = { + {160, 240}, /* UDMA Mode 0 */ + {125, 160}, /* UDMA Mode 1 */ + {100, 120}, /* UDMA Mode 2 */ + {100, 90}, /* UDMA Mode 3 */ + {85, 60}, /* UDMA Mode 4 */ +}; + +static struct clk *ideclkp; + +static void palm_bk3710_setudmamode(void __iomem *base, unsigned int dev, + unsigned int mode) +{ + u8 tenv, trp, t0; + u32 val32; + u16 val16; + + /* DMA Data Setup */ + t0 = (palm_bk3710_udmatimings[mode].cycletime + ide_palm_clk - 1) + / ide_palm_clk - 1; + tenv = (20 + ide_palm_clk - 1) / ide_palm_clk - 1; + trp = (palm_bk3710_udmatimings[mode].rptime + ide_palm_clk - 1) + / ide_palm_clk - 1; + + /* udmatim Register */ + val16 = readw(base + BK3710_UDMATIM) & (dev ? 0xFF0F : 0xFFF0); + val16 |= (mode << (dev ? 4 : 0)); + writew(val16, base + BK3710_UDMATIM); + + /* udmastb Ultra DMA Access Strobe Width */ + val32 = readl(base + BK3710_UDMASTB) & (0xFF << (dev ? 0 : 8)); + val32 |= (t0 << (dev ? 8 : 0)); + writel(val32, base + BK3710_UDMASTB); + + /* udmatrp Ultra DMA Ready to Pause Time */ + val32 = readl(base + BK3710_UDMATRP) & (0xFF << (dev ? 0 : 8)); + val32 |= (trp << (dev ? 8 : 0)); + writel(val32, base + BK3710_UDMATRP); + + /* udmaenv Ultra DMA envelop Time */ + val32 = readl(base + BK3710_UDMAENV) & (0xFF << (dev ? 0 : 8)); + val32 |= (tenv << (dev ? 8 : 0)); + writel(val32, base + BK3710_UDMAENV); + + /* Enable UDMA for Device */ + val16 = readw(base + BK3710_UDMACTL) | (1 << dev); + writew(val16, base + BK3710_UDMACTL); +} + +static void palm_bk3710_setdmamode(void __iomem *base, unsigned int dev, + unsigned short min_cycle, + unsigned int mode) +{ + u8 td, tkw, t0; + u32 val32; + u16 val16; + struct ide_timing *t; + int cycletime; + + t = ide_timing_find_mode(mode); + cycletime = max_t(int, t->cycle, min_cycle); + + /* DMA Data Setup */ + t0 = (cycletime + ide_palm_clk - 1) / ide_palm_clk; + td = (t->active + ide_palm_clk - 1) / ide_palm_clk; + tkw = t0 - td - 1; + td -= 1; + + val32 = readl(base + BK3710_DMASTB) & (0xFF << (dev ? 0 : 8)); + val32 |= (td << (dev ? 8 : 0)); + writel(val32, base + BK3710_DMASTB); + + val32 = readl(base + BK3710_DMARCVR) & (0xFF << (dev ? 0 : 8)); + val32 |= (tkw << (dev ? 8 : 0)); + writel(val32, base + BK3710_DMARCVR); + + /* Disable UDMA for Device */ + val16 = readw(base + BK3710_UDMACTL) & ~(1 << dev); + writew(val16, base + BK3710_UDMACTL); +} + +static void palm_bk3710_setpiomode(void __iomem *base, ide_drive_t *mate, + unsigned int dev, unsigned int cycletime, + unsigned int mode) +{ + u8 t2, t2i, t0; + u32 val32; + struct ide_timing *t; + + /* PIO Data Setup */ + t0 = (cycletime + ide_palm_clk - 1) / ide_palm_clk; + t2 = (ide_timing_find_mode(XFER_PIO_0 + mode)->active + + ide_palm_clk - 1) / ide_palm_clk; + + t2i = t0 - t2 - 1; + t2 -= 1; + + val32 = readl(base + BK3710_DATSTB) & (0xFF << (dev ? 0 : 8)); + val32 |= (t2 << (dev ? 8 : 0)); + writel(val32, base + BK3710_DATSTB); + + val32 = readl(base + BK3710_DATRCVR) & (0xFF << (dev ? 0 : 8)); + val32 |= (t2i << (dev ? 8 : 0)); + writel(val32, base + BK3710_DATRCVR); + + if (mate && mate->present) { + u8 mode2 = ide_get_best_pio_mode(mate, 255, 4); + + if (mode2 < mode) + mode = mode2; + } + + /* TASKFILE Setup */ + t = ide_timing_find_mode(XFER_PIO_0 + mode); + t0 = (t->cyc8b + ide_palm_clk - 1) / ide_palm_clk; + t2 = (t->act8b + ide_palm_clk - 1) / ide_palm_clk; + + t2i = t0 - t2 - 1; + t2 -= 1; + + val32 = readl(base + BK3710_REGSTB) & (0xFF << (dev ? 0 : 8)); + val32 |= (t2 << (dev ? 8 : 0)); + writel(val32, base + BK3710_REGSTB); + + val32 = readl(base + BK3710_REGRCVR) & (0xFF << (dev ? 0 : 8)); + val32 |= (t2i << (dev ? 8 : 0)); + writel(val32, base + BK3710_REGRCVR); +} + +static void palm_bk3710_set_dma_mode(ide_drive_t *drive, u8 xferspeed) +{ + int is_slave = drive->dn & 1; + void __iomem *base = (void *)drive->hwif->dma_base; + + if (xferspeed >= XFER_UDMA_0) { + palm_bk3710_setudmamode(base, is_slave, + xferspeed - XFER_UDMA_0); + } else { + palm_bk3710_setdmamode(base, is_slave, drive->id->eide_dma_min, + xferspeed); + } +} + +static void palm_bk3710_set_pio_mode(ide_drive_t *drive, u8 pio) +{ + unsigned int cycle_time; + int is_slave = drive->dn & 1; + ide_drive_t *mate; + void __iomem *base = (void *)drive->hwif->dma_base; + + /* + * Obtain the drive PIO data for tuning the Palm Chip registers + */ + cycle_time = ide_pio_cycle_time(drive, pio); + mate = ide_get_paired_drive(drive); + palm_bk3710_setpiomode(base, mate, is_slave, cycle_time, pio); +} + +static void __devinit palm_bk3710_chipinit(void __iomem *base) +{ + /* + * enable the reset_en of ATA controller so that when ata signals + * are brought out, by writing into device config. at that + * time por_n signal should not be 'Z' and have a stable value. + */ + writel(0x0300, base + BK3710_MISCCTL); + + /* wait for some time and deassert the reset of ATA Device. */ + mdelay(100); + + /* Deassert the Reset */ + writel(0x0200, base + BK3710_MISCCTL); + + /* + * Program the IDETIMP Register Value based on the following assumptions + * + * (ATA_IDETIMP_IDEEN , ENABLE ) | + * (ATA_IDETIMP_SLVTIMEN , DISABLE) | + * (ATA_IDETIMP_RDYSMPL , 70NS) | + * (ATA_IDETIMP_RDYRCVRY , 50NS) | + * (ATA_IDETIMP_DMAFTIM1 , PIOCOMP) | + * (ATA_IDETIMP_PREPOST1 , DISABLE) | + * (ATA_IDETIMP_RDYSEN1 , DISABLE) | + * (ATA_IDETIMP_PIOFTIM1 , DISABLE) | + * (ATA_IDETIMP_DMAFTIM0 , PIOCOMP) | + * (ATA_IDETIMP_PREPOST0 , DISABLE) | + * (ATA_IDETIMP_RDYSEN0 , DISABLE) | + * (ATA_IDETIMP_PIOFTIM0 , DISABLE) + */ + writew(0xB388, base + BK3710_IDETIMP); + + /* + * Configure SIDETIM Register + * (ATA_SIDETIM_RDYSMPS1 ,120NS ) | + * (ATA_SIDETIM_RDYRCYS1 ,120NS ) + */ + writeb(0, base + BK3710_SIDETIM); + + /* + * UDMACTL Ultra-ATA DMA Control + * (ATA_UDMACTL_UDMAP1 , 0 ) | + * (ATA_UDMACTL_UDMAP0 , 0 ) + * + */ + writew(0, base + BK3710_UDMACTL); + + /* + * MISCCTL Miscellaneous Conrol Register + * (ATA_MISCCTL_RSTMODEP , 1) | + * (ATA_MISCCTL_RESETP , 0) | + * (ATA_MISCCTL_TIMORIDE , 1) + */ + writel(0x201, base + BK3710_MISCCTL); + + /* + * IORDYTMP IORDY Timer for Primary Register + * (ATA_IORDYTMP_IORDYTMP , 0xffff ) + */ + writel(0xFFFF, base + BK3710_IORDYTMP); + + /* + * Configure BMISP Register + * (ATA_BMISP_DMAEN1 , DISABLE ) | + * (ATA_BMISP_DMAEN0 , DISABLE ) | + * (ATA_BMISP_IORDYINT , CLEAR) | + * (ATA_BMISP_INTRSTAT , CLEAR) | + * (ATA_BMISP_DMAERROR , CLEAR) + */ + writew(0, base + BK3710_BMISP); + + palm_bk3710_setpiomode(base, NULL, 0, 600, 0); + palm_bk3710_setpiomode(base, NULL, 1, 600, 0); +} +static int __devinit palm_bk3710_probe(struct platform_device *pdev) +{ + hw_regs_t ide_ctlr_info; + int index = 0; + int pribase; + struct clk *clkp; + struct resource *mem, *irq; + ide_hwif_t *hwif; + void __iomem *base; + + clkp = clk_get(NULL, "IDECLK"); + if (IS_ERR(clkp)) + return -ENODEV; + + ideclkp = clkp; + clk_enable(ideclkp); + ide_palm_clk = clk_get_rate(ideclkp)/100000; + ide_palm_clk = (10000/ide_palm_clk) + 1; + /* Register the IDE interface with Linux ATA Interface */ + memset(&ide_ctlr_info, 0, sizeof(ide_ctlr_info)); + + mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (mem == NULL) { + printk(KERN_ERR "failed to get memory region resource\n"); + return -ENODEV; + } + irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0); + if (irq == NULL) { + printk(KERN_ERR "failed to get IRQ resource\n"); + return -ENODEV; + } + + base = (void *)mem->start; + + /* Configure the Palm Chip controller */ + palm_bk3710_chipinit(base); + + pribase = mem->start + IDE_PALM_ATA_PRI_REG_OFFSET; + for (index = 0; index < IDE_NR_PORTS - 2; index++) + ide_ctlr_info.io_ports[index] = pribase + index; + ide_ctlr_info.io_ports[IDE_CONTROL_OFFSET] = mem->start + + IDE_PALM_ATA_PRI_CTL_OFFSET; + ide_ctlr_info.irq = irq->start; + ide_ctlr_info.chipset = ide_palm3710; + + if (ide_register_hw(&ide_ctlr_info, NULL, &hwif) < 0) { + printk(KERN_WARNING "Palm Chip BK3710 IDE Register Fail\n"); + return -ENODEV; + } + + hwif->set_pio_mode = &palm_bk3710_set_pio_mode; + hwif->set_dma_mode = &palm_bk3710_set_dma_mode; + hwif->mmio = 1; + default_hwif_mmiops(hwif); + hwif->cbl = ATA_CBL_PATA80; + hwif->ultra_mask = 0x1f; /* Ultra DMA Mode 4 Max + (input clk 99MHz) */ + hwif->mwdma_mask = 0x7; + hwif->drives[0].autotune = 1; + hwif->drives[1].autotune = 1; + + ide_setup_dma(hwif, mem->start); + + return 0; +} + +static struct platform_driver platform_bk_driver = { + .driver = { + .name = "palm_bk3710", + }, + .probe = palm_bk3710_probe, + .remove = NULL, +}; + +static int __init palm_bk3710_init(void) +{ + return platform_driver_register(&platform_bk_driver); +} + +module_init(palm_bk3710_init); +MODULE_LICENSE("GPL"); + diff --git a/drivers/ide/cris/ide-cris.c b/drivers/ide/cris/ide-cris.c index 00587a8c2ba1..e79bf8f9b7db 100644 --- a/drivers/ide/cris/ide-cris.c +++ b/drivers/ide/cris/ide-cris.c @@ -753,6 +753,25 @@ static void cris_set_dma_mode(ide_drive_t *drive, const u8 speed) cris_ide_set_speed(TYPE_DMA, 0, strobe, hold); } +static void __init cris_setup_ports(hw_regs_t *hw, unsigned long base) +{ + int i; + + memset(hw, 0, sizeof(*hw)); + + for (i = 0; i <= 7; i++) + hw->io_ports[i] = base + cris_ide_reg_addr(i, 0, 1); + + /* + * the IDE control register is at ATA address 6, + * with CS1 active instead of CS0 + */ + hw->io_ports[IDE_CONTROL_OFFSET] = base + cris_ide_reg_addr(6, 1, 0); + + hw->irq = ide_default_irq(0); + hw->ack_intr = cris_ide_ack_intr; +} + static const struct ide_port_info cris_port_info __initdata = { .chipset = ide_etrax100, .host_flags = IDE_HFLAG_NO_ATAPI_DMA | @@ -765,24 +784,16 @@ static const struct ide_port_info cris_port_info __initdata = { static int __init init_e100_ide(void) { hw_regs_t hw; - int ide_offsets[IDE_NR_PORTS], h, i; + int h; u8 idx[4] = { 0xff, 0xff, 0xff, 0xff }; printk("ide: ETRAX FS built-in ATA DMA controller\n"); - for (i = IDE_DATA_OFFSET; i <= IDE_STATUS_OFFSET; i++) - ide_offsets[i] = cris_ide_reg_addr(i, 0, 1); - - /* the IDE control register is at ATA address 6, with CS1 active instead of CS0 */ - ide_offsets[IDE_CONTROL_OFFSET] = cris_ide_reg_addr(6, 1, 0); - for (h = 0; h < 4; h++) { ide_hwif_t *hwif = NULL; - ide_setup_ports(&hw, cris_ide_base_address(h), - ide_offsets, - 0, 0, cris_ide_ack_intr, - ide_default_irq(0)); + cris_setup_ports(&hw, cris_ide_base_address(h)); + hwif = ide_find_port(hw.io_ports[IDE_DATA_OFFSET]); if (hwif == NULL) continue; diff --git a/drivers/ide/ide-acpi.c b/drivers/ide/ide-acpi.c index 25aaeae1e830..e07b189f3ec8 100644 --- a/drivers/ide/ide-acpi.c +++ b/drivers/ide/ide-acpi.c @@ -171,7 +171,7 @@ err: static acpi_handle ide_acpi_hwif_get_handle(ide_hwif_t *hwif) { struct device *dev = hwif->gendev.parent; - acpi_handle dev_handle; + acpi_handle uninitialized_var(dev_handle); acpi_integer pcidevfn; acpi_handle chan_handle; int err; diff --git a/drivers/ide/ide-cd.c b/drivers/ide/ide-cd.c index ee4d458e2bbf..5e42c19a03e3 100644 --- a/drivers/ide/ide-cd.c +++ b/drivers/ide/ide-cd.c @@ -295,7 +295,8 @@ static int cdrom_decode_status(ide_drive_t *drive, int good_stat, int *stat_ret) int stat, err, sense_key; /* Check for errors. */ - stat = HWIF(drive)->INB(IDE_STATUS_REG); + stat = ide_read_status(drive); + if (stat_ret) *stat_ret = stat; @@ -303,7 +304,7 @@ static int cdrom_decode_status(ide_drive_t *drive, int good_stat, int *stat_ret) return 0; /* Get the IDE error register. */ - err = HWIF(drive)->INB(IDE_ERROR_REG); + err = ide_read_error(drive); sense_key = err >> 4; if (rq == NULL) { @@ -692,7 +693,7 @@ int ide_cd_check_ireason(ide_drive_t *drive, int len, int ireason, int rw) /* Some drives (ASUS) seem to tell us that status * info is available. just get it and ignore. */ - (void) HWIF(drive)->INB(IDE_STATUS_REG); + (void)ide_read_status(drive); return 0; } else { /* Drive wants a command packet, or invalid ireason... */ @@ -1326,7 +1327,7 @@ ide_do_rw_cdrom (ide_drive_t *drive, struct request *rq, sector_t block) if (blk_fs_request(rq)) { if (info->cd_flags & IDE_CD_FLAG_SEEKING) { unsigned long elapsed = jiffies - info->start_seek; - int stat = HWIF(drive)->INB(IDE_STATUS_REG); + int stat = ide_read_status(drive); if ((stat & SEEK_STAT) != SEEK_STAT) { if (elapsed < IDECD_SEEK_TIMEOUT) { diff --git a/drivers/ide/ide-dma.c b/drivers/ide/ide-dma.c index 3cf59f2c3928..a4bb32883c6b 100644 --- a/drivers/ide/ide-dma.c +++ b/drivers/ide/ide-dma.c @@ -147,7 +147,8 @@ ide_startstop_t ide_dma_intr (ide_drive_t *drive) u8 stat = 0, dma_stat = 0; dma_stat = HWIF(drive)->ide_dma_end(drive); - stat = HWIF(drive)->INB(IDE_STATUS_REG); /* get drive status */ + stat = ide_read_status(drive); + if (OK_STAT(stat,DRIVE_READY,drive->bad_wstat|DRQ_STAT)) { if (!dma_stat) { struct request *rq = HWGROUP(drive)->rq; diff --git a/drivers/ide/ide-floppy.c b/drivers/ide/ide-floppy.c index f8fe6ee128f3..faf22d716f80 100644 --- a/drivers/ide/ide-floppy.c +++ b/drivers/ide/ide-floppy.c @@ -465,7 +465,7 @@ static void idefloppy_retry_pc(ide_drive_t *drive) idefloppy_pc_t *pc; struct request *rq; - (void)drive->hwif->INB(IDE_ERROR_REG); + (void)ide_read_error(drive); pc = idefloppy_next_pc_storage(drive); rq = idefloppy_next_rq_storage(drive); idefloppy_create_request_sense_cmd(pc); @@ -501,7 +501,7 @@ static ide_startstop_t idefloppy_pc_intr (ide_drive_t *drive) } /* Clear the interrupt */ - stat = drive->hwif->INB(IDE_STATUS_REG); + stat = ide_read_status(drive); /* No more interrupts */ if ((stat & DRQ_STAT) == 0) { @@ -1246,7 +1246,7 @@ static int idefloppy_get_format_progress(ide_drive_t *drive, int __user *arg) u8 stat; local_irq_save(flags); - stat = drive->hwif->INB(IDE_STATUS_REG); + stat = ide_read_status(drive); local_irq_restore(flags); progress_indication = ((stat & SEEK_STAT) == 0) ? 0 : 0x10000; diff --git a/drivers/ide/ide-generic.c b/drivers/ide/ide-generic.c index be469dbbe8fb..709b9e4d2871 100644 --- a/drivers/ide/ide-generic.c +++ b/drivers/ide/ide-generic.c @@ -20,8 +20,14 @@ static int __init ide_generic_init(void) if (ide_hwifs[0].io_ports[IDE_DATA_OFFSET]) ide_get_lock(NULL, NULL); /* for atari only */ - for (i = 0; i < MAX_HWIFS; i++) - idx[i] = ide_hwifs[i].present ? 0xff : i; + for (i = 0; i < MAX_HWIFS; i++) { + ide_hwif_t *hwif = &ide_hwifs[i]; + + if (hwif->io_ports[IDE_DATA_OFFSET] && !hwif->present) + idx[i] = i; + else + idx[i] = 0xff; + } ide_device_add_all(idx, NULL); diff --git a/drivers/ide/ide-io.c b/drivers/ide/ide-io.c index 4bddef0c0b96..3addbe478d26 100644 --- a/drivers/ide/ide-io.c +++ b/drivers/ide/ide-io.c @@ -466,7 +466,7 @@ static ide_startstop_t ide_ata_error(ide_drive_t *drive, struct request *rq, u8 return ide_stopped; } - if (hwif->INB(IDE_STATUS_REG) & (BUSY_STAT|DRQ_STAT)) + if (ide_read_status(drive) & (BUSY_STAT | DRQ_STAT)) rq->errors |= ERROR_RESET; if ((rq->errors & ERROR_RESET) == ERROR_RESET) { @@ -493,7 +493,7 @@ static ide_startstop_t ide_atapi_error(ide_drive_t *drive, struct request *rq, u /* add decoding error stuff */ } - if (hwif->INB(IDE_STATUS_REG) & (BUSY_STAT|DRQ_STAT)) + if (ide_read_status(drive) & (BUSY_STAT | DRQ_STAT)) /* force an abort */ hwif->OUTB(WIN_IDLEIMMEDIATE, IDE_COMMAND_REG); @@ -821,9 +821,8 @@ static ide_startstop_t execute_drive_cmd (ide_drive_t *drive, #ifdef DEBUG printk("%s: DRIVE_CMD (null)\n", drive->name); #endif - ide_end_drive_cmd(drive, - hwif->INB(IDE_STATUS_REG), - hwif->INB(IDE_ERROR_REG)); + ide_end_drive_cmd(drive, ide_read_status(drive), ide_read_error(drive)); + return ide_stopped; } @@ -1231,7 +1230,7 @@ static ide_startstop_t ide_dma_timeout_retry(ide_drive_t *drive, int error) printk(KERN_WARNING "%s: DMA timeout error\n", drive->name); (void)HWIF(drive)->ide_dma_end(drive); ret = ide_error(drive, "dma timeout error", - hwif->INB(IDE_STATUS_REG)); + ide_read_status(drive)); } else { printk(KERN_WARNING "%s: DMA timeout retry\n", drive->name); hwif->dma_timeout(drive); @@ -1355,7 +1354,8 @@ void ide_timer_expiry (unsigned long data) startstop = ide_dma_timeout_retry(drive, wait); } else startstop = - ide_error(drive, "irq timeout", hwif->INB(IDE_STATUS_REG)); + ide_error(drive, "irq timeout", + ide_read_status(drive)); } drive->service_time = jiffies - drive->service_start; spin_lock_irq(&ide_lock); diff --git a/drivers/ide/ide-iops.c b/drivers/ide/ide-iops.c index a95178f5e1bb..c32e759df208 100644 --- a/drivers/ide/ide-iops.c +++ b/drivers/ide/ide-iops.c @@ -430,10 +430,10 @@ int drive_is_ready (ide_drive_t *drive) * about possible isa-pnp and pci-pnp issues yet. */ if (IDE_CONTROL_REG) - stat = hwif->INB(IDE_ALTSTATUS_REG); + stat = ide_read_altstatus(drive); else /* Note: this may clear a pending IRQ!! */ - stat = hwif->INB(IDE_STATUS_REG); + stat = ide_read_status(drive); if (stat & BUSY_STAT) /* drive busy: definitely not interrupting */ @@ -458,23 +458,24 @@ EXPORT_SYMBOL(drive_is_ready); */ static int __ide_wait_stat(ide_drive_t *drive, u8 good, u8 bad, unsigned long timeout, u8 *rstat) { - ide_hwif_t *hwif = drive->hwif; unsigned long flags; int i; u8 stat; udelay(1); /* spec allows drive 400ns to assert "BUSY" */ - if ((stat = hwif->INB(IDE_STATUS_REG)) & BUSY_STAT) { + stat = ide_read_status(drive); + + if (stat & BUSY_STAT) { local_irq_set(flags); timeout += jiffies; - while ((stat = hwif->INB(IDE_STATUS_REG)) & BUSY_STAT) { + while ((stat = ide_read_status(drive)) & BUSY_STAT) { if (time_after(jiffies, timeout)) { /* * One last read after the timeout in case * heavy interrupt load made us not make any * progress during the timeout.. */ - stat = hwif->INB(IDE_STATUS_REG); + stat = ide_read_status(drive); if (!(stat & BUSY_STAT)) break; @@ -494,7 +495,9 @@ static int __ide_wait_stat(ide_drive_t *drive, u8 good, u8 bad, unsigned long ti */ for (i = 0; i < 10; i++) { udelay(1); - if (OK_STAT((stat = hwif->INB(IDE_STATUS_REG)), good, bad)) { + stat = ide_read_status(drive); + + if (OK_STAT(stat, good, bad)) { *rstat = stat; return 0; } @@ -617,6 +620,7 @@ int ide_driveid_update(ide_drive_t *drive) ide_hwif_t *hwif = drive->hwif; struct hd_driveid *id; unsigned long timeout, flags; + u8 stat; /* * Re-read drive->id for possible DMA mode @@ -633,10 +637,15 @@ int ide_driveid_update(ide_drive_t *drive) SELECT_MASK(drive, 0); return 0; /* drive timed-out */ } + msleep(50); /* give drive a breather */ - } while (hwif->INB(IDE_ALTSTATUS_REG) & BUSY_STAT); + stat = ide_read_altstatus(drive); + } while (stat & BUSY_STAT); + msleep(50); /* wait for IRQ and DRQ_STAT */ - if (!OK_STAT(hwif->INB(IDE_STATUS_REG),DRQ_STAT,BAD_R_STAT)) { + stat = ide_read_status(drive); + + if (!OK_STAT(stat, DRQ_STAT, BAD_R_STAT)) { SELECT_MASK(drive, 0); printk("%s: CHECK for good STATUS\n", drive->name); return 0; @@ -649,7 +658,7 @@ int ide_driveid_update(ide_drive_t *drive) return 0; } ata_input_data(drive, id, SECTOR_WORDS); - (void) hwif->INB(IDE_STATUS_REG); /* clear drive IRQ */ + (void)ide_read_status(drive); /* clear drive IRQ */ local_irq_enable(); local_irq_restore(flags); ide_fix_driveid(id); @@ -850,17 +859,16 @@ static ide_startstop_t do_reset1 (ide_drive_t *, int); static ide_startstop_t atapi_reset_pollfunc (ide_drive_t *drive) { ide_hwgroup_t *hwgroup = HWGROUP(drive); - ide_hwif_t *hwif = HWIF(drive); u8 stat; SELECT_DRIVE(drive); udelay (10); + stat = ide_read_status(drive); - if (OK_STAT(stat = hwif->INB(IDE_STATUS_REG), 0, BUSY_STAT)) { + if (OK_STAT(stat, 0, BUSY_STAT)) printk("%s: ATAPI reset complete\n", drive->name); - } else { + else { if (time_before(jiffies, hwgroup->poll_timeout)) { - BUG_ON(HWGROUP(drive)->handler != NULL); ide_set_handler(drive, &atapi_reset_pollfunc, HZ/20, NULL); /* continue polling */ return ide_started; @@ -898,9 +906,10 @@ static ide_startstop_t reset_pollfunc (ide_drive_t *drive) } } - if (!OK_STAT(tmp = hwif->INB(IDE_STATUS_REG), 0, BUSY_STAT)) { + tmp = ide_read_status(drive); + + if (!OK_STAT(tmp, 0, BUSY_STAT)) { if (time_before(jiffies, hwgroup->poll_timeout)) { - BUG_ON(HWGROUP(drive)->handler != NULL); ide_set_handler(drive, &reset_pollfunc, HZ/20, NULL); /* continue polling */ return ide_started; @@ -909,7 +918,9 @@ static ide_startstop_t reset_pollfunc (ide_drive_t *drive) drive->failures++; } else { printk("%s: reset: ", hwif->name); - if ((tmp = hwif->INB(IDE_ERROR_REG)) == 1) { + tmp = ide_read_error(drive); + + if (tmp == 1) { printk("success\n"); drive->failures = 0; } else { diff --git a/drivers/ide/ide-lib.c b/drivers/ide/ide-lib.c index b42940d8bf70..1ff676cc6473 100644 --- a/drivers/ide/ide-lib.c +++ b/drivers/ide/ide-lib.c @@ -578,7 +578,7 @@ u8 ide_dump_status(ide_drive_t *drive, const char *msg, u8 stat) } printk("}\n"); if ((stat & (BUSY_STAT|ERR_STAT)) == ERR_STAT) { - err = drive->hwif->INB(IDE_ERROR_REG); + err = ide_read_error(drive); printk("%s: %s: error=0x%02x ", drive->name, msg, err); if (drive->media == ide_disk) ide_dump_ata_error(drive, err); diff --git a/drivers/ide/ide-probe.c b/drivers/ide/ide-probe.c index 9c07bdb68d1a..6daea896c5db 100644 --- a/drivers/ide/ide-probe.c +++ b/drivers/ide/ide-probe.c @@ -264,8 +264,7 @@ err_misc: static int actual_try_to_identify (ide_drive_t *drive, u8 cmd) { ide_hwif_t *hwif = HWIF(drive); - int rc; - unsigned long hd_status; + int use_altstatus = 0, rc; unsigned long timeout; u8 s = 0, a = 0; @@ -273,19 +272,17 @@ static int actual_try_to_identify (ide_drive_t *drive, u8 cmd) msleep(50); if (IDE_CONTROL_REG) { - a = hwif->INB(IDE_ALTSTATUS_REG); - s = hwif->INB(IDE_STATUS_REG); - if ((a ^ s) & ~INDEX_STAT) { - printk(KERN_INFO "%s: probing with STATUS(0x%02x) instead of " - "ALTSTATUS(0x%02x)\n", drive->name, s, a); + a = ide_read_altstatus(drive); + s = ide_read_status(drive); + if ((a ^ s) & ~INDEX_STAT) /* ancient Seagate drives, broken interfaces */ - hd_status = IDE_STATUS_REG; - } else { + printk(KERN_INFO "%s: probing with STATUS(0x%02x) " + "instead of ALTSTATUS(0x%02x)\n", + drive->name, s, a); + else /* use non-intrusive polling */ - hd_status = IDE_ALTSTATUS_REG; - } - } else - hd_status = IDE_STATUS_REG; + use_altstatus = 1; + } /* set features register for atapi * identify command to be sure of reply @@ -306,11 +303,15 @@ static int actual_try_to_identify (ide_drive_t *drive, u8 cmd) } /* give drive a breather */ msleep(50); - } while ((hwif->INB(hd_status)) & BUSY_STAT); + s = use_altstatus ? ide_read_altstatus(drive) + : ide_read_status(drive); + } while (s & BUSY_STAT); /* wait for IRQ and DRQ_STAT */ msleep(50); - if (OK_STAT((hwif->INB(IDE_STATUS_REG)), DRQ_STAT, BAD_R_STAT)) { + s = ide_read_status(drive); + + if (OK_STAT(s, DRQ_STAT, BAD_R_STAT)) { unsigned long flags; /* local CPU only; some systems need this */ @@ -320,7 +321,7 @@ static int actual_try_to_identify (ide_drive_t *drive, u8 cmd) /* drive responded with ID */ rc = 0; /* clear drive IRQ */ - (void) hwif->INB(IDE_STATUS_REG); + (void)ide_read_status(drive); local_irq_restore(flags); } else { /* drive refused ID */ @@ -367,7 +368,7 @@ static int try_to_identify (ide_drive_t *drive, u8 cmd) ide_set_irq(drive, 0); /* clear drive IRQ */ - (void) hwif->INB(IDE_STATUS_REG); + (void)ide_read_status(drive); udelay(5); irq = probe_irq_off(cookie); if (!hwif->irq) { @@ -455,7 +456,9 @@ static int do_probe (ide_drive_t *drive, u8 cmd) return 3; } - if (OK_STAT((hwif->INB(IDE_STATUS_REG)), READY_STAT, BUSY_STAT) || + stat = ide_read_status(drive); + + if (OK_STAT(stat, READY_STAT, BUSY_STAT) || drive->present || cmd == WIN_PIDENTIFY) { /* send cmd and wait */ if ((rc = try_to_identify(drive, cmd))) { @@ -463,7 +466,7 @@ static int do_probe (ide_drive_t *drive, u8 cmd) rc = try_to_identify(drive,cmd); } - stat = hwif->INB(IDE_STATUS_REG); + stat = ide_read_status(drive); if (stat == (BUSY_STAT | READY_STAT)) return 4; @@ -482,7 +485,7 @@ static int do_probe (ide_drive_t *drive, u8 cmd) } /* ensure drive IRQ is clear */ - stat = hwif->INB(IDE_STATUS_REG); + stat = ide_read_status(drive); if (rc == 1) printk(KERN_ERR "%s: no response (status = 0x%02x)\n", @@ -496,7 +499,7 @@ static int do_probe (ide_drive_t *drive, u8 cmd) SELECT_DRIVE(&hwif->drives[0]); msleep(50); /* ensure drive irq is clear */ - (void) hwif->INB(IDE_STATUS_REG); + (void)ide_read_status(drive); } return rc; } @@ -521,7 +524,7 @@ static void enable_nest (ide_drive_t *drive) msleep(50); - stat = hwif->INB(IDE_STATUS_REG); + stat = ide_read_status(drive); if (!OK_STAT(stat, 0, BAD_STAT)) printk(KERN_CONT "failed (status = 0x%02x)\n", stat); @@ -1046,7 +1049,7 @@ static int init_irq (ide_hwif_t *hwif) */ if (!match || match->irq != hwif->irq) { int sa = 0; -#if defined(__mc68000__) || defined(CONFIG_APUS) +#if defined(__mc68000__) sa = IRQF_SHARED; #endif /* __mc68000__ || CONFIG_APUS */ @@ -1069,7 +1072,7 @@ static int init_irq (ide_hwif_t *hwif) hwif->rqsize = 65536; } -#if !defined(__mc68000__) && !defined(CONFIG_APUS) +#if !defined(__mc68000__) printk("%s at 0x%03lx-0x%03lx,0x%03lx on irq %d", hwif->name, hwif->io_ports[IDE_DATA_OFFSET], hwif->io_ports[IDE_DATA_OFFSET]+7, @@ -1077,7 +1080,7 @@ static int init_irq (ide_hwif_t *hwif) #else printk("%s at 0x%08lx on irq %d", hwif->name, hwif->io_ports[IDE_DATA_OFFSET], hwif->irq); -#endif /* __mc68000__ && CONFIG_APUS */ +#endif /* __mc68000__ */ if (match) printk(" (%sed with %s)", hwif->sharing_irq ? "shar" : "serializ", match->name); diff --git a/drivers/ide/ide-proc.c b/drivers/ide/ide-proc.c index 975c0ff0f438..bab88ca7f7ec 100644 --- a/drivers/ide/ide-proc.c +++ b/drivers/ide/ide-proc.c @@ -65,6 +65,7 @@ static int proc_ide_read_imodel case ide_4drives: name = "4drives"; break; case ide_pmac: name = "mac-io"; break; case ide_au1xxx: name = "au1xxx"; break; + case ide_palm3710: name = "palm3710"; break; case ide_etrax100: name = "etrax100"; break; case ide_acorn: name = "acorn"; break; default: name = "(unknown)"; break; diff --git a/drivers/ide/ide-tape.c b/drivers/ide/ide-tape.c index bf40d8c824ad..49dd2e7bae7a 100644 --- a/drivers/ide/ide-tape.c +++ b/drivers/ide/ide-tape.c @@ -15,7 +15,7 @@ * Documentation/ide/ChangeLog.ide-tape.1995-2002 */ -#define IDETAPE_VERSION "1.19" +#define IDETAPE_VERSION "1.20" #include <linux/module.h> #include <linux/types.h> @@ -39,63 +39,70 @@ #include <scsi/scsi.h> #include <asm/byteorder.h> -#include <asm/irq.h> -#include <asm/uaccess.h> -#include <asm/io.h> +#include <linux/irq.h> +#include <linux/uaccess.h> +#include <linux/io.h> #include <asm/unaligned.h> #include <linux/mtio.h> +enum { + /* output errors only */ + DBG_ERR = (1 << 0), + /* output all sense key/asc */ + DBG_SENSE = (1 << 1), + /* info regarding all chrdev-related procedures */ + DBG_CHRDEV = (1 << 2), + /* all remaining procedures */ + DBG_PROCS = (1 << 3), + /* buffer alloc info (pc_stack & rq_stack) */ + DBG_PCRQ_STACK = (1 << 4), +}; + +/* define to see debug info */ +#define IDETAPE_DEBUG_LOG 0 + +#if IDETAPE_DEBUG_LOG +#define debug_log(lvl, fmt, args...) \ +{ \ + if (tape->debug_mask & lvl) \ + printk(KERN_INFO "ide-tape: " fmt, ## args); \ +} +#else +#define debug_log(lvl, fmt, args...) do {} while (0) +#endif + /**************************** Tunable parameters *****************************/ /* - * Pipelined mode parameters. + * Pipelined mode parameters. * - * We try to use the minimum number of stages which is enough to - * keep the tape constantly streaming. To accomplish that, we implement - * a feedback loop around the maximum number of stages: + * We try to use the minimum number of stages which is enough to keep the tape + * constantly streaming. To accomplish that, we implement a feedback loop around + * the maximum number of stages: * - * We start from MIN maximum stages (we will not even use MIN stages - * if we don't need them), increment it by RATE*(MAX-MIN) - * whenever we sense that the pipeline is empty, until we reach - * the optimum value or until we reach MAX. + * We start from MIN maximum stages (we will not even use MIN stages if we don't + * need them), increment it by RATE*(MAX-MIN) whenever we sense that the + * pipeline is empty, until we reach the optimum value or until we reach MAX. * - * Setting the following parameter to 0 is illegal: the pipelined mode - * cannot be disabled (calculate_speeds() divides by tape->max_stages.) + * Setting the following parameter to 0 is illegal: the pipelined mode cannot be + * disabled (idetape_calculate_speeds() divides by tape->max_stages.) */ #define IDETAPE_MIN_PIPELINE_STAGES 1 #define IDETAPE_MAX_PIPELINE_STAGES 400 #define IDETAPE_INCREASE_STAGES_RATE 20 /* - * The following are used to debug the driver: - * - * Setting IDETAPE_DEBUG_LOG to 1 will log driver flow control. + * After each failed packet command we issue a request sense command and retry + * the packet command IDETAPE_MAX_PC_RETRIES times. * - * Setting them to 0 will restore normal operation mode: - * - * 1. Disable logging normal successful operations. - * 2. Disable self-sanity checks. - * 3. Errors will still be logged, of course. - * - * All the #if DEBUG code will be removed some day, when the driver - * is verified to be stable enough. This will make it much more - * esthetic. - */ -#define IDETAPE_DEBUG_LOG 0 - -/* - * After each failed packet command we issue a request sense command - * and retry the packet command IDETAPE_MAX_PC_RETRIES times. - * - * Setting IDETAPE_MAX_PC_RETRIES to 0 will disable retries. + * Setting IDETAPE_MAX_PC_RETRIES to 0 will disable retries. */ #define IDETAPE_MAX_PC_RETRIES 3 /* - * With each packet command, we allocate a buffer of - * IDETAPE_PC_BUFFER_SIZE bytes. This is used for several packet - * commands (Not for READ/WRITE commands). + * With each packet command, we allocate a buffer of IDETAPE_PC_BUFFER_SIZE + * bytes. This is used for several packet commands (Not for READ/WRITE commands) */ #define IDETAPE_PC_BUFFER_SIZE 256 @@ -114,48 +121,39 @@ #define IDETAPE_WAIT_CMD (900*HZ) /* - * The following parameter is used to select the point in the internal - * tape fifo in which we will start to refill the buffer. Decreasing - * the following parameter will improve the system's latency and - * interactive response, while using a high value might improve system - * throughput. + * The following parameter is used to select the point in the internal tape fifo + * in which we will start to refill the buffer. Decreasing the following + * parameter will improve the system's latency and interactive response, while + * using a high value might improve system throughput. */ -#define IDETAPE_FIFO_THRESHOLD 2 +#define IDETAPE_FIFO_THRESHOLD 2 /* - * DSC polling parameters. - * - * Polling for DSC (a single bit in the status register) is a very - * important function in ide-tape. There are two cases in which we - * poll for DSC: + * DSC polling parameters. * - * 1. Before a read/write packet command, to ensure that we - * can transfer data from/to the tape's data buffers, without - * causing an actual media access. In case the tape is not - * ready yet, we take out our request from the device - * request queue, so that ide.c will service requests from - * the other device on the same interface meanwhile. + * Polling for DSC (a single bit in the status register) is a very important + * function in ide-tape. There are two cases in which we poll for DSC: * - * 2. After the successful initialization of a "media access - * packet command", which is a command which can take a long - * time to complete (it can be several seconds or even an hour). + * 1. Before a read/write packet command, to ensure that we can transfer data + * from/to the tape's data buffers, without causing an actual media access. + * In case the tape is not ready yet, we take out our request from the device + * request queue, so that ide.c could service requests from the other device + * on the same interface in the meantime. * - * Again, we postpone our request in the middle to free the bus - * for the other device. The polling frequency here should be - * lower than the read/write frequency since those media access - * commands are slow. We start from a "fast" frequency - - * IDETAPE_DSC_MA_FAST (one second), and if we don't receive DSC - * after IDETAPE_DSC_MA_THRESHOLD (5 minutes), we switch it to a - * lower frequency - IDETAPE_DSC_MA_SLOW (1 minute). + * 2. After the successful initialization of a "media access packet command", + * which is a command that can take a long time to complete (the interval can + * range from several seconds to even an hour). Again, we postpone our request + * in the middle to free the bus for the other device. The polling frequency + * here should be lower than the read/write frequency since those media access + * commands are slow. We start from a "fast" frequency - IDETAPE_DSC_MA_FAST + * (1 second), and if we don't receive DSC after IDETAPE_DSC_MA_THRESHOLD + * (5 min), we switch it to a lower frequency - IDETAPE_DSC_MA_SLOW (1 min). * - * We also set a timeout for the timer, in case something goes wrong. - * The timeout should be longer then the maximum execution time of a - * tape operation. - */ - -/* - * DSC timings. + * We also set a timeout for the timer, in case something goes wrong. The + * timeout should be longer then the maximum execution time of a tape operation. */ + +/* DSC timings. */ #define IDETAPE_DSC_RW_MIN 5*HZ/100 /* 50 msec */ #define IDETAPE_DSC_RW_MAX 40*HZ/100 /* 400 msec */ #define IDETAPE_DSC_RW_TIMEOUT 2*60*HZ /* 2 minutes */ @@ -166,19 +164,15 @@ /*************************** End of tunable parameters ***********************/ -/* - * Read/Write error simulation - */ +/* Read/Write error simulation */ #define SIMULATE_ERRORS 0 -/* - * For general magnetic tape device compatibility. - */ -typedef enum { - idetape_direction_none, - idetape_direction_read, - idetape_direction_write -} idetape_chrdev_direction_t; +/* tape directions */ +enum { + IDETAPE_DIR_NONE = (1 << 0), + IDETAPE_DIR_READ = (1 << 1), + IDETAPE_DIR_WRITE = (1 << 2), +}; struct idetape_bh { u32 b_size; @@ -187,24 +181,32 @@ struct idetape_bh { char *b_data; }; -/* - * Our view of a packet command. - */ typedef struct idetape_packet_command_s { - u8 c[12]; /* Actual packet bytes */ - int retries; /* On each retry, we increment retries */ - int error; /* Error code */ - int request_transfer; /* Bytes to transfer */ - int actually_transferred; /* Bytes actually transferred */ - int buffer_size; /* Size of our data buffer */ + /* Actual packet bytes */ + u8 c[12]; + /* On each retry, we increment retries */ + int retries; + /* Error code */ + int error; + /* Bytes to transfer */ + int request_transfer; + /* Bytes actually transferred */ + int actually_transferred; + /* Size of our data buffer */ + int buffer_size; struct idetape_bh *bh; char *b_data; int b_count; - u8 *buffer; /* Data buffer */ - u8 *current_position; /* Pointer into the above buffer */ - ide_startstop_t (*callback) (ide_drive_t *); /* Called when this packet command is completed */ - u8 pc_buffer[IDETAPE_PC_BUFFER_SIZE]; /* Temporary buffer */ - unsigned long flags; /* Status/Action bit flags: long for set_bit */ + /* Data buffer */ + u8 *buffer; + /* Pointer into the above buffer */ + u8 *current_position; + /* Called when this packet command is completed */ + ide_startstop_t (*callback) (ide_drive_t *); + /* Temporary buffer */ + u8 pc_buffer[IDETAPE_PC_BUFFER_SIZE]; + /* Status/Action bit flags: long for set_bit */ + unsigned long flags; } idetape_pc_t; /* @@ -223,9 +225,7 @@ typedef struct idetape_packet_command_s { /* Data direction */ #define PC_WRITING 5 -/* - * A pipeline stage. - */ +/* A pipeline stage. */ typedef struct idetape_stage_s { struct request rq; /* The corresponding request */ struct idetape_bh *bh; /* The data buffers */ @@ -233,9 +233,8 @@ typedef struct idetape_stage_s { } idetape_stage_t; /* - * Most of our global data which we need to save even as we leave the - * driver due to an interrupt or a timer event is stored in a variable - * of type idetape_tape_t, defined below. + * Most of our global data which we need to save even as we leave the driver due + * to an interrupt or a timer event is stored in the struct defined below. */ typedef struct ide_tape_obj { ide_drive_t *drive; @@ -271,15 +270,14 @@ typedef struct ide_tape_obj { int rq_stack_index; /* - * DSC polling variables. + * DSC polling variables. * - * While polling for DSC we use postponed_rq to postpone the - * current request so that ide.c will be able to service - * pending requests on the other device. Note that at most - * we will have only one DSC (usually data transfer) request - * in the device request queue. Additional requests can be - * queued in our internal pipeline, but they will be visible - * to ide.c only one at a time. + * While polling for DSC we use postponed_rq to postpone the current + * request so that ide.c will be able to service pending requests on the + * other device. Note that at most we will have only one DSC (usually + * data transfer) request in the device request queue. Additional + * requests can be queued in our internal pipeline, but they will be + * visible to ide.c only one at a time. */ struct request *postponed_rq; /* The time in which we started polling for DSC */ @@ -287,73 +285,57 @@ typedef struct ide_tape_obj { /* Timer used to poll for dsc */ struct timer_list dsc_timer; /* Read/Write dsc polling frequency */ - unsigned long best_dsc_rw_frequency; - /* The current polling frequency */ - unsigned long dsc_polling_frequency; - /* Maximum waiting time */ + unsigned long best_dsc_rw_freq; + unsigned long dsc_poll_freq; unsigned long dsc_timeout; - /* - * Read position information - */ + /* Read position information */ u8 partition; /* Current block */ - unsigned int first_frame_position; - unsigned int last_frame_position; - unsigned int blocks_in_buffer; + unsigned int first_frame; - /* - * Last error information - */ + /* Last error information */ u8 sense_key, asc, ascq; - /* - * Character device operation - */ + /* Character device operation */ unsigned int minor; /* device name */ char name[4]; /* Current character device data transfer direction */ - idetape_chrdev_direction_t chrdev_direction; + u8 chrdev_dir; - /* - * Device information - */ - /* Usually 512 or 1024 bytes */ - unsigned short tape_block_size; + /* tape block size, usually 512 or 1024 bytes */ + unsigned short blk_size; int user_bs_factor; /* Copy of the tape's Capabilities and Mechanical Page */ u8 caps[20]; /* - * Active data transfer request parameters. - * - * At most, there is only one ide-tape originated data transfer - * request in the device request queue. This allows ide.c to - * easily service requests from the other device when we - * postpone our active request. In the pipelined operation - * mode, we use our internal pipeline structure to hold - * more data requests. + * Active data transfer request parameters. * - * The data buffer size is chosen based on the tape's - * recommendation. + * At most, there is only one ide-tape originated data transfer request + * in the device request queue. This allows ide.c to easily service + * requests from the other device when we postpone our active request. + * In the pipelined operation mode, we use our internal pipeline + * structure to hold more data requests. The data buffer size is chosen + * based on the tape's recommendation. */ - /* Pointer to the request which is waiting in the device request queue */ - struct request *active_data_request; - /* Data buffer size (chosen based on the tape's recommendation */ + /* ptr to the request which is waiting in the device request queue */ + struct request *active_data_rq; + /* Data buffer size chosen based on the tape's recommendation */ int stage_size; idetape_stage_t *merge_stage; int merge_stage_size; struct idetape_bh *bh; char *b_data; int b_count; - + /* - * Pipeline parameters. + * Pipeline parameters. * - * To accomplish non-pipelined mode, we simply set the following - * variables to zero (or NULL, where appropriate). + * To accomplish non-pipelined mode, we simply set the following + * variables to zero (or NULL, where appropriate). */ /* Number of currently used stages */ int nr_stages; @@ -378,20 +360,13 @@ typedef struct ide_tape_obj { /* Status/Action flags: long for set_bit */ unsigned long flags; /* protects the ide-tape queue */ - spinlock_t spinlock; + spinlock_t lock; - /* - * Measures average tape speed - */ + /* Measures average tape speed */ unsigned long avg_time; int avg_size; int avg_speed; - char vendor_id[10]; - char product_id[18]; - char firmware_revision[6]; - int firmware_revision_num; - /* the door is currently locked */ int door_locked; /* the tape hardware is write protected */ @@ -400,11 +375,9 @@ typedef struct ide_tape_obj { char write_prot; /* - * Limit the number of times a request can - * be postponed, to avoid an infinite postpone - * deadlock. + * Limit the number of times a request can be postponed, to avoid an + * infinite postpone deadlock. */ - /* request postpone count limit */ int postpone_cnt; /* @@ -419,30 +392,19 @@ typedef struct ide_tape_obj { int tape_head; int last_tape_head; - /* - * Speed control at the tape buffers input/output - */ + /* Speed control at the tape buffers input/output */ unsigned long insert_time; int insert_size; int insert_speed; int max_insert_speed; int measure_insert_time; - /* - * Measure tape still time, in milliseconds - */ - unsigned long tape_still_time_begin; - int tape_still_time; - - /* - * Speed regulation negative feedback loop - */ + /* Speed regulation negative feedback loop */ int speed_control; int pipeline_head_speed; int controlled_pipeline_head_speed; int uncontrolled_pipeline_head_speed; int controlled_last_pipeline_head; - int uncontrolled_last_pipeline_head; unsigned long uncontrolled_pipeline_head_time; unsigned long controlled_pipeline_head_time; int controlled_previous_pipeline_head; @@ -451,18 +413,7 @@ typedef struct ide_tape_obj { unsigned long uncontrolled_previous_head_time; int restart_speed_control_req; - /* - * Debug_level determines amount of debugging output; - * can be changed using /proc/ide/hdx/settings - * 0 : almost no debugging output - * 1 : 0+output errors only - * 2 : 1+output all sensekey/asc - * 3 : 2+follow all chrdev related procedures - * 4 : 3+follow all procedures - * 5 : 4+include pc_stack rq_stack info - * 6 : 5+USE_COUNT updates - */ - int debug_level; + u32 debug_mask; } idetape_tape_t; static DEFINE_MUTEX(idetape_ref_mutex); @@ -495,9 +446,7 @@ static void ide_tape_put(struct ide_tape_obj *tape) mutex_unlock(&idetape_ref_mutex); } -/* - * Tape door status - */ +/* Tape door status */ #define DOOR_UNLOCKED 0 #define DOOR_LOCKED 1 #define DOOR_EXPLICITLY_LOCKED 2 @@ -517,30 +466,23 @@ static void ide_tape_put(struct ide_tape_obj *tape) /* 0 = no tape is loaded, so we don't rewind after ejecting */ #define IDETAPE_MEDIUM_PRESENT 9 -/* - * Some defines for the READ BUFFER command - */ +/* A define for the READ BUFFER command */ #define IDETAPE_RETRIEVE_FAULTY_BLOCK 6 -/* - * Some defines for the SPACE command - */ +/* Some defines for the SPACE command */ #define IDETAPE_SPACE_OVER_FILEMARK 1 #define IDETAPE_SPACE_TO_EOD 3 -/* - * Some defines for the LOAD UNLOAD command - */ +/* Some defines for the LOAD UNLOAD command */ #define IDETAPE_LU_LOAD_MASK 1 #define IDETAPE_LU_RETENSION_MASK 2 #define IDETAPE_LU_EOT_MASK 4 /* - * Special requests for our block device strategy routine. + * Special requests for our block device strategy routine. * - * In order to service a character device command, we add special - * requests to the tail of our block device request queue and wait - * for their completion. + * In order to service a character device command, we add special requests to + * the tail of our block device request queue and wait for their completion. */ enum { @@ -551,55 +493,20 @@ enum { REQ_IDETAPE_READ_BUFFER = (1 << 4), }; -/* - * Error codes which are returned in rq->errors to the higher part - * of the driver. - */ +/* Error codes returned in rq->errors to the higher part of the driver. */ #define IDETAPE_ERROR_GENERAL 101 #define IDETAPE_ERROR_FILEMARK 102 #define IDETAPE_ERROR_EOD 103 -/* - * The following is used to format the general configuration word of - * the ATAPI IDENTIFY DEVICE command. - */ -struct idetape_id_gcw { - unsigned packet_size :2; /* Packet Size */ - unsigned reserved234 :3; /* Reserved */ - unsigned drq_type :2; /* Command packet DRQ type */ - unsigned removable :1; /* Removable media */ - unsigned device_type :5; /* Device type */ - unsigned reserved13 :1; /* Reserved */ - unsigned protocol :2; /* Protocol type */ -}; - -/* - * READ POSITION packet command - Data Format (From Table 6-57) - */ -typedef struct { - unsigned reserved0_10 :2; /* Reserved */ - unsigned bpu :1; /* Block Position Unknown */ - unsigned reserved0_543 :3; /* Reserved */ - unsigned eop :1; /* End Of Partition */ - unsigned bop :1; /* Beginning Of Partition */ - u8 partition; /* Partition Number */ - u8 reserved2, reserved3; /* Reserved */ - u32 first_block; /* First Block Location */ - u32 last_block; /* Last Block Location (Optional) */ - u8 reserved12; /* Reserved */ - u8 blocks_in_buffer[3]; /* Blocks In Buffer - (Optional) */ - u32 bytes_in_buffer; /* Bytes In Buffer (Optional) */ -} idetape_read_position_result_t; - /* Structures related to the SELECT SENSE / MODE SENSE packet commands. */ #define IDETAPE_BLOCK_DESCRIPTOR 0 #define IDETAPE_CAPABILITIES_PAGE 0x2a /* - * The variables below are used for the character device interface. - * Additional state variables are defined in our ide_drive_t structure. + * The variables below are used for the character device interface. Additional + * state variables are defined in our ide_drive_t structure. */ -static struct ide_tape_obj * idetape_devs[MAX_HWIFS * MAX_DRIVES]; +static struct ide_tape_obj *idetape_devs[MAX_HWIFS * MAX_DRIVES]; #define ide_tape_f(file) ((file)->private_data) @@ -616,23 +523,17 @@ static struct ide_tape_obj *ide_tape_chrdev_get(unsigned int i) } /* - * Function declarations - * - */ -static int idetape_chrdev_release (struct inode *inode, struct file *filp); -static void idetape_write_release (ide_drive_t *drive, unsigned int minor); - -/* * Too bad. The drive wants to send us data which we are not ready to accept. * Just throw it away. */ -static void idetape_discard_data (ide_drive_t *drive, unsigned int bcount) +static void idetape_discard_data(ide_drive_t *drive, unsigned int bcount) { while (bcount--) (void) HWIF(drive)->INB(IDE_DATA_REG); } -static void idetape_input_buffers (ide_drive_t *drive, idetape_pc_t *pc, unsigned int bcount) +static void idetape_input_buffers(ide_drive_t *drive, idetape_pc_t *pc, + unsigned int bcount) { struct idetape_bh *bh = pc->bh; int count; @@ -644,8 +545,11 @@ static void idetape_input_buffers (ide_drive_t *drive, idetape_pc_t *pc, unsigne idetape_discard_data(drive, bcount); return; } - count = min((unsigned int)(bh->b_size - atomic_read(&bh->b_count)), bcount); - HWIF(drive)->atapi_input_bytes(drive, bh->b_data + atomic_read(&bh->b_count), count); + count = min( + (unsigned int)(bh->b_size - atomic_read(&bh->b_count)), + bcount); + HWIF(drive)->atapi_input_bytes(drive, bh->b_data + + atomic_read(&bh->b_count), count); bcount -= count; atomic_add(count, &bh->b_count); if (atomic_read(&bh->b_count) == bh->b_size) { @@ -657,15 +561,16 @@ static void idetape_input_buffers (ide_drive_t *drive, idetape_pc_t *pc, unsigne pc->bh = bh; } -static void idetape_output_buffers (ide_drive_t *drive, idetape_pc_t *pc, unsigned int bcount) +static void idetape_output_buffers(ide_drive_t *drive, idetape_pc_t *pc, + unsigned int bcount) { struct idetape_bh *bh = pc->bh; int count; while (bcount) { if (bh == NULL) { - printk(KERN_ERR "ide-tape: bh == NULL in " - "idetape_output_buffers\n"); + printk(KERN_ERR "ide-tape: bh == NULL in %s\n", + __func__); return; } count = min((unsigned int)pc->b_count, (unsigned int)bcount); @@ -674,7 +579,8 @@ static void idetape_output_buffers (ide_drive_t *drive, idetape_pc_t *pc, unsign pc->b_data += count; pc->b_count -= count; if (!pc->b_count) { - pc->bh = bh = bh->b_reqnext; + bh = bh->b_reqnext; + pc->bh = bh; if (bh) { pc->b_data = bh->b_data; pc->b_count = atomic_read(&bh->b_count); @@ -683,7 +589,7 @@ static void idetape_output_buffers (ide_drive_t *drive, idetape_pc_t *pc, unsign } } -static void idetape_update_buffers (idetape_pc_t *pc) +static void idetape_update_buffers(idetape_pc_t *pc) { struct idetape_bh *bh = pc->bh; int count; @@ -693,8 +599,8 @@ static void idetape_update_buffers (idetape_pc_t *pc) return; while (bcount) { if (bh == NULL) { - printk(KERN_ERR "ide-tape: bh == NULL in " - "idetape_update_buffers\n"); + printk(KERN_ERR "ide-tape: bh == NULL in %s\n", + __func__); return; } count = min((unsigned int)bh->b_size, (unsigned int)bcount); @@ -712,17 +618,14 @@ static void idetape_update_buffers (idetape_pc_t *pc) * driver. A storage space for a maximum of IDETAPE_PC_STACK packet * commands is allocated at initialization time. */ -static idetape_pc_t *idetape_next_pc_storage (ide_drive_t *drive) +static idetape_pc_t *idetape_next_pc_storage(ide_drive_t *drive) { idetape_tape_t *tape = drive->driver_data; -#if IDETAPE_DEBUG_LOG - if (tape->debug_level >= 5) - printk(KERN_INFO "ide-tape: pc_stack_index=%d\n", - tape->pc_stack_index); -#endif /* IDETAPE_DEBUG_LOG */ + debug_log(DBG_PCRQ_STACK, "pc_stack_index=%d\n", tape->pc_stack_index); + if (tape->pc_stack_index == IDETAPE_PC_STACK) - tape->pc_stack_index=0; + tape->pc_stack_index = 0; return (&tape->pc_stack[tape->pc_stack_index++]); } @@ -731,32 +634,26 @@ static idetape_pc_t *idetape_next_pc_storage (ide_drive_t *drive) * Since we queue packet commands in the request queue, we need to * allocate a request, along with the allocation of a packet command. */ - + /************************************************************** * * * This should get fixed to use kmalloc(.., GFP_ATOMIC) * * followed later on by kfree(). -ml * * * **************************************************************/ - -static struct request *idetape_next_rq_storage (ide_drive_t *drive) + +static struct request *idetape_next_rq_storage(ide_drive_t *drive) { idetape_tape_t *tape = drive->driver_data; -#if IDETAPE_DEBUG_LOG - if (tape->debug_level >= 5) - printk(KERN_INFO "ide-tape: rq_stack_index=%d\n", - tape->rq_stack_index); -#endif /* IDETAPE_DEBUG_LOG */ + debug_log(DBG_PCRQ_STACK, "rq_stack_index=%d\n", tape->rq_stack_index); + if (tape->rq_stack_index == IDETAPE_PC_STACK) - tape->rq_stack_index=0; + tape->rq_stack_index = 0; return (&tape->rq_stack[tape->rq_stack_index++]); } -/* - * idetape_init_pc initializes a packet command. - */ -static void idetape_init_pc (idetape_pc_t *pc) +static void idetape_init_pc(idetape_pc_t *pc) { memset(pc->c, 0, 12); pc->retries = 0; @@ -780,22 +677,14 @@ static void idetape_analyze_error(ide_drive_t *drive, u8 *sense) tape->sense_key = sense[2] & 0xF; tape->asc = sense[12]; tape->ascq = sense[13]; -#if IDETAPE_DEBUG_LOG - /* - * Without debugging, we only log an error if we decided to give up - * retrying. - */ - if (tape->debug_level >= 1) - printk(KERN_INFO "ide-tape: pc = %x, sense key = %x, " - "asc = %x, ascq = %x\n", - pc->c[0], tape->sense_key, - tape->asc, tape->ascq); -#endif /* IDETAPE_DEBUG_LOG */ + + debug_log(DBG_ERR, "pc = %x, sense key = %x, asc = %x, ascq = %x\n", + pc->c[0], tape->sense_key, tape->asc, tape->ascq); /* Correct pc->actually_transferred by asking the tape. */ if (test_bit(PC_DMA_ERROR, &pc->flags)) { pc->actually_transferred = pc->request_transfer - - tape->tape_block_size * + tape->blk_size * be32_to_cpu(get_unaligned((u32 *)&sense[3])); idetape_update_buffers(pc); } @@ -843,50 +732,24 @@ static void idetape_activate_next_stage(ide_drive_t *drive) idetape_stage_t *stage = tape->next_stage; struct request *rq = &stage->rq; -#if IDETAPE_DEBUG_LOG - if (tape->debug_level >= 4) - printk(KERN_INFO "ide-tape: Reached idetape_active_next_stage\n"); -#endif /* IDETAPE_DEBUG_LOG */ + debug_log(DBG_PROCS, "Enter %s\n", __func__); + if (stage == NULL) { - printk(KERN_ERR "ide-tape: bug: Trying to activate a non existing stage\n"); + printk(KERN_ERR "ide-tape: bug: Trying to activate a non" + " existing stage\n"); return; } rq->rq_disk = tape->disk; rq->buffer = NULL; rq->special = (void *)stage->bh; - tape->active_data_request = rq; + tape->active_data_rq = rq; tape->active_stage = stage; tape->next_stage = stage->next; } -/* - * idetape_increase_max_pipeline_stages is a part of the feedback - * loop which tries to find the optimum number of stages. In the - * feedback loop, we are starting from a minimum maximum number of - * stages, and if we sense that the pipeline is empty, we try to - * increase it, until we reach the user compile time memory limit. - */ -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 - if (tape->debug_level >= 4) - printk (KERN_INFO "ide-tape: Reached idetape_increase_max_pipeline_stages\n"); -#endif /* IDETAPE_DEBUG_LOG */ - - tape->max_stages += max(increase, 1); - tape->max_stages = max(tape->max_stages, tape->min_pipeline); - tape->max_stages = min(tape->max_stages, tape->max_pipeline); -} - -/* - * idetape_kfree_stage calls kfree to completely free a stage, along with - * its related buffers. - */ -static void __idetape_kfree_stage (idetape_stage_t *stage) +/* Free a stage along with its related buffers completely. */ +static void __idetape_kfree_stage(idetape_stage_t *stage) { struct idetape_bh *prev_bh, *bh = stage->bh; int size; @@ -907,30 +770,29 @@ static void __idetape_kfree_stage (idetape_stage_t *stage) kfree(stage); } -static void idetape_kfree_stage (idetape_tape_t *tape, idetape_stage_t *stage) +static void idetape_kfree_stage(idetape_tape_t *tape, idetape_stage_t *stage) { __idetape_kfree_stage(stage); } /* - * idetape_remove_stage_head removes tape->first_stage from the pipeline. - * The caller should avoid race conditions. + * Remove tape->first_stage from the pipeline. The caller should avoid race + * conditions. */ -static void idetape_remove_stage_head (ide_drive_t *drive) +static void idetape_remove_stage_head(ide_drive_t *drive) { idetape_tape_t *tape = drive->driver_data; idetape_stage_t *stage; - -#if IDETAPE_DEBUG_LOG - if (tape->debug_level >= 4) - printk(KERN_INFO "ide-tape: Reached idetape_remove_stage_head\n"); -#endif /* IDETAPE_DEBUG_LOG */ + + debug_log(DBG_PROCS, "Enter %s\n", __func__); + if (tape->first_stage == NULL) { printk(KERN_ERR "ide-tape: bug: tape->first_stage is NULL\n"); return; } if (tape->active_stage == tape->first_stage) { - printk(KERN_ERR "ide-tape: bug: Trying to free our active pipeline stage\n"); + printk(KERN_ERR "ide-tape: bug: Trying to free our active " + "pipeline stage\n"); return; } stage = tape->first_stage; @@ -940,9 +802,11 @@ static void idetape_remove_stage_head (ide_drive_t *drive) if (tape->first_stage == NULL) { tape->last_stage = NULL; if (tape->next_stage != NULL) - printk(KERN_ERR "ide-tape: bug: tape->next_stage != NULL\n"); + printk(KERN_ERR "ide-tape: bug: tape->next_stage !=" + " NULL\n"); if (tape->nr_stages) - printk(KERN_ERR "ide-tape: bug: nr_stages should be 0 now\n"); + printk(KERN_ERR "ide-tape: bug: nr_stages should be 0 " + "now\n"); } } @@ -957,10 +821,8 @@ static void idetape_abort_pipeline(ide_drive_t *drive, idetape_stage_t *stage = new_last_stage->next; idetape_stage_t *nstage; -#if IDETAPE_DEBUG_LOG - if (tape->debug_level >= 4) - printk(KERN_INFO "ide-tape: %s: idetape_abort_pipeline called\n", tape->name); -#endif + debug_log(DBG_PROCS, "%s: Enter %s\n", tape->name, __func__); + while (stage) { nstage = stage->next; idetape_kfree_stage(tape, stage); @@ -975,8 +837,8 @@ static void idetape_abort_pipeline(ide_drive_t *drive, } /* - * idetape_end_request is used to finish servicing a request, and to - * insert a pending pipeline request into the main device queue. + * Finish servicing a request and insert a pending pipeline request into the + * main device queue. */ static int idetape_end_request(ide_drive_t *drive, int uptodate, int nr_sects) { @@ -987,15 +849,12 @@ static int idetape_end_request(ide_drive_t *drive, int uptodate, int nr_sects) int remove_stage = 0; idetape_stage_t *active_stage; -#if IDETAPE_DEBUG_LOG - if (tape->debug_level >= 4) - printk(KERN_INFO "ide-tape: Reached idetape_end_request\n"); -#endif /* IDETAPE_DEBUG_LOG */ + debug_log(DBG_PROCS, "Enter %s\n", __func__); switch (uptodate) { - case 0: error = IDETAPE_ERROR_GENERAL; break; - case 1: error = 0; break; - default: error = uptodate; + case 0: error = IDETAPE_ERROR_GENERAL; break; + case 1: error = 0; break; + default: error = uptodate; } rq->errors = error; if (error) @@ -1006,20 +865,21 @@ static int idetape_end_request(ide_drive_t *drive, int uptodate, int nr_sects) return 0; } - spin_lock_irqsave(&tape->spinlock, flags); + spin_lock_irqsave(&tape->lock, flags); /* The request was a pipelined data transfer request */ - if (tape->active_data_request == rq) { + if (tape->active_data_rq == rq) { active_stage = tape->active_stage; tape->active_stage = NULL; - tape->active_data_request = NULL; + tape->active_data_rq = NULL; tape->nr_pending_stages--; if (rq->cmd[0] & REQ_IDETAPE_WRITE) { remove_stage = 1; if (error) { set_bit(IDETAPE_PIPELINE_ERROR, &tape->flags); if (error == IDETAPE_ERROR_EOD) - idetape_abort_pipeline(drive, active_stage); + idetape_abort_pipeline(drive, + active_stage); } } else if (rq->cmd[0] & REQ_IDETAPE_READ) { if (error == IDETAPE_ERROR_EOD) { @@ -1030,48 +890,57 @@ static int idetape_end_request(ide_drive_t *drive, int uptodate, int nr_sects) if (tape->next_stage != NULL) { idetape_activate_next_stage(drive); + /* Insert the next request into the request queue. */ + (void)ide_do_drive_cmd(drive, tape->active_data_rq, + ide_end); + } else if (!error) { /* - * Insert the next request into the request queue. + * This is a part of the feedback loop which tries to + * find the optimum number of stages. We are starting + * from a minimum maximum number of stages, and if we + * sense that the pipeline is empty, we try to increase + * it, until we reach the user compile time memory + * limit. */ - (void) ide_do_drive_cmd(drive, tape->active_data_request, ide_end); - } else if (!error) { - idetape_increase_max_pipeline_stages(drive); + int i = (tape->max_pipeline - tape->min_pipeline) / 10; + + tape->max_stages += max(i, 1); + tape->max_stages = max(tape->max_stages, + tape->min_pipeline); + tape->max_stages = min(tape->max_stages, + tape->max_pipeline); } } ide_end_drive_cmd(drive, 0, 0); -// blkdev_dequeue_request(rq); -// drive->rq = NULL; -// end_that_request_last(rq); if (remove_stage) idetape_remove_stage_head(drive); - if (tape->active_data_request == NULL) + if (tape->active_data_rq == NULL) clear_bit(IDETAPE_PIPELINE_ACTIVE, &tape->flags); - spin_unlock_irqrestore(&tape->spinlock, flags); + spin_unlock_irqrestore(&tape->lock, flags); return 0; } -static ide_startstop_t idetape_request_sense_callback (ide_drive_t *drive) +static ide_startstop_t idetape_request_sense_callback(ide_drive_t *drive) { idetape_tape_t *tape = drive->driver_data; -#if IDETAPE_DEBUG_LOG - if (tape->debug_level >= 4) - printk(KERN_INFO "ide-tape: Reached idetape_request_sense_callback\n"); -#endif /* IDETAPE_DEBUG_LOG */ + debug_log(DBG_PROCS, "Enter %s\n", __func__); + if (!tape->pc->error) { idetape_analyze_error(drive, tape->pc->buffer); idetape_end_request(drive, 1, 0); } else { - printk(KERN_ERR "ide-tape: Error in REQUEST SENSE itself - Aborting request!\n"); + printk(KERN_ERR "ide-tape: Error in REQUEST SENSE itself - " + "Aborting request!\n"); idetape_end_request(drive, 0, 0); } return ide_stopped; } -static void idetape_create_request_sense_cmd (idetape_pc_t *pc) +static void idetape_create_request_sense_cmd(idetape_pc_t *pc) { - idetape_init_pc(pc); + idetape_init_pc(pc); pc->c[0] = REQUEST_SENSE; pc->c[4] = 20; pc->request_transfer = 20; @@ -1086,25 +955,22 @@ static void idetape_init_rq(struct request *rq, u8 cmd) } /* - * idetape_queue_pc_head generates a new packet command request in front - * of the request queue, before the current request, so that it will be - * processed immediately, on the next pass through the driver. - * - * idetape_queue_pc_head is called from the request handling part of - * the driver (the "bottom" part). Safe storage for the request should - * be allocated with idetape_next_pc_storage and idetape_next_rq_storage - * before calling idetape_queue_pc_head. + * Generate a new packet command request in front of the request queue, before + * the current request, so that it will be processed immediately, on the next + * pass through the driver. The function below is called from the request + * handling part of the driver (the "bottom" part). Safe storage for the request + * should be allocated with ide_tape_next_{pc,rq}_storage() prior to that. * - * Memory for those requests is pre-allocated at initialization time, and - * is limited to IDETAPE_PC_STACK requests. We assume that we have enough - * space for the maximum possible number of inter-dependent packet commands. + * Memory for those requests is pre-allocated at initialization time, and is + * limited to IDETAPE_PC_STACK requests. We assume that we have enough space for + * the maximum possible number of inter-dependent packet commands. * - * The higher level of the driver - The ioctl handler and the character - * device handling functions should queue request to the lower level part - * and wait for their completion using idetape_queue_pc_tail or - * idetape_queue_rw_tail. + * The higher level of the driver - The ioctl handler and the character device + * handling functions should queue request to the lower level part and wait for + * their completion using idetape_queue_pc_tail or idetape_queue_rw_tail. */ -static void idetape_queue_pc_head (ide_drive_t *drive, idetape_pc_t *pc,struct request *rq) +static void idetape_queue_pc_head(ide_drive_t *drive, idetape_pc_t *pc, + struct request *rq) { struct ide_tape_obj *tape = drive->driver_data; @@ -1125,7 +991,7 @@ static ide_startstop_t idetape_retry_pc (ide_drive_t *drive) idetape_pc_t *pc; struct request *rq; - (void)drive->hwif->INB(IDE_ERROR_REG); + (void)ide_read_error(drive); pc = idetape_next_pc_storage(drive); rq = idetape_next_rq_storage(drive); idetape_create_request_sense_cmd(pc); @@ -1135,50 +1001,46 @@ static ide_startstop_t idetape_retry_pc (ide_drive_t *drive) } /* - * idetape_postpone_request postpones the current request so that - * ide.c will be able to service requests from another device on - * the same hwgroup while we are polling for DSC. + * Postpone the current request so that ide.c will be able to service requests + * from another device on the same hwgroup while we are polling for DSC. */ -static void idetape_postpone_request (ide_drive_t *drive) +static void idetape_postpone_request(ide_drive_t *drive) { idetape_tape_t *tape = drive->driver_data; -#if IDETAPE_DEBUG_LOG - if (tape->debug_level >= 4) - printk(KERN_INFO "ide-tape: idetape_postpone_request\n"); -#endif + debug_log(DBG_PROCS, "Enter %s\n", __func__); + tape->postponed_rq = HWGROUP(drive)->rq; - ide_stall_queue(drive, tape->dsc_polling_frequency); + ide_stall_queue(drive, tape->dsc_poll_freq); } +typedef void idetape_io_buf(ide_drive_t *, idetape_pc_t *, unsigned int); + /* - * idetape_pc_intr is the usual interrupt handler which will be called - * during a packet command. We will transfer some of the data (as - * requested by the drive) and will re-point interrupt handler to us. - * When data transfer is finished, we will act according to the - * algorithm described before idetape_issue_packet_command. - * + * This is the usual interrupt handler which will be called during a packet + * command. We will transfer some of the data (as requested by the drive) and + * will re-point interrupt handler to us. When data transfer is finished, we + * will act according to the algorithm described before + * idetape_issue_pc. */ -static ide_startstop_t idetape_pc_intr (ide_drive_t *drive) +static ide_startstop_t idetape_pc_intr(ide_drive_t *drive) { ide_hwif_t *hwif = drive->hwif; idetape_tape_t *tape = drive->driver_data; idetape_pc_t *pc = tape->pc; + xfer_func_t *xferfunc; + idetape_io_buf *iobuf; unsigned int temp; #if SIMULATE_ERRORS - static int error_sim_count = 0; + static int error_sim_count; #endif u16 bcount; u8 stat, ireason; -#if IDETAPE_DEBUG_LOG - if (tape->debug_level >= 4) - printk(KERN_INFO "ide-tape: Reached idetape_pc_intr " - "interrupt handler\n"); -#endif /* IDETAPE_DEBUG_LOG */ + debug_log(DBG_PROCS, "Enter %s - interrupt handler\n", __func__); /* Clear the interrupt */ - stat = hwif->INB(IDE_STATUS_REG); + stat = ide_read_status(drive); if (test_bit(PC_DMA_IN_PROGRESS, &pc->flags)) { if (hwif->ide_dma_end(drive) || (stat & ERR_STAT)) { @@ -1208,20 +1070,16 @@ static ide_startstop_t idetape_pc_intr (ide_drive_t *drive) pc->actually_transferred = pc->request_transfer; idetape_update_buffers(pc); } -#if IDETAPE_DEBUG_LOG - if (tape->debug_level >= 4) - printk(KERN_INFO "ide-tape: DMA finished\n"); -#endif /* IDETAPE_DEBUG_LOG */ + debug_log(DBG_PROCS, "DMA finished\n"); + } /* No more interrupts */ if ((stat & DRQ_STAT) == 0) { -#if IDETAPE_DEBUG_LOG - if (tape->debug_level >= 2) - printk(KERN_INFO "ide-tape: Packet command completed, %d bytes transferred\n", pc->actually_transferred); -#endif /* IDETAPE_DEBUG_LOG */ - clear_bit(PC_DMA_IN_PROGRESS, &pc->flags); + debug_log(DBG_SENSE, "Packet command completed, %d bytes" + " transferred\n", pc->actually_transferred); + clear_bit(PC_DMA_IN_PROGRESS, &pc->flags); local_irq_enable(); #if SIMULATE_ERRORS @@ -1236,19 +1094,16 @@ static ide_startstop_t idetape_pc_intr (ide_drive_t *drive) stat &= ~ERR_STAT; if ((stat & ERR_STAT) || test_bit(PC_DMA_ERROR, &pc->flags)) { /* Error detected */ -#if IDETAPE_DEBUG_LOG - if (tape->debug_level >= 1) - printk(KERN_INFO "ide-tape: %s: I/O error\n", - tape->name); -#endif /* IDETAPE_DEBUG_LOG */ + debug_log(DBG_ERR, "%s: I/O error\n", tape->name); + if (pc->c[0] == REQUEST_SENSE) { - printk(KERN_ERR "ide-tape: I/O error in request sense command\n"); + printk(KERN_ERR "ide-tape: I/O error in request" + " sense command\n"); return ide_do_reset(drive); } -#if IDETAPE_DEBUG_LOG - if (tape->debug_level >= 1) - printk(KERN_INFO "ide-tape: [cmd %x]: check condition\n", pc->c[0]); -#endif + debug_log(DBG_ERR, "[cmd %x]: check condition\n", + pc->c[0]); + /* Retry operation */ return idetape_retry_pc(drive); } @@ -1257,7 +1112,7 @@ static ide_startstop_t idetape_pc_intr (ide_drive_t *drive) (stat & SEEK_STAT) == 0) { /* Media access command */ tape->dsc_polling_start = jiffies; - tape->dsc_polling_frequency = IDETAPE_DSC_MA_FAST; + tape->dsc_poll_freq = IDETAPE_DSC_MA_FAST; tape->dsc_timeout = jiffies + IDETAPE_DSC_MA_TIMEOUT; /* Allow ide.c to handle other requests */ idetape_postpone_request(drive); @@ -1282,7 +1137,7 @@ static ide_startstop_t idetape_pc_intr (ide_drive_t *drive) ireason = hwif->INB(IDE_IREASON_REG); if (ireason & CD) { - printk(KERN_ERR "ide-tape: CoD != 0 in idetape_pc_intr\n"); + printk(KERN_ERR "ide-tape: CoD != 0 in %s\n", __func__); return ide_do_reset(drive); } if (((ireason & IO) == IO) == test_bit(PC_WRITING, &pc->flags)) { @@ -1298,86 +1153,76 @@ static ide_startstop_t idetape_pc_intr (ide_drive_t *drive) temp = pc->actually_transferred + bcount; if (temp > pc->request_transfer) { if (temp > pc->buffer_size) { - printk(KERN_ERR "ide-tape: The tape wants to send us more data than expected - discarding data\n"); + printk(KERN_ERR "ide-tape: The tape wants to " + "send us more data than expected " + "- discarding data\n"); idetape_discard_data(drive, bcount); - ide_set_handler(drive, &idetape_pc_intr, IDETAPE_WAIT_CMD, NULL); + ide_set_handler(drive, &idetape_pc_intr, + IDETAPE_WAIT_CMD, NULL); return ide_started; } -#if IDETAPE_DEBUG_LOG - if (tape->debug_level >= 2) - printk(KERN_NOTICE "ide-tape: The tape wants to send us more data than expected - allowing transfer\n"); -#endif /* IDETAPE_DEBUG_LOG */ + debug_log(DBG_SENSE, "The tape wants to send us more " + "data than expected - allowing transfer\n"); } - } - if (test_bit(PC_WRITING, &pc->flags)) { - if (pc->bh != NULL) - idetape_output_buffers(drive, pc, bcount); - else - /* Write the current buffer */ - hwif->atapi_output_bytes(drive, pc->current_position, - bcount); + iobuf = &idetape_input_buffers; + xferfunc = hwif->atapi_input_bytes; } else { - if (pc->bh != NULL) - idetape_input_buffers(drive, pc, bcount); - else - /* Read the current buffer */ - hwif->atapi_input_bytes(drive, pc->current_position, - bcount); + iobuf = &idetape_output_buffers; + xferfunc = hwif->atapi_output_bytes; } + + if (pc->bh) + iobuf(drive, pc, bcount); + else + xferfunc(drive, pc->current_position, bcount); + /* Update the current position */ pc->actually_transferred += bcount; pc->current_position += bcount; -#if IDETAPE_DEBUG_LOG - if (tape->debug_level >= 2) - printk(KERN_INFO "ide-tape: [cmd %x] transferred %d bytes " - "on that interrupt\n", pc->c[0], bcount); -#endif + + debug_log(DBG_SENSE, "[cmd %x] transferred %d bytes on that intr.\n", + pc->c[0], bcount); + /* And set the interrupt handler again */ ide_set_handler(drive, &idetape_pc_intr, IDETAPE_WAIT_CMD, NULL); return ide_started; } /* - * Packet Command Interface - * - * The current Packet Command is available in tape->pc, and will not - * change until we finish handling it. Each packet command is associated - * with a callback function that will be called when the command is - * finished. + * Packet Command Interface * - * The handling will be done in three stages: + * The current Packet Command is available in tape->pc, and will not change + * until we finish handling it. Each packet command is associated with a + * callback function that will be called when the command is finished. * - * 1. idetape_issue_packet_command will send the packet command to the - * drive, and will set the interrupt handler to idetape_pc_intr. + * The handling will be done in three stages: * - * 2. On each interrupt, idetape_pc_intr will be called. This step - * will be repeated until the device signals us that no more - * interrupts will be issued. + * 1. idetape_issue_pc will send the packet command to the drive, and will set + * the interrupt handler to idetape_pc_intr. * - * 3. ATAPI Tape media access commands have immediate status with a - * delayed process. In case of a successful initiation of a - * media access packet command, the DSC bit will be set when the - * actual execution of the command is finished. - * Since the tape drive will not issue an interrupt, we have to - * poll for this event. In this case, we define the request as - * "low priority request" by setting rq_status to - * IDETAPE_RQ_POSTPONED, set a timer to poll for DSC and exit - * the driver. + * 2. On each interrupt, idetape_pc_intr will be called. This step will be + * repeated until the device signals us that no more interrupts will be issued. * - * ide.c will then give higher priority to requests which - * originate from the other device, until will change rq_status - * to RQ_ACTIVE. + * 3. ATAPI Tape media access commands have immediate status with a delayed + * process. In case of a successful initiation of a media access packet command, + * the DSC bit will be set when the actual execution of the command is finished. + * Since the tape drive will not issue an interrupt, we have to poll for this + * event. In this case, we define the request as "low priority request" by + * setting rq_status to IDETAPE_RQ_POSTPONED, set a timer to poll for DSC and + * exit the driver. * - * 4. When the packet command is finished, it will be checked for errors. + * ide.c will then give higher priority to requests which originate from the + * other device, until will change rq_status to RQ_ACTIVE. * - * 5. In case an error was found, we queue a request sense packet - * command in front of the request queue and retry the operation - * up to IDETAPE_MAX_PC_RETRIES times. + * 4. When the packet command is finished, it will be checked for errors. * - * 6. In case no error was found, or we decided to give up and not - * to retry again, the callback function will be called and then - * we will handle the next request. + * 5. In case an error was found, we queue a request sense packet command in + * front of the request queue and retry the operation up to + * IDETAPE_MAX_PC_RETRIES times. * + * 6. In case no error was found, or we decided to give up and not to retry + * again, the callback function will be called and then we will handle the next + * request. */ static ide_startstop_t idetape_transfer_pc(ide_drive_t *drive) { @@ -1388,8 +1233,9 @@ static ide_startstop_t idetape_transfer_pc(ide_drive_t *drive) ide_startstop_t startstop; u8 ireason; - if (ide_wait_stat(&startstop,drive,DRQ_STAT,BUSY_STAT,WAIT_READY)) { - printk(KERN_ERR "ide-tape: Strange, packet command initiated yet DRQ isn't asserted\n"); + if (ide_wait_stat(&startstop, drive, DRQ_STAT, BUSY_STAT, WAIT_READY)) { + printk(KERN_ERR "ide-tape: Strange, packet command initiated " + "yet DRQ isn't asserted\n"); return startstop; } ireason = hwif->INB(IDE_IREASON_REG); @@ -1422,7 +1268,7 @@ static ide_startstop_t idetape_transfer_pc(ide_drive_t *drive) return ide_started; } -static ide_startstop_t idetape_issue_packet_command (ide_drive_t *drive, idetape_pc_t *pc) +static ide_startstop_t idetape_issue_pc(ide_drive_t *drive, idetape_pc_t *pc) { ide_hwif_t *hwif = drive->hwif; idetape_tape_t *tape = drive->driver_data; @@ -1443,9 +1289,9 @@ static ide_startstop_t idetape_issue_packet_command (ide_drive_t *drive, idetape if (pc->retries > IDETAPE_MAX_PC_RETRIES || test_bit(PC_ABORT, &pc->flags)) { /* - * We will "abort" retrying a packet command in case - * a legitimate error code was received (crossing a - * filemark, or end of the media, for example). + * We will "abort" retrying a packet command in case legitimate + * error code was received (crossing a filemark, or end of the + * media, for example). */ if (!test_bit(PC_ABORT, &pc->flags)) { if (!(pc->c[0] == TEST_UNIT_READY && @@ -1464,10 +1310,7 @@ static ide_startstop_t idetape_issue_packet_command (ide_drive_t *drive, idetape tape->failed_pc = NULL; return pc->callback(drive); } -#if IDETAPE_DEBUG_LOG - if (tape->debug_level >= 2) - printk(KERN_INFO "ide-tape: Retry number - %d, cmd = %02X\n", pc->retries, pc->c[0]); -#endif /* IDETAPE_DEBUG_LOG */ + debug_log(DBG_SENSE, "Retry #%d, cmd = %02X\n", pc->retries, pc->c[0]); pc->retries++; /* We haven't transferred any data yet */ @@ -1499,31 +1342,24 @@ static ide_startstop_t idetape_issue_packet_command (ide_drive_t *drive, idetape } } -/* - * General packet command callback function. - */ -static ide_startstop_t idetape_pc_callback (ide_drive_t *drive) +static ide_startstop_t idetape_pc_callback(ide_drive_t *drive) { idetape_tape_t *tape = drive->driver_data; - -#if IDETAPE_DEBUG_LOG - if (tape->debug_level >= 4) - printk(KERN_INFO "ide-tape: Reached idetape_pc_callback\n"); -#endif /* IDETAPE_DEBUG_LOG */ + + debug_log(DBG_PROCS, "Enter %s\n", __func__); idetape_end_request(drive, tape->pc->error ? 0 : 1, 0); return ide_stopped; } -/* - * A mode sense command is used to "sense" tape parameters. - */ -static void idetape_create_mode_sense_cmd (idetape_pc_t *pc, u8 page_code) +/* A mode sense command is used to "sense" tape parameters. */ +static void idetape_create_mode_sense_cmd(idetape_pc_t *pc, u8 page_code) { idetape_init_pc(pc); pc->c[0] = MODE_SENSE; if (page_code != IDETAPE_BLOCK_DESCRIPTOR) - pc->c[1] = 8; /* DBD = 1 - Don't return block descriptors */ + /* DBD = 1 - Don't return block descriptors */ + pc->c[1] = 8; pc->c[2] = page_code; /* * Changed pc->c[3] to 0 (255 will at best return unused info). @@ -1533,7 +1369,8 @@ static void idetape_create_mode_sense_cmd (idetape_pc_t *pc, u8 page_code) * and return an error when 255 is used. */ pc->c[3] = 0; - pc->c[4] = 255; /* (We will just discard data in that case) */ + /* We will just discard data in that case */ + pc->c[4] = 255; if (page_code == IDETAPE_BLOCK_DESCRIPTOR) pc->request_transfer = 12; else if (page_code == IDETAPE_CAPABILITIES_PAGE) @@ -1543,62 +1380,77 @@ static void idetape_create_mode_sense_cmd (idetape_pc_t *pc, u8 page_code) pc->callback = &idetape_pc_callback; } -static void calculate_speeds(ide_drive_t *drive) +static void idetape_calculate_speeds(ide_drive_t *drive) { idetape_tape_t *tape = drive->driver_data; - int full = 125, empty = 75; - if (time_after(jiffies, tape->controlled_pipeline_head_time + 120 * HZ)) { - tape->controlled_previous_pipeline_head = tape->controlled_last_pipeline_head; - tape->controlled_previous_head_time = tape->controlled_pipeline_head_time; + if (time_after(jiffies, + tape->controlled_pipeline_head_time + 120 * HZ)) { + tape->controlled_previous_pipeline_head = + tape->controlled_last_pipeline_head; + tape->controlled_previous_head_time = + tape->controlled_pipeline_head_time; tape->controlled_last_pipeline_head = tape->pipeline_head; tape->controlled_pipeline_head_time = jiffies; } if (time_after(jiffies, tape->controlled_pipeline_head_time + 60 * HZ)) - tape->controlled_pipeline_head_speed = (tape->pipeline_head - tape->controlled_last_pipeline_head) * 32 * HZ / (jiffies - tape->controlled_pipeline_head_time); + tape->controlled_pipeline_head_speed = (tape->pipeline_head - + tape->controlled_last_pipeline_head) * 32 * HZ / + (jiffies - tape->controlled_pipeline_head_time); else if (time_after(jiffies, tape->controlled_previous_head_time)) - tape->controlled_pipeline_head_speed = (tape->pipeline_head - tape->controlled_previous_pipeline_head) * 32 * HZ / (jiffies - tape->controlled_previous_head_time); + tape->controlled_pipeline_head_speed = (tape->pipeline_head - + tape->controlled_previous_pipeline_head) * 32 * + HZ / (jiffies - tape->controlled_previous_head_time); - if (tape->nr_pending_stages < tape->max_stages /*- 1 */) { + if (tape->nr_pending_stages < tape->max_stages/*- 1 */) { /* -1 for read mode error recovery */ - if (time_after(jiffies, tape->uncontrolled_previous_head_time + 10 * HZ)) { + if (time_after(jiffies, tape->uncontrolled_previous_head_time + + 10 * HZ)) { tape->uncontrolled_pipeline_head_time = jiffies; - tape->uncontrolled_pipeline_head_speed = (tape->pipeline_head - tape->uncontrolled_previous_pipeline_head) * 32 * HZ / (jiffies - tape->uncontrolled_previous_head_time); + tape->uncontrolled_pipeline_head_speed = + (tape->pipeline_head - + tape->uncontrolled_previous_pipeline_head) * + 32 * HZ / (jiffies - + tape->uncontrolled_previous_head_time); } } else { tape->uncontrolled_previous_head_time = jiffies; tape->uncontrolled_previous_pipeline_head = tape->pipeline_head; - if (time_after(jiffies, tape->uncontrolled_pipeline_head_time + 30 * HZ)) { + if (time_after(jiffies, tape->uncontrolled_pipeline_head_time + + 30 * HZ)) tape->uncontrolled_pipeline_head_time = jiffies; - } + } - tape->pipeline_head_speed = max(tape->uncontrolled_pipeline_head_speed, tape->controlled_pipeline_head_speed); - if (tape->speed_control == 0) { - tape->max_insert_speed = 5000; - } else if (tape->speed_control == 1) { + tape->pipeline_head_speed = max(tape->uncontrolled_pipeline_head_speed, + tape->controlled_pipeline_head_speed); + + if (tape->speed_control == 1) { if (tape->nr_pending_stages >= tape->max_stages / 2) tape->max_insert_speed = tape->pipeline_head_speed + - (1100 - tape->pipeline_head_speed) * 2 * (tape->nr_pending_stages - tape->max_stages / 2) / tape->max_stages; + (1100 - tape->pipeline_head_speed) * 2 * + (tape->nr_pending_stages - tape->max_stages / 2) + / tape->max_stages; else tape->max_insert_speed = 500 + - (tape->pipeline_head_speed - 500) * 2 * tape->nr_pending_stages / tape->max_stages; + (tape->pipeline_head_speed - 500) * 2 * + tape->nr_pending_stages / tape->max_stages; + if (tape->nr_pending_stages >= tape->max_stages * 99 / 100) tape->max_insert_speed = 5000; - } else if (tape->speed_control == 2) { - tape->max_insert_speed = tape->pipeline_head_speed * empty / 100 + - (tape->pipeline_head_speed * full / 100 - tape->pipeline_head_speed * empty / 100) * tape->nr_pending_stages / tape->max_stages; } else tape->max_insert_speed = tape->speed_control; + tape->max_insert_speed = max(tape->max_insert_speed, 500); } -static ide_startstop_t idetape_media_access_finished (ide_drive_t *drive) +static ide_startstop_t idetape_media_access_finished(ide_drive_t *drive) { idetape_tape_t *tape = drive->driver_data; idetape_pc_t *pc = tape->pc; u8 stat; - stat = drive->hwif->INB(IDE_STATUS_REG); + stat = ide_read_status(drive); + if (stat & SEEK_STAT) { if (stat & ERR_STAT) { /* Error detected */ @@ -1618,14 +1470,14 @@ static ide_startstop_t idetape_media_access_finished (ide_drive_t *drive) return pc->callback(drive); } -static ide_startstop_t idetape_rw_callback (ide_drive_t *drive) +static ide_startstop_t idetape_rw_callback(ide_drive_t *drive) { idetape_tape_t *tape = drive->driver_data; struct request *rq = HWGROUP(drive)->rq; - int blocks = tape->pc->actually_transferred / tape->tape_block_size; + int blocks = tape->pc->actually_transferred / tape->blk_size; - tape->avg_size += blocks * tape->tape_block_size; - tape->insert_size += blocks * tape->tape_block_size; + tape->avg_size += blocks * tape->blk_size; + tape->insert_size += blocks * tape->blk_size; if (tape->insert_size > 1024 * 1024) tape->measure_insert_time = 1; if (tape->measure_insert_time) { @@ -1634,19 +1486,17 @@ static ide_startstop_t idetape_rw_callback (ide_drive_t *drive) tape->insert_size = 0; } if (time_after(jiffies, tape->insert_time)) - tape->insert_speed = tape->insert_size / 1024 * HZ / (jiffies - tape->insert_time); + tape->insert_speed = tape->insert_size / 1024 * HZ / + (jiffies - tape->insert_time); if (time_after_eq(jiffies, tape->avg_time + HZ)) { - tape->avg_speed = tape->avg_size * HZ / (jiffies - tape->avg_time) / 1024; + tape->avg_speed = tape->avg_size * HZ / + (jiffies - tape->avg_time) / 1024; tape->avg_size = 0; tape->avg_time = jiffies; } + debug_log(DBG_PROCS, "Enter %s\n", __func__); -#if IDETAPE_DEBUG_LOG - if (tape->debug_level >= 4) - printk(KERN_INFO "ide-tape: Reached idetape_rw_callback\n"); -#endif /* IDETAPE_DEBUG_LOG */ - - tape->first_frame_position += blocks; + tape->first_frame += blocks; rq->current_nr_sectors -= blocks; if (!tape->pc->error) @@ -1656,7 +1506,8 @@ static ide_startstop_t idetape_rw_callback (ide_drive_t *drive) return ide_stopped; } -static void idetape_create_read_cmd(idetape_tape_t *tape, idetape_pc_t *pc, unsigned int length, struct idetape_bh *bh) +static void idetape_create_read_cmd(idetape_tape_t *tape, idetape_pc_t *pc, + unsigned int length, struct idetape_bh *bh) { idetape_init_pc(pc); pc->c[0] = READ_6; @@ -1666,12 +1517,14 @@ static void idetape_create_read_cmd(idetape_tape_t *tape, idetape_pc_t *pc, unsi pc->bh = bh; atomic_set(&bh->b_count, 0); pc->buffer = NULL; - pc->request_transfer = pc->buffer_size = length * tape->tape_block_size; + pc->buffer_size = length * tape->blk_size; + pc->request_transfer = pc->buffer_size; if (pc->request_transfer == tape->stage_size) set_bit(PC_DMA_RECOMMENDED, &pc->flags); } -static void idetape_create_read_buffer_cmd(idetape_tape_t *tape, idetape_pc_t *pc, unsigned int length, struct idetape_bh *bh) +static void idetape_create_read_buffer_cmd(idetape_tape_t *tape, + idetape_pc_t *pc, struct idetape_bh *bh) { int size = 32768; struct idetape_bh *p = bh; @@ -1689,10 +1542,12 @@ static void idetape_create_read_buffer_cmd(idetape_tape_t *tape, idetape_pc_t *p atomic_set(&p->b_count, 0); p = p->b_reqnext; } - pc->request_transfer = pc->buffer_size = size; + pc->request_transfer = size; + pc->buffer_size = size; } -static void idetape_create_write_cmd(idetape_tape_t *tape, idetape_pc_t *pc, unsigned int length, struct idetape_bh *bh) +static void idetape_create_write_cmd(idetape_tape_t *tape, idetape_pc_t *pc, + unsigned int length, struct idetape_bh *bh) { idetape_init_pc(pc); pc->c[0] = WRITE_6; @@ -1704,14 +1559,12 @@ static void idetape_create_write_cmd(idetape_tape_t *tape, idetape_pc_t *pc, uns pc->b_data = bh->b_data; pc->b_count = atomic_read(&bh->b_count); pc->buffer = NULL; - pc->request_transfer = pc->buffer_size = length * tape->tape_block_size; + pc->buffer_size = length * tape->blk_size; + pc->request_transfer = pc->buffer_size; if (pc->request_transfer == tape->stage_size) set_bit(PC_DMA_RECOMMENDED, &pc->flags); } -/* - * idetape_do_request is our request handling function. - */ static ide_startstop_t idetape_do_request(ide_drive_t *drive, struct request *rq, sector_t block) { @@ -1720,30 +1573,22 @@ static ide_startstop_t idetape_do_request(ide_drive_t *drive, struct request *postponed_rq = tape->postponed_rq; u8 stat; -#if IDETAPE_DEBUG_LOG - if (tape->debug_level >= 2) - printk(KERN_INFO "ide-tape: sector: %ld, " - "nr_sectors: %ld, current_nr_sectors: %d\n", + debug_log(DBG_SENSE, "sector: %ld, nr_sectors: %ld," + " current_nr_sectors: %d\n", rq->sector, rq->nr_sectors, rq->current_nr_sectors); -#endif /* IDETAPE_DEBUG_LOG */ if (!blk_special_request(rq)) { - /* - * We do not support buffer cache originated requests. - */ + /* We do not support buffer cache originated requests. */ printk(KERN_NOTICE "ide-tape: %s: Unsupported request in " "request queue (%d)\n", drive->name, rq->cmd_type); ide_end_request(drive, 0, 0); return ide_stopped; } - /* - * Retry a failed packet command - */ - if (tape->failed_pc != NULL && - tape->pc->c[0] == REQUEST_SENSE) { - return idetape_issue_packet_command(drive, tape->failed_pc); - } + /* Retry a failed packet command */ + if (tape->failed_pc && tape->pc->c[0] == REQUEST_SENSE) + return idetape_issue_pc(drive, tape->failed_pc); + if (postponed_rq != NULL) if (rq != postponed_rq) { printk(KERN_ERR "ide-tape: ide-tape.c bug - " @@ -1758,7 +1603,7 @@ static ide_startstop_t idetape_do_request(ide_drive_t *drive, * If the tape is still busy, postpone our request and service * the other device meanwhile. */ - stat = drive->hwif->INB(IDE_STATUS_REG); + stat = ide_read_status(drive); if (!drive->dsc_overlap && !(rq->cmd[0] & REQ_IDETAPE_PC2)) set_bit(IDETAPE_IGNORE_DSC, &tape->flags); @@ -1768,16 +1613,15 @@ static ide_startstop_t idetape_do_request(ide_drive_t *drive, drive->post_reset = 0; } - if (tape->tape_still_time > 100 && tape->tape_still_time < 200) - tape->measure_insert_time = 1; if (time_after(jiffies, tape->insert_time)) - tape->insert_speed = tape->insert_size / 1024 * HZ / (jiffies - tape->insert_time); - calculate_speeds(drive); + tape->insert_speed = tape->insert_size / 1024 * HZ / + (jiffies - tape->insert_time); + idetape_calculate_speeds(drive); if (!test_and_clear_bit(IDETAPE_IGNORE_DSC, &tape->flags) && (stat & SEEK_STAT) == 0) { if (postponed_rq == NULL) { tape->dsc_polling_start = jiffies; - tape->dsc_polling_frequency = tape->best_dsc_rw_frequency; + tape->dsc_poll_freq = tape->best_dsc_rw_freq; tape->dsc_timeout = jiffies + IDETAPE_DSC_RW_TIMEOUT; } else if (time_after(jiffies, tape->dsc_timeout)) { printk(KERN_ERR "ide-tape: %s: DSC timeout\n", @@ -1788,8 +1632,10 @@ static ide_startstop_t idetape_do_request(ide_drive_t *drive, } else { return ide_do_reset(drive); } - } else if (time_after(jiffies, tape->dsc_polling_start + IDETAPE_DSC_MA_THRESHOLD)) - tape->dsc_polling_frequency = IDETAPE_DSC_MA_SLOW; + } else if (time_after(jiffies, + tape->dsc_polling_start + + IDETAPE_DSC_MA_THRESHOLD)) + tape->dsc_poll_freq = IDETAPE_DSC_MA_SLOW; idetape_postpone_request(drive); return ide_stopped; } @@ -1797,20 +1643,23 @@ static ide_startstop_t idetape_do_request(ide_drive_t *drive, tape->buffer_head++; tape->postpone_cnt = 0; pc = idetape_next_pc_storage(drive); - idetape_create_read_cmd(tape, pc, rq->current_nr_sectors, (struct idetape_bh *)rq->special); + idetape_create_read_cmd(tape, pc, rq->current_nr_sectors, + (struct idetape_bh *)rq->special); goto out; } if (rq->cmd[0] & REQ_IDETAPE_WRITE) { tape->buffer_head++; tape->postpone_cnt = 0; pc = idetape_next_pc_storage(drive); - idetape_create_write_cmd(tape, pc, rq->current_nr_sectors, (struct idetape_bh *)rq->special); + idetape_create_write_cmd(tape, pc, rq->current_nr_sectors, + (struct idetape_bh *)rq->special); goto out; } if (rq->cmd[0] & REQ_IDETAPE_READ_BUFFER) { tape->postpone_cnt = 0; pc = idetape_next_pc_storage(drive); - idetape_create_read_buffer_cmd(tape, pc, rq->current_nr_sectors, (struct idetape_bh *)rq->special); + idetape_create_read_buffer_cmd(tape, pc, + (struct idetape_bh *)rq->special); goto out; } if (rq->cmd[0] & REQ_IDETAPE_PC1) { @@ -1825,49 +1674,51 @@ static ide_startstop_t idetape_do_request(ide_drive_t *drive, } BUG(); out: - return idetape_issue_packet_command(drive, pc); + return idetape_issue_pc(drive, pc); } -/* - * Pipeline related functions - */ -static inline int idetape_pipeline_active (idetape_tape_t *tape) +/* Pipeline related functions */ +static inline int idetape_pipeline_active(idetape_tape_t *tape) { int rc1, rc2; rc1 = test_bit(IDETAPE_PIPELINE_ACTIVE, &tape->flags); - rc2 = (tape->active_data_request != NULL); + rc2 = (tape->active_data_rq != NULL); return rc1; } /* - * idetape_kmalloc_stage uses __get_free_page to allocate a pipeline - * stage, along with all the necessary small buffers which together make - * a buffer of size tape->stage_size (or a bit more). We attempt to - * combine sequential pages as much as possible. + * The function below uses __get_free_page to allocate a pipeline stage, along + * with all the necessary small buffers which together make a buffer of size + * tape->stage_size (or a bit more). We attempt to combine sequential pages as + * much as possible. * - * Returns a pointer to the new allocated stage, or NULL if we - * can't (or don't want to) allocate a stage. + * It returns a pointer to the new allocated stage, or NULL if we can't (or + * don't want to) allocate a stage. * - * Pipeline stages are optional and are used to increase performance. - * If we can't allocate them, we'll manage without them. + * Pipeline stages are optional and are used to increase performance. If we + * can't allocate them, we'll manage without them. */ -static idetape_stage_t *__idetape_kmalloc_stage (idetape_tape_t *tape, int full, int clear) +static idetape_stage_t *__idetape_kmalloc_stage(idetape_tape_t *tape, int full, + int clear) { idetape_stage_t *stage; struct idetape_bh *prev_bh, *bh; int pages = tape->pages_per_stage; char *b_data = NULL; - if ((stage = kmalloc(sizeof (idetape_stage_t),GFP_KERNEL)) == NULL) + stage = kmalloc(sizeof(idetape_stage_t), GFP_KERNEL); + if (!stage) return NULL; stage->next = NULL; - bh = stage->bh = kmalloc(sizeof(struct idetape_bh), GFP_KERNEL); + stage->bh = kmalloc(sizeof(struct idetape_bh), GFP_KERNEL); + bh = stage->bh; if (bh == NULL) goto abort; bh->b_reqnext = NULL; - if ((bh->b_data = (char *) __get_free_page (GFP_KERNEL)) == NULL) + bh->b_data = (char *) __get_free_page(GFP_KERNEL); + if (!bh->b_data) goto abort; if (clear) memset(bh->b_data, 0, PAGE_SIZE); @@ -1875,7 +1726,8 @@ static idetape_stage_t *__idetape_kmalloc_stage (idetape_tape_t *tape, int full, atomic_set(&bh->b_count, full ? bh->b_size : 0); while (--pages) { - if ((b_data = (char *) __get_free_page (GFP_KERNEL)) == NULL) + b_data = (char *) __get_free_page(GFP_KERNEL); + if (!b_data) goto abort; if (clear) memset(b_data, 0, PAGE_SIZE); @@ -1893,7 +1745,8 @@ static idetape_stage_t *__idetape_kmalloc_stage (idetape_tape_t *tape, int full, continue; } prev_bh = bh; - if ((bh = kmalloc(sizeof(struct idetape_bh), GFP_KERNEL)) == NULL) { + bh = kmalloc(sizeof(struct idetape_bh), GFP_KERNEL); + if (!bh) { free_page((unsigned long) b_data); goto abort; } @@ -1912,14 +1765,11 @@ abort: return NULL; } -static idetape_stage_t *idetape_kmalloc_stage (idetape_tape_t *tape) +static idetape_stage_t *idetape_kmalloc_stage(idetape_tape_t *tape) { idetape_stage_t *cache_stage = tape->cache_stage; -#if IDETAPE_DEBUG_LOG - if (tape->debug_level >= 4) - printk(KERN_INFO "ide-tape: Reached idetape_kmalloc_stage\n"); -#endif /* IDETAPE_DEBUG_LOG */ + debug_log(DBG_PROCS, "Enter %s\n", __func__); if (tape->nr_stages >= tape->max_stages) return NULL; @@ -1930,7 +1780,8 @@ static idetape_stage_t *idetape_kmalloc_stage (idetape_tape_t *tape) return __idetape_kmalloc_stage(tape, 0, 0); } -static int idetape_copy_stage_from_user (idetape_tape_t *tape, idetape_stage_t *stage, const char __user *buf, int n) +static int idetape_copy_stage_from_user(idetape_tape_t *tape, + idetape_stage_t *stage, const char __user *buf, int n) { struct idetape_bh *bh = tape->bh; int count; @@ -1938,12 +1789,15 @@ static int idetape_copy_stage_from_user (idetape_tape_t *tape, idetape_stage_t * while (n) { if (bh == NULL) { - printk(KERN_ERR "ide-tape: bh == NULL in " - "idetape_copy_stage_from_user\n"); + printk(KERN_ERR "ide-tape: bh == NULL in %s\n", + __func__); return 1; } - count = min((unsigned int)(bh->b_size - atomic_read(&bh->b_count)), (unsigned int)n); - if (copy_from_user(bh->b_data + atomic_read(&bh->b_count), buf, count)) + count = min((unsigned int) + (bh->b_size - atomic_read(&bh->b_count)), + (unsigned int)n); + if (copy_from_user(bh->b_data + atomic_read(&bh->b_count), buf, + count)) ret = 1; n -= count; atomic_add(count, &bh->b_count); @@ -1958,7 +1812,8 @@ static int idetape_copy_stage_from_user (idetape_tape_t *tape, idetape_stage_t * return ret; } -static int idetape_copy_stage_to_user (idetape_tape_t *tape, char __user *buf, idetape_stage_t *stage, int n) +static int idetape_copy_stage_to_user(idetape_tape_t *tape, char __user *buf, + idetape_stage_t *stage, int n) { struct idetape_bh *bh = tape->bh; int count; @@ -1966,8 +1821,8 @@ static int idetape_copy_stage_to_user (idetape_tape_t *tape, char __user *buf, i while (n) { if (bh == NULL) { - printk(KERN_ERR "ide-tape: bh == NULL in " - "idetape_copy_stage_to_user\n"); + printk(KERN_ERR "ide-tape: bh == NULL in %s\n", + __func__); return 1; } count = min(tape->b_count, n); @@ -1978,7 +1833,8 @@ static int idetape_copy_stage_to_user (idetape_tape_t *tape, char __user *buf, i tape->b_count -= count; buf += count; if (!tape->b_count) { - tape->bh = bh = bh->b_reqnext; + bh = bh->b_reqnext; + tape->bh = bh; if (bh) { tape->b_data = bh->b_data; tape->b_count = atomic_read(&bh->b_count); @@ -1988,12 +1844,12 @@ static int idetape_copy_stage_to_user (idetape_tape_t *tape, char __user *buf, i return ret; } -static void idetape_init_merge_stage (idetape_tape_t *tape) +static void idetape_init_merge_stage(idetape_tape_t *tape) { struct idetape_bh *bh = tape->merge_stage->bh; - + tape->bh = bh; - if (tape->chrdev_direction == idetape_direction_write) + if (tape->chrdev_dir == IDETAPE_DIR_WRITE) atomic_set(&bh->b_count, 0); else { tape->b_data = bh->b_data; @@ -2001,7 +1857,7 @@ static void idetape_init_merge_stage (idetape_tape_t *tape) } } -static void idetape_switch_buffers (idetape_tape_t *tape, idetape_stage_t *stage) +static void idetape_switch_buffers(idetape_tape_t *tape, idetape_stage_t *stage) { struct idetape_bh *tmp; @@ -2011,87 +1867,76 @@ static void idetape_switch_buffers (idetape_tape_t *tape, idetape_stage_t *stage idetape_init_merge_stage(tape); } -/* - * idetape_add_stage_tail adds a new stage at the end of the pipeline. - */ -static void idetape_add_stage_tail (ide_drive_t *drive,idetape_stage_t *stage) +/* Add a new stage at the end of the pipeline. */ +static void idetape_add_stage_tail(ide_drive_t *drive, idetape_stage_t *stage) { idetape_tape_t *tape = drive->driver_data; unsigned long flags; - -#if IDETAPE_DEBUG_LOG - if (tape->debug_level >= 4) - printk (KERN_INFO "ide-tape: Reached idetape_add_stage_tail\n"); -#endif /* IDETAPE_DEBUG_LOG */ - spin_lock_irqsave(&tape->spinlock, flags); + + debug_log(DBG_PROCS, "Enter %s\n", __func__); + + spin_lock_irqsave(&tape->lock, flags); stage->next = NULL; if (tape->last_stage != NULL) - tape->last_stage->next=stage; + tape->last_stage->next = stage; else - tape->first_stage = tape->next_stage=stage; + tape->first_stage = stage; + tape->next_stage = stage; tape->last_stage = stage; if (tape->next_stage == NULL) tape->next_stage = tape->last_stage; tape->nr_stages++; tape->nr_pending_stages++; - spin_unlock_irqrestore(&tape->spinlock, flags); + spin_unlock_irqrestore(&tape->lock, flags); } -/* - * idetape_wait_for_request installs a completion in a pending request - * and sleeps until it is serviced. - * - * The caller should ensure that the request will not be serviced - * before we install the completion (usually by disabling interrupts). +/* Install a completion in a pending request and sleep until it is serviced. The + * caller should ensure that the request will not be serviced before we install + * the completion (usually by disabling interrupts). */ -static void idetape_wait_for_request (ide_drive_t *drive, struct request *rq) +static void idetape_wait_for_request(ide_drive_t *drive, struct request *rq) { DECLARE_COMPLETION_ONSTACK(wait); idetape_tape_t *tape = drive->driver_data; if (rq == NULL || !blk_special_request(rq)) { - printk (KERN_ERR "ide-tape: bug: Trying to sleep on non-valid request\n"); + printk(KERN_ERR "ide-tape: bug: Trying to sleep on non-valid" + " request\n"); return; } rq->end_io_data = &wait; rq->end_io = blk_end_sync_rq; - spin_unlock_irq(&tape->spinlock); + spin_unlock_irq(&tape->lock); wait_for_completion(&wait); /* The stage and its struct request have been deallocated */ - spin_lock_irq(&tape->spinlock); + spin_lock_irq(&tape->lock); } -static ide_startstop_t idetape_read_position_callback (ide_drive_t *drive) +static ide_startstop_t idetape_read_position_callback(ide_drive_t *drive) { idetape_tape_t *tape = drive->driver_data; - idetape_read_position_result_t *result; - -#if IDETAPE_DEBUG_LOG - if (tape->debug_level >= 4) - printk(KERN_INFO "ide-tape: Reached idetape_read_position_callback\n"); -#endif /* IDETAPE_DEBUG_LOG */ + u8 *readpos = tape->pc->buffer; + + debug_log(DBG_PROCS, "Enter %s\n", __func__); if (!tape->pc->error) { - result = (idetape_read_position_result_t *) tape->pc->buffer; -#if IDETAPE_DEBUG_LOG - if (tape->debug_level >= 2) - printk(KERN_INFO "ide-tape: BOP - %s\n",result->bop ? "Yes":"No"); - if (tape->debug_level >= 2) - printk(KERN_INFO "ide-tape: EOP - %s\n",result->eop ? "Yes":"No"); -#endif /* IDETAPE_DEBUG_LOG */ - if (result->bpu) { - printk(KERN_INFO "ide-tape: Block location is unknown to the tape\n"); + debug_log(DBG_SENSE, "BOP - %s\n", + (readpos[0] & 0x80) ? "Yes" : "No"); + debug_log(DBG_SENSE, "EOP - %s\n", + (readpos[0] & 0x40) ? "Yes" : "No"); + + if (readpos[0] & 0x4) { + printk(KERN_INFO "ide-tape: Block location is unknown" + "to the tape\n"); clear_bit(IDETAPE_ADDRESS_VALID, &tape->flags); idetape_end_request(drive, 0, 0); } else { -#if IDETAPE_DEBUG_LOG - if (tape->debug_level >= 2) - printk(KERN_INFO "ide-tape: Block Location - %u\n", ntohl(result->first_block)); -#endif /* IDETAPE_DEBUG_LOG */ - tape->partition = result->partition; - tape->first_frame_position = ntohl(result->first_block); - tape->last_frame_position = ntohl(result->last_block); - tape->blocks_in_buffer = result->blocks_in_buffer[2]; + debug_log(DBG_SENSE, "Block Location - %u\n", + be32_to_cpu(*(u32 *)&readpos[4])); + + tape->partition = readpos[1]; + tape->first_frame = + be32_to_cpu(*(u32 *)&readpos[4]); set_bit(IDETAPE_ADDRESS_VALID, &tape->flags); idetape_end_request(drive, 1, 0); } @@ -2102,14 +1947,11 @@ static ide_startstop_t idetape_read_position_callback (ide_drive_t *drive) } /* - * idetape_create_write_filemark_cmd will: - * - * 1. Write a filemark if write_filemark=1. - * 2. Flush the device buffers without writing a filemark - * if write_filemark=0. - * + * Write a filemark if write_filemark=1. Flush the device buffers without + * writing a filemark otherwise. */ -static void idetape_create_write_filemark_cmd (ide_drive_t *drive, idetape_pc_t *pc,int write_filemark) +static void idetape_create_write_filemark_cmd(ide_drive_t *drive, + idetape_pc_t *pc, int write_filemark) { idetape_init_pc(pc); pc->c[0] = WRITE_FILEMARKS; @@ -2126,26 +1968,19 @@ static void idetape_create_test_unit_ready_cmd(idetape_pc_t *pc) } /* - * idetape_queue_pc_tail is based on the following functions: - * - * ide_do_drive_cmd from ide.c - * cdrom_queue_request and cdrom_queue_packet_command from ide-cd.c + * We add a special packet command request to the tail of the request queue, and + * wait for it to be serviced. This is not to be called from within the request + * handling part of the driver! We allocate here data on the stack and it is + * valid until the request is finished. This is not the case for the bottom part + * of the driver, where we are always leaving the functions to wait for an + * interrupt or a timer event. * - * We add a special packet command request to the tail of the request - * queue, and wait for it to be serviced. - * - * This is not to be called from within the request handling part - * of the driver ! We allocate here data in the stack, and it is valid - * until the request is finished. This is not the case for the bottom - * part of the driver, where we are always leaving the functions to wait - * for an interrupt or a timer event. - * - * From the bottom part of the driver, we should allocate safe memory - * using idetape_next_pc_storage and idetape_next_rq_storage, and add - * the request to the request list without waiting for it to be serviced ! - * In that case, we usually use idetape_queue_pc_head. + * From the bottom part of the driver, we should allocate safe memory using + * idetape_next_pc_storage() and ide_tape_next_rq_storage(), and add the request + * to the request list without waiting for it to be serviced! In that case, we + * usually use idetape_queue_pc_head(). */ -static int __idetape_queue_pc_tail (ide_drive_t *drive, idetape_pc_t *pc) +static int __idetape_queue_pc_tail(ide_drive_t *drive, idetape_pc_t *pc) { struct ide_tape_obj *tape = drive->driver_data; struct request rq; @@ -2156,7 +1991,8 @@ static int __idetape_queue_pc_tail (ide_drive_t *drive, idetape_pc_t *pc) return ide_do_drive_cmd(drive, &rq, ide_wait); } -static void idetape_create_load_unload_cmd (ide_drive_t *drive, idetape_pc_t *pc,int cmd) +static void idetape_create_load_unload_cmd(ide_drive_t *drive, idetape_pc_t *pc, + int cmd) { idetape_init_pc(pc); pc->c[0] = START_STOP; @@ -2171,9 +2007,7 @@ static int idetape_wait_ready(ide_drive_t *drive, unsigned long timeout) idetape_pc_t pc; int load_attempted = 0; - /* - * Wait for the tape to become ready - */ + /* Wait for the tape to become ready */ set_bit(IDETAPE_MEDIUM_PRESENT, &tape->flags); timeout += jiffies; while (time_before(jiffies, timeout)) { @@ -2181,10 +2015,12 @@ static int idetape_wait_ready(ide_drive_t *drive, unsigned long timeout) if (!__idetape_queue_pc_tail(drive, &pc)) return 0; if ((tape->sense_key == 2 && tape->asc == 4 && tape->ascq == 2) - || (tape->asc == 0x3A)) { /* no media */ + || (tape->asc == 0x3A)) { + /* no media */ if (load_attempted) return -ENOMEDIUM; - idetape_create_load_unload_cmd(drive, &pc, IDETAPE_LU_LOAD_MASK); + idetape_create_load_unload_cmd(drive, &pc, + IDETAPE_LU_LOAD_MASK); __idetape_queue_pc_tail(drive, &pc); load_attempted = 1; /* not about to be ready */ @@ -2196,24 +2032,25 @@ static int idetape_wait_ready(ide_drive_t *drive, unsigned long timeout) return -EIO; } -static int idetape_queue_pc_tail (ide_drive_t *drive,idetape_pc_t *pc) +static int idetape_queue_pc_tail(ide_drive_t *drive, idetape_pc_t *pc) { return __idetape_queue_pc_tail(drive, pc); } -static int idetape_flush_tape_buffers (ide_drive_t *drive) +static int idetape_flush_tape_buffers(ide_drive_t *drive) { idetape_pc_t pc; int rc; idetape_create_write_filemark_cmd(drive, &pc, 0); - if ((rc = idetape_queue_pc_tail(drive, &pc))) + rc = idetape_queue_pc_tail(drive, &pc); + if (rc) return rc; idetape_wait_ready(drive, 60 * 5 * HZ); return 0; } -static void idetape_create_read_position_cmd (idetape_pc_t *pc) +static void idetape_create_read_position_cmd(idetape_pc_t *pc) { idetape_init_pc(pc); pc->c[0] = READ_POSITION; @@ -2221,25 +2058,23 @@ static void idetape_create_read_position_cmd (idetape_pc_t *pc) pc->callback = &idetape_read_position_callback; } -static int idetape_read_position (ide_drive_t *drive) +static int idetape_read_position(ide_drive_t *drive) { idetape_tape_t *tape = drive->driver_data; idetape_pc_t pc; int position; -#if IDETAPE_DEBUG_LOG - if (tape->debug_level >= 4) - printk(KERN_INFO "ide-tape: Reached idetape_read_position\n"); -#endif /* IDETAPE_DEBUG_LOG */ + debug_log(DBG_PROCS, "Enter %s\n", __func__); idetape_create_read_position_cmd(&pc); if (idetape_queue_pc_tail(drive, &pc)) return -1; - position = tape->first_frame_position; + position = tape->first_frame; return position; } -static void idetape_create_locate_cmd (ide_drive_t *drive, idetape_pc_t *pc, unsigned int block, u8 partition, int skip) +static void idetape_create_locate_cmd(ide_drive_t *drive, idetape_pc_t *pc, + unsigned int block, u8 partition, int skip) { idetape_init_pc(pc); pc->c[0] = POSITION_TO_ELEMENT; @@ -2250,7 +2085,8 @@ static void idetape_create_locate_cmd (ide_drive_t *drive, idetape_pc_t *pc, uns pc->callback = &idetape_pc_callback; } -static int idetape_create_prevent_cmd (ide_drive_t *drive, idetape_pc_t *pc, int prevent) +static int idetape_create_prevent_cmd(ide_drive_t *drive, idetape_pc_t *pc, + int prevent) { idetape_tape_t *tape = drive->driver_data; @@ -2265,17 +2101,17 @@ static int idetape_create_prevent_cmd (ide_drive_t *drive, idetape_pc_t *pc, int return 1; } -static int __idetape_discard_read_pipeline (ide_drive_t *drive) +static int __idetape_discard_read_pipeline(ide_drive_t *drive) { idetape_tape_t *tape = drive->driver_data; unsigned long flags; int cnt; - if (tape->chrdev_direction != idetape_direction_read) + if (tape->chrdev_dir != IDETAPE_DIR_READ) return 0; /* Remove merge stage. */ - cnt = tape->merge_stage_size / tape->tape_block_size; + cnt = tape->merge_stage_size / tape->blk_size; if (test_and_clear_bit(IDETAPE_FILEMARK, &tape->flags)) ++cnt; /* Filemarks count as 1 sector */ tape->merge_stage_size = 0; @@ -2286,22 +2122,22 @@ static int __idetape_discard_read_pipeline (ide_drive_t *drive) /* Clear pipeline flags. */ clear_bit(IDETAPE_PIPELINE_ERROR, &tape->flags); - tape->chrdev_direction = idetape_direction_none; + tape->chrdev_dir = IDETAPE_DIR_NONE; /* Remove pipeline stages. */ if (tape->first_stage == NULL) return 0; - spin_lock_irqsave(&tape->spinlock, flags); + spin_lock_irqsave(&tape->lock, flags); tape->next_stage = NULL; if (idetape_pipeline_active(tape)) - idetape_wait_for_request(drive, tape->active_data_request); - spin_unlock_irqrestore(&tape->spinlock, flags); + idetape_wait_for_request(drive, tape->active_data_rq); + spin_unlock_irqrestore(&tape->lock, flags); while (tape->first_stage != NULL) { struct request *rq_ptr = &tape->first_stage->rq; - cnt += rq_ptr->nr_sectors - rq_ptr->current_nr_sectors; + cnt += rq_ptr->nr_sectors - rq_ptr->current_nr_sectors; if (rq_ptr->errors == IDETAPE_ERROR_FILEMARK) ++cnt; idetape_remove_stage_head(drive); @@ -2312,21 +2148,19 @@ static int __idetape_discard_read_pipeline (ide_drive_t *drive) } /* - * idetape_position_tape positions the tape to the requested block - * using the LOCATE packet command. A READ POSITION command is then - * issued to check where we are positioned. - * - * Like all higher level operations, we queue the commands at the tail - * of the request queue and wait for their completion. - * + * Position the tape to the requested block using the LOCATE packet command. + * A READ POSITION command is then issued to check where we are positioned. Like + * all higher level operations, we queue the commands at the tail of the request + * queue and wait for their completion. */ -static int idetape_position_tape (ide_drive_t *drive, unsigned int block, u8 partition, int skip) +static int idetape_position_tape(ide_drive_t *drive, unsigned int block, + u8 partition, int skip) { idetape_tape_t *tape = drive->driver_data; int retval; idetape_pc_t pc; - if (tape->chrdev_direction == idetape_direction_read) + if (tape->chrdev_dir == IDETAPE_DIR_READ) __idetape_discard_read_pipeline(drive); idetape_wait_ready(drive, 60 * 5 * HZ); idetape_create_locate_cmd(drive, &pc, block, partition, skip); @@ -2338,7 +2172,8 @@ static int idetape_position_tape (ide_drive_t *drive, unsigned int block, u8 par return (idetape_queue_pc_tail(drive, &pc)); } -static void idetape_discard_read_pipeline (ide_drive_t *drive, int restore_position) +static void idetape_discard_read_pipeline(ide_drive_t *drive, + int restore_position) { idetape_tape_t *tape = drive->driver_data; int cnt; @@ -2349,35 +2184,37 @@ static void idetape_discard_read_pipeline (ide_drive_t *drive, int restore_posit position = idetape_read_position(drive); seek = position > cnt ? position - cnt : 0; if (idetape_position_tape(drive, seek, 0, 0)) { - printk(KERN_INFO "ide-tape: %s: position_tape failed in discard_pipeline()\n", tape->name); + printk(KERN_INFO "ide-tape: %s: position_tape failed in" + " discard_pipeline()\n", tape->name); return; } } } /* - * idetape_queue_rw_tail generates a read/write request for the block - * device interface and wait for it to be serviced. + * Generate a read/write request for the block device interface and wait for it + * to be serviced. */ -static int idetape_queue_rw_tail(ide_drive_t *drive, int cmd, int blocks, struct idetape_bh *bh) +static int idetape_queue_rw_tail(ide_drive_t *drive, int cmd, int blocks, + struct idetape_bh *bh) { idetape_tape_t *tape = drive->driver_data; struct request rq; -#if IDETAPE_DEBUG_LOG - if (tape->debug_level >= 2) - printk(KERN_INFO "ide-tape: idetape_queue_rw_tail: cmd=%d\n",cmd); -#endif /* IDETAPE_DEBUG_LOG */ + debug_log(DBG_SENSE, "%s: cmd=%d\n", __func__, cmd); + if (idetape_pipeline_active(tape)) { - printk(KERN_ERR "ide-tape: bug: the pipeline is active in idetape_queue_rw_tail\n"); + printk(KERN_ERR "ide-tape: bug: the pipeline is active in %s\n", + __func__); return (0); } idetape_init_rq(&rq, cmd); rq.rq_disk = tape->disk; rq.special = (void *)bh; - rq.sector = tape->first_frame_position; - rq.nr_sectors = rq.current_nr_sectors = blocks; + rq.sector = tape->first_frame; + rq.nr_sectors = blocks; + rq.current_nr_sectors = blocks; (void) ide_do_drive_cmd(drive, &rq, ide_wait); if ((cmd & (REQ_IDETAPE_READ | REQ_IDETAPE_WRITE)) == 0) @@ -2387,14 +2224,11 @@ static int idetape_queue_rw_tail(ide_drive_t *drive, int cmd, int blocks, struct idetape_init_merge_stage(tape); if (rq.errors == IDETAPE_ERROR_GENERAL) return -EIO; - return (tape->tape_block_size * (blocks-rq.current_nr_sectors)); + return (tape->blk_size * (blocks-rq.current_nr_sectors)); } -/* - * idetape_insert_pipeline_into_queue is used to start servicing the - * pipeline stages, starting from tape->next_stage. - */ -static void idetape_insert_pipeline_into_queue (ide_drive_t *drive) +/* start servicing the pipeline stages, starting from tape->next_stage. */ +static void idetape_plug_pipeline(ide_drive_t *drive) { idetape_tape_t *tape = drive->driver_data; @@ -2403,19 +2237,20 @@ static void idetape_insert_pipeline_into_queue (ide_drive_t *drive) if (!idetape_pipeline_active(tape)) { set_bit(IDETAPE_PIPELINE_ACTIVE, &tape->flags); idetape_activate_next_stage(drive); - (void) ide_do_drive_cmd(drive, tape->active_data_request, ide_end); + (void) ide_do_drive_cmd(drive, tape->active_data_rq, ide_end); } } -static void idetape_create_inquiry_cmd (idetape_pc_t *pc) +static void idetape_create_inquiry_cmd(idetape_pc_t *pc) { idetape_init_pc(pc); pc->c[0] = INQUIRY; - pc->c[4] = pc->request_transfer = 254; + pc->c[4] = 254; + pc->request_transfer = 254; pc->callback = &idetape_pc_callback; } -static void idetape_create_rewind_cmd (ide_drive_t *drive, idetape_pc_t *pc) +static void idetape_create_rewind_cmd(ide_drive_t *drive, idetape_pc_t *pc) { idetape_init_pc(pc); pc->c[0] = REZERO_UNIT; @@ -2423,7 +2258,7 @@ static void idetape_create_rewind_cmd (ide_drive_t *drive, idetape_pc_t *pc) pc->callback = &idetape_pc_callback; } -static void idetape_create_erase_cmd (idetape_pc_t *pc) +static void idetape_create_erase_cmd(idetape_pc_t *pc) { idetape_init_pc(pc); pc->c[0] = ERASE; @@ -2432,7 +2267,7 @@ static void idetape_create_erase_cmd (idetape_pc_t *pc) pc->callback = &idetape_pc_callback; } -static void idetape_create_space_cmd (idetape_pc_t *pc,int count, u8 cmd) +static void idetape_create_space_cmd(idetape_pc_t *pc, int count, u8 cmd) { idetape_init_pc(pc); pc->c[0] = SPACE; @@ -2442,89 +2277,87 @@ static void idetape_create_space_cmd (idetape_pc_t *pc,int count, u8 cmd) pc->callback = &idetape_pc_callback; } -static void idetape_wait_first_stage (ide_drive_t *drive) +static void idetape_wait_first_stage(ide_drive_t *drive) { idetape_tape_t *tape = drive->driver_data; unsigned long flags; if (tape->first_stage == NULL) return; - spin_lock_irqsave(&tape->spinlock, flags); + spin_lock_irqsave(&tape->lock, flags); if (tape->active_stage == tape->first_stage) - idetape_wait_for_request(drive, tape->active_data_request); - spin_unlock_irqrestore(&tape->spinlock, flags); + idetape_wait_for_request(drive, tape->active_data_rq); + spin_unlock_irqrestore(&tape->lock, flags); } /* - * idetape_add_chrdev_write_request tries to add a character device - * originated write request to our pipeline. In case we don't succeed, - * we revert to non-pipelined operation mode for this request. + * Try to add a character device originated write request to our pipeline. In + * case we don't succeed, we revert to non-pipelined operation mode for this + * request. In order to accomplish that, we * - * 1. Try to allocate a new pipeline stage. - * 2. If we can't, wait for more and more requests to be serviced - * and try again each time. - * 3. If we still can't allocate a stage, fallback to - * non-pipelined operation mode for this request. + * 1. Try to allocate a new pipeline stage. + * 2. If we can't, wait for more and more requests to be serviced and try again + * each time. + * 3. If we still can't allocate a stage, fallback to non-pipelined operation + * mode for this request. */ -static int idetape_add_chrdev_write_request (ide_drive_t *drive, int blocks) +static int idetape_add_chrdev_write_request(ide_drive_t *drive, int blocks) { idetape_tape_t *tape = drive->driver_data; idetape_stage_t *new_stage; unsigned long flags; struct request *rq; -#if IDETAPE_DEBUG_LOG - if (tape->debug_level >= 3) - printk(KERN_INFO "ide-tape: Reached idetape_add_chrdev_write_request\n"); -#endif /* IDETAPE_DEBUG_LOG */ + debug_log(DBG_CHRDEV, "Enter %s\n", __func__); - /* - * Attempt to allocate a new stage. - * Pay special attention to possible race conditions. - */ + /* Attempt to allocate a new stage. Beware possible race conditions. */ while ((new_stage = idetape_kmalloc_stage(tape)) == NULL) { - spin_lock_irqsave(&tape->spinlock, flags); + spin_lock_irqsave(&tape->lock, flags); if (idetape_pipeline_active(tape)) { - idetape_wait_for_request(drive, tape->active_data_request); - spin_unlock_irqrestore(&tape->spinlock, flags); + idetape_wait_for_request(drive, tape->active_data_rq); + spin_unlock_irqrestore(&tape->lock, flags); } else { - spin_unlock_irqrestore(&tape->spinlock, flags); - idetape_insert_pipeline_into_queue(drive); + spin_unlock_irqrestore(&tape->lock, flags); + idetape_plug_pipeline(drive); if (idetape_pipeline_active(tape)) continue; /* - * Linux is short on memory. Fallback to - * non-pipelined operation mode for this request. + * The machine is short on memory. Fallback to non- + * pipelined operation mode for this request. */ - return idetape_queue_rw_tail(drive, REQ_IDETAPE_WRITE, blocks, tape->merge_stage->bh); + return idetape_queue_rw_tail(drive, REQ_IDETAPE_WRITE, + blocks, tape->merge_stage->bh); } } rq = &new_stage->rq; idetape_init_rq(rq, REQ_IDETAPE_WRITE); /* Doesn't actually matter - We always assume sequential access */ - rq->sector = tape->first_frame_position; - rq->nr_sectors = rq->current_nr_sectors = blocks; + rq->sector = tape->first_frame; + rq->current_nr_sectors = blocks; + rq->nr_sectors = blocks; idetape_switch_buffers(tape, new_stage); idetape_add_stage_tail(drive, new_stage); tape->pipeline_head++; - calculate_speeds(drive); + idetape_calculate_speeds(drive); /* - * Estimate whether the tape has stopped writing by checking - * if our write pipeline is currently empty. If we are not - * writing anymore, wait for the pipeline to be full enough - * (90%) before starting to service requests, so that we will - * be able to keep up with the higher speeds of the tape. + * Estimate whether the tape has stopped writing by checking if our + * write pipeline is currently empty. If we are not writing anymore, + * wait for the pipeline to be almost completely full (90%) before + * starting to service requests, so that we will be able to keep up with + * the higher speeds of the tape. */ if (!idetape_pipeline_active(tape)) { if (tape->nr_stages >= tape->max_stages * 9 / 10 || - tape->nr_stages >= tape->max_stages - tape->uncontrolled_pipeline_head_speed * 3 * 1024 / tape->tape_block_size) { + tape->nr_stages >= tape->max_stages - + tape->uncontrolled_pipeline_head_speed * 3 * 1024 / + tape->blk_size) { tape->measure_insert_time = 1; tape->insert_time = jiffies; tape->insert_size = 0; tape->insert_speed = 0; - idetape_insert_pipeline_into_queue(drive); + idetape_plug_pipeline(drive); } } if (test_and_clear_bit(IDETAPE_PIPELINE_ERROR, &tape->flags)) @@ -2534,31 +2367,32 @@ static int idetape_add_chrdev_write_request (ide_drive_t *drive, int blocks) } /* - * idetape_wait_for_pipeline will wait until all pending pipeline - * requests are serviced. Typically called on device close. + * Wait until all pending pipeline requests are serviced. Typically called on + * device close. */ -static void idetape_wait_for_pipeline (ide_drive_t *drive) +static void idetape_wait_for_pipeline(ide_drive_t *drive) { idetape_tape_t *tape = drive->driver_data; unsigned long flags; while (tape->next_stage || idetape_pipeline_active(tape)) { - idetape_insert_pipeline_into_queue(drive); - spin_lock_irqsave(&tape->spinlock, flags); + idetape_plug_pipeline(drive); + spin_lock_irqsave(&tape->lock, flags); if (idetape_pipeline_active(tape)) - idetape_wait_for_request(drive, tape->active_data_request); - spin_unlock_irqrestore(&tape->spinlock, flags); + idetape_wait_for_request(drive, tape->active_data_rq); + spin_unlock_irqrestore(&tape->lock, flags); } } -static void idetape_empty_write_pipeline (ide_drive_t *drive) +static void idetape_empty_write_pipeline(ide_drive_t *drive) { idetape_tape_t *tape = drive->driver_data; int blocks, min; struct idetape_bh *bh; - if (tape->chrdev_direction != idetape_direction_write) { - printk(KERN_ERR "ide-tape: bug: Trying to empty write pipeline, but we are not writing.\n"); + if (tape->chrdev_dir != IDETAPE_DIR_WRITE) { + printk(KERN_ERR "ide-tape: bug: Trying to empty write pipeline," + " but we are not writing.\n"); return; } if (tape->merge_stage_size > tape->stage_size) { @@ -2566,12 +2400,13 @@ static void idetape_empty_write_pipeline (ide_drive_t *drive) tape->merge_stage_size = tape->stage_size; } if (tape->merge_stage_size) { - blocks = tape->merge_stage_size / tape->tape_block_size; - if (tape->merge_stage_size % tape->tape_block_size) { + blocks = tape->merge_stage_size / tape->blk_size; + if (tape->merge_stage_size % tape->blk_size) { unsigned int i; blocks++; - i = tape->tape_block_size - tape->merge_stage_size % tape->tape_block_size; + i = tape->blk_size - tape->merge_stage_size % + tape->blk_size; bh = tape->bh->b_reqnext; while (bh) { atomic_set(&bh->b_count, 0); @@ -2580,12 +2415,14 @@ static void idetape_empty_write_pipeline (ide_drive_t *drive) bh = tape->bh; while (i) { if (bh == NULL) { - - printk(KERN_INFO "ide-tape: bug, bh NULL\n"); + printk(KERN_INFO "ide-tape: bug," + " bh NULL\n"); break; } - min = min(i, (unsigned int)(bh->b_size - atomic_read(&bh->b_count))); - memset(bh->b_data + atomic_read(&bh->b_count), 0, min); + min = min(i, (unsigned int)(bh->b_size - + atomic_read(&bh->b_count))); + memset(bh->b_data + atomic_read(&bh->b_count), + 0, min); atomic_add(min, &bh->b_count); i -= min; bh = bh->b_reqnext; @@ -2600,13 +2437,13 @@ static void idetape_empty_write_pipeline (ide_drive_t *drive) tape->merge_stage = NULL; } clear_bit(IDETAPE_PIPELINE_ERROR, &tape->flags); - tape->chrdev_direction = idetape_direction_none; + tape->chrdev_dir = IDETAPE_DIR_NONE; /* - * On the next backup, perform the feedback loop again. - * (I don't want to keep sense information between backups, - * as some systems are constantly on, and the system load - * can be totally different on the next backup). + * On the next backup, perform the feedback loop again. (I don't want to + * keep sense information between backups, as some systems are + * constantly on, and the system load can be totally different on the + * next backup). */ tape->max_stages = tape->min_pipeline; if (tape->first_stage != NULL || @@ -2621,21 +2458,25 @@ static void idetape_empty_write_pipeline (ide_drive_t *drive) } } -static void idetape_restart_speed_control (ide_drive_t *drive) +static void idetape_restart_speed_control(ide_drive_t *drive) { idetape_tape_t *tape = drive->driver_data; tape->restart_speed_control_req = 0; tape->pipeline_head = 0; - tape->controlled_last_pipeline_head = tape->uncontrolled_last_pipeline_head = 0; - tape->controlled_previous_pipeline_head = tape->uncontrolled_previous_pipeline_head = 0; - tape->pipeline_head_speed = tape->controlled_pipeline_head_speed = 5000; + tape->controlled_last_pipeline_head = 0; + tape->controlled_previous_pipeline_head = 0; + tape->uncontrolled_previous_pipeline_head = 0; + tape->controlled_pipeline_head_speed = 5000; + tape->pipeline_head_speed = 5000; tape->uncontrolled_pipeline_head_speed = 0; - tape->controlled_pipeline_head_time = tape->uncontrolled_pipeline_head_time = jiffies; - tape->controlled_previous_head_time = tape->uncontrolled_previous_head_time = jiffies; + tape->controlled_pipeline_head_time = + tape->uncontrolled_pipeline_head_time = jiffies; + tape->controlled_previous_head_time = + tape->uncontrolled_previous_head_time = jiffies; } -static int idetape_initiate_read (ide_drive_t *drive, int max_stages) +static int idetape_init_read(ide_drive_t *drive, int max_stages) { idetape_tape_t *tape = drive->driver_data; idetape_stage_t *new_stage; @@ -2644,32 +2485,35 @@ static int idetape_initiate_read (ide_drive_t *drive, int max_stages) u16 blocks = *(u16 *)&tape->caps[12]; /* Initialize read operation */ - if (tape->chrdev_direction != idetape_direction_read) { - if (tape->chrdev_direction == idetape_direction_write) { + if (tape->chrdev_dir != IDETAPE_DIR_READ) { + if (tape->chrdev_dir == IDETAPE_DIR_WRITE) { idetape_empty_write_pipeline(drive); idetape_flush_tape_buffers(drive); } if (tape->merge_stage || tape->merge_stage_size) { - printk (KERN_ERR "ide-tape: merge_stage_size should be 0 now\n"); + printk(KERN_ERR "ide-tape: merge_stage_size should be" + " 0 now\n"); tape->merge_stage_size = 0; } - if ((tape->merge_stage = __idetape_kmalloc_stage(tape, 0, 0)) == NULL) + tape->merge_stage = __idetape_kmalloc_stage(tape, 0, 0); + if (!tape->merge_stage) return -ENOMEM; - tape->chrdev_direction = idetape_direction_read; + tape->chrdev_dir = IDETAPE_DIR_READ; /* - * Issue a read 0 command to ensure that DSC handshake - * is switched from completion mode to buffer available - * mode. - * No point in issuing this if DSC overlap isn't supported, - * some drives (Seagate STT3401A) will return an error. + * Issue a read 0 command to ensure that DSC handshake is + * switched from completion mode to buffer available mode. + * No point in issuing this if DSC overlap isn't supported, some + * drives (Seagate STT3401A) will return an error. */ if (drive->dsc_overlap) { - bytes_read = idetape_queue_rw_tail(drive, REQ_IDETAPE_READ, 0, tape->merge_stage->bh); + bytes_read = idetape_queue_rw_tail(drive, + REQ_IDETAPE_READ, 0, + tape->merge_stage->bh); if (bytes_read < 0) { __idetape_kfree_stage(tape->merge_stage); tape->merge_stage = NULL; - tape->chrdev_direction = idetape_direction_none; + tape->chrdev_dir = IDETAPE_DIR_NONE; return bytes_read; } } @@ -2677,8 +2521,9 @@ static int idetape_initiate_read (ide_drive_t *drive, int max_stages) if (tape->restart_speed_control_req) idetape_restart_speed_control(drive); idetape_init_rq(&rq, REQ_IDETAPE_READ); - rq.sector = tape->first_frame_position; - rq.nr_sectors = rq.current_nr_sectors = blocks; + rq.sector = tape->first_frame; + rq.nr_sectors = blocks; + rq.current_nr_sectors = blocks; if (!test_bit(IDETAPE_PIPELINE_ERROR, &tape->flags) && tape->nr_stages < max_stages) { new_stage = idetape_kmalloc_stage(tape); @@ -2696,50 +2541,43 @@ static int idetape_initiate_read (ide_drive_t *drive, int max_stages) tape->insert_time = jiffies; tape->insert_size = 0; tape->insert_speed = 0; - idetape_insert_pipeline_into_queue(drive); + idetape_plug_pipeline(drive); } } return 0; } /* - * idetape_add_chrdev_read_request is called from idetape_chrdev_read - * to service a character device read request and add read-ahead - * requests to our pipeline. + * Called from idetape_chrdev_read() to service a character device read request + * and add read-ahead requests to our pipeline. */ -static int idetape_add_chrdev_read_request (ide_drive_t *drive,int blocks) +static int idetape_add_chrdev_read_request(ide_drive_t *drive, int blocks) { idetape_tape_t *tape = drive->driver_data; unsigned long flags; struct request *rq_ptr; int bytes_read; -#if IDETAPE_DEBUG_LOG - if (tape->debug_level >= 4) - printk(KERN_INFO "ide-tape: Reached idetape_add_chrdev_read_request, %d blocks\n", blocks); -#endif /* IDETAPE_DEBUG_LOG */ + debug_log(DBG_PROCS, "Enter %s, %d blocks\n", __func__, blocks); - /* - * If we are at a filemark, return a read length of 0 - */ + /* If we are at a filemark, return a read length of 0 */ if (test_bit(IDETAPE_FILEMARK, &tape->flags)) return 0; - /* - * Wait for the next block to be available at the head - * of the pipeline - */ - idetape_initiate_read(drive, tape->max_stages); + /* Wait for the next block to reach the head of the pipeline. */ + idetape_init_read(drive, tape->max_stages); if (tape->first_stage == NULL) { if (test_bit(IDETAPE_PIPELINE_ERROR, &tape->flags)) return 0; - return idetape_queue_rw_tail(drive, REQ_IDETAPE_READ, blocks, tape->merge_stage->bh); + return idetape_queue_rw_tail(drive, REQ_IDETAPE_READ, blocks, + tape->merge_stage->bh); } idetape_wait_first_stage(drive); rq_ptr = &tape->first_stage->rq; - bytes_read = tape->tape_block_size * (rq_ptr->nr_sectors - rq_ptr->current_nr_sectors); - rq_ptr->nr_sectors = rq_ptr->current_nr_sectors = 0; - + bytes_read = tape->blk_size * (rq_ptr->nr_sectors - + rq_ptr->current_nr_sectors); + rq_ptr->nr_sectors = 0; + rq_ptr->current_nr_sectors = 0; if (rq_ptr->errors == IDETAPE_ERROR_EOD) return 0; @@ -2747,43 +2585,46 @@ static int idetape_add_chrdev_read_request (ide_drive_t *drive,int blocks) idetape_switch_buffers(tape, tape->first_stage); if (rq_ptr->errors == IDETAPE_ERROR_FILEMARK) set_bit(IDETAPE_FILEMARK, &tape->flags); - spin_lock_irqsave(&tape->spinlock, flags); + spin_lock_irqsave(&tape->lock, flags); idetape_remove_stage_head(drive); - spin_unlock_irqrestore(&tape->spinlock, flags); + spin_unlock_irqrestore(&tape->lock, flags); tape->pipeline_head++; - calculate_speeds(drive); + idetape_calculate_speeds(drive); } - if (bytes_read > blocks * tape->tape_block_size) { - printk(KERN_ERR "ide-tape: bug: trying to return more bytes than requested\n"); - bytes_read = blocks * tape->tape_block_size; + if (bytes_read > blocks * tape->blk_size) { + printk(KERN_ERR "ide-tape: bug: trying to return more bytes" + " than requested\n"); + bytes_read = blocks * tape->blk_size; } return (bytes_read); } -static void idetape_pad_zeros (ide_drive_t *drive, int bcount) +static void idetape_pad_zeros(ide_drive_t *drive, int bcount) { idetape_tape_t *tape = drive->driver_data; struct idetape_bh *bh; int blocks; - + while (bcount) { unsigned int count; bh = tape->merge_stage->bh; count = min(tape->stage_size, bcount); bcount -= count; - blocks = count / tape->tape_block_size; + blocks = count / tape->blk_size; while (count) { - atomic_set(&bh->b_count, min(count, (unsigned int)bh->b_size)); + atomic_set(&bh->b_count, + min(count, (unsigned int)bh->b_size)); memset(bh->b_data, 0, atomic_read(&bh->b_count)); count -= atomic_read(&bh->b_count); bh = bh->b_reqnext; } - idetape_queue_rw_tail(drive, REQ_IDETAPE_WRITE, blocks, tape->merge_stage->bh); + idetape_queue_rw_tail(drive, REQ_IDETAPE_WRITE, blocks, + tape->merge_stage->bh); } } -static int idetape_pipeline_size (ide_drive_t *drive) +static int idetape_pipeline_size(ide_drive_t *drive) { idetape_tape_t *tape = drive->driver_data; idetape_stage_t *stage; @@ -2794,9 +2635,10 @@ static int idetape_pipeline_size (ide_drive_t *drive) stage = tape->first_stage; while (stage != NULL) { rq = &stage->rq; - size += tape->tape_block_size * (rq->nr_sectors-rq->current_nr_sectors); + size += tape->blk_size * (rq->nr_sectors - + rq->current_nr_sectors); if (rq->errors == IDETAPE_ERROR_FILEMARK) - size += tape->tape_block_size; + size += tape->blk_size; stage = stage->next; } size += tape->merge_stage_size; @@ -2804,20 +2646,18 @@ static int idetape_pipeline_size (ide_drive_t *drive) } /* - * Rewinds the tape to the Beginning Of the current Partition (BOP). - * - * We currently support only one partition. - */ -static int idetape_rewind_tape (ide_drive_t *drive) + * Rewinds the tape to the Beginning Of the current Partition (BOP). We + * currently support only one partition. + */ +static int idetape_rewind_tape(ide_drive_t *drive) { int retval; idetape_pc_t pc; -#if IDETAPE_DEBUG_LOG - idetape_tape_t *tape = drive->driver_data; - if (tape->debug_level >= 2) - printk(KERN_INFO "ide-tape: Reached idetape_rewind_tape\n"); -#endif /* IDETAPE_DEBUG_LOG */ - + idetape_tape_t *tape; + tape = drive->driver_data; + + debug_log(DBG_SENSE, "Enter %s\n", __func__); + idetape_create_rewind_cmd(drive, &pc); retval = idetape_queue_pc_tail(drive, &pc); if (retval) @@ -2830,14 +2670,9 @@ static int idetape_rewind_tape (ide_drive_t *drive) return 0; } -/* - * Our special ide-tape ioctl's. - * - * Currently there aren't any ioctl's. - * mtio.h compatible commands should be issued to the character device - * interface. - */ -static int idetape_blkdev_ioctl(ide_drive_t *drive, unsigned int cmd, unsigned long arg) +/* mtio.h compatible commands should be issued to the chrdev interface. */ +static int idetape_blkdev_ioctl(ide_drive_t *drive, unsigned int cmd, + unsigned long arg) { idetape_tape_t *tape = drive->driver_data; void __user *argp = (void __user *)arg; @@ -2848,44 +2683,41 @@ static int idetape_blkdev_ioctl(ide_drive_t *drive, unsigned int cmd, unsigned l int nr_stages; } config; -#if IDETAPE_DEBUG_LOG - if (tape->debug_level >= 4) - printk(KERN_INFO "ide-tape: Reached idetape_blkdev_ioctl\n"); -#endif /* IDETAPE_DEBUG_LOG */ + debug_log(DBG_PROCS, "Enter %s\n", __func__); + switch (cmd) { - case 0x0340: - if (copy_from_user(&config, argp, sizeof(config))) - return -EFAULT; - tape->best_dsc_rw_frequency = config.dsc_rw_frequency; - tape->max_stages = config.nr_stages; - break; - case 0x0350: - config.dsc_rw_frequency = (int) tape->best_dsc_rw_frequency; - config.nr_stages = tape->max_stages; - if (copy_to_user(argp, &config, sizeof(config))) - return -EFAULT; - break; - default: - return -EIO; + case 0x0340: + if (copy_from_user(&config, argp, sizeof(config))) + return -EFAULT; + tape->best_dsc_rw_freq = config.dsc_rw_frequency; + tape->max_stages = config.nr_stages; + break; + case 0x0350: + config.dsc_rw_frequency = (int) tape->best_dsc_rw_freq; + config.nr_stages = tape->max_stages; + if (copy_to_user(argp, &config, sizeof(config))) + return -EFAULT; + break; + default: + return -EIO; } return 0; } /* - * idetape_space_over_filemarks is now a bit more complicated than just - * passing the command to the tape since we may have crossed some - * filemarks during our pipelined read-ahead mode. - * - * As a minor side effect, the pipeline enables us to support MTFSFM when - * the filemark is in our internal pipeline even if the tape doesn't - * support spacing over filemarks in the reverse direction. + * The function below is now a bit more complicated than just passing the + * command to the tape since we may have crossed some filemarks during our + * pipelined read-ahead mode. As a minor side effect, the pipeline enables us to + * support MTFSFM when the filemark is in our internal pipeline even if the tape + * doesn't support spacing over filemarks in the reverse direction. */ -static int idetape_space_over_filemarks (ide_drive_t *drive,short mt_op,int mt_count) +static int idetape_space_over_filemarks(ide_drive_t *drive, short mt_op, + int mt_count) { idetape_tape_t *tape = drive->driver_data; idetape_pc_t pc; unsigned long flags; - int retval,count=0; + int retval, count = 0; int sprev = !!(tape->caps[4] & 0x20); if (mt_count == 0) @@ -2893,14 +2725,11 @@ static int idetape_space_over_filemarks (ide_drive_t *drive,short mt_op,int mt_c if (MTBSF == mt_op || MTBSFM == mt_op) { if (!sprev) return -EIO; - mt_count = - mt_count; + mt_count = -mt_count; } - if (tape->chrdev_direction == idetape_direction_read) { - /* - * We have a read-ahead buffer. Scan it for crossed - * filemarks. - */ + if (tape->chrdev_dir == IDETAPE_DIR_READ) { + /* its a read-ahead buffer, scan it for crossed filemarks. */ tape->merge_stage_size = 0; if (test_and_clear_bit(IDETAPE_FILEMARK, &tape->flags)) ++count; @@ -2910,24 +2739,27 @@ static int idetape_space_over_filemarks (ide_drive_t *drive,short mt_op,int mt_c set_bit(IDETAPE_FILEMARK, &tape->flags); return 0; } - spin_lock_irqsave(&tape->spinlock, flags); + spin_lock_irqsave(&tape->lock, flags); if (tape->first_stage == tape->active_stage) { /* - * We have reached the active stage in the read pipeline. - * There is no point in allowing the drive to continue - * reading any farther, so we stop the pipeline. + * We have reached the active stage in the read + * pipeline. There is no point in allowing the + * drive to continue reading any farther, so we + * stop the pipeline. * - * This section should be moved to a separate subroutine, - * because a similar function is performed in - * __idetape_discard_read_pipeline(), for example. + * This section should be moved to a separate + * subroutine because similar operations are + * done in __idetape_discard_read_pipeline(), + * for example. */ tape->next_stage = NULL; - spin_unlock_irqrestore(&tape->spinlock, flags); + spin_unlock_irqrestore(&tape->lock, flags); idetape_wait_first_stage(drive); tape->next_stage = tape->first_stage->next; } else - spin_unlock_irqrestore(&tape->spinlock, flags); - if (tape->first_stage->rq.errors == IDETAPE_ERROR_FILEMARK) + spin_unlock_irqrestore(&tape->lock, flags); + if (tape->first_stage->rq.errors == + IDETAPE_ERROR_FILEMARK) ++count; idetape_remove_stage_head(drive); } @@ -2935,73 +2767,74 @@ static int idetape_space_over_filemarks (ide_drive_t *drive,short mt_op,int mt_c } /* - * The filemark was not found in our internal pipeline. - * Now we can issue the space command. + * The filemark was not found in our internal pipeline; now we can issue + * the space command. */ switch (mt_op) { - case MTFSF: - case MTBSF: - idetape_create_space_cmd(&pc,mt_count-count,IDETAPE_SPACE_OVER_FILEMARK); - return (idetape_queue_pc_tail(drive, &pc)); - case MTFSFM: - case MTBSFM: - if (!sprev) - return (-EIO); - retval = idetape_space_over_filemarks(drive, MTFSF, mt_count-count); - if (retval) return (retval); - count = (MTBSFM == mt_op ? 1 : -1); - return (idetape_space_over_filemarks(drive, MTFSF, count)); - default: - printk(KERN_ERR "ide-tape: MTIO operation %d not supported\n",mt_op); - return (-EIO); + case MTFSF: + case MTBSF: + idetape_create_space_cmd(&pc, mt_count - count, + IDETAPE_SPACE_OVER_FILEMARK); + return idetape_queue_pc_tail(drive, &pc); + case MTFSFM: + case MTBSFM: + if (!sprev) + return -EIO; + retval = idetape_space_over_filemarks(drive, MTFSF, + mt_count - count); + if (retval) + return retval; + count = (MTBSFM == mt_op ? 1 : -1); + return idetape_space_over_filemarks(drive, MTFSF, count); + default: + printk(KERN_ERR "ide-tape: MTIO operation %d not supported\n", + mt_op); + return -EIO; } } - /* - * Our character device read / write functions. + * Our character device read / write functions. * - * The tape is optimized to maximize throughput when it is transferring - * an integral number of the "continuous transfer limit", which is - * a parameter of the specific tape (26 KB on my particular tape). - * (32 kB for Onstream) + * The tape is optimized to maximize throughput when it is transferring an + * integral number of the "continuous transfer limit", which is a parameter of + * the specific tape (26kB on my particular tape, 32kB for Onstream). * - * As of version 1.3 of the driver, the character device provides an - * abstract continuous view of the media - any mix of block sizes (even 1 - * byte) on the same backup/restore procedure is supported. The driver - * will internally convert the requests to the recommended transfer unit, - * so that an unmatch between the user's block size to the recommended - * size will only result in a (slightly) increased driver overhead, but - * will no longer hit performance. - * This is not applicable to Onstream. + * As of version 1.3 of the driver, the character device provides an abstract + * continuous view of the media - any mix of block sizes (even 1 byte) on the + * same backup/restore procedure is supported. The driver will internally + * convert the requests to the recommended transfer unit, so that an unmatch + * between the user's block size to the recommended size will only result in a + * (slightly) increased driver overhead, but will no longer hit performance. + * This is not applicable to Onstream. */ -static ssize_t idetape_chrdev_read (struct file *file, char __user *buf, - size_t count, loff_t *ppos) +static ssize_t idetape_chrdev_read(struct file *file, char __user *buf, + size_t count, loff_t *ppos) { struct ide_tape_obj *tape = ide_tape_f(file); ide_drive_t *drive = tape->drive; - ssize_t bytes_read,temp, actually_read = 0, rc; + ssize_t bytes_read, temp, actually_read = 0, rc; ssize_t ret = 0; u16 ctl = *(u16 *)&tape->caps[12]; -#if IDETAPE_DEBUG_LOG - if (tape->debug_level >= 3) - printk(KERN_INFO "ide-tape: Reached idetape_chrdev_read, count %Zd\n", count); -#endif /* IDETAPE_DEBUG_LOG */ + debug_log(DBG_CHRDEV, "Enter %s, count %Zd\n", __func__, count); - if (tape->chrdev_direction != idetape_direction_read) { + if (tape->chrdev_dir != IDETAPE_DIR_READ) { if (test_bit(IDETAPE_DETECT_BS, &tape->flags)) - if (count > tape->tape_block_size && - (count % tape->tape_block_size) == 0) - tape->user_bs_factor = count / tape->tape_block_size; + if (count > tape->blk_size && + (count % tape->blk_size) == 0) + tape->user_bs_factor = count / tape->blk_size; } - if ((rc = idetape_initiate_read(drive, tape->max_stages)) < 0) + rc = idetape_init_read(drive, tape->max_stages); + if (rc < 0) return rc; if (count == 0) return (0); if (tape->merge_stage_size) { - actually_read = min((unsigned int)(tape->merge_stage_size), (unsigned int)count); - if (idetape_copy_stage_to_user(tape, buf, tape->merge_stage, actually_read)) + actually_read = min((unsigned int)(tape->merge_stage_size), + (unsigned int)count); + if (idetape_copy_stage_to_user(tape, buf, tape->merge_stage, + actually_read)) ret = -EFAULT; buf += actually_read; tape->merge_stage_size -= actually_read; @@ -3011,7 +2844,8 @@ static ssize_t idetape_chrdev_read (struct file *file, char __user *buf, bytes_read = idetape_add_chrdev_read_request(drive, ctl); if (bytes_read <= 0) goto finish; - if (idetape_copy_stage_to_user(tape, buf, tape->merge_stage, bytes_read)) + if (idetape_copy_stage_to_user(tape, buf, tape->merge_stage, + bytes_read)) ret = -EFAULT; buf += bytes_read; count -= bytes_read; @@ -3022,25 +2856,24 @@ static ssize_t idetape_chrdev_read (struct file *file, char __user *buf, if (bytes_read <= 0) goto finish; temp = min((unsigned long)count, (unsigned long)bytes_read); - if (idetape_copy_stage_to_user(tape, buf, tape->merge_stage, temp)) + if (idetape_copy_stage_to_user(tape, buf, tape->merge_stage, + temp)) ret = -EFAULT; actually_read += temp; tape->merge_stage_size = bytes_read-temp; } finish: if (!actually_read && test_bit(IDETAPE_FILEMARK, &tape->flags)) { -#if IDETAPE_DEBUG_LOG - if (tape->debug_level >= 2) - printk(KERN_INFO "ide-tape: %s: spacing over filemark\n", tape->name); -#endif + debug_log(DBG_SENSE, "%s: spacing over filemark\n", tape->name); + idetape_space_over_filemarks(drive, MTFSF, 1); return 0; } - return (ret) ? ret : actually_read; + return ret ? ret : actually_read; } -static ssize_t idetape_chrdev_write (struct file *file, const char __user *buf, +static ssize_t idetape_chrdev_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) { struct ide_tape_obj *tape = ide_tape_f(file); @@ -3053,39 +2886,37 @@ static ssize_t idetape_chrdev_write (struct file *file, const char __user *buf, if (tape->write_prot) return -EACCES; -#if IDETAPE_DEBUG_LOG - if (tape->debug_level >= 3) - printk(KERN_INFO "ide-tape: Reached idetape_chrdev_write, " - "count %Zd\n", count); -#endif /* IDETAPE_DEBUG_LOG */ + debug_log(DBG_CHRDEV, "Enter %s, count %Zd\n", __func__, count); /* Initialize write operation */ - if (tape->chrdev_direction != idetape_direction_write) { - if (tape->chrdev_direction == idetape_direction_read) + if (tape->chrdev_dir != IDETAPE_DIR_WRITE) { + if (tape->chrdev_dir == IDETAPE_DIR_READ) idetape_discard_read_pipeline(drive, 1); if (tape->merge_stage || tape->merge_stage_size) { printk(KERN_ERR "ide-tape: merge_stage_size " "should be 0 now\n"); tape->merge_stage_size = 0; } - if ((tape->merge_stage = __idetape_kmalloc_stage(tape, 0, 0)) == NULL) + tape->merge_stage = __idetape_kmalloc_stage(tape, 0, 0); + if (!tape->merge_stage) return -ENOMEM; - tape->chrdev_direction = idetape_direction_write; + tape->chrdev_dir = IDETAPE_DIR_WRITE; idetape_init_merge_stage(tape); /* - * Issue a write 0 command to ensure that DSC handshake - * is switched from completion mode to buffer available - * mode. - * No point in issuing this if DSC overlap isn't supported, - * some drives (Seagate STT3401A) will return an error. + * Issue a write 0 command to ensure that DSC handshake is + * switched from completion mode to buffer available mode. No + * point in issuing this if DSC overlap isn't supported, some + * drives (Seagate STT3401A) will return an error. */ if (drive->dsc_overlap) { - ssize_t retval = idetape_queue_rw_tail(drive, REQ_IDETAPE_WRITE, 0, tape->merge_stage->bh); + ssize_t retval = idetape_queue_rw_tail(drive, + REQ_IDETAPE_WRITE, 0, + tape->merge_stage->bh); if (retval < 0) { __idetape_kfree_stage(tape->merge_stage); tape->merge_stage = NULL; - tape->chrdev_direction = idetape_direction_none; + tape->chrdev_dir = IDETAPE_DIR_NONE; return retval; } } @@ -3096,11 +2927,14 @@ static ssize_t idetape_chrdev_write (struct file *file, const char __user *buf, idetape_restart_speed_control(drive); if (tape->merge_stage_size) { if (tape->merge_stage_size >= tape->stage_size) { - printk(KERN_ERR "ide-tape: bug: merge buffer too big\n"); + printk(KERN_ERR "ide-tape: bug: merge buf too big\n"); tape->merge_stage_size = 0; } - actually_written = min((unsigned int)(tape->stage_size - tape->merge_stage_size), (unsigned int)count); - if (idetape_copy_stage_from_user(tape, tape->merge_stage, buf, actually_written)) + actually_written = min((unsigned int) + (tape->stage_size - tape->merge_stage_size), + (unsigned int)count); + if (idetape_copy_stage_from_user(tape, tape->merge_stage, buf, + actually_written)) ret = -EFAULT; buf += actually_written; tape->merge_stage_size += actually_written; @@ -3116,7 +2950,8 @@ static ssize_t idetape_chrdev_write (struct file *file, const char __user *buf, } while (count >= tape->stage_size) { ssize_t retval; - if (idetape_copy_stage_from_user(tape, tape->merge_stage, buf, tape->stage_size)) + if (idetape_copy_stage_from_user(tape, tape->merge_stage, buf, + tape->stage_size)) ret = -EFAULT; buf += tape->stage_size; count -= tape->stage_size; @@ -3127,14 +2962,15 @@ static ssize_t idetape_chrdev_write (struct file *file, const char __user *buf, } if (count) { actually_written += count; - if (idetape_copy_stage_from_user(tape, tape->merge_stage, buf, count)) + if (idetape_copy_stage_from_user(tape, tape->merge_stage, buf, + count)) ret = -EFAULT; tape->merge_stage_size += count; } - return (ret) ? ret : actually_written; + return ret ? ret : actually_written; } -static int idetape_write_filemark (ide_drive_t *drive) +static int idetape_write_filemark(ide_drive_t *drive) { idetape_pc_t pc; @@ -3165,113 +3001,117 @@ static int idetape_mtioctop(ide_drive_t *drive, short mt_op, int mt_count) { idetape_tape_t *tape = drive->driver_data; idetape_pc_t pc; - int i,retval; + int i, retval; -#if IDETAPE_DEBUG_LOG - if (tape->debug_level >= 1) - printk(KERN_INFO "ide-tape: Handling MTIOCTOP ioctl: " - "mt_op=%d, mt_count=%d\n", mt_op, mt_count); -#endif /* IDETAPE_DEBUG_LOG */ - /* - * Commands which need our pipelined read-ahead stages. - */ + debug_log(DBG_ERR, "Handling MTIOCTOP ioctl: mt_op=%d, mt_count=%d\n", + mt_op, mt_count); + + /* Commands which need our pipelined read-ahead stages. */ switch (mt_op) { - case MTFSF: - case MTFSFM: - case MTBSF: - case MTBSFM: - if (!mt_count) - return (0); - return (idetape_space_over_filemarks(drive,mt_op,mt_count)); - default: - break; + case MTFSF: + case MTFSFM: + case MTBSF: + case MTBSFM: + if (!mt_count) + return 0; + return idetape_space_over_filemarks(drive, mt_op, mt_count); + default: + break; } + switch (mt_op) { - case MTWEOF: - if (tape->write_prot) - return -EACCES; - idetape_discard_read_pipeline(drive, 1); - for (i = 0; i < mt_count; i++) { - retval = idetape_write_filemark(drive); - if (retval) - return retval; - } - return (0); - case MTREW: - idetape_discard_read_pipeline(drive, 0); - if (idetape_rewind_tape(drive)) + case MTWEOF: + if (tape->write_prot) + return -EACCES; + idetape_discard_read_pipeline(drive, 1); + for (i = 0; i < mt_count; i++) { + retval = idetape_write_filemark(drive); + if (retval) + return retval; + } + return 0; + case MTREW: + idetape_discard_read_pipeline(drive, 0); + if (idetape_rewind_tape(drive)) + return -EIO; + return 0; + case MTLOAD: + idetape_discard_read_pipeline(drive, 0); + idetape_create_load_unload_cmd(drive, &pc, + IDETAPE_LU_LOAD_MASK); + return idetape_queue_pc_tail(drive, &pc); + case MTUNLOAD: + case MTOFFL: + /* + * If door is locked, attempt to unlock before + * attempting to eject. + */ + if (tape->door_locked) { + if (idetape_create_prevent_cmd(drive, &pc, 0)) + if (!idetape_queue_pc_tail(drive, &pc)) + tape->door_locked = DOOR_UNLOCKED; + } + idetape_discard_read_pipeline(drive, 0); + idetape_create_load_unload_cmd(drive, &pc, + !IDETAPE_LU_LOAD_MASK); + retval = idetape_queue_pc_tail(drive, &pc); + if (!retval) + clear_bit(IDETAPE_MEDIUM_PRESENT, &tape->flags); + return retval; + case MTNOP: + idetape_discard_read_pipeline(drive, 0); + return idetape_flush_tape_buffers(drive); + case MTRETEN: + idetape_discard_read_pipeline(drive, 0); + idetape_create_load_unload_cmd(drive, &pc, + IDETAPE_LU_RETENSION_MASK | IDETAPE_LU_LOAD_MASK); + return idetape_queue_pc_tail(drive, &pc); + case MTEOM: + idetape_create_space_cmd(&pc, 0, IDETAPE_SPACE_TO_EOD); + return idetape_queue_pc_tail(drive, &pc); + case MTERASE: + (void)idetape_rewind_tape(drive); + idetape_create_erase_cmd(&pc); + return idetape_queue_pc_tail(drive, &pc); + case MTSETBLK: + if (mt_count) { + if (mt_count < tape->blk_size || + mt_count % tape->blk_size) return -EIO; + tape->user_bs_factor = mt_count / tape->blk_size; + clear_bit(IDETAPE_DETECT_BS, &tape->flags); + } else + set_bit(IDETAPE_DETECT_BS, &tape->flags); + return 0; + case MTSEEK: + idetape_discard_read_pipeline(drive, 0); + return idetape_position_tape(drive, + mt_count * tape->user_bs_factor, tape->partition, 0); + case MTSETPART: + idetape_discard_read_pipeline(drive, 0); + return idetape_position_tape(drive, 0, mt_count, 0); + case MTFSR: + case MTBSR: + case MTLOCK: + if (!idetape_create_prevent_cmd(drive, &pc, 1)) return 0; - case MTLOAD: - idetape_discard_read_pipeline(drive, 0); - idetape_create_load_unload_cmd(drive, &pc, IDETAPE_LU_LOAD_MASK); - return (idetape_queue_pc_tail(drive, &pc)); - case MTUNLOAD: - case MTOFFL: - /* - * If door is locked, attempt to unlock before - * attempting to eject. - */ - if (tape->door_locked) { - if (idetape_create_prevent_cmd(drive, &pc, 0)) - if (!idetape_queue_pc_tail(drive, &pc)) - tape->door_locked = DOOR_UNLOCKED; - } - idetape_discard_read_pipeline(drive, 0); - idetape_create_load_unload_cmd(drive, &pc,!IDETAPE_LU_LOAD_MASK); - retval = idetape_queue_pc_tail(drive, &pc); - if (!retval) - clear_bit(IDETAPE_MEDIUM_PRESENT, &tape->flags); + retval = idetape_queue_pc_tail(drive, &pc); + if (retval) return retval; - case MTNOP: - idetape_discard_read_pipeline(drive, 0); - return (idetape_flush_tape_buffers(drive)); - case MTRETEN: - idetape_discard_read_pipeline(drive, 0); - idetape_create_load_unload_cmd(drive, &pc,IDETAPE_LU_RETENSION_MASK | IDETAPE_LU_LOAD_MASK); - return (idetape_queue_pc_tail(drive, &pc)); - case MTEOM: - idetape_create_space_cmd(&pc, 0, IDETAPE_SPACE_TO_EOD); - return (idetape_queue_pc_tail(drive, &pc)); - case MTERASE: - (void) idetape_rewind_tape(drive); - idetape_create_erase_cmd(&pc); - return (idetape_queue_pc_tail(drive, &pc)); - case MTSETBLK: - if (mt_count) { - if (mt_count < tape->tape_block_size || mt_count % tape->tape_block_size) - return -EIO; - tape->user_bs_factor = mt_count / tape->tape_block_size; - clear_bit(IDETAPE_DETECT_BS, &tape->flags); - } else - set_bit(IDETAPE_DETECT_BS, &tape->flags); - return 0; - case MTSEEK: - idetape_discard_read_pipeline(drive, 0); - return idetape_position_tape(drive, mt_count * tape->user_bs_factor, tape->partition, 0); - case MTSETPART: - idetape_discard_read_pipeline(drive, 0); - return (idetape_position_tape(drive, 0, mt_count, 0)); - case MTFSR: - case MTBSR: - case MTLOCK: - if (!idetape_create_prevent_cmd(drive, &pc, 1)) - return 0; - retval = idetape_queue_pc_tail(drive, &pc); - if (retval) return retval; - tape->door_locked = DOOR_EXPLICITLY_LOCKED; - return 0; - case MTUNLOCK: - if (!idetape_create_prevent_cmd(drive, &pc, 0)) - return 0; - retval = idetape_queue_pc_tail(drive, &pc); - if (retval) return retval; - tape->door_locked = DOOR_UNLOCKED; + tape->door_locked = DOOR_EXPLICITLY_LOCKED; + return 0; + case MTUNLOCK: + if (!idetape_create_prevent_cmd(drive, &pc, 0)) return 0; - default: - printk(KERN_ERR "ide-tape: MTIO operation %d not " - "supported\n", mt_op); - return (-EIO); + retval = idetape_queue_pc_tail(drive, &pc); + if (retval) + return retval; + tape->door_locked = DOOR_UNLOCKED; + return 0; + default: + printk(KERN_ERR "ide-tape: MTIO operation %d not supported\n", + mt_op); + return -EIO; } } @@ -3288,50 +3128,51 @@ static int idetape_chrdev_ioctl(struct inode *inode, struct file *file, struct mtop mtop; struct mtget mtget; struct mtpos mtpos; - int block_offset = 0, position = tape->first_frame_position; + int block_offset = 0, position = tape->first_frame; void __user *argp = (void __user *)arg; -#if IDETAPE_DEBUG_LOG - if (tape->debug_level >= 3) - printk(KERN_INFO "ide-tape: Reached idetape_chrdev_ioctl, " - "cmd=%u\n", cmd); -#endif /* IDETAPE_DEBUG_LOG */ + debug_log(DBG_CHRDEV, "Enter %s, cmd=%u\n", __func__, cmd); tape->restart_speed_control_req = 1; - if (tape->chrdev_direction == idetape_direction_write) { + if (tape->chrdev_dir == IDETAPE_DIR_WRITE) { idetape_empty_write_pipeline(drive); idetape_flush_tape_buffers(drive); } if (cmd == MTIOCGET || cmd == MTIOCPOS) { - block_offset = idetape_pipeline_size(drive) / (tape->tape_block_size * tape->user_bs_factor); - if ((position = idetape_read_position(drive)) < 0) + block_offset = idetape_pipeline_size(drive) / + (tape->blk_size * tape->user_bs_factor); + position = idetape_read_position(drive); + if (position < 0) return -EIO; } switch (cmd) { - case MTIOCTOP: - if (copy_from_user(&mtop, argp, sizeof (struct mtop))) - return -EFAULT; - return (idetape_mtioctop(drive,mtop.mt_op,mtop.mt_count)); - case MTIOCGET: - memset(&mtget, 0, sizeof (struct mtget)); - mtget.mt_type = MT_ISSCSI2; - mtget.mt_blkno = position / tape->user_bs_factor - block_offset; - mtget.mt_dsreg = ((tape->tape_block_size * tape->user_bs_factor) << MT_ST_BLKSIZE_SHIFT) & MT_ST_BLKSIZE_MASK; - if (tape->drv_write_prot) { - mtget.mt_gstat |= GMT_WR_PROT(0xffffffff); - } - if (copy_to_user(argp, &mtget, sizeof(struct mtget))) - return -EFAULT; - return 0; - case MTIOCPOS: - mtpos.mt_blkno = position / tape->user_bs_factor - block_offset; - if (copy_to_user(argp, &mtpos, sizeof(struct mtpos))) - return -EFAULT; - return 0; - default: - if (tape->chrdev_direction == idetape_direction_read) - idetape_discard_read_pipeline(drive, 1); - return idetape_blkdev_ioctl(drive, cmd, arg); + case MTIOCTOP: + if (copy_from_user(&mtop, argp, sizeof(struct mtop))) + return -EFAULT; + return idetape_mtioctop(drive, mtop.mt_op, mtop.mt_count); + case MTIOCGET: + memset(&mtget, 0, sizeof(struct mtget)); + mtget.mt_type = MT_ISSCSI2; + mtget.mt_blkno = position / tape->user_bs_factor - block_offset; + mtget.mt_dsreg = + ((tape->blk_size * tape->user_bs_factor) + << MT_ST_BLKSIZE_SHIFT) & MT_ST_BLKSIZE_MASK; + + if (tape->drv_write_prot) + mtget.mt_gstat |= GMT_WR_PROT(0xffffffff); + + if (copy_to_user(argp, &mtget, sizeof(struct mtget))) + return -EFAULT; + return 0; + case MTIOCPOS: + mtpos.mt_blkno = position / tape->user_bs_factor - block_offset; + if (copy_to_user(argp, &mtpos, sizeof(struct mtpos))) + return -EFAULT; + return 0; + default: + if (tape->chrdev_dir == IDETAPE_DIR_READ) + idetape_discard_read_pipeline(drive, 1); + return idetape_blkdev_ioctl(drive, cmd, arg); } } @@ -3347,23 +3188,20 @@ static void ide_tape_get_bsize_from_bdesc(ide_drive_t *drive) idetape_create_mode_sense_cmd(&pc, IDETAPE_BLOCK_DESCRIPTOR); if (idetape_queue_pc_tail(drive, &pc)) { printk(KERN_ERR "ide-tape: Can't get block descriptor\n"); - if (tape->tape_block_size == 0) { + if (tape->blk_size == 0) { printk(KERN_WARNING "ide-tape: Cannot deal with zero " "block size, assuming 32k\n"); - tape->tape_block_size = 32768; + tape->blk_size = 32768; } return; } - tape->tape_block_size = (pc.buffer[4 + 5] << 16) + + tape->blk_size = (pc.buffer[4 + 5] << 16) + (pc.buffer[4 + 6] << 8) + pc.buffer[4 + 7]; tape->drv_write_prot = (pc.buffer[2] & 0x80) >> 7; } -/* - * Our character device open function. - */ -static int idetape_chrdev_open (struct inode *inode, struct file *filp) +static int idetape_chrdev_open(struct inode *inode, struct file *filp) { unsigned int minor = iminor(inode), i = minor & ~0xc0; ide_drive_t *drive; @@ -3371,6 +3209,15 @@ static int idetape_chrdev_open (struct inode *inode, struct file *filp) idetape_pc_t pc; int retval; + if (i >= MAX_HWIFS * MAX_DRIVES) + return -ENXIO; + + tape = ide_tape_chrdev_get(i); + if (!tape) + return -ENXIO; + + debug_log(DBG_CHRDEV, "Enter %s\n", __func__); + /* * We really want to do nonseekable_open(inode, filp); here, but some * versions of tar incorrectly call lseek on tapes and bail out if that @@ -3378,16 +3225,6 @@ static int idetape_chrdev_open (struct inode *inode, struct file *filp) */ filp->f_mode &= ~(FMODE_PREAD | FMODE_PWRITE); -#if IDETAPE_DEBUG_LOG - printk(KERN_INFO "ide-tape: Reached idetape_chrdev_open\n"); -#endif /* IDETAPE_DEBUG_LOG */ - - if (i >= MAX_HWIFS * MAX_DRIVES) - return -ENXIO; - - if (!(tape = ide_tape_chrdev_get(i))) - return -ENXIO; - drive = tape->drive; filp->private_data = tape; @@ -3408,7 +3245,7 @@ static int idetape_chrdev_open (struct inode *inode, struct file *filp) if (!test_bit(IDETAPE_ADDRESS_VALID, &tape->flags)) (void)idetape_rewind_tape(drive); - if (tape->chrdev_direction != idetape_direction_read) + if (tape->chrdev_dir != IDETAPE_DIR_READ) clear_bit(IDETAPE_PIPELINE_ERROR, &tape->flags); /* Read block size and write protect status from drive. */ @@ -3430,10 +3267,8 @@ static int idetape_chrdev_open (struct inode *inode, struct file *filp) } } - /* - * Lock the tape drive door so user can't eject. - */ - if (tape->chrdev_direction == idetape_direction_none) { + /* Lock the tape drive door so user can't eject. */ + if (tape->chrdev_dir == IDETAPE_DIR_NONE) { if (idetape_create_prevent_cmd(drive, &pc, 1)) { if (!idetape_queue_pc_tail(drive, &pc)) { if (tape->door_locked != DOOR_EXPLICITLY_LOCKED) @@ -3450,14 +3285,15 @@ out_put_tape: return retval; } -static void idetape_write_release (ide_drive_t *drive, unsigned int minor) +static void idetape_write_release(ide_drive_t *drive, unsigned int minor) { idetape_tape_t *tape = drive->driver_data; idetape_empty_write_pipeline(drive); tape->merge_stage = __idetape_kmalloc_stage(tape, 1, 0); if (tape->merge_stage != NULL) { - idetape_pad_zeros(drive, tape->tape_block_size * (tape->user_bs_factor - 1)); + idetape_pad_zeros(drive, tape->blk_size * + (tape->user_bs_factor - 1)); __idetape_kfree_stage(tape->merge_stage); tape->merge_stage = NULL; } @@ -3466,10 +3302,7 @@ static void idetape_write_release (ide_drive_t *drive, unsigned int minor) idetape_flush_tape_buffers(drive); } -/* - * Our character device release function. - */ -static int idetape_chrdev_release (struct inode *inode, struct file *filp) +static int idetape_chrdev_release(struct inode *inode, struct file *filp) { struct ide_tape_obj *tape = ide_tape_f(filp); ide_drive_t *drive = tape->drive; @@ -3478,14 +3311,12 @@ static int idetape_chrdev_release (struct inode *inode, struct file *filp) lock_kernel(); tape = drive->driver_data; -#if IDETAPE_DEBUG_LOG - if (tape->debug_level >= 3) - printk(KERN_INFO "ide-tape: Reached idetape_chrdev_release\n"); -#endif /* IDETAPE_DEBUG_LOG */ - if (tape->chrdev_direction == idetape_direction_write) + debug_log(DBG_CHRDEV, "Enter %s\n", __func__); + + if (tape->chrdev_dir == IDETAPE_DIR_WRITE) idetape_write_release(drive, minor); - if (tape->chrdev_direction == idetape_direction_read) { + if (tape->chrdev_dir == IDETAPE_DIR_READ) { if (minor < 128) idetape_discard_read_pipeline(drive, 1); else @@ -3497,7 +3328,7 @@ static int idetape_chrdev_release (struct inode *inode, struct file *filp) } if (minor < 128 && test_bit(IDETAPE_MEDIUM_PRESENT, &tape->flags)) (void) idetape_rewind_tape(drive); - if (tape->chrdev_direction == idetape_direction_none) { + if (tape->chrdev_dir == IDETAPE_DIR_NONE) { if (tape->door_locked == DOOR_LOCKED) { if (idetape_create_prevent_cmd(drive, &pc, 0)) { if (!idetape_queue_pc_tail(drive, &pc)) @@ -3512,37 +3343,39 @@ static int idetape_chrdev_release (struct inode *inode, struct file *filp) } /* - * idetape_identify_device is called to check the contents of the - * ATAPI IDENTIFY command results. We return: + * check the contents of the ATAPI IDENTIFY command results. We return: * - * 1 If the tape can be supported by us, based on the information - * we have so far. + * 1 - If the tape can be supported by us, based on the information we have so + * far. * - * 0 If this tape driver is not currently supported by us. + * 0 - If this tape driver is not currently supported by us. */ -static int idetape_identify_device (ide_drive_t *drive) +static int idetape_identify_device(ide_drive_t *drive) { - struct idetape_id_gcw gcw; - struct hd_driveid *id = drive->id; + u8 gcw[2], protocol, device_type, removable, packet_size; if (drive->id_read == 0) return 1; - *((unsigned short *) &gcw) = id->config; + *((unsigned short *) &gcw) = drive->id->config; + + protocol = (gcw[1] & 0xC0) >> 6; + device_type = gcw[1] & 0x1F; + removable = !!(gcw[0] & 0x80); + packet_size = gcw[0] & 0x3; /* Check that we can support this device */ - - if (gcw.protocol != 2) + if (protocol != 2) printk(KERN_ERR "ide-tape: Protocol (0x%02x) is not ATAPI\n", - gcw.protocol); - else if (gcw.device_type != 1) + protocol); + else if (device_type != 1) printk(KERN_ERR "ide-tape: Device type (0x%02x) is not set " - "to tape\n", gcw.device_type); - else if (!gcw.removable) + "to tape\n", device_type); + else if (!removable) printk(KERN_ERR "ide-tape: The removable flag is not set\n"); - else if (gcw.packet_size != 0) { - printk(KERN_ERR "ide-tape: Packet size (0x%02x) is not 12 " - "bytes long\n", gcw.packet_size); + else if (packet_size != 0) { + printk(KERN_ERR "ide-tape: Packet size (0x%02x) is not 12" + " bytes\n", packet_size); } else return 1; return 0; @@ -3550,9 +3383,9 @@ static int idetape_identify_device (ide_drive_t *drive) static void idetape_get_inquiry_results(ide_drive_t *drive) { - char *r; idetape_tape_t *tape = drive->driver_data; idetape_pc_t pc; + char fw_rev[6], vendor_id[10], product_id[18]; idetape_create_inquiry_cmd(&pc); if (idetape_queue_pc_tail(drive, &pc)) { @@ -3560,27 +3393,23 @@ static void idetape_get_inquiry_results(ide_drive_t *drive) tape->name); return; } - memcpy(tape->vendor_id, &pc.buffer[8], 8); - memcpy(tape->product_id, &pc.buffer[16], 16); - memcpy(tape->firmware_revision, &pc.buffer[32], 4); - - ide_fixstring(tape->vendor_id, 10, 0); - ide_fixstring(tape->product_id, 18, 0); - ide_fixstring(tape->firmware_revision, 6, 0); - r = tape->firmware_revision; - if (*(r + 1) == '.') - tape->firmware_revision_num = (*r - '0') * 100 + - (*(r + 2) - '0') * 10 + *(r + 3) - '0'; + memcpy(vendor_id, &pc.buffer[8], 8); + memcpy(product_id, &pc.buffer[16], 16); + memcpy(fw_rev, &pc.buffer[32], 4); + + ide_fixstring(vendor_id, 10, 0); + ide_fixstring(product_id, 18, 0); + ide_fixstring(fw_rev, 6, 0); + printk(KERN_INFO "ide-tape: %s <-> %s: %s %s rev %s\n", - drive->name, tape->name, tape->vendor_id, - tape->product_id, tape->firmware_revision); + drive->name, tape->name, vendor_id, product_id, fw_rev); } /* * Ask the tape about its various parameters. In particular, we will adjust our * data transfer buffer size to the recommended value as returned by the tape. */ -static void idetape_get_mode_sense_results (ide_drive_t *drive) +static void idetape_get_mode_sense_results(ide_drive_t *drive) { idetape_tape_t *tape = drive->driver_data; idetape_pc_t pc; @@ -3591,7 +3420,7 @@ static void idetape_get_mode_sense_results (ide_drive_t *drive) if (idetape_queue_pc_tail(drive, &pc)) { printk(KERN_ERR "ide-tape: Can't get tape parameters - assuming" " some default values\n"); - tape->tape_block_size = 512; + tape->blk_size = 512; put_unaligned(52, (u16 *)&tape->caps[12]); put_unaligned(540, (u16 *)&tape->caps[14]); put_unaligned(6*52, (u16 *)&tape->caps[16]); @@ -3621,62 +3450,75 @@ static void idetape_get_mode_sense_results (ide_drive_t *drive) memcpy(&tape->caps, caps, 20); if (caps[7] & 0x02) - tape->tape_block_size = 512; + tape->blk_size = 512; else if (caps[7] & 0x04) - tape->tape_block_size = 1024; + tape->blk_size = 1024; } #ifdef CONFIG_IDE_PROC_FS -static void idetape_add_settings (ide_drive_t *drive) +static void idetape_add_settings(ide_drive_t *drive) { idetape_tape_t *tape = drive->driver_data; -/* - * drive setting name read/write data type min max mul_factor div_factor data pointer set function - */ ide_add_setting(drive, "buffer", SETTING_READ, TYPE_SHORT, 0, 0xffff, 1, 2, (u16 *)&tape->caps[16], NULL); - ide_add_setting(drive, "pipeline_min", SETTING_RW, TYPE_INT, 1, 0xffff, tape->stage_size / 1024, 1, &tape->min_pipeline, NULL); - ide_add_setting(drive, "pipeline", SETTING_RW, TYPE_INT, 1, 0xffff, tape->stage_size / 1024, 1, &tape->max_stages, NULL); - ide_add_setting(drive, "pipeline_max", SETTING_RW, TYPE_INT, 1, 0xffff, tape->stage_size / 1024, 1, &tape->max_pipeline, NULL); - ide_add_setting(drive, "pipeline_used", SETTING_READ, TYPE_INT, 0, 0xffff, tape->stage_size / 1024, 1, &tape->nr_stages, NULL); - ide_add_setting(drive, "pipeline_pending", SETTING_READ, TYPE_INT, 0, 0xffff, tape->stage_size / 1024, 1, &tape->nr_pending_stages, NULL); + ide_add_setting(drive, "pipeline_min", SETTING_RW, TYPE_INT, 1, 0xffff, + tape->stage_size / 1024, 1, &tape->min_pipeline, NULL); + ide_add_setting(drive, "pipeline", SETTING_RW, TYPE_INT, 1, 0xffff, + tape->stage_size / 1024, 1, &tape->max_stages, NULL); + ide_add_setting(drive, "pipeline_max", SETTING_RW, TYPE_INT, 1, 0xffff, + tape->stage_size / 1024, 1, &tape->max_pipeline, NULL); + ide_add_setting(drive, "pipeline_used", SETTING_READ, TYPE_INT, 0, + 0xffff, tape->stage_size / 1024, 1, &tape->nr_stages, + NULL); + ide_add_setting(drive, "pipeline_pending", SETTING_READ, TYPE_INT, 0, + 0xffff, tape->stage_size / 1024, 1, + &tape->nr_pending_stages, NULL); ide_add_setting(drive, "speed", SETTING_READ, TYPE_SHORT, 0, 0xffff, 1, 1, (u16 *)&tape->caps[14], NULL); - ide_add_setting(drive, "stage", SETTING_READ, TYPE_INT, 0, 0xffff, 1, 1024, &tape->stage_size, NULL); - ide_add_setting(drive, "tdsc", SETTING_RW, 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, TYPE_BYTE, 0, 1, 1, 1, &drive->dsc_overlap, NULL); - ide_add_setting(drive, "pipeline_head_speed_c",SETTING_READ, TYPE_INT, 0, 0xffff, 1, 1, &tape->controlled_pipeline_head_speed, NULL); - ide_add_setting(drive, "pipeline_head_speed_u",SETTING_READ, TYPE_INT, 0, 0xffff, 1, 1, &tape->uncontrolled_pipeline_head_speed,NULL); - ide_add_setting(drive, "avg_speed", SETTING_READ, TYPE_INT, 0, 0xffff, 1, 1, &tape->avg_speed, NULL); - ide_add_setting(drive, "debug_level", SETTING_RW, TYPE_INT, 0, 0xffff, 1, 1, &tape->debug_level, NULL); + ide_add_setting(drive, "stage", SETTING_READ, TYPE_INT, 0, 0xffff, 1, + 1024, &tape->stage_size, NULL); + ide_add_setting(drive, "tdsc", SETTING_RW, TYPE_INT, IDETAPE_DSC_RW_MIN, + IDETAPE_DSC_RW_MAX, 1000, HZ, &tape->best_dsc_rw_freq, + NULL); + ide_add_setting(drive, "dsc_overlap", SETTING_RW, TYPE_BYTE, 0, 1, 1, + 1, &drive->dsc_overlap, NULL); + ide_add_setting(drive, "pipeline_head_speed_c", SETTING_READ, TYPE_INT, + 0, 0xffff, 1, 1, &tape->controlled_pipeline_head_speed, + NULL); + ide_add_setting(drive, "pipeline_head_speed_u", SETTING_READ, TYPE_INT, + 0, 0xffff, 1, 1, + &tape->uncontrolled_pipeline_head_speed, NULL); + ide_add_setting(drive, "avg_speed", SETTING_READ, TYPE_INT, 0, 0xffff, + 1, 1, &tape->avg_speed, NULL); + ide_add_setting(drive, "debug_mask", SETTING_RW, TYPE_INT, 0, 0xffff, 1, + 1, &tape->debug_mask, NULL); } #else static inline void idetape_add_settings(ide_drive_t *drive) { ; } #endif /* - * ide_setup is called to: + * The function below is called to: * - * 1. Initialize our various state variables. - * 2. Ask the tape for its capabilities. - * 3. Allocate a buffer which will be used for data - * transfer. The buffer size is chosen based on - * the recommendation which we received in step (2). + * 1. Initialize our various state variables. + * 2. Ask the tape for its capabilities. + * 3. Allocate a buffer which will be used for data transfer. The buffer size + * is chosen based on the recommendation which we received in step 2. * - * Note that at this point ide.c already assigned us an irq, so that - * we can queue requests here and wait for their completion. + * Note that at this point ide.c already assigned us an irq, so that we can + * queue requests here and wait for their completion. */ -static void idetape_setup (ide_drive_t *drive, idetape_tape_t *tape, int minor) +static void idetape_setup(ide_drive_t *drive, idetape_tape_t *tape, int minor) { unsigned long t1, tmid, tn, t; int speed; - struct idetape_id_gcw gcw; int stage_size; + u8 gcw[2]; struct sysinfo si; u16 *ctl = (u16 *)&tape->caps[12]; - spin_lock_init(&tape->spinlock); + spin_lock_init(&tape->lock); drive->dsc_overlap = 1; if (drive->hwif->host_flags & IDE_HFLAG_NO_DSC) { printk(KERN_INFO "ide-tape: %s: disabling DSC overlap\n", @@ -3690,25 +3532,29 @@ static void idetape_setup (ide_drive_t *drive, idetape_tape_t *tape, int minor) tape->name[0] = 'h'; tape->name[1] = 't'; tape->name[2] = '0' + minor; - tape->chrdev_direction = idetape_direction_none; + tape->chrdev_dir = IDETAPE_DIR_NONE; tape->pc = tape->pc_stack; tape->max_insert_speed = 10000; tape->speed_control = 1; *((unsigned short *) &gcw) = drive->id->config; - if (gcw.drq_type == 1) + + /* Command packet DRQ type */ + if (((gcw[0] & 0x60) >> 5) == 1) set_bit(IDETAPE_DRQ_INTERRUPT, &tape->flags); - tape->min_pipeline = tape->max_pipeline = tape->max_stages = 10; - + tape->min_pipeline = 10; + tape->max_pipeline = 10; + tape->max_stages = 10; + idetape_get_inquiry_results(drive); idetape_get_mode_sense_results(drive); ide_tape_get_bsize_from_bdesc(drive); tape->user_bs_factor = 1; - tape->stage_size = *ctl * tape->tape_block_size; + tape->stage_size = *ctl * tape->blk_size; while (tape->stage_size > 0xffff) { printk(KERN_NOTICE "ide-tape: decreasing stage size\n"); *ctl /= 2; - tape->stage_size = *ctl * tape->tape_block_size; + tape->stage_size = *ctl * tape->blk_size; } stage_size = tape->stage_size; tape->pages_per_stage = stage_size / PAGE_SIZE; @@ -3722,17 +3568,22 @@ static void idetape_setup (ide_drive_t *drive, idetape_tape_t *tape, int minor) tape->max_stages = speed * 1000 * 10 / tape->stage_size; - /* - * Limit memory use for pipeline to 10% of physical memory - */ + /* Limit memory use for pipeline to 10% of physical memory */ si_meminfo(&si); - if (tape->max_stages * tape->stage_size > si.totalram * si.mem_unit / 10) - tape->max_stages = si.totalram * si.mem_unit / (10 * tape->stage_size); + if (tape->max_stages * tape->stage_size > + si.totalram * si.mem_unit / 10) + tape->max_stages = + si.totalram * si.mem_unit / (10 * tape->stage_size); + tape->max_stages = min(tape->max_stages, IDETAPE_MAX_PIPELINE_STAGES); tape->min_pipeline = min(tape->max_stages, IDETAPE_MIN_PIPELINE_STAGES); - tape->max_pipeline = min(tape->max_stages * 2, IDETAPE_MAX_PIPELINE_STAGES); - if (tape->max_stages == 0) - tape->max_stages = tape->min_pipeline = tape->max_pipeline = 1; + tape->max_pipeline = + min(tape->max_stages * 2, IDETAPE_MAX_PIPELINE_STAGES); + if (tape->max_stages == 0) { + tape->max_stages = 1; + tape->min_pipeline = 1; + tape->max_pipeline = 1; + } t1 = (tape->stage_size * HZ) / (speed * 1000); tmid = (*(u16 *)&tape->caps[16] * 32 * HZ) / (speed * 125); @@ -3744,17 +3595,19 @@ static void idetape_setup (ide_drive_t *drive, idetape_tape_t *tape, int minor) t = t1; /* - * Ensure that the number we got makes sense; limit - * it within IDETAPE_DSC_RW_MIN and IDETAPE_DSC_RW_MAX. + * Ensure that the number we got makes sense; limit it within + * IDETAPE_DSC_RW_MIN and IDETAPE_DSC_RW_MAX. */ - tape->best_dsc_rw_frequency = max_t(unsigned long, min_t(unsigned long, t, IDETAPE_DSC_RW_MAX), IDETAPE_DSC_RW_MIN); + tape->best_dsc_rw_freq = max_t(unsigned long, + min_t(unsigned long, t, IDETAPE_DSC_RW_MAX), + IDETAPE_DSC_RW_MIN); printk(KERN_INFO "ide-tape: %s <-> %s: %dKBps, %d*%dkB buffer, " "%dkB pipeline, %lums tDSC%s\n", drive->name, tape->name, *(u16 *)&tape->caps[14], (*(u16 *)&tape->caps[16] * 512) / tape->stage_size, tape->stage_size / 1024, tape->max_stages * tape->stage_size / 1024, - tape->best_dsc_rw_frequency * 1000 / HZ, + tape->best_dsc_rw_freq * 1000 / HZ, drive->using_dma ? ", DMA":""); idetape_add_settings(drive); @@ -3782,7 +3635,8 @@ static void ide_tape_release(struct kref *kref) drive->dsc_overlap = 0; drive->driver_data = NULL; device_destroy(idetape_sysfs_class, MKDEV(IDETAPE_MAJOR, tape->minor)); - device_destroy(idetape_sysfs_class, MKDEV(IDETAPE_MAJOR, tape->minor + 128)); + device_destroy(idetape_sysfs_class, + MKDEV(IDETAPE_MAJOR, tape->minor + 128)); idetape_devs[tape->minor] = NULL; g->private_data = NULL; put_disk(g); @@ -3831,9 +3685,7 @@ static ide_driver_t idetape_driver = { #endif }; -/* - * Our character device supporting functions, passed to register_chrdev. - */ +/* Our character device supporting functions, passed to register_chrdev. */ static const struct file_operations idetape_fops = { .owner = THIS_MODULE, .read = idetape_chrdev_read, @@ -3848,7 +3700,8 @@ static int idetape_open(struct inode *inode, struct file *filp) struct gendisk *disk = inode->i_bdev->bd_disk; struct ide_tape_obj *tape; - if (!(tape = ide_tape_get(disk))) + tape = ide_tape_get(disk); + if (!tape) return -ENXIO; return 0; @@ -3895,21 +3748,20 @@ static int ide_tape_probe(ide_drive_t *drive) goto failed; if (drive->media != ide_tape) goto failed; - if (!idetape_identify_device (drive)) { - printk(KERN_ERR "ide-tape: %s: not supported by this version of ide-tape\n", drive->name); + if (!idetape_identify_device(drive)) { + printk(KERN_ERR "ide-tape: %s: not supported by this version of" + " the driver\n", drive->name); goto failed; } if (drive->scsi) { - printk("ide-tape: passing drive %s to ide-scsi emulation.\n", drive->name); + printk(KERN_INFO "ide-tape: passing drive %s to ide-scsi" + " emulation.\n", drive->name); goto failed; } - if (strstr(drive->id->model, "OnStream DI-")) { - printk(KERN_WARNING "ide-tape: Use drive %s with ide-scsi emulation and osst.\n", drive->name); - printk(KERN_WARNING "ide-tape: OnStream support will be removed soon from ide-tape!\n"); - } - tape = kzalloc(sizeof (idetape_tape_t), GFP_KERNEL); + tape = kzalloc(sizeof(idetape_tape_t), GFP_KERNEL); if (tape == NULL) { - printk(KERN_ERR "ide-tape: %s: Can't allocate a tape structure\n", drive->name); + printk(KERN_ERR "ide-tape: %s: Can't allocate a tape struct\n", + drive->name); goto failed; } @@ -3955,10 +3807,7 @@ failed: return -ENODEV; } -MODULE_DESCRIPTION("ATAPI Streaming TAPE Driver"); -MODULE_LICENSE("GPL"); - -static void __exit idetape_exit (void) +static void __exit idetape_exit(void) { driver_unregister(&idetape_driver.gen_driver); class_destroy(idetape_sysfs_class); @@ -3977,7 +3826,8 @@ static int __init idetape_init(void) } if (register_chrdev(IDETAPE_MAJOR, "ht", &idetape_fops)) { - printk(KERN_ERR "ide-tape: Failed to register character device interface\n"); + printk(KERN_ERR "ide-tape: Failed to register chrdev" + " interface\n"); error = -EBUSY; goto out_free_class; } @@ -4000,3 +3850,5 @@ MODULE_ALIAS("ide:*m-tape*"); module_init(idetape_init); module_exit(idetape_exit); MODULE_ALIAS_CHARDEV_MAJOR(IDETAPE_MAJOR); +MODULE_DESCRIPTION("ATAPI Streaming TAPE Driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/ide/ide-taskfile.c b/drivers/ide/ide-taskfile.c index 4e1da1c78cb5..0518a2e948cf 100644 --- a/drivers/ide/ide-taskfile.c +++ b/drivers/ide/ide-taskfile.c @@ -189,12 +189,11 @@ EXPORT_SYMBOL_GPL(do_rw_taskfile); */ static ide_startstop_t set_multmode_intr(ide_drive_t *drive) { - ide_hwif_t *hwif = HWIF(drive); - u8 stat; + u8 stat = ide_read_status(drive); - if (OK_STAT(stat = hwif->INB(IDE_STATUS_REG),READY_STAT,BAD_STAT)) { + if (OK_STAT(stat, READY_STAT, BAD_STAT)) drive->mult_count = drive->mult_req; - } else { + else { drive->mult_req = drive->mult_count = 0; drive->special.b.recalibrate = 1; (void) ide_dump_status(drive, "set_multmode", stat); @@ -207,11 +206,10 @@ static ide_startstop_t set_multmode_intr(ide_drive_t *drive) */ static ide_startstop_t set_geometry_intr(ide_drive_t *drive) { - ide_hwif_t *hwif = HWIF(drive); int retries = 5; u8 stat; - while (((stat = hwif->INB(IDE_STATUS_REG)) & BUSY_STAT) && retries--) + while (((stat = ide_read_status(drive)) & BUSY_STAT) && retries--) udelay(10); if (OK_STAT(stat, READY_STAT, BAD_STAT)) @@ -230,10 +228,9 @@ static ide_startstop_t set_geometry_intr(ide_drive_t *drive) */ static ide_startstop_t recal_intr(ide_drive_t *drive) { - ide_hwif_t *hwif = HWIF(drive); - u8 stat; + u8 stat = ide_read_status(drive); - if (!OK_STAT(stat = hwif->INB(IDE_STATUS_REG), READY_STAT, BAD_STAT)) + if (!OK_STAT(stat, READY_STAT, BAD_STAT)) return ide_error(drive, "recal_intr", stat); return ide_stopped; } @@ -244,23 +241,23 @@ static ide_startstop_t recal_intr(ide_drive_t *drive) static ide_startstop_t task_no_data_intr(ide_drive_t *drive) { ide_task_t *args = HWGROUP(drive)->rq->special; - ide_hwif_t *hwif = HWIF(drive); u8 stat; local_irq_enable_in_hardirq(); - if (!OK_STAT(stat = hwif->INB(IDE_STATUS_REG),READY_STAT,BAD_STAT)) { + stat = ide_read_status(drive); + + if (!OK_STAT(stat, READY_STAT, BAD_STAT)) return ide_error(drive, "task_no_data_intr", stat); /* calls ide_end_drive_cmd */ - } + if (args) - ide_end_drive_cmd(drive, stat, hwif->INB(IDE_ERROR_REG)); + ide_end_drive_cmd(drive, stat, ide_read_error(drive)); return ide_stopped; } static u8 wait_drive_not_busy(ide_drive_t *drive) { - ide_hwif_t *hwif = HWIF(drive); int retries; u8 stat; @@ -269,7 +266,9 @@ static u8 wait_drive_not_busy(ide_drive_t *drive) * This can take up to 10 usec, but we will wait max 1 ms. */ for (retries = 0; retries < 100; retries++) { - if ((stat = hwif->INB(IDE_STATUS_REG)) & BUSY_STAT) + stat = ide_read_status(drive); + + if (stat & BUSY_STAT) udelay(10); else break; @@ -408,7 +407,7 @@ static ide_startstop_t task_error(ide_drive_t *drive, struct request *rq, void task_end_request(ide_drive_t *drive, struct request *rq, u8 stat) { if (rq->cmd_type == REQ_TYPE_ATA_TASKFILE) { - u8 err = drive->hwif->INB(IDE_ERROR_REG); + u8 err = ide_read_error(drive); ide_end_drive_cmd(drive, stat, err); return; @@ -430,7 +429,7 @@ static ide_startstop_t task_in_intr(ide_drive_t *drive) { ide_hwif_t *hwif = drive->hwif; struct request *rq = HWGROUP(drive)->rq; - u8 stat = hwif->INB(IDE_STATUS_REG); + u8 stat = ide_read_status(drive); /* new way for dealing with premature shared PCI interrupts */ if (!OK_STAT(stat, DRQ_STAT, BAD_R_STAT)) { @@ -465,7 +464,7 @@ static ide_startstop_t task_out_intr (ide_drive_t *drive) { ide_hwif_t *hwif = drive->hwif; struct request *rq = HWGROUP(drive)->rq; - u8 stat = hwif->INB(IDE_STATUS_REG); + u8 stat = ide_read_status(drive); if (!OK_STAT(stat, DRIVE_READY, drive->bad_wstat)) return task_error(drive, rq, __FUNCTION__, stat); diff --git a/drivers/ide/ide.c b/drivers/ide/ide.c index ac6136001615..ad0e9955f73c 100644 --- a/drivers/ide/ide.c +++ b/drivers/ide/ide.c @@ -618,60 +618,6 @@ abort: EXPORT_SYMBOL(ide_unregister); - -/** - * ide_setup_ports - set up IDE interface ports - * @hw: register descriptions - * @base: base register - * @offsets: table of register offsets - * @ctrl: control register - * @ack_irq: IRQ ack - * @irq: interrupt lie - * - * Setup hw_regs_t structure described by parameters. You - * may set up the hw structure yourself OR use this routine to - * do it for you. This is basically a helper - * - */ - -void ide_setup_ports ( hw_regs_t *hw, - unsigned long base, int *offsets, - unsigned long ctrl, unsigned long intr, - ide_ack_intr_t *ack_intr, -/* - * ide_io_ops_t *iops, - */ - int irq) -{ - int i; - - memset(hw, 0, sizeof(hw_regs_t)); - for (i = 0; i < IDE_NR_PORTS; i++) { - if (offsets[i] == -1) { - switch(i) { - case IDE_CONTROL_OFFSET: - hw->io_ports[i] = ctrl; - break; -#if defined(CONFIG_AMIGA) || defined(CONFIG_MAC) - case IDE_IRQ_OFFSET: - hw->io_ports[i] = intr; - break; -#endif /* (CONFIG_AMIGA) || (CONFIG_MAC) */ - default: - hw->io_ports[i] = 0; - break; - } - } else { - hw->io_ports[i] = base + offsets[i]; - } - } - hw->irq = irq; - hw->ack_intr = ack_intr; -/* - * hw->iops = iops; - */ -} - void ide_init_port_hw(ide_hwif_t *hwif, hw_regs_t *hw) { memcpy(hwif->io_ports, hw->io_ports, sizeof(hwif->io_ports)); diff --git a/drivers/ide/legacy/buddha.c b/drivers/ide/legacy/buddha.c index 8bdb79da17e8..50ffa871d5e9 100644 --- a/drivers/ide/legacy/buddha.c +++ b/drivers/ide/legacy/buddha.c @@ -56,31 +56,11 @@ static u_int xsurf_bases[XSURF_NUM_HWIFS] __initdata = { XSURF_BASE1, XSURF_BASE2 }; - /* * Offsets from one of the above bases */ -#define BUDDHA_DATA 0x00 -#define BUDDHA_ERROR 0x06 /* see err-bits */ -#define BUDDHA_NSECTOR 0x0a /* nr of sectors to read/write */ -#define BUDDHA_SECTOR 0x0e /* starting sector */ -#define BUDDHA_LCYL 0x12 /* starting cylinder */ -#define BUDDHA_HCYL 0x16 /* high byte of starting cyl */ -#define BUDDHA_SELECT 0x1a /* 101dhhhh , d=drive, hhhh=head */ -#define BUDDHA_STATUS 0x1e /* see status-bits */ #define BUDDHA_CONTROL 0x11a -#define XSURF_CONTROL -1 /* X-Surf has no CS1* (Control/AltStat) */ - -static int buddha_offsets[IDE_NR_PORTS] __initdata = { - BUDDHA_DATA, BUDDHA_ERROR, BUDDHA_NSECTOR, BUDDHA_SECTOR, BUDDHA_LCYL, - BUDDHA_HCYL, BUDDHA_SELECT, BUDDHA_STATUS, BUDDHA_CONTROL, -1 -}; - -static int xsurf_offsets[IDE_NR_PORTS] __initdata = { - BUDDHA_DATA, BUDDHA_ERROR, BUDDHA_NSECTOR, BUDDHA_SECTOR, BUDDHA_LCYL, - BUDDHA_HCYL, BUDDHA_SELECT, BUDDHA_STATUS, XSURF_CONTROL, -1 -}; /* * Other registers @@ -140,6 +120,26 @@ static int xsurf_ack_intr(ide_hwif_t *hwif) return 1; } +static void __init buddha_setup_ports(hw_regs_t *hw, unsigned long base, + unsigned long ctl, unsigned long irq_port, + ide_ack_intr_t *ack_intr) +{ + int i; + + memset(hw, 0, sizeof(*hw)); + + hw->io_ports[IDE_DATA_OFFSET] = base; + + for (i = 1; i < 8; i++) + hw->io_ports[i] = base + 2 + i * 4; + + hw->io_ports[IDE_CONTROL_OFFSET] = ctl; + hw->io_ports[IDE_IRQ_OFFSET] = irq_port; + + hw->irq = IRQ_AMIGA_PORTS; + hw->ack_intr = ack_intr; +} + /* * Probe for a Buddha or Catweasel IDE interface */ @@ -202,22 +202,24 @@ fail_base2: printk(KERN_INFO "ide: %s IDE controller\n", buddha_board_name[type]); - for(i=0;i<buddha_num_hwifs;i++) { - if(type != BOARD_XSURF) { - ide_setup_ports(&hw, (buddha_board+buddha_bases[i]), - buddha_offsets, 0, - (buddha_board+buddha_irqports[i]), - buddha_ack_intr, -// budda_iops, - IRQ_AMIGA_PORTS); + for (i = 0; i < buddha_num_hwifs; i++) { + unsigned long base, ctl, irq_port; + ide_ack_intr_t *ack_intr; + + if (type != BOARD_XSURF) { + base = buddha_board + buddha_bases[i]; + ctl = base + BUDDHA_CONTROL; + irq_port = buddha_board + buddha_irqports[i]; + ack_intr = buddha_ack_intr; } else { - ide_setup_ports(&hw, (buddha_board+xsurf_bases[i]), - xsurf_offsets, 0, - (buddha_board+xsurf_irqports[i]), - xsurf_ack_intr, -// xsurf_iops, - IRQ_AMIGA_PORTS); - } + base = buddha_board + xsurf_bases[i]; + /* X-Surf has no CS1* (Control/AltStat) */ + ctl = 0; + irq_port = buddha_board + xsurf_irqports[i]; + ack_intr = xsurf_ack_intr; + } + + buddha_setup_ports(&hw, base, ctl, irq_port, ack_intr); hwif = ide_find_port(hw.io_ports[IDE_DATA_OFFSET]); if (hwif) { diff --git a/drivers/ide/legacy/falconide.c b/drivers/ide/legacy/falconide.c index 85b69a82825f..f044048903b3 100644 --- a/drivers/ide/legacy/falconide.c +++ b/drivers/ide/legacy/falconide.c @@ -33,22 +33,8 @@ * Offsets from the above base */ -#define ATA_HD_DATA 0x00 -#define ATA_HD_ERROR 0x05 /* see err-bits */ -#define ATA_HD_NSECTOR 0x09 /* nr of sectors to read/write */ -#define ATA_HD_SECTOR 0x0d /* starting sector */ -#define ATA_HD_LCYL 0x11 /* starting cylinder */ -#define ATA_HD_HCYL 0x15 /* high byte of starting cyl */ -#define ATA_HD_SELECT 0x19 /* 101dhhhh , d=drive, hhhh=head */ -#define ATA_HD_STATUS 0x1d /* see status-bits */ #define ATA_HD_CONTROL 0x39 -static int falconide_offsets[IDE_NR_PORTS] __initdata = { - ATA_HD_DATA, ATA_HD_ERROR, ATA_HD_NSECTOR, ATA_HD_SECTOR, ATA_HD_LCYL, - ATA_HD_HCYL, ATA_HD_SELECT, ATA_HD_STATUS, ATA_HD_CONTROL, -1 -}; - - /* * falconide_intr_lock is used to obtain access to the IDE interrupt, * which is shared between several drivers. @@ -57,6 +43,22 @@ static int falconide_offsets[IDE_NR_PORTS] __initdata = { int falconide_intr_lock; EXPORT_SYMBOL(falconide_intr_lock); +static void __init falconide_setup_ports(hw_regs_t *hw) +{ + int i; + + memset(hw, 0, sizeof(*hw)); + + hw->io_ports[IDE_DATA_OFFSET] = ATA_HD_BASE; + + for (i = 1; i < 8; i++) + hw->io_ports[i] = ATA_HD_BASE + 1 + i * 4; + + hw->io_ports[IDE_CONTROL_OFFSET] = ATA_HD_CONTROL; + + hw->irq = IRQ_MFP_IDE; + hw->ack_intr = NULL; +} /* * Probe for a Falcon IDE interface @@ -64,16 +66,15 @@ EXPORT_SYMBOL(falconide_intr_lock); static int __init falconide_init(void) { - if (MACH_IS_ATARI && ATARIHW_PRESENT(IDE)) { hw_regs_t hw; ide_hwif_t *hwif; + if (!MACH_IS_ATARI || !ATARIHW_PRESENT(IDE)) + return 0; + printk(KERN_INFO "ide: Falcon IDE controller\n"); - ide_setup_ports(&hw, ATA_HD_BASE, falconide_offsets, - 0, 0, NULL, -// falconide_iops, - IRQ_MFP_IDE); + falconide_setup_ports(&hw); hwif = ide_find_port(hw.io_ports[IDE_DATA_OFFSET]); if (hwif) { @@ -85,9 +86,8 @@ static int __init falconide_init(void) ide_device_add(idx, NULL); } - } - return 0; + return 0; } module_init(falconide_init); diff --git a/drivers/ide/legacy/gayle.c b/drivers/ide/legacy/gayle.c index fc29ce75aff1..9d3851d27677 100644 --- a/drivers/ide/legacy/gayle.c +++ b/drivers/ide/legacy/gayle.c @@ -34,22 +34,8 @@ * Offsets from one of the above bases */ -#define GAYLE_DATA 0x00 -#define GAYLE_ERROR 0x06 /* see err-bits */ -#define GAYLE_NSECTOR 0x0a /* nr of sectors to read/write */ -#define GAYLE_SECTOR 0x0e /* starting sector */ -#define GAYLE_LCYL 0x12 /* starting cylinder */ -#define GAYLE_HCYL 0x16 /* high byte of starting cyl */ -#define GAYLE_SELECT 0x1a /* 101dhhhh , d=drive, hhhh=head */ -#define GAYLE_STATUS 0x1e /* see status-bits */ #define GAYLE_CONTROL 0x101a -static int gayle_offsets[IDE_NR_PORTS] __initdata = { - GAYLE_DATA, GAYLE_ERROR, GAYLE_NSECTOR, GAYLE_SECTOR, GAYLE_LCYL, - GAYLE_HCYL, GAYLE_SELECT, GAYLE_STATUS, -1, -1 -}; - - /* * These are at different offsets from the base */ @@ -106,6 +92,26 @@ static int gayle_ack_intr_a1200(ide_hwif_t *hwif) return 1; } +static void __init gayle_setup_ports(hw_regs_t *hw, unsigned long base, + unsigned long ctl, unsigned long irq_port, + ide_ack_intr_t *ack_intr); +{ + int i; + + memset(hw, 0, sizeof(*hw)); + + hw->io_ports[IDE_DATA_OFFSET] = base; + + for (i = 1; i < 8; i++) + hw->io_ports[i] = base + 2 + i * 4; + + hw->io_ports[IDE_CONTROL_OFFSET] = ctl; + hw->io_ports[IDE_IRQ_OFFSET] = irq_port; + + hw->irq = IRQ_AMIGA_PORTS; + hw->ack_intr = ack_intr; +} + /* * Probe for a Gayle IDE interface (and optionally for an IDE doubler) */ @@ -167,10 +173,7 @@ found: base = (unsigned long)ZTWO_VADDR(phys_base); ctrlport = GAYLE_HAS_CONTROL_REG ? (base + GAYLE_CONTROL) : 0; - ide_setup_ports(&hw, base, gayle_offsets, - ctrlport, irqport, ack_intr, -// &gayle_iops, - IRQ_AMIGA_PORTS); + gayle_setup_ports(&hw, base, ctrlport, irqport, ack_intr); hwif = ide_find_port(base); if (hwif) { diff --git a/drivers/ide/legacy/hd.c b/drivers/ide/legacy/hd.c index 8e05d88e81ba..0b0d86731927 100644 --- a/drivers/ide/legacy/hd.c +++ b/drivers/ide/legacy/hd.c @@ -421,11 +421,14 @@ static void bad_rw_intr(void) static inline int wait_DRQ(void) { - int retries = 100000, stat; + int retries; + int stat; - while (--retries > 0) - if ((stat = inb_p(HD_STATUS)) & DRQ_STAT) + for (retries = 0; retries < 100000; retries++) { + stat = inb_p(HD_STATUS); + if (stat & DRQ_STAT) return 0; + } dump_status("wait_DRQ", stat); return -1; } diff --git a/drivers/ide/legacy/macide.c b/drivers/ide/legacy/macide.c index 06df8df857a3..a61e60737dc7 100644 --- a/drivers/ide/legacy/macide.c +++ b/drivers/ide/legacy/macide.c @@ -31,14 +31,6 @@ * These match MkLinux so they should be correct. */ -#define IDE_DATA 0x00 -#define IDE_ERROR 0x04 /* see err-bits */ -#define IDE_NSECTOR 0x08 /* nr of sectors to read/write */ -#define IDE_SECTOR 0x0c /* starting sector */ -#define IDE_LCYL 0x10 /* starting cylinder */ -#define IDE_HCYL 0x14 /* high byte of starting cyl */ -#define IDE_SELECT 0x18 /* 101dhhhh , d=drive, hhhh=head */ -#define IDE_STATUS 0x1c /* see status-bits */ #define IDE_CONTROL 0x38 /* control/altstatus */ /* @@ -63,11 +55,6 @@ volatile unsigned char *ide_ifr = (unsigned char *) (IDE_BASE + IDE_IFR); -static int macide_offsets[IDE_NR_PORTS] = { - IDE_DATA, IDE_ERROR, IDE_NSECTOR, IDE_SECTOR, IDE_LCYL, - IDE_HCYL, IDE_SELECT, IDE_STATUS, IDE_CONTROL -}; - int macide_ack_intr(ide_hwif_t* hwif) { if (*ide_ifr & 0x20) { @@ -77,6 +64,22 @@ int macide_ack_intr(ide_hwif_t* hwif) return 0; } +static void __init macide_setup_ports(hw_regs_t *hw, unsigned long base, + int irq, ide_ack_intr_t *ack_intr) +{ + int i; + + memset(hw, 0, sizeof(*hw)); + + for (i = 0; i < 8; i++) + hw->io_ports[i] = base + i * 4; + + hw->io_ports[IDE_CONTROL_OFFSET] = IDE_CONTROL; + + hw->irq = irq; + hw->ack_intr = ack_intr; +} + static const char *mac_ide_name[] = { "Quadra", "Powerbook", "Powerbook Baboon" }; @@ -86,27 +89,27 @@ static const char *mac_ide_name[] = static int __init macide_init(void) { - hw_regs_t hw; ide_hwif_t *hwif; + ide_ack_intr_t *ack_intr; + unsigned long base; + int irq; + hw_regs_t hw; switch (macintosh_config->ide_type) { case MAC_IDE_QUADRA: - ide_setup_ports(&hw, IDE_BASE, macide_offsets, - 0, 0, macide_ack_intr, -// quadra_ide_iops, - IRQ_NUBUS_F); + base = IDE_BASE; + ack_intr = macide_ack_intr; + irq = IRQ_NUBUS_F; break; case MAC_IDE_PB: - ide_setup_ports(&hw, IDE_BASE, macide_offsets, - 0, 0, macide_ack_intr, -// macide_pb_iops, - IRQ_NUBUS_C); + base = IDE_BASE; + ack_intr = macide_ack_intr; + irq = IRQ_NUBUS_C; break; case MAC_IDE_BABOON: - ide_setup_ports(&hw, BABOON_BASE, macide_offsets, - 0, 0, NULL, -// macide_baboon_iops, - IRQ_BABOON_1); + base = BABOON_BASE; + ack_intr = NULL; + irq = IRQ_BABOON_1; break; default: return -ENODEV; @@ -115,6 +118,8 @@ static int __init macide_init(void) printk(KERN_INFO "ide: Macintosh %s IDE controller\n", mac_ide_name[macintosh_config->ide_type - 1]); + macide_setup_ports(&hw, base, irq, ack_intr); + hwif = ide_find_port(hw.io_ports[IDE_DATA_OFFSET]); if (hwif) { u8 index = hwif->index; diff --git a/drivers/ide/legacy/q40ide.c b/drivers/ide/legacy/q40ide.c index 2f0b34d892a1..1381b91bc316 100644 --- a/drivers/ide/legacy/q40ide.c +++ b/drivers/ide/legacy/q40ide.c @@ -66,16 +66,12 @@ static int q40ide_default_irq(unsigned long base) /* - * This is very similar to ide_setup_ports except that addresses - * are pretranslated for q40 ISA access + * Addresses are pretranslated for Q40 ISA access. */ void q40_ide_setup_ports ( hw_regs_t *hw, unsigned long base, int *offsets, unsigned long ctrl, unsigned long intr, ide_ack_intr_t *ack_intr, -/* - * ide_io_ops_t *iops, - */ int irq) { int i; @@ -92,9 +88,6 @@ void q40_ide_setup_ports ( hw_regs_t *hw, hw->irq = irq; hw->ack_intr = ack_intr; -/* - * hw->iops = iops; - */ } diff --git a/drivers/ide/pci/Makefile b/drivers/ide/pci/Makefile index 94803253e8af..02e6ee7d751d 100644 --- a/drivers/ide/pci/Makefile +++ b/drivers/ide/pci/Makefile @@ -34,7 +34,8 @@ obj-$(CONFIG_BLK_DEV_TRM290) += trm290.o obj-$(CONFIG_BLK_DEV_VIA82CXXX) += via82cxxx.o # Must appear at the end of the block -obj-$(CONFIG_BLK_DEV_GENERIC) += generic.o +obj-$(CONFIG_BLK_DEV_GENERIC) += ide-pci-generic.o +ide-pci-generic-y += generic.o ifeq ($(CONFIG_BLK_DEV_CMD640), m) obj-m += cmd640.o diff --git a/drivers/ide/pci/generic.c b/drivers/ide/pci/generic.c index 9262a9174b4e..7fd83a9d4dee 100644 --- a/drivers/ide/pci/generic.c +++ b/drivers/ide/pci/generic.c @@ -29,19 +29,6 @@ static int ide_generic_all; /* Set to claim all devices */ -/* - * the module_param_named() was added for the modular case - * the __setup() is left as compatibility for existing setups - */ -#ifndef MODULE -static int __init ide_generic_all_on(char *unused) -{ - ide_generic_all = 1; - printk(KERN_INFO "IDE generic will claim all unknown PCI IDE storage controllers.\n"); - return 1; -} -const __setup("all-generic-ide", ide_generic_all_on); -#endif module_param_named(all_generic_ide, ide_generic_all, bool, 0444); MODULE_PARM_DESC(all_generic_ide, "IDE generic will claim all unknown PCI IDE storage controllers."); diff --git a/drivers/ide/pci/siimage.c b/drivers/ide/pci/siimage.c index ef5b39fa042b..cc4be9621bc0 100644 --- a/drivers/ide/pci/siimage.c +++ b/drivers/ide/pci/siimage.c @@ -704,9 +704,6 @@ static void __devinit init_mmio_iops_siimage(ide_hwif_t *hwif) hwif->sata_scr[SATA_STATUS_OFFSET] = base + 0x104; hwif->sata_scr[SATA_ERROR_OFFSET] = base + 0x108; hwif->sata_scr[SATA_CONTROL_OFFSET] = base + 0x100; - hwif->sata_misc[SATA_MISC_OFFSET] = base + 0x140; - hwif->sata_misc[SATA_PHY_OFFSET] = base + 0x144; - hwif->sata_misc[SATA_IEN_OFFSET] = base + 0x148; } memcpy(hwif->io_ports, hw.io_ports, sizeof(hwif->io_ports)); diff --git a/drivers/input/touchscreen/h3600_ts_input.c b/drivers/input/touchscreen/h3600_ts_input.c index 2ae6c6016a86..28ae15ed12c5 100644 --- a/drivers/input/touchscreen/h3600_ts_input.c +++ b/drivers/input/touchscreen/h3600_ts_input.c @@ -109,7 +109,7 @@ struct h3600_dev { static irqreturn_t action_button_handler(int irq, void *dev_id) { int down = (GPLR & GPIO_BITSY_ACTION_BUTTON) ? 0 : 1; - struct input_dev *dev = (struct input_dev *) dev_id; + struct input_dev *dev = dev_id; input_report_key(dev, KEY_ENTER, down); input_sync(dev); @@ -120,7 +120,7 @@ static irqreturn_t action_button_handler(int irq, void *dev_id) static irqreturn_t npower_button_handler(int irq, void *dev_id) { int down = (GPLR & GPIO_BITSY_NPOWER_BUTTON) ? 0 : 1; - struct input_dev *dev = (struct input_dev *) dev_id; + struct input_dev *dev = dev_id; /* * This interrupt is only called when we release the key. So we have diff --git a/drivers/isdn/act2000/module.c b/drivers/isdn/act2000/module.c index ee2b0b9f8f46..8325022e2bed 100644 --- a/drivers/isdn/act2000/module.c +++ b/drivers/isdn/act2000/module.c @@ -310,7 +310,7 @@ act2000_command(act2000_card * card, isdn_ctrl * c) } break; case ISDN_CMD_DIAL: - if (!card->flags & ACT2000_FLAGS_RUNNING) + if (!(card->flags & ACT2000_FLAGS_RUNNING)) return -ENODEV; if (!(chan = find_channel(card, c->arg & 0x0f))) break; @@ -339,7 +339,7 @@ act2000_command(act2000_card * card, isdn_ctrl * c) } return ret; case ISDN_CMD_ACCEPTD: - if (!card->flags & ACT2000_FLAGS_RUNNING) + if (!(card->flags & ACT2000_FLAGS_RUNNING)) return -ENODEV; if (!(chan = find_channel(card, c->arg & 0x0f))) break; @@ -347,11 +347,11 @@ act2000_command(act2000_card * card, isdn_ctrl * c) actcapi_select_b2_protocol_req(card, chan); return 0; case ISDN_CMD_ACCEPTB: - if (!card->flags & ACT2000_FLAGS_RUNNING) + if (!(card->flags & ACT2000_FLAGS_RUNNING)) return -ENODEV; return 0; case ISDN_CMD_HANGUP: - if (!card->flags & ACT2000_FLAGS_RUNNING) + if (!(card->flags & ACT2000_FLAGS_RUNNING)) return -ENODEV; if (!(chan = find_channel(card, c->arg & 0x0f))) break; @@ -366,7 +366,7 @@ act2000_command(act2000_card * card, isdn_ctrl * c) } return 0; case ISDN_CMD_SETEAZ: - if (!card->flags & ACT2000_FLAGS_RUNNING) + if (!(card->flags & ACT2000_FLAGS_RUNNING)) return -ENODEV; if (!(chan = find_channel(card, c->arg & 0x0f))) break; @@ -386,7 +386,7 @@ act2000_command(act2000_card * card, isdn_ctrl * c) actcapi_listen_req(card); return 0; case ISDN_CMD_CLREAZ: - if (!card->flags & ACT2000_FLAGS_RUNNING) + if (!(card->flags & ACT2000_FLAGS_RUNNING)) return -ENODEV; if (!(chan = find_channel(card, c->arg & 0x0f))) break; @@ -394,14 +394,14 @@ act2000_command(act2000_card * card, isdn_ctrl * c) actcapi_listen_req(card); return 0; case ISDN_CMD_SETL2: - if (!card->flags & ACT2000_FLAGS_RUNNING) + if (!(card->flags & ACT2000_FLAGS_RUNNING)) return -ENODEV; if (!(chan = find_channel(card, c->arg & 0x0f))) break; chan->l2prot = (c->arg >> 8); return 0; case ISDN_CMD_SETL3: - if (!card->flags & ACT2000_FLAGS_RUNNING) + if (!(card->flags & ACT2000_FLAGS_RUNNING)) return -ENODEV; if ((c->arg >> 8) != ISDN_PROTO_L3_TRANS) { printk(KERN_WARNING "L3 protocol unknown\n"); @@ -524,7 +524,7 @@ if_writecmd(const u_char __user *buf, int len, int id, int channel) act2000_card *card = act2000_findcard(id); if (card) { - if (!card->flags & ACT2000_FLAGS_RUNNING) + if (!(card->flags & ACT2000_FLAGS_RUNNING)) return -ENODEV; return (len); } @@ -539,7 +539,7 @@ if_readstatus(u_char __user * buf, int len, int id, int channel) act2000_card *card = act2000_findcard(id); if (card) { - if (!card->flags & ACT2000_FLAGS_RUNNING) + if (!(card->flags & ACT2000_FLAGS_RUNNING)) return -ENODEV; return (act2000_readstatus(buf, len, card)); } @@ -554,7 +554,7 @@ if_sendbuf(int id, int channel, int ack, struct sk_buff *skb) act2000_card *card = act2000_findcard(id); if (card) { - if (!card->flags & ACT2000_FLAGS_RUNNING) + if (!(card->flags & ACT2000_FLAGS_RUNNING)) return -ENODEV; return (act2000_sendbuf(card, channel, ack, skb)); } diff --git a/drivers/isdn/gigaset/asyncdata.c b/drivers/isdn/gigaset/asyncdata.c index 00a3be5b862b..091deb9d1c47 100644 --- a/drivers/isdn/gigaset/asyncdata.c +++ b/drivers/isdn/gigaset/asyncdata.c @@ -350,8 +350,8 @@ void gigaset_m10x_input(struct inbuf_t *inbuf) unsigned char *src, c; int procbytes; - head = atomic_read(&inbuf->head); - tail = atomic_read(&inbuf->tail); + head = inbuf->head; + tail = inbuf->tail; gig_dbg(DEBUG_INTR, "buffer state: %u -> %u", head, tail); if (head != tail) { @@ -361,7 +361,7 @@ void gigaset_m10x_input(struct inbuf_t *inbuf) gig_dbg(DEBUG_INTR, "processing %u bytes", numbytes); while (numbytes) { - if (atomic_read(&cs->mstate) == MS_LOCKED) { + if (cs->mstate == MS_LOCKED) { procbytes = lock_loop(src, numbytes, inbuf); src += procbytes; numbytes -= procbytes; @@ -436,7 +436,7 @@ nextbyte: } gig_dbg(DEBUG_INTR, "setting head to %u", head); - atomic_set(&inbuf->head, head); + inbuf->head = head; } } EXPORT_SYMBOL_GPL(gigaset_m10x_input); diff --git a/drivers/isdn/gigaset/bas-gigaset.c b/drivers/isdn/gigaset/bas-gigaset.c index af7648274b38..5255b5e20e13 100644 --- a/drivers/isdn/gigaset/bas-gigaset.c +++ b/drivers/isdn/gigaset/bas-gigaset.c @@ -73,6 +73,14 @@ static int gigaset_probe(struct usb_interface *interface, /* Function will be called if the device is unplugged */ static void gigaset_disconnect(struct usb_interface *interface); +/* functions called before/after suspend */ +static int gigaset_suspend(struct usb_interface *intf, pm_message_t message); +static int gigaset_resume(struct usb_interface *intf); + +/* functions called before/after device reset */ +static int gigaset_pre_reset(struct usb_interface *intf); +static int gigaset_post_reset(struct usb_interface *intf); + static int atread_submit(struct cardstate *, int); static void stopurbs(struct bas_bc_state *); static int req_submit(struct bc_state *, int, int, int); @@ -105,8 +113,9 @@ struct bas_cardstate { unsigned char int_in_buf[3]; spinlock_t lock; /* locks all following */ - atomic_t basstate; /* bitmap (BS_*) */ + int basstate; /* bitmap (BS_*) */ int pending; /* uncompleted base request */ + wait_queue_head_t waitqueue; int rcvbuf_size; /* size of AT receive buffer */ /* 0: no receive in progress */ int retry_cmd_in; /* receive req retry count */ @@ -121,10 +130,10 @@ struct bas_cardstate { #define BS_ATTIMER 0x020 /* waiting for HD_READY_SEND_ATDATA */ #define BS_ATRDPEND 0x040 /* urb_cmd_in in use */ #define BS_ATWRPEND 0x080 /* urb_cmd_out in use */ +#define BS_SUSPEND 0x100 /* USB port suspended */ static struct gigaset_driver *driver = NULL; -static struct cardstate *cardstate = NULL; /* usb specific object needed to register this driver with the usb subsystem */ static struct usb_driver gigaset_usb_driver = { @@ -132,6 +141,11 @@ static struct usb_driver gigaset_usb_driver = { .probe = gigaset_probe, .disconnect = gigaset_disconnect, .id_table = gigaset_table, + .suspend = gigaset_suspend, + .resume = gigaset_resume, + .reset_resume = gigaset_post_reset, + .pre_reset = gigaset_pre_reset, + .post_reset = gigaset_post_reset, }; /* get message text for usb_submit_urb return code @@ -248,12 +262,12 @@ static inline void dump_urb(enum debuglevel level, const char *tag, if (urb) { gig_dbg(level, " dev=0x%08lx, pipe=%s:EP%d/DV%d:%s, " - "status=%d, hcpriv=0x%08lx, transfer_flags=0x%x,", + "hcpriv=0x%08lx, transfer_flags=0x%x,", (unsigned long) urb->dev, usb_pipetype_str(urb->pipe), usb_pipeendpoint(urb->pipe), usb_pipedevice(urb->pipe), usb_pipein(urb->pipe) ? "in" : "out", - urb->status, (unsigned long) urb->hcpriv, + (unsigned long) urb->hcpriv, urb->transfer_flags); gig_dbg(level, " transfer_buffer=0x%08lx[%d], actual_length=%d, " @@ -355,27 +369,27 @@ static void check_pending(struct bas_cardstate *ucs) case 0: break; case HD_OPEN_ATCHANNEL: - if (atomic_read(&ucs->basstate) & BS_ATOPEN) + if (ucs->basstate & BS_ATOPEN) ucs->pending = 0; break; case HD_OPEN_B1CHANNEL: - if (atomic_read(&ucs->basstate) & BS_B1OPEN) + if (ucs->basstate & BS_B1OPEN) ucs->pending = 0; break; case HD_OPEN_B2CHANNEL: - if (atomic_read(&ucs->basstate) & BS_B2OPEN) + if (ucs->basstate & BS_B2OPEN) ucs->pending = 0; break; case HD_CLOSE_ATCHANNEL: - if (!(atomic_read(&ucs->basstate) & BS_ATOPEN)) + if (!(ucs->basstate & BS_ATOPEN)) ucs->pending = 0; break; case HD_CLOSE_B1CHANNEL: - if (!(atomic_read(&ucs->basstate) & BS_B1OPEN)) + if (!(ucs->basstate & BS_B1OPEN)) ucs->pending = 0; break; case HD_CLOSE_B2CHANNEL: - if (!(atomic_read(&ucs->basstate) & BS_B2OPEN)) + if (!(ucs->basstate & BS_B2OPEN)) ucs->pending = 0; break; case HD_DEVICE_INIT_ACK: /* no reply expected */ @@ -441,8 +455,8 @@ inline static int update_basstate(struct bas_cardstate *ucs, int state; spin_lock_irqsave(&ucs->lock, flags); - state = atomic_read(&ucs->basstate); - atomic_set(&ucs->basstate, (state & ~clear) | set); + state = ucs->basstate; + ucs->basstate = (state & ~clear) | set; spin_unlock_irqrestore(&ucs->lock, flags); return state; } @@ -459,11 +473,13 @@ static void read_ctrl_callback(struct urb *urb) struct inbuf_t *inbuf = urb->context; struct cardstate *cs = inbuf->cs; struct bas_cardstate *ucs = cs->hw.bas; + int status = urb->status; int have_data = 0; unsigned numbytes; int rc; update_basstate(ucs, 0, BS_ATRDPEND); + wake_up(&ucs->waitqueue); if (!ucs->rcvbuf_size) { dev_warn(cs->dev, "%s: no receive in progress\n", __func__); @@ -472,7 +488,7 @@ static void read_ctrl_callback(struct urb *urb) del_timer(&ucs->timer_cmd_in); - switch (urb->status) { + switch (status) { case 0: /* normal completion */ numbytes = urb->actual_length; if (unlikely(numbytes != ucs->rcvbuf_size)) { @@ -506,12 +522,12 @@ static void read_ctrl_callback(struct urb *urb) case -ESHUTDOWN: /* device shut down */ /* no action necessary */ gig_dbg(DEBUG_USBREQ, "%s: %s", - __func__, get_usb_statmsg(urb->status)); + __func__, get_usb_statmsg(status)); break; default: /* severe trouble */ dev_warn(cs->dev, "control read: %s\n", - get_usb_statmsg(urb->status)); + get_usb_statmsg(status)); if (ucs->retry_cmd_in++ < BAS_RETRY) { dev_notice(cs->dev, "control read: retry %d\n", ucs->retry_cmd_in); @@ -550,17 +566,28 @@ static void read_ctrl_callback(struct urb *urb) static int atread_submit(struct cardstate *cs, int timeout) { struct bas_cardstate *ucs = cs->hw.bas; + int basstate; int ret; gig_dbg(DEBUG_USBREQ, "-------> HD_READ_ATMESSAGE (%d)", ucs->rcvbuf_size); - if (update_basstate(ucs, BS_ATRDPEND, 0) & BS_ATRDPEND) { + basstate = update_basstate(ucs, BS_ATRDPEND, 0); + if (basstate & BS_ATRDPEND) { dev_err(cs->dev, "could not submit HD_READ_ATMESSAGE: URB busy\n"); return -EBUSY; } + if (basstate & BS_SUSPEND) { + dev_notice(cs->dev, + "HD_READ_ATMESSAGE not submitted, " + "suspend in progress\n"); + update_basstate(ucs, 0, BS_ATRDPEND); + /* treat like disconnect */ + return -ENODEV; + } + ucs->dr_cmd_in.bRequestType = IN_VENDOR_REQ; ucs->dr_cmd_in.bRequest = HD_READ_ATMESSAGE; ucs->dr_cmd_in.wValue = 0; @@ -601,12 +628,13 @@ static void read_int_callback(struct urb *urb) struct cardstate *cs = urb->context; struct bas_cardstate *ucs = cs->hw.bas; struct bc_state *bcs; + int status = urb->status; unsigned long flags; int rc; unsigned l; int channel; - switch (urb->status) { + switch (status) { case 0: /* success */ break; case -ENOENT: /* cancelled */ @@ -614,7 +642,7 @@ static void read_int_callback(struct urb *urb) case -EINPROGRESS: /* pending */ /* ignore silently */ gig_dbg(DEBUG_USBREQ, "%s: %s", - __func__, get_usb_statmsg(urb->status)); + __func__, get_usb_statmsg(status)); return; case -ENODEV: /* device removed */ case -ESHUTDOWN: /* device shut down */ @@ -623,7 +651,7 @@ static void read_int_callback(struct urb *urb) return; default: /* severe trouble */ dev_warn(cs->dev, "interrupt read: %s\n", - get_usb_statmsg(urb->status)); + get_usb_statmsg(status)); //FIXME corrective action? resubmission always ok? goto resubmit; } @@ -745,6 +773,7 @@ static void read_int_callback(struct urb *urb) } check_pending(ucs); + wake_up(&ucs->waitqueue); resubmit: rc = usb_submit_urb(urb, GFP_ATOMIC); @@ -766,17 +795,18 @@ static void read_iso_callback(struct urb *urb) { struct bc_state *bcs; struct bas_bc_state *ubc; + int status = urb->status; unsigned long flags; int i, rc; /* status codes not worth bothering the tasklet with */ - if (unlikely(urb->status == -ENOENT || - urb->status == -ECONNRESET || - urb->status == -EINPROGRESS || - urb->status == -ENODEV || - urb->status == -ESHUTDOWN)) { + if (unlikely(status == -ENOENT || + status == -ECONNRESET || + status == -EINPROGRESS || + status == -ENODEV || + status == -ESHUTDOWN)) { gig_dbg(DEBUG_ISO, "%s: %s", - __func__, get_usb_statmsg(urb->status)); + __func__, get_usb_statmsg(status)); return; } @@ -787,10 +817,11 @@ static void read_iso_callback(struct urb *urb) if (likely(ubc->isoindone == NULL)) { /* pass URB to tasklet */ ubc->isoindone = urb; + ubc->isoinstatus = status; tasklet_schedule(&ubc->rcvd_tasklet); } else { /* tasklet still busy, drop data and resubmit URB */ - ubc->loststatus = urb->status; + ubc->loststatus = status; for (i = 0; i < BAS_NUMFRAMES; i++) { ubc->isoinlost += urb->iso_frame_desc[i].actual_length; if (unlikely(urb->iso_frame_desc[i].status != 0 && @@ -800,7 +831,7 @@ static void read_iso_callback(struct urb *urb) urb->iso_frame_desc[i].status = 0; urb->iso_frame_desc[i].actual_length = 0; } - if (likely(atomic_read(&ubc->running))) { + if (likely(ubc->running)) { /* urb->dev is clobbered by USB subsystem */ urb->dev = bcs->cs->hw.bas->udev; urb->transfer_flags = URB_ISO_ASAP; @@ -831,22 +862,24 @@ static void write_iso_callback(struct urb *urb) { struct isow_urbctx_t *ucx; struct bas_bc_state *ubc; + int status = urb->status; unsigned long flags; /* status codes not worth bothering the tasklet with */ - if (unlikely(urb->status == -ENOENT || - urb->status == -ECONNRESET || - urb->status == -EINPROGRESS || - urb->status == -ENODEV || - urb->status == -ESHUTDOWN)) { + if (unlikely(status == -ENOENT || + status == -ECONNRESET || + status == -EINPROGRESS || + status == -ENODEV || + status == -ESHUTDOWN)) { gig_dbg(DEBUG_ISO, "%s: %s", - __func__, get_usb_statmsg(urb->status)); + __func__, get_usb_statmsg(status)); return; } /* pass URB context to tasklet */ ucx = urb->context; ubc = ucx->bcs->hw.bas; + ucx->status = status; spin_lock_irqsave(&ubc->isooutlock, flags); ubc->isooutovfl = ubc->isooutdone; @@ -875,7 +908,7 @@ static int starturbs(struct bc_state *bcs) bcs->inputstate |= INS_flag_hunt; /* submit all isochronous input URBs */ - atomic_set(&ubc->running, 1); + ubc->running = 1; for (k = 0; k < BAS_INURBS; k++) { urb = ubc->isoinurbs[k]; if (!urb) { @@ -932,15 +965,15 @@ static int starturbs(struct bc_state *bcs) ubc->isoouturbs[k].limit = -1; } - /* submit two URBs, keep third one */ - for (k = 0; k < 2; ++k) { + /* keep one URB free, submit the others */ + for (k = 0; k < BAS_OUTURBS-1; ++k) { dump_urb(DEBUG_ISO, "Initial isoc write", urb); rc = usb_submit_urb(ubc->isoouturbs[k].urb, GFP_ATOMIC); if (rc != 0) goto error; } dump_urb(DEBUG_ISO, "Initial isoc write (free)", urb); - ubc->isooutfree = &ubc->isoouturbs[2]; + ubc->isooutfree = &ubc->isoouturbs[BAS_OUTURBS-1]; ubc->isooutdone = ubc->isooutovfl = NULL; return 0; error: @@ -958,7 +991,7 @@ static void stopurbs(struct bas_bc_state *ubc) { int k, rc; - atomic_set(&ubc->running, 0); + ubc->running = 0; for (k = 0; k < BAS_INURBS; ++k) { rc = usb_unlink_urb(ubc->isoinurbs[k]); @@ -1034,7 +1067,7 @@ static int submit_iso_write_urb(struct isow_urbctx_t *ucx) } break; } - ucx->limit = atomic_read(&ubc->isooutbuf->nextread); + ucx->limit = ubc->isooutbuf->nextread; ifd->status = 0; ifd->actual_length = 0; } @@ -1070,6 +1103,7 @@ static void write_iso_tasklet(unsigned long data) struct cardstate *cs = bcs->cs; struct isow_urbctx_t *done, *next, *ovfl; struct urb *urb; + int status; struct usb_iso_packet_descriptor *ifd; int offset; unsigned long flags; @@ -1080,7 +1114,7 @@ static void write_iso_tasklet(unsigned long data) /* loop while completed URBs arrive in time */ for (;;) { - if (unlikely(!(atomic_read(&ubc->running)))) { + if (unlikely(!(ubc->running))) { gig_dbg(DEBUG_ISO, "%s: not running", __func__); return; } @@ -1126,7 +1160,8 @@ static void write_iso_tasklet(unsigned long data) /* process completed URB */ urb = done->urb; - switch (urb->status) { + status = done->status; + switch (status) { case -EXDEV: /* partial completion */ gig_dbg(DEBUG_ISO, "%s: URB partially completed", __func__); @@ -1179,12 +1214,12 @@ static void write_iso_tasklet(unsigned long data) break; default: /* severe trouble */ dev_warn(cs->dev, "isochronous write: %s\n", - get_usb_statmsg(urb->status)); + get_usb_statmsg(status)); } /* mark the write buffer area covered by this URB as free */ if (done->limit >= 0) - atomic_set(&ubc->isooutbuf->read, done->limit); + ubc->isooutbuf->read = done->limit; /* mark URB as free */ spin_lock_irqsave(&ubc->isooutlock, flags); @@ -1233,6 +1268,7 @@ static void read_iso_tasklet(unsigned long data) struct bas_bc_state *ubc = bcs->hw.bas; struct cardstate *cs = bcs->cs; struct urb *urb; + int status; char *rcvbuf; unsigned long flags; int totleft, numbytes, offset, frame, rc; @@ -1245,6 +1281,7 @@ static void read_iso_tasklet(unsigned long data) spin_unlock_irqrestore(&ubc->isoinlock, flags); return; } + status = ubc->isoinstatus; ubc->isoindone = NULL; if (unlikely(ubc->loststatus != -EINPROGRESS)) { dev_warn(cs->dev, @@ -1256,15 +1293,15 @@ static void read_iso_tasklet(unsigned long data) } spin_unlock_irqrestore(&ubc->isoinlock, flags); - if (unlikely(!(atomic_read(&ubc->running)))) { + if (unlikely(!(ubc->running))) { gig_dbg(DEBUG_ISO, "%s: channel not running, " "dropped URB with status: %s", - __func__, get_usb_statmsg(urb->status)); + __func__, get_usb_statmsg(status)); return; } - switch (urb->status) { + switch (status) { case 0: /* normal completion */ break; case -EXDEV: /* inspect individual frames @@ -1276,7 +1313,7 @@ static void read_iso_tasklet(unsigned long data) case -ECONNRESET: case -EINPROGRESS: gig_dbg(DEBUG_ISO, "%s: %s", - __func__, get_usb_statmsg(urb->status)); + __func__, get_usb_statmsg(status)); continue; /* -> skip */ case -EPIPE: dev_err(cs->dev, "isochronous read stalled\n"); @@ -1284,7 +1321,7 @@ static void read_iso_tasklet(unsigned long data) continue; /* -> skip */ default: /* severe trouble */ dev_warn(cs->dev, "isochronous read: %s\n", - get_usb_statmsg(urb->status)); + get_usb_statmsg(status)); goto error; } @@ -1406,6 +1443,8 @@ static void req_timeout(unsigned long data) dev_warn(bcs->cs->dev, "request 0x%02x timed out, clearing\n", pending); } + + wake_up(&ucs->waitqueue); } /* write_ctrl_callback @@ -1418,11 +1457,12 @@ static void req_timeout(unsigned long data) static void write_ctrl_callback(struct urb *urb) { struct bas_cardstate *ucs = urb->context; + int status = urb->status; int rc; unsigned long flags; /* check status */ - switch (urb->status) { + switch (status) { case 0: /* normal completion */ spin_lock_irqsave(&ucs->lock, flags); switch (ucs->pending) { @@ -1441,20 +1481,22 @@ static void write_ctrl_callback(struct urb *urb) case -ESHUTDOWN: /* device shut down */ /* ignore silently */ gig_dbg(DEBUG_USBREQ, "%s: %s", - __func__, get_usb_statmsg(urb->status)); + __func__, get_usb_statmsg(status)); break; default: /* any failure */ - if (++ucs->retry_ctrl > BAS_RETRY) { + /* don't retry if suspend requested */ + if (++ucs->retry_ctrl > BAS_RETRY || + (ucs->basstate & BS_SUSPEND)) { dev_err(&ucs->interface->dev, "control request 0x%02x failed: %s\n", ucs->dr_ctrl.bRequest, - get_usb_statmsg(urb->status)); + get_usb_statmsg(status)); break; /* give up */ } dev_notice(&ucs->interface->dev, "control request 0x%02x: %s, retry %d\n", - ucs->dr_ctrl.bRequest, get_usb_statmsg(urb->status), + ucs->dr_ctrl.bRequest, get_usb_statmsg(status), ucs->retry_ctrl); /* urb->dev is clobbered by USB subsystem */ urb->dev = ucs->udev; @@ -1474,6 +1516,7 @@ static void write_ctrl_callback(struct urb *urb) del_timer(&ucs->timer_ctrl); ucs->pending = 0; spin_unlock_irqrestore(&ucs->lock, flags); + wake_up(&ucs->waitqueue); } /* req_submit @@ -1548,37 +1591,46 @@ static int req_submit(struct bc_state *bcs, int req, int val, int timeout) */ static int gigaset_init_bchannel(struct bc_state *bcs) { + struct cardstate *cs = bcs->cs; int req, ret; unsigned long flags; - spin_lock_irqsave(&bcs->cs->lock, flags); - if (unlikely(!bcs->cs->connected)) { + spin_lock_irqsave(&cs->lock, flags); + if (unlikely(!cs->connected)) { gig_dbg(DEBUG_USBREQ, "%s: not connected", __func__); - spin_unlock_irqrestore(&bcs->cs->lock, flags); + spin_unlock_irqrestore(&cs->lock, flags); return -ENODEV; } + if (cs->hw.bas->basstate & BS_SUSPEND) { + dev_notice(cs->dev, + "not starting isochronous I/O, " + "suspend in progress\n"); + spin_unlock_irqrestore(&cs->lock, flags); + return -EHOSTUNREACH; + } + if ((ret = starturbs(bcs)) < 0) { - dev_err(bcs->cs->dev, + dev_err(cs->dev, "could not start isochronous I/O for channel B%d: %s\n", bcs->channel + 1, ret == -EFAULT ? "null URB" : get_usb_rcmsg(ret)); if (ret != -ENODEV) error_hangup(bcs); - spin_unlock_irqrestore(&bcs->cs->lock, flags); + spin_unlock_irqrestore(&cs->lock, flags); return ret; } req = bcs->channel ? HD_OPEN_B2CHANNEL : HD_OPEN_B1CHANNEL; if ((ret = req_submit(bcs, req, 0, BAS_TIMEOUT)) < 0) { - dev_err(bcs->cs->dev, "could not open channel B%d\n", + dev_err(cs->dev, "could not open channel B%d\n", bcs->channel + 1); stopurbs(bcs->hw.bas); if (ret != -ENODEV) error_hangup(bcs); } - spin_unlock_irqrestore(&bcs->cs->lock, flags); + spin_unlock_irqrestore(&cs->lock, flags); return ret; } @@ -1594,20 +1646,20 @@ static int gigaset_init_bchannel(struct bc_state *bcs) */ static int gigaset_close_bchannel(struct bc_state *bcs) { + struct cardstate *cs = bcs->cs; int req, ret; unsigned long flags; - spin_lock_irqsave(&bcs->cs->lock, flags); - if (unlikely(!bcs->cs->connected)) { - spin_unlock_irqrestore(&bcs->cs->lock, flags); + spin_lock_irqsave(&cs->lock, flags); + if (unlikely(!cs->connected)) { + spin_unlock_irqrestore(&cs->lock, flags); gig_dbg(DEBUG_USBREQ, "%s: not connected", __func__); return -ENODEV; } - if (!(atomic_read(&bcs->cs->hw.bas->basstate) & - (bcs->channel ? BS_B2OPEN : BS_B1OPEN))) { + if (!(cs->hw.bas->basstate & (bcs->channel ? BS_B2OPEN : BS_B1OPEN))) { /* channel not running: just signal common.c */ - spin_unlock_irqrestore(&bcs->cs->lock, flags); + spin_unlock_irqrestore(&cs->lock, flags); gigaset_bchannel_down(bcs); return 0; } @@ -1615,10 +1667,10 @@ static int gigaset_close_bchannel(struct bc_state *bcs) /* channel running: tell device to close it */ req = bcs->channel ? HD_CLOSE_B2CHANNEL : HD_CLOSE_B1CHANNEL; if ((ret = req_submit(bcs, req, 0, BAS_TIMEOUT)) < 0) - dev_err(bcs->cs->dev, "closing channel B%d failed\n", + dev_err(cs->dev, "closing channel B%d failed\n", bcs->channel + 1); - spin_unlock_irqrestore(&bcs->cs->lock, flags); + spin_unlock_irqrestore(&cs->lock, flags); return ret; } @@ -1665,12 +1717,14 @@ static void write_command_callback(struct urb *urb) { struct cardstate *cs = urb->context; struct bas_cardstate *ucs = cs->hw.bas; + int status = urb->status; unsigned long flags; update_basstate(ucs, 0, BS_ATWRPEND); + wake_up(&ucs->waitqueue); /* check status */ - switch (urb->status) { + switch (status) { case 0: /* normal completion */ break; case -ENOENT: /* cancelled */ @@ -1680,26 +1734,33 @@ static void write_command_callback(struct urb *urb) case -ESHUTDOWN: /* device shut down */ /* ignore silently */ gig_dbg(DEBUG_USBREQ, "%s: %s", - __func__, get_usb_statmsg(urb->status)); + __func__, get_usb_statmsg(status)); return; default: /* any failure */ if (++ucs->retry_cmd_out > BAS_RETRY) { dev_warn(cs->dev, "command write: %s, " "giving up after %d retries\n", - get_usb_statmsg(urb->status), + get_usb_statmsg(status), ucs->retry_cmd_out); break; } + if (ucs->basstate & BS_SUSPEND) { + dev_warn(cs->dev, + "command write: %s, " + "won't retry - suspend requested\n", + get_usb_statmsg(status)); + break; + } if (cs->cmdbuf == NULL) { dev_warn(cs->dev, "command write: %s, " "cannot retry - cmdbuf gone\n", - get_usb_statmsg(urb->status)); + get_usb_statmsg(status)); break; } dev_notice(cs->dev, "command write: %s, retry %d\n", - get_usb_statmsg(urb->status), ucs->retry_cmd_out); + get_usb_statmsg(status), ucs->retry_cmd_out); if (atwrite_submit(cs, cs->cmdbuf->buf, cs->cmdbuf->len) >= 0) /* resubmitted - bypass regular exit block */ return; @@ -1799,8 +1860,14 @@ static int start_cbsend(struct cardstate *cs) int rc; int retval = 0; + /* check if suspend requested */ + if (ucs->basstate & BS_SUSPEND) { + gig_dbg(DEBUG_TRANSCMD|DEBUG_LOCKCMD, "suspending"); + return -EHOSTUNREACH; + } + /* check if AT channel is open */ - if (!(atomic_read(&ucs->basstate) & BS_ATOPEN)) { + if (!(ucs->basstate & BS_ATOPEN)) { gig_dbg(DEBUG_TRANSCMD|DEBUG_LOCKCMD, "AT channel not open"); rc = req_submit(cs->bcs, HD_OPEN_ATCHANNEL, 0, BAS_TIMEOUT); if (rc < 0) { @@ -1816,8 +1883,7 @@ static int start_cbsend(struct cardstate *cs) /* try to send first command in queue */ spin_lock_irqsave(&cs->cmdlock, flags); - while ((cb = cs->cmdbuf) != NULL && - atomic_read(&ucs->basstate) & BS_ATREADY) { + while ((cb = cs->cmdbuf) != NULL && (ucs->basstate & BS_ATREADY)) { ucs->retry_cmd_out = 0; rc = atwrite_submit(cs, cb->buf, cb->len); if (unlikely(rc)) { @@ -1855,7 +1921,7 @@ static int gigaset_write_cmd(struct cardstate *cs, unsigned long flags; int rc; - gigaset_dbg_buffer(atomic_read(&cs->mstate) != MS_LOCKED ? + gigaset_dbg_buffer(cs->mstate != MS_LOCKED ? DEBUG_TRANSCMD : DEBUG_LOCKCMD, "CMD Transmit", len, buf); @@ -1970,7 +2036,7 @@ static int gigaset_freebcshw(struct bc_state *bcs) return 0; /* kill URBs and tasklets before freeing - better safe than sorry */ - atomic_set(&ubc->running, 0); + ubc->running = 0; gig_dbg(DEBUG_INIT, "%s: killing iso URBs", __func__); for (i = 0; i < BAS_OUTURBS; ++i) { usb_kill_urb(ubc->isoouturbs[i].urb); @@ -2005,7 +2071,7 @@ static int gigaset_initbcshw(struct bc_state *bcs) return 0; } - atomic_set(&ubc->running, 0); + ubc->running = 0; atomic_set(&ubc->corrbytes, 0); spin_lock_init(&ubc->isooutlock); for (i = 0; i < BAS_OUTURBS; ++i) { @@ -2050,7 +2116,7 @@ static void gigaset_reinitbcshw(struct bc_state *bcs) { struct bas_bc_state *ubc = bcs->hw.bas; - atomic_set(&bcs->hw.bas->running, 0); + bcs->hw.bas->running = 0; atomic_set(&bcs->hw.bas->corrbytes, 0); bcs->hw.bas->numsub = 0; spin_lock_init(&ubc->isooutlock); @@ -2081,10 +2147,11 @@ static int gigaset_initcshw(struct cardstate *cs) spin_lock_init(&ucs->lock); ucs->pending = 0; - atomic_set(&ucs->basstate, 0); + ucs->basstate = 0; init_timer(&ucs->timer_ctrl); init_timer(&ucs->timer_atrdy); init_timer(&ucs->timer_cmd_in); + init_waitqueue_head(&ucs->waitqueue); return 1; } @@ -2102,7 +2169,7 @@ static void freeurbs(struct cardstate *cs) int i, j; gig_dbg(DEBUG_INIT, "%s: killing URBs", __func__); - for (j = 0; j < 2; ++j) { + for (j = 0; j < BAS_CHANNELS; ++j) { ubc = cs->bcs[j].hw.bas; for (i = 0; i < BAS_OUTURBS; ++i) { usb_kill_urb(ubc->isoouturbs[i].urb); @@ -2179,11 +2246,11 @@ static int gigaset_probe(struct usb_interface *interface, __func__, le16_to_cpu(udev->descriptor.idVendor), le16_to_cpu(udev->descriptor.idProduct)); - cs = gigaset_getunassignedcs(driver); - if (!cs) { - dev_err(&udev->dev, "no free cardstate\n"); + /* allocate memory for our device state and intialize it */ + cs = gigaset_initcs(driver, BAS_CHANNELS, 0, 0, cidmode, + GIGASET_MODULENAME); + if (!cs) return -ENODEV; - } ucs = cs->hw.bas; /* save off device structure ptrs for later use */ @@ -2203,7 +2270,7 @@ static int gigaset_probe(struct usb_interface *interface, !(ucs->urb_ctrl = usb_alloc_urb(0, GFP_KERNEL))) goto allocerr; - for (j = 0; j < 2; ++j) { + for (j = 0; j < BAS_CHANNELS; ++j) { ubc = cs->bcs[j].hw.bas; for (i = 0; i < BAS_OUTURBS; ++i) if (!(ubc->isoouturbs[i].urb = @@ -2237,7 +2304,7 @@ static int gigaset_probe(struct usb_interface *interface, /* tell common part that the device is ready */ if (startmode == SM_LOCKED) - atomic_set(&cs->mstate, MS_LOCKED); + cs->mstate = MS_LOCKED; /* save address of controller structure */ usb_set_intfdata(interface, cs); @@ -2252,7 +2319,7 @@ allocerr: error: freeurbs(cs); usb_set_intfdata(interface, NULL); - gigaset_unassign(cs); + gigaset_freecs(cs); return -ENODEV; } @@ -2272,11 +2339,10 @@ static void gigaset_disconnect(struct usb_interface *interface) dev_info(cs->dev, "disconnecting Gigaset base\n"); /* mark base as not ready, all channels disconnected */ - atomic_set(&ucs->basstate, 0); + ucs->basstate = 0; /* tell LL all channels are down */ - //FIXME shouldn't gigaset_stop() do this? - for (j = 0; j < 2; ++j) + for (j = 0; j < BAS_CHANNELS; ++j) gigaset_bchannel_down(cs->bcs + j); /* stop driver (common part) */ @@ -2295,9 +2361,113 @@ static void gigaset_disconnect(struct usb_interface *interface) ucs->interface = NULL; ucs->udev = NULL; cs->dev = NULL; - gigaset_unassign(cs); + gigaset_freecs(cs); } +/* gigaset_suspend + * This function is called before the USB connection is suspended. + */ +static int gigaset_suspend(struct usb_interface *intf, pm_message_t message) +{ + struct cardstate *cs = usb_get_intfdata(intf); + struct bas_cardstate *ucs = cs->hw.bas; + int rc; + + /* set suspend flag; this stops AT command/response traffic */ + if (update_basstate(ucs, BS_SUSPEND, 0) & BS_SUSPEND) { + gig_dbg(DEBUG_SUSPEND, "already suspended"); + return 0; + } + + /* wait a bit for blocking conditions to go away */ + rc = wait_event_timeout(ucs->waitqueue, + !(ucs->basstate & + (BS_B1OPEN|BS_B2OPEN|BS_ATRDPEND|BS_ATWRPEND)), + BAS_TIMEOUT*HZ/10); + gig_dbg(DEBUG_SUSPEND, "wait_event_timeout() -> %d", rc); + + /* check for conditions preventing suspend */ + if (ucs->basstate & (BS_B1OPEN|BS_B2OPEN|BS_ATRDPEND|BS_ATWRPEND)) { + dev_warn(cs->dev, "cannot suspend:\n"); + if (ucs->basstate & BS_B1OPEN) + dev_warn(cs->dev, " B channel 1 open\n"); + if (ucs->basstate & BS_B2OPEN) + dev_warn(cs->dev, " B channel 2 open\n"); + if (ucs->basstate & BS_ATRDPEND) + dev_warn(cs->dev, " receiving AT reply\n"); + if (ucs->basstate & BS_ATWRPEND) + dev_warn(cs->dev, " sending AT command\n"); + update_basstate(ucs, 0, BS_SUSPEND); + return -EBUSY; + } + + /* close AT channel if open */ + if (ucs->basstate & BS_ATOPEN) { + gig_dbg(DEBUG_SUSPEND, "closing AT channel"); + rc = req_submit(cs->bcs, HD_CLOSE_ATCHANNEL, 0, 0); + if (rc) { + update_basstate(ucs, 0, BS_SUSPEND); + return rc; + } + wait_event_timeout(ucs->waitqueue, !ucs->pending, + BAS_TIMEOUT*HZ/10); + /* in case of timeout, proceed anyway */ + } + + /* kill all URBs and timers that might still be pending */ + usb_kill_urb(ucs->urb_ctrl); + usb_kill_urb(ucs->urb_int_in); + del_timer_sync(&ucs->timer_ctrl); + + gig_dbg(DEBUG_SUSPEND, "suspend complete"); + return 0; +} + +/* gigaset_resume + * This function is called after the USB connection has been resumed. + */ +static int gigaset_resume(struct usb_interface *intf) +{ + struct cardstate *cs = usb_get_intfdata(intf); + struct bas_cardstate *ucs = cs->hw.bas; + int rc; + + /* resubmit interrupt URB for spontaneous messages from base */ + rc = usb_submit_urb(ucs->urb_int_in, GFP_KERNEL); + if (rc) { + dev_err(cs->dev, "could not resubmit interrupt URB: %s\n", + get_usb_rcmsg(rc)); + return rc; + } + + /* clear suspend flag to reallow activity */ + update_basstate(ucs, 0, BS_SUSPEND); + + gig_dbg(DEBUG_SUSPEND, "resume complete"); + return 0; +} + +/* gigaset_pre_reset + * This function is called before the USB connection is reset. + */ +static int gigaset_pre_reset(struct usb_interface *intf) +{ + /* handle just like suspend */ + return gigaset_suspend(intf, PMSG_ON); +} + +/* gigaset_post_reset + * This function is called after the USB connection has been reset. + */ +static int gigaset_post_reset(struct usb_interface *intf) +{ + /* FIXME: send HD_DEVICE_INIT_ACK? */ + + /* resume operations */ + return gigaset_resume(intf); +} + + static const struct gigaset_ops gigops = { gigaset_write_cmd, gigaset_write_room, @@ -2330,12 +2500,6 @@ static int __init bas_gigaset_init(void) &gigops, THIS_MODULE)) == NULL) goto error; - /* allocate memory for our device state and intialize it */ - cardstate = gigaset_initcs(driver, 2, 0, 0, cidmode, - GIGASET_MODULENAME); - if (!cardstate) - goto error; - /* register this driver with the USB subsystem */ result = usb_register(&gigaset_usb_driver); if (result < 0) { @@ -2347,9 +2511,7 @@ static int __init bas_gigaset_init(void) info(DRIVER_DESC); return 0; -error: if (cardstate) - gigaset_freecs(cardstate); - cardstate = NULL; +error: if (driver) gigaset_freedriver(driver); driver = NULL; @@ -2361,43 +2523,50 @@ error: if (cardstate) */ static void __exit bas_gigaset_exit(void) { - struct bas_cardstate *ucs = cardstate->hw.bas; + struct bas_cardstate *ucs; + int i; gigaset_blockdriver(driver); /* => probe will fail * => no gigaset_start any more */ - gigaset_shutdown(cardstate); - /* from now on, no isdn callback should be possible */ - - /* close all still open channels */ - if (atomic_read(&ucs->basstate) & BS_B1OPEN) { - gig_dbg(DEBUG_INIT, "closing B1 channel"); - usb_control_msg(ucs->udev, usb_sndctrlpipe(ucs->udev, 0), - HD_CLOSE_B1CHANNEL, OUT_VENDOR_REQ, 0, 0, - NULL, 0, BAS_TIMEOUT); - } - if (atomic_read(&ucs->basstate) & BS_B2OPEN) { - gig_dbg(DEBUG_INIT, "closing B2 channel"); - usb_control_msg(ucs->udev, usb_sndctrlpipe(ucs->udev, 0), - HD_CLOSE_B2CHANNEL, OUT_VENDOR_REQ, 0, 0, - NULL, 0, BAS_TIMEOUT); - } - if (atomic_read(&ucs->basstate) & BS_ATOPEN) { - gig_dbg(DEBUG_INIT, "closing AT channel"); - usb_control_msg(ucs->udev, usb_sndctrlpipe(ucs->udev, 0), - HD_CLOSE_ATCHANNEL, OUT_VENDOR_REQ, 0, 0, - NULL, 0, BAS_TIMEOUT); + /* stop all connected devices */ + for (i = 0; i < driver->minors; i++) { + if (gigaset_shutdown(driver->cs + i) < 0) + continue; /* no device */ + /* from now on, no isdn callback should be possible */ + + /* close all still open channels */ + ucs = driver->cs[i].hw.bas; + if (ucs->basstate & BS_B1OPEN) { + gig_dbg(DEBUG_INIT, "closing B1 channel"); + usb_control_msg(ucs->udev, + usb_sndctrlpipe(ucs->udev, 0), + HD_CLOSE_B1CHANNEL, OUT_VENDOR_REQ, + 0, 0, NULL, 0, BAS_TIMEOUT); + } + if (ucs->basstate & BS_B2OPEN) { + gig_dbg(DEBUG_INIT, "closing B2 channel"); + usb_control_msg(ucs->udev, + usb_sndctrlpipe(ucs->udev, 0), + HD_CLOSE_B2CHANNEL, OUT_VENDOR_REQ, + 0, 0, NULL, 0, BAS_TIMEOUT); + } + if (ucs->basstate & BS_ATOPEN) { + gig_dbg(DEBUG_INIT, "closing AT channel"); + usb_control_msg(ucs->udev, + usb_sndctrlpipe(ucs->udev, 0), + HD_CLOSE_ATCHANNEL, OUT_VENDOR_REQ, + 0, 0, NULL, 0, BAS_TIMEOUT); + } + ucs->basstate = 0; } - atomic_set(&ucs->basstate, 0); /* deregister this driver with the USB subsystem */ usb_deregister(&gigaset_usb_driver); /* this will call the disconnect-callback */ /* from now on, no disconnect/probe callback should be running */ - gigaset_freecs(cardstate); - cardstate = NULL; gigaset_freedriver(driver); driver = NULL; } diff --git a/drivers/isdn/gigaset/common.c b/drivers/isdn/gigaset/common.c index acd417197d03..aacedec4986f 100644 --- a/drivers/isdn/gigaset/common.c +++ b/drivers/isdn/gigaset/common.c @@ -31,7 +31,6 @@ MODULE_PARM_DESC(debug, "debug level"); /* driver state flags */ #define VALID_MINOR 0x01 #define VALID_ID 0x02 -#define ASSIGNED 0x04 void gigaset_dbg_buffer(enum debuglevel level, const unsigned char *msg, size_t len, const unsigned char *buf) @@ -178,7 +177,7 @@ int gigaset_get_channel(struct bc_state *bcs) unsigned long flags; spin_lock_irqsave(&bcs->cs->lock, flags); - if (bcs->use_count) { + if (bcs->use_count || !try_module_get(bcs->cs->driver->owner)) { gig_dbg(DEBUG_ANY, "could not allocate channel %d", bcs->channel); spin_unlock_irqrestore(&bcs->cs->lock, flags); @@ -203,6 +202,7 @@ void gigaset_free_channel(struct bc_state *bcs) } --bcs->use_count; bcs->busy = 0; + module_put(bcs->cs->driver->owner); gig_dbg(DEBUG_ANY, "freed channel %d", bcs->channel); spin_unlock_irqrestore(&bcs->cs->lock, flags); } @@ -356,31 +356,28 @@ static struct cardstate *alloc_cs(struct gigaset_driver *drv) { unsigned long flags; unsigned i; + struct cardstate *cs; struct cardstate *ret = NULL; spin_lock_irqsave(&drv->lock, flags); + if (drv->blocked) + goto exit; for (i = 0; i < drv->minors; ++i) { - if (!(drv->flags[i] & VALID_MINOR)) { - if (try_module_get(drv->owner)) { - drv->flags[i] = VALID_MINOR; - ret = drv->cs + i; - } + cs = drv->cs + i; + if (!(cs->flags & VALID_MINOR)) { + cs->flags = VALID_MINOR; + ret = cs; break; } } +exit: spin_unlock_irqrestore(&drv->lock, flags); return ret; } static void free_cs(struct cardstate *cs) { - unsigned long flags; - struct gigaset_driver *drv = cs->driver; - spin_lock_irqsave(&drv->lock, flags); - if (drv->flags[cs->minor_index] & VALID_MINOR) - module_put(drv->owner); - drv->flags[cs->minor_index] = 0; - spin_unlock_irqrestore(&drv->lock, flags); + cs->flags = 0; } static void make_valid(struct cardstate *cs, unsigned mask) @@ -388,7 +385,7 @@ static void make_valid(struct cardstate *cs, unsigned mask) unsigned long flags; struct gigaset_driver *drv = cs->driver; spin_lock_irqsave(&drv->lock, flags); - drv->flags[cs->minor_index] |= mask; + cs->flags |= mask; spin_unlock_irqrestore(&drv->lock, flags); } @@ -397,7 +394,7 @@ static void make_invalid(struct cardstate *cs, unsigned mask) unsigned long flags; struct gigaset_driver *drv = cs->driver; spin_lock_irqsave(&drv->lock, flags); - drv->flags[cs->minor_index] &= ~mask; + cs->flags &= ~mask; spin_unlock_irqrestore(&drv->lock, flags); } @@ -501,11 +498,11 @@ static void gigaset_inbuf_init(struct inbuf_t *inbuf, struct bc_state *bcs, struct cardstate *cs, int inputstate) /* inbuf->read must be allocated before! */ { - atomic_set(&inbuf->head, 0); - atomic_set(&inbuf->tail, 0); + inbuf->head = 0; + inbuf->tail = 0; inbuf->cs = cs; inbuf->bcs = bcs; /*base driver: NULL*/ - inbuf->rcvbuf = NULL; //FIXME + inbuf->rcvbuf = NULL; inbuf->inputstate = inputstate; } @@ -521,8 +518,8 @@ int gigaset_fill_inbuf(struct inbuf_t *inbuf, const unsigned char *src, return 0; bytesleft = numbytes; - tail = atomic_read(&inbuf->tail); - head = atomic_read(&inbuf->head); + tail = inbuf->tail; + head = inbuf->head; gig_dbg(DEBUG_INTR, "buffer state: %u -> %u", head, tail); while (bytesleft) { @@ -546,7 +543,7 @@ int gigaset_fill_inbuf(struct inbuf_t *inbuf, const unsigned char *src, src += n; } gig_dbg(DEBUG_INTR, "setting tail to %u", tail); - atomic_set(&inbuf->tail, tail); + inbuf->tail = tail; return numbytes != bytesleft; } EXPORT_SYMBOL_GPL(gigaset_fill_inbuf); @@ -668,7 +665,7 @@ struct cardstate *gigaset_initcs(struct gigaset_driver *drv, int channels, tasklet_init(&cs->event_tasklet, &gigaset_handle_event, (unsigned long) cs); - atomic_set(&cs->commands_pending, 0); + cs->commands_pending = 0; cs->cur_at_seq = 0; cs->gotfwver = -1; cs->open_count = 0; @@ -688,8 +685,8 @@ struct cardstate *gigaset_initcs(struct gigaset_driver *drv, int channels, init_waitqueue_head(&cs->waitqueue); cs->waiting = 0; - atomic_set(&cs->mode, M_UNKNOWN); - atomic_set(&cs->mstate, MS_UNINITIALIZED); + cs->mode = M_UNKNOWN; + cs->mstate = MS_UNINITIALIZED; for (i = 0; i < channels; ++i) { gig_dbg(DEBUG_INIT, "setting up bcs[%d].read", i); @@ -806,8 +803,8 @@ static void cleanup_cs(struct cardstate *cs) spin_lock_irqsave(&cs->lock, flags); - atomic_set(&cs->mode, M_UNKNOWN); - atomic_set(&cs->mstate, MS_UNINITIALIZED); + cs->mode = M_UNKNOWN; + cs->mstate = MS_UNINITIALIZED; clear_at_state(&cs->at_state); dealloc_at_states(cs); @@ -817,8 +814,8 @@ static void cleanup_cs(struct cardstate *cs) kfree(cs->inbuf->rcvbuf); cs->inbuf->rcvbuf = NULL; cs->inbuf->inputstate = INS_command; - atomic_set(&cs->inbuf->head, 0); - atomic_set(&cs->inbuf->tail, 0); + cs->inbuf->head = 0; + cs->inbuf->tail = 0; cb = cs->cmdbuf; while (cb) { @@ -832,7 +829,7 @@ static void cleanup_cs(struct cardstate *cs) cs->gotfwver = -1; cs->dle = 0; cs->cur_at_seq = 0; - atomic_set(&cs->commands_pending, 0); + cs->commands_pending = 0; cs->cbytes = 0; spin_unlock_irqrestore(&cs->lock, flags); @@ -862,7 +859,7 @@ int gigaset_start(struct cardstate *cs) cs->connected = 1; spin_unlock_irqrestore(&cs->lock, flags); - if (atomic_read(&cs->mstate) != MS_LOCKED) { + if (cs->mstate != MS_LOCKED) { cs->ops->set_modem_ctrl(cs, 0, TIOCM_DTR|TIOCM_RTS); cs->ops->baud_rate(cs, B115200); cs->ops->set_line_ctrl(cs, CS8); @@ -893,10 +890,17 @@ error: } EXPORT_SYMBOL_GPL(gigaset_start); -void gigaset_shutdown(struct cardstate *cs) +/* gigaset_shutdown + * check if a device is associated to the cardstate structure and stop it + * return value: 0 if ok, -1 if no device was associated + */ +int gigaset_shutdown(struct cardstate *cs) { mutex_lock(&cs->mutex); + if (!(cs->flags & VALID_MINOR)) + return -1; + cs->waiting = 1; if (!gigaset_add_event(cs, &cs->at_state, EV_SHUTDOWN, NULL, 0, NULL)) { @@ -913,6 +917,7 @@ void gigaset_shutdown(struct cardstate *cs) exit: mutex_unlock(&cs->mutex); + return 0; } EXPORT_SYMBOL_GPL(gigaset_shutdown); @@ -954,13 +959,11 @@ struct cardstate *gigaset_get_cs_by_id(int id) list_for_each_entry(drv, &drivers, list) { spin_lock(&drv->lock); for (i = 0; i < drv->minors; ++i) { - if (drv->flags[i] & VALID_ID) { - cs = drv->cs + i; - if (cs->myid == id) - ret = cs; - } - if (ret) + cs = drv->cs + i; + if ((cs->flags & VALID_ID) && cs->myid == id) { + ret = cs; break; + } } spin_unlock(&drv->lock); if (ret) @@ -983,10 +986,9 @@ void gigaset_debugdrivers(void) spin_lock(&drv->lock); for (i = 0; i < drv->minors; ++i) { gig_dbg(DEBUG_DRIVER, " index %u", i); - gig_dbg(DEBUG_DRIVER, " flags 0x%02x", - drv->flags[i]); cs = drv->cs + i; gig_dbg(DEBUG_DRIVER, " cardstate %p", cs); + gig_dbg(DEBUG_DRIVER, " flags 0x%02x", cs->flags); gig_dbg(DEBUG_DRIVER, " minor_index %u", cs->minor_index); gig_dbg(DEBUG_DRIVER, " driver %p", cs->driver); @@ -1010,7 +1012,7 @@ static struct cardstate *gigaset_get_cs_by_minor(unsigned minor) continue; index = minor - drv->minor; spin_lock(&drv->lock); - if (drv->flags[index] & VALID_MINOR) + if (drv->cs[index].flags & VALID_MINOR) ret = drv->cs + index; spin_unlock(&drv->lock); if (ret) @@ -1038,7 +1040,6 @@ void gigaset_freedriver(struct gigaset_driver *drv) gigaset_if_freedriver(drv); kfree(drv->cs); - kfree(drv->flags); kfree(drv); } EXPORT_SYMBOL_GPL(gigaset_freedriver); @@ -1080,12 +1081,8 @@ struct gigaset_driver *gigaset_initdriver(unsigned minor, unsigned minors, if (!drv->cs) goto error; - drv->flags = kmalloc(minors * sizeof *drv->flags, GFP_KERNEL); - if (!drv->flags) - goto error; - for (i = 0; i < minors; ++i) { - drv->flags[i] = 0; + drv->cs[i].flags = 0; drv->cs[i].driver = drv; drv->cs[i].ops = drv->ops; drv->cs[i].minor_index = i; @@ -1106,53 +1103,9 @@ error: } EXPORT_SYMBOL_GPL(gigaset_initdriver); -/* For drivers without fixed assignment device<->cardstate (usb) */ -struct cardstate *gigaset_getunassignedcs(struct gigaset_driver *drv) -{ - unsigned long flags; - struct cardstate *cs = NULL; - unsigned i; - - spin_lock_irqsave(&drv->lock, flags); - if (drv->blocked) - goto exit; - for (i = 0; i < drv->minors; ++i) { - if ((drv->flags[i] & VALID_MINOR) && - !(drv->flags[i] & ASSIGNED)) { - drv->flags[i] |= ASSIGNED; - cs = drv->cs + i; - break; - } - } -exit: - spin_unlock_irqrestore(&drv->lock, flags); - return cs; -} -EXPORT_SYMBOL_GPL(gigaset_getunassignedcs); - -void gigaset_unassign(struct cardstate *cs) -{ - unsigned long flags; - unsigned *minor_flags; - struct gigaset_driver *drv; - - if (!cs) - return; - drv = cs->driver; - spin_lock_irqsave(&drv->lock, flags); - minor_flags = drv->flags + cs->minor_index; - if (*minor_flags & VALID_MINOR) - *minor_flags &= ~ASSIGNED; - spin_unlock_irqrestore(&drv->lock, flags); -} -EXPORT_SYMBOL_GPL(gigaset_unassign); - void gigaset_blockdriver(struct gigaset_driver *drv) { - unsigned long flags; - spin_lock_irqsave(&drv->lock, flags); drv->blocked = 1; - spin_unlock_irqrestore(&drv->lock, flags); } EXPORT_SYMBOL_GPL(gigaset_blockdriver); diff --git a/drivers/isdn/gigaset/ev-layer.c b/drivers/isdn/gigaset/ev-layer.c index cec1ef342fcc..5cbf64d850ee 100644 --- a/drivers/isdn/gigaset/ev-layer.c +++ b/drivers/isdn/gigaset/ev-layer.c @@ -735,7 +735,7 @@ static void disconnect(struct at_state_t **at_state_p) /* revert to selected idle mode */ if (!cs->cidmode) { cs->at_state.pending_commands |= PC_UMMODE; - atomic_set(&cs->commands_pending, 1); //FIXME + cs->commands_pending = 1; gig_dbg(DEBUG_CMD, "Scheduling PC_UMMODE"); } spin_unlock_irqrestore(&cs->lock, flags); @@ -793,15 +793,15 @@ static void init_failed(struct cardstate *cs, int mode) struct at_state_t *at_state; cs->at_state.pending_commands &= ~PC_INIT; - atomic_set(&cs->mode, mode); - atomic_set(&cs->mstate, MS_UNINITIALIZED); + cs->mode = mode; + cs->mstate = MS_UNINITIALIZED; gigaset_free_channels(cs); for (i = 0; i < cs->channels; ++i) { at_state = &cs->bcs[i].at_state; if (at_state->pending_commands & PC_CID) { at_state->pending_commands &= ~PC_CID; at_state->pending_commands |= PC_NOCID; - atomic_set(&cs->commands_pending, 1); + cs->commands_pending = 1; } } } @@ -812,11 +812,11 @@ static void schedule_init(struct cardstate *cs, int state) gig_dbg(DEBUG_CMD, "not scheduling PC_INIT again"); return; } - atomic_set(&cs->mstate, state); - atomic_set(&cs->mode, M_UNKNOWN); + cs->mstate = state; + cs->mode = M_UNKNOWN; gigaset_block_channels(cs); cs->at_state.pending_commands |= PC_INIT; - atomic_set(&cs->commands_pending, 1); + cs->commands_pending = 1; gig_dbg(DEBUG_CMD, "Scheduling PC_INIT"); } @@ -953,13 +953,13 @@ static void start_dial(struct at_state_t *at_state, void *data, unsigned seq_ind at_state->pending_commands |= PC_CID; gig_dbg(DEBUG_CMD, "Scheduling PC_CID"); - atomic_set(&cs->commands_pending, 1); + cs->commands_pending = 1; return; error: at_state->pending_commands |= PC_NOCID; gig_dbg(DEBUG_CMD, "Scheduling PC_NOCID"); - atomic_set(&cs->commands_pending, 1); + cs->commands_pending = 1; return; } @@ -973,12 +973,12 @@ static void start_accept(struct at_state_t *at_state) if (retval == 0) { at_state->pending_commands |= PC_ACCEPT; gig_dbg(DEBUG_CMD, "Scheduling PC_ACCEPT"); - atomic_set(&cs->commands_pending, 1); + cs->commands_pending = 1; } else { - //FIXME + /* error reset */ at_state->pending_commands |= PC_HUP; gig_dbg(DEBUG_CMD, "Scheduling PC_HUP"); - atomic_set(&cs->commands_pending, 1); + cs->commands_pending = 1; } } @@ -986,7 +986,7 @@ static void do_start(struct cardstate *cs) { gigaset_free_channels(cs); - if (atomic_read(&cs->mstate) != MS_LOCKED) + if (cs->mstate != MS_LOCKED) schedule_init(cs, MS_INIT); cs->isdn_up = 1; @@ -1000,9 +1000,9 @@ static void do_start(struct cardstate *cs) static void finish_shutdown(struct cardstate *cs) { - if (atomic_read(&cs->mstate) != MS_LOCKED) { - atomic_set(&cs->mstate, MS_UNINITIALIZED); - atomic_set(&cs->mode, M_UNKNOWN); + if (cs->mstate != MS_LOCKED) { + cs->mstate = MS_UNINITIALIZED; + cs->mode = M_UNKNOWN; } /* Tell the LL that the device is not available .. */ @@ -1022,10 +1022,10 @@ static void do_shutdown(struct cardstate *cs) { gigaset_block_channels(cs); - if (atomic_read(&cs->mstate) == MS_READY) { - atomic_set(&cs->mstate, MS_SHUTDOWN); + if (cs->mstate == MS_READY) { + cs->mstate = MS_SHUTDOWN; cs->at_state.pending_commands |= PC_SHUTDOWN; - atomic_set(&cs->commands_pending, 1); + cs->commands_pending = 1; gig_dbg(DEBUG_CMD, "Scheduling PC_SHUTDOWN"); } else finish_shutdown(cs); @@ -1120,7 +1120,7 @@ static void handle_icall(struct cardstate *cs, struct bc_state *bcs, * In fact it doesn't. */ at_state->pending_commands |= PC_HUP; - atomic_set(&cs->commands_pending, 1); + cs->commands_pending = 1; break; } } @@ -1130,7 +1130,7 @@ static int do_lock(struct cardstate *cs) int mode; int i; - switch (atomic_read(&cs->mstate)) { + switch (cs->mstate) { case MS_UNINITIALIZED: case MS_READY: if (cs->cur_at_seq || !list_empty(&cs->temp_at_states) || @@ -1152,20 +1152,20 @@ static int do_lock(struct cardstate *cs) return -EBUSY; } - mode = atomic_read(&cs->mode); - atomic_set(&cs->mstate, MS_LOCKED); - atomic_set(&cs->mode, M_UNKNOWN); + mode = cs->mode; + cs->mstate = MS_LOCKED; + cs->mode = M_UNKNOWN; return mode; } static int do_unlock(struct cardstate *cs) { - if (atomic_read(&cs->mstate) != MS_LOCKED) + if (cs->mstate != MS_LOCKED) return -EINVAL; - atomic_set(&cs->mstate, MS_UNINITIALIZED); - atomic_set(&cs->mode, M_UNKNOWN); + cs->mstate = MS_UNINITIALIZED; + cs->mode = M_UNKNOWN; gigaset_free_channels(cs); if (cs->connected) schedule_init(cs, MS_INIT); @@ -1198,17 +1198,17 @@ static void do_action(int action, struct cardstate *cs, case ACT_INIT: cs->at_state.pending_commands &= ~PC_INIT; cs->cur_at_seq = SEQ_NONE; - atomic_set(&cs->mode, M_UNIMODEM); + cs->mode = M_UNIMODEM; spin_lock_irqsave(&cs->lock, flags); if (!cs->cidmode) { spin_unlock_irqrestore(&cs->lock, flags); gigaset_free_channels(cs); - atomic_set(&cs->mstate, MS_READY); + cs->mstate = MS_READY; break; } spin_unlock_irqrestore(&cs->lock, flags); cs->at_state.pending_commands |= PC_CIDMODE; - atomic_set(&cs->commands_pending, 1); + cs->commands_pending = 1; gig_dbg(DEBUG_CMD, "Scheduling PC_CIDMODE"); break; case ACT_FAILINIT: @@ -1234,22 +1234,20 @@ static void do_action(int action, struct cardstate *cs, | INS_command; break; case ACT_CMODESET: - if (atomic_read(&cs->mstate) == MS_INIT || - atomic_read(&cs->mstate) == MS_RECOVER) { + if (cs->mstate == MS_INIT || cs->mstate == MS_RECOVER) { gigaset_free_channels(cs); - atomic_set(&cs->mstate, MS_READY); + cs->mstate = MS_READY; } - atomic_set(&cs->mode, M_CID); + cs->mode = M_CID; cs->cur_at_seq = SEQ_NONE; break; case ACT_UMODESET: - atomic_set(&cs->mode, M_UNIMODEM); + cs->mode = M_UNIMODEM; cs->cur_at_seq = SEQ_NONE; break; case ACT_FAILCMODE: cs->cur_at_seq = SEQ_NONE; - if (atomic_read(&cs->mstate) == MS_INIT || - atomic_read(&cs->mstate) == MS_RECOVER) { + if (cs->mstate == MS_INIT || cs->mstate == MS_RECOVER) { init_failed(cs, M_UNKNOWN); break; } @@ -1307,7 +1305,7 @@ static void do_action(int action, struct cardstate *cs, case ACT_CONNECT: if (cs->onechannel) { at_state->pending_commands |= PC_DLE1; - atomic_set(&cs->commands_pending, 1); + cs->commands_pending = 1; break; } bcs->chstate |= CHS_D_UP; @@ -1333,7 +1331,7 @@ static void do_action(int action, struct cardstate *cs, * DLE only used for M10x with one B channel. */ at_state->pending_commands |= PC_DLE0; - atomic_set(&cs->commands_pending, 1); + cs->commands_pending = 1; } else disconnect(p_at_state); break; @@ -1369,7 +1367,7 @@ static void do_action(int action, struct cardstate *cs, "Could not enter DLE mode. Trying to hang up.\n"); channel = cs->curchannel; cs->bcs[channel].at_state.pending_commands |= PC_HUP; - atomic_set(&cs->commands_pending, 1); + cs->commands_pending = 1; break; case ACT_CID: /* got cid; start dialing */ @@ -1379,7 +1377,7 @@ static void do_action(int action, struct cardstate *cs, cs->bcs[channel].at_state.cid = ev->parameter; cs->bcs[channel].at_state.pending_commands |= PC_DIAL; - atomic_set(&cs->commands_pending, 1); + cs->commands_pending = 1; break; } /* fall through */ @@ -1411,14 +1409,14 @@ static void do_action(int action, struct cardstate *cs, case ACT_ABORTDIAL: /* error/timeout during dial preparation */ cs->cur_at_seq = SEQ_NONE; at_state->pending_commands |= PC_HUP; - atomic_set(&cs->commands_pending, 1); + cs->commands_pending = 1; break; case ACT_REMOTEREJECT: /* DISCONNECT_IND after dialling */ case ACT_CONNTIMEOUT: /* timeout waiting for ZSAU=ACTIVE */ case ACT_REMOTEHUP: /* DISCONNECT_IND with established connection */ at_state->pending_commands |= PC_HUP; - atomic_set(&cs->commands_pending, 1); + cs->commands_pending = 1; break; case ACT_GETSTRING: /* warning: RING, ZDLE, ... are not handled properly anymore */ @@ -1515,7 +1513,7 @@ static void do_action(int action, struct cardstate *cs, break; case ACT_HUP: at_state->pending_commands |= PC_HUP; - atomic_set(&cs->commands_pending, 1); + cs->commands_pending = 1; gig_dbg(DEBUG_CMD, "Scheduling PC_HUP"); break; @@ -1558,7 +1556,7 @@ static void do_action(int action, struct cardstate *cs, cs->at_state.pending_commands |= PC_UMMODE; gig_dbg(DEBUG_CMD, "Scheduling PC_UMMODE"); } - atomic_set(&cs->commands_pending, 1); + cs->commands_pending = 1; } spin_unlock_irqrestore(&cs->lock, flags); cs->waiting = 0; @@ -1741,7 +1739,7 @@ static void process_command_flags(struct cardstate *cs) int sequence; unsigned long flags; - atomic_set(&cs->commands_pending, 0); + cs->commands_pending = 0; if (cs->cur_at_seq) { gig_dbg(DEBUG_CMD, "not searching scheduled commands: busy"); @@ -1779,7 +1777,7 @@ static void process_command_flags(struct cardstate *cs) ~(PC_DLE1 | PC_ACCEPT | PC_DIAL); if (at_state->cid > 0) at_state->pending_commands |= PC_HUP; - if (atomic_read(&cs->mstate) == MS_RECOVER) { + if (cs->mstate == MS_RECOVER) { if (at_state->pending_commands & PC_CID) { at_state->pending_commands |= PC_NOCID; at_state->pending_commands &= ~PC_CID; @@ -1793,7 +1791,7 @@ static void process_command_flags(struct cardstate *cs) if (cs->at_state.pending_commands == PC_UMMODE && !cs->cidmode && list_empty(&cs->temp_at_states) - && atomic_read(&cs->mode) == M_CID) { + && cs->mode == M_CID) { sequence = SEQ_UMMODE; at_state = &cs->at_state; for (i = 0; i < cs->channels; ++i) { @@ -1860,7 +1858,7 @@ static void process_command_flags(struct cardstate *cs) } if (cs->at_state.pending_commands & PC_CIDMODE) { cs->at_state.pending_commands &= ~PC_CIDMODE; - if (atomic_read(&cs->mode) == M_UNIMODEM) { + if (cs->mode == M_UNIMODEM) { cs->retry_count = 1; schedule_sequence(cs, &cs->at_state, SEQ_CIDMODE); return; @@ -1886,11 +1884,11 @@ static void process_command_flags(struct cardstate *cs) return; } if (bcs->at_state.pending_commands & PC_CID) { - switch (atomic_read(&cs->mode)) { + switch (cs->mode) { case M_UNIMODEM: cs->at_state.pending_commands |= PC_CIDMODE; gig_dbg(DEBUG_CMD, "Scheduling PC_CIDMODE"); - atomic_set(&cs->commands_pending, 1); + cs->commands_pending = 1; return; #ifdef GIG_MAYINITONDIAL case M_UNKNOWN: @@ -1926,7 +1924,7 @@ static void process_events(struct cardstate *cs) for (i = 0; i < 2 * MAX_EVENTS; ++i) { tail = cs->ev_tail; if (tail == head) { - if (!check_flags && !atomic_read(&cs->commands_pending)) + if (!check_flags && !cs->commands_pending) break; check_flags = 0; spin_unlock_irqrestore(&cs->ev_lock, flags); @@ -1934,7 +1932,7 @@ static void process_events(struct cardstate *cs) spin_lock_irqsave(&cs->ev_lock, flags); tail = cs->ev_tail; if (tail == head) { - if (!atomic_read(&cs->commands_pending)) + if (!cs->commands_pending) break; continue; } @@ -1971,7 +1969,7 @@ void gigaset_handle_event(unsigned long data) struct cardstate *cs = (struct cardstate *) data; /* handle incoming data on control/common channel */ - if (atomic_read(&cs->inbuf->head) != atomic_read(&cs->inbuf->tail)) { + if (cs->inbuf->head != cs->inbuf->tail) { gig_dbg(DEBUG_INTR, "processing new data"); cs->ops->handle_input(cs->inbuf); } diff --git a/drivers/isdn/gigaset/gigaset.h b/drivers/isdn/gigaset/gigaset.h index 02bdaf22d7ea..f365993161fc 100644 --- a/drivers/isdn/gigaset/gigaset.h +++ b/drivers/isdn/gigaset/gigaset.h @@ -70,22 +70,13 @@ extern int gigaset_debuglevel; /* "needs" cast to (enum debuglevel) */ -/* any combination of these can be given with the 'debug=' parameter to insmod, - * e.g. 'insmod usb_gigaset.o debug=0x2c' will set DEBUG_OPEN, DEBUG_CMD and - * DEBUG_INTR. - */ +/* debug flags, combine by adding/bitwise OR */ enum debuglevel { - DEBUG_REG = 0x0002, /* serial port I/O register operations */ - DEBUG_OPEN = 0x0004, /* open/close serial port */ - DEBUG_INTR = 0x0008, /* interrupt processing */ - DEBUG_INTR_DUMP = 0x0010, /* Activating hexdump debug output on - interrupt requests, not available as - run-time option */ + DEBUG_INTR = 0x00008, /* interrupt processing */ DEBUG_CMD = 0x00020, /* sent/received LL commands */ DEBUG_STREAM = 0x00040, /* application data stream I/O events */ DEBUG_STREAM_DUMP = 0x00080, /* application data stream content */ DEBUG_LLDATA = 0x00100, /* sent/received LL data */ - DEBUG_INTR_0 = 0x00200, /* serial port interrupt processing */ DEBUG_DRIVER = 0x00400, /* driver structure */ DEBUG_HDLC = 0x00800, /* M10x HDLC processing */ DEBUG_WRITE = 0x01000, /* M105 data write */ @@ -93,7 +84,7 @@ enum debuglevel { DEBUG_MCMD = 0x04000, /* COMMANDS THAT ARE SENT VERY OFTEN */ DEBUG_INIT = 0x08000, /* (de)allocation+initialization of data structures */ - DEBUG_LOCK = 0x10000, /* semaphore operations */ + DEBUG_SUSPEND = 0x10000, /* suspend/resume processing */ DEBUG_OUTPUT = 0x20000, /* output to device */ DEBUG_ISO = 0x40000, /* isochronous transfers */ DEBUG_IF = 0x80000, /* character device operations */ @@ -191,6 +182,9 @@ void gigaset_dbg_buffer(enum debuglevel level, const unsigned char *msg, #define HD_OPEN_ATCHANNEL (0x28) // 3070 #define HD_CLOSE_ATCHANNEL (0x29) // 3070 +/* number of B channels supported by base driver */ +#define BAS_CHANNELS 2 + /* USB frames for isochronous transfer */ #define BAS_FRAMETIME 1 /* number of milliseconds between frames */ #define BAS_NUMFRAMES 8 /* number of frames per URB */ @@ -313,7 +307,7 @@ struct inbuf_t { struct bc_state *bcs; struct cardstate *cs; int inputstate; - atomic_t head, tail; + int head, tail; unsigned char data[RBUFSIZE]; }; @@ -335,9 +329,9 @@ struct inbuf_t { * are also filled with that value */ struct isowbuf_t { - atomic_t read; - atomic_t nextread; - atomic_t write; + int read; + int nextread; + int write; atomic_t writesem; int wbits; unsigned char data[BAS_OUTBUFSIZE + BAS_OUTBUFPAD]; @@ -350,11 +344,13 @@ struct isowbuf_t { * - urb: pointer to the URB itself * - bcs: pointer to the B Channel control structure * - limit: end of write buffer area covered by this URB + * - status: URB completion status */ struct isow_urbctx_t { struct urb *urb; struct bc_state *bcs; int limit; + int status; }; /* AT state structure @@ -439,14 +435,15 @@ struct cardstate { unsigned minor_index; struct device *dev; struct device *tty_dev; + unsigned flags; const struct gigaset_ops *ops; /* Stuff to handle communication */ wait_queue_head_t waitqueue; int waiting; - atomic_t mode; /* see M_XXXX */ - atomic_t mstate; /* Modem state: see MS_XXXX */ + int mode; /* see M_XXXX */ + int mstate; /* Modem state: see MS_XXXX */ /* only changed by the event layer */ int cmd_result; @@ -503,7 +500,7 @@ struct cardstate { processed */ int curchannel; /* channel those commands are meant for */ - atomic_t commands_pending; /* flag(s) in xxx.commands_pending have + int commands_pending; /* flag(s) in xxx.commands_pending have been set */ struct tasklet_struct event_tasklet; /* tasklet for serializing AT commands. @@ -543,7 +540,6 @@ struct gigaset_driver { unsigned minor; unsigned minors; struct cardstate *cs; - unsigned *flags; int blocked; const struct gigaset_ops *ops; @@ -559,7 +555,7 @@ struct cmdbuf_t { struct bas_bc_state { /* isochronous output state */ - atomic_t running; + int running; atomic_t corrbytes; spinlock_t isooutlock; struct isow_urbctx_t isoouturbs[BAS_OUTURBS]; @@ -574,6 +570,7 @@ struct bas_bc_state { struct urb *isoinurbs[BAS_INURBS]; unsigned char isoinbuf[BAS_INBUFSIZE * BAS_INURBS]; struct urb *isoindone; /* completed isoc read URB */ + int isoinstatus; /* status of completed URB */ int loststatus; /* status of dropped URB */ unsigned isoinlost; /* number of bytes lost */ /* state of bit unstuffing algorithm @@ -770,10 +767,6 @@ void gigaset_freedriver(struct gigaset_driver *drv); void gigaset_debugdrivers(void); struct cardstate *gigaset_get_cs_by_tty(struct tty_struct *tty); struct cardstate *gigaset_get_cs_by_id(int id); - -/* For drivers without fixed assignment device<->cardstate (usb) */ -struct cardstate *gigaset_getunassignedcs(struct gigaset_driver *drv); -void gigaset_unassign(struct cardstate *cs); void gigaset_blockdriver(struct gigaset_driver *drv); /* Allocate and initialize card state. Calls hardware dependent @@ -792,7 +785,7 @@ int gigaset_start(struct cardstate *cs); void gigaset_stop(struct cardstate *cs); /* Tell common.c that the driver is being unloaded. */ -void gigaset_shutdown(struct cardstate *cs); +int gigaset_shutdown(struct cardstate *cs); /* Tell common.c that an skb has been sent. */ void gigaset_skb_sent(struct bc_state *bcs, struct sk_buff *skb); diff --git a/drivers/isdn/gigaset/interface.c b/drivers/isdn/gigaset/interface.c index eb50f3dab5f7..af195b07c191 100644 --- a/drivers/isdn/gigaset/interface.c +++ b/drivers/isdn/gigaset/interface.c @@ -28,12 +28,11 @@ static int if_lock(struct cardstate *cs, int *arg) return -EINVAL; if (cmd < 0) { - *arg = atomic_read(&cs->mstate) == MS_LOCKED; //FIXME remove? + *arg = cs->mstate == MS_LOCKED; return 0; } - if (!cmd && atomic_read(&cs->mstate) == MS_LOCKED - && cs->connected) { + if (!cmd && cs->mstate == MS_LOCKED && cs->connected) { cs->ops->set_modem_ctrl(cs, 0, TIOCM_DTR|TIOCM_RTS); cs->ops->baud_rate(cs, B115200); cs->ops->set_line_ctrl(cs, CS8); @@ -104,7 +103,7 @@ static int if_config(struct cardstate *cs, int *arg) if (*arg != 1) return -EINVAL; - if (atomic_read(&cs->mstate) != MS_LOCKED) + if (cs->mstate != MS_LOCKED) return -EBUSY; if (!cs->connected) { @@ -162,7 +161,7 @@ static int if_open(struct tty_struct *tty, struct file *filp) tty->driver_data = NULL; cs = gigaset_get_cs_by_tty(tty); - if (!cs) + if (!cs || !try_module_get(cs->driver->owner)) return -ENODEV; if (mutex_lock_interruptible(&cs->mutex)) @@ -208,6 +207,8 @@ static void if_close(struct tty_struct *tty, struct file *filp) } mutex_unlock(&cs->mutex); + + module_put(cs->driver->owner); } static int if_ioctl(struct tty_struct *tty, struct file *file, @@ -364,7 +365,7 @@ static int if_write(struct tty_struct *tty, const unsigned char *buf, int count) if (!cs->open_count) warn("%s: device not opened", __func__); - else if (atomic_read(&cs->mstate) != MS_LOCKED) { + else if (cs->mstate != MS_LOCKED) { warn("can't write to unlocked device"); retval = -EBUSY; } else if (!cs->connected) { @@ -398,9 +399,9 @@ static int if_write_room(struct tty_struct *tty) if (!cs->open_count) warn("%s: device not opened", __func__); - else if (atomic_read(&cs->mstate) != MS_LOCKED) { + else if (cs->mstate != MS_LOCKED) { warn("can't write to unlocked device"); - retval = -EBUSY; //FIXME + retval = -EBUSY; } else if (!cs->connected) { gig_dbg(DEBUG_ANY, "can't write to unplugged device"); retval = -EBUSY; //FIXME @@ -430,7 +431,7 @@ static int if_chars_in_buffer(struct tty_struct *tty) if (!cs->open_count) warn("%s: device not opened", __func__); - else if (atomic_read(&cs->mstate) != MS_LOCKED) { + else if (cs->mstate != MS_LOCKED) { warn("can't write to unlocked device"); retval = -EBUSY; } else if (!cs->connected) { diff --git a/drivers/isdn/gigaset/isocdata.c b/drivers/isdn/gigaset/isocdata.c index e0505f238807..e30a7773f93c 100644 --- a/drivers/isdn/gigaset/isocdata.c +++ b/drivers/isdn/gigaset/isocdata.c @@ -23,9 +23,9 @@ */ void gigaset_isowbuf_init(struct isowbuf_t *iwb, unsigned char idle) { - atomic_set(&iwb->read, 0); - atomic_set(&iwb->nextread, 0); - atomic_set(&iwb->write, 0); + iwb->read = 0; + iwb->nextread = 0; + iwb->write = 0; atomic_set(&iwb->writesem, 1); iwb->wbits = 0; iwb->idle = idle; @@ -39,8 +39,8 @@ static inline int isowbuf_freebytes(struct isowbuf_t *iwb) { int read, write, freebytes; - read = atomic_read(&iwb->read); - write = atomic_read(&iwb->write); + read = iwb->read; + write = iwb->write; if ((freebytes = read - write) > 0) { /* no wraparound: need padding space within regular area */ return freebytes - BAS_OUTBUFPAD; @@ -62,7 +62,7 @@ static inline int isowbuf_poscmp(struct isowbuf_t *iwb, int a, int b) int read; if (a == b) return 0; - read = atomic_read(&iwb->read); + read = iwb->read; if (a < b) { if (a < read && read <= b) return +1; @@ -91,18 +91,18 @@ static inline int isowbuf_startwrite(struct isowbuf_t *iwb) #ifdef CONFIG_GIGASET_DEBUG gig_dbg(DEBUG_ISO, "%s: acquired iso write semaphore, data[write]=%02x, nbits=%d", - __func__, iwb->data[atomic_read(&iwb->write)], iwb->wbits); + __func__, iwb->data[iwb->write], iwb->wbits); #endif return 1; } /* finish writing - * release the write semaphore and update the maximum buffer fill level + * release the write semaphore * returns the current write position */ static inline int isowbuf_donewrite(struct isowbuf_t *iwb) { - int write = atomic_read(&iwb->write); + int write = iwb->write; atomic_inc(&iwb->writesem); return write; } @@ -116,7 +116,7 @@ static inline int isowbuf_donewrite(struct isowbuf_t *iwb) */ static inline void isowbuf_putbits(struct isowbuf_t *iwb, u32 data, int nbits) { - int write = atomic_read(&iwb->write); + int write = iwb->write; data <<= iwb->wbits; data |= iwb->data[write]; nbits += iwb->wbits; @@ -128,7 +128,7 @@ static inline void isowbuf_putbits(struct isowbuf_t *iwb, u32 data, int nbits) } iwb->wbits = nbits; iwb->data[write] = data & 0xff; - atomic_set(&iwb->write, write); + iwb->write = write; } /* put final flag on HDLC bitstream @@ -142,7 +142,7 @@ static inline void isowbuf_putflag(struct isowbuf_t *iwb) /* add two flags, thus reliably covering one byte */ isowbuf_putbits(iwb, 0x7e7e, 8); /* recover the idle flag byte */ - write = atomic_read(&iwb->write); + write = iwb->write; iwb->idle = iwb->data[write]; gig_dbg(DEBUG_ISO, "idle fill byte %02x", iwb->idle); /* mask extraneous bits in buffer */ @@ -160,8 +160,8 @@ int gigaset_isowbuf_getbytes(struct isowbuf_t *iwb, int size) int read, write, limit, src, dst; unsigned char pbyte; - read = atomic_read(&iwb->nextread); - write = atomic_read(&iwb->write); + read = iwb->nextread; + write = iwb->write; if (likely(read == write)) { /* return idle frame */ return read < BAS_OUTBUFPAD ? @@ -176,7 +176,7 @@ int gigaset_isowbuf_getbytes(struct isowbuf_t *iwb, int size) err("invalid size %d", size); return -EINVAL; } - src = atomic_read(&iwb->read); + src = iwb->read; if (unlikely(limit > BAS_OUTBUFSIZE + BAS_OUTBUFPAD || (read < src && limit >= src))) { err("isoc write buffer frame reservation violated"); @@ -191,7 +191,8 @@ int gigaset_isowbuf_getbytes(struct isowbuf_t *iwb, int size) if (!isowbuf_startwrite(iwb)) return -EBUSY; /* write position could have changed */ - if (limit >= (write = atomic_read(&iwb->write))) { + write = iwb->write; + if (limit >= write) { pbyte = iwb->data[write]; /* save partial byte */ limit = write + BAS_OUTBUFPAD; @@ -213,7 +214,7 @@ int gigaset_isowbuf_getbytes(struct isowbuf_t *iwb, int size) __func__, pbyte, limit); iwb->data[limit] = pbyte; /* restore partial byte */ - atomic_set(&iwb->write, limit); + iwb->write = limit; } isowbuf_donewrite(iwb); } @@ -233,7 +234,7 @@ int gigaset_isowbuf_getbytes(struct isowbuf_t *iwb, int size) limit = src; } } - atomic_set(&iwb->nextread, limit); + iwb->nextread = limit; return read; } @@ -477,7 +478,7 @@ static inline int trans_buildframe(struct isowbuf_t *iwb, unsigned char c; if (unlikely(count <= 0)) - return atomic_read(&iwb->write); /* better ideas? */ + return iwb->write; if (isowbuf_freebytes(iwb) < count || !isowbuf_startwrite(iwb)) { @@ -486,13 +487,13 @@ static inline int trans_buildframe(struct isowbuf_t *iwb, } gig_dbg(DEBUG_STREAM, "put %d bytes", count); - write = atomic_read(&iwb->write); + write = iwb->write; do { c = bitrev8(*in++); iwb->data[write++] = c; write %= BAS_OUTBUFSIZE; } while (--count > 0); - atomic_set(&iwb->write, write); + iwb->write = write; iwb->idle = c; return isowbuf_donewrite(iwb); @@ -947,8 +948,8 @@ void gigaset_isoc_input(struct inbuf_t *inbuf) unsigned tail, head, numbytes; unsigned char *src; - head = atomic_read(&inbuf->head); - while (head != (tail = atomic_read(&inbuf->tail))) { + head = inbuf->head; + while (head != (tail = inbuf->tail)) { gig_dbg(DEBUG_INTR, "buffer state: %u -> %u", head, tail); if (head > tail) tail = RBUFSIZE; @@ -956,7 +957,7 @@ void gigaset_isoc_input(struct inbuf_t *inbuf) numbytes = tail - head; gig_dbg(DEBUG_INTR, "processing %u bytes", numbytes); - if (atomic_read(&cs->mstate) == MS_LOCKED) { + if (cs->mstate == MS_LOCKED) { gigaset_dbg_buffer(DEBUG_LOCKCMD, "received response", numbytes, src); gigaset_if_receive(inbuf->cs, src, numbytes); @@ -970,7 +971,7 @@ void gigaset_isoc_input(struct inbuf_t *inbuf) if (head == RBUFSIZE) head = 0; gig_dbg(DEBUG_INTR, "setting head to %u", head); - atomic_set(&inbuf->head, head); + inbuf->head = head; } } diff --git a/drivers/isdn/gigaset/ser-gigaset.c b/drivers/isdn/gigaset/ser-gigaset.c index ea44302e6e7e..fceeb1d57682 100644 --- a/drivers/isdn/gigaset/ser-gigaset.c +++ b/drivers/isdn/gigaset/ser-gigaset.c @@ -17,6 +17,7 @@ #include <linux/platform_device.h> #include <linux/tty.h> #include <linux/poll.h> +#include <linux/completion.h> /* Version Information */ #define DRIVER_AUTHOR "Tilman Schmidt" @@ -48,7 +49,7 @@ struct ser_cardstate { struct platform_device dev; struct tty_struct *tty; atomic_t refcnt; - struct mutex dead_mutex; + struct completion dead_cmp; }; static struct platform_driver device_driver = { @@ -240,7 +241,7 @@ static int gigaset_write_cmd(struct cardstate *cs, const unsigned char *buf, struct cmdbuf_t *cb; unsigned long flags; - gigaset_dbg_buffer(atomic_read(&cs->mstate) != MS_LOCKED ? + gigaset_dbg_buffer(cs->mstate != MS_LOCKED ? DEBUG_TRANSCMD : DEBUG_LOCKCMD, "CMD Transmit", len, buf); @@ -498,7 +499,7 @@ static struct cardstate *cs_get(struct tty_struct *tty) static void cs_put(struct cardstate *cs) { if (atomic_dec_and_test(&cs->hw.ser->refcnt)) - mutex_unlock(&cs->hw.ser->dead_mutex); + complete(&cs->hw.ser->dead_cmp); } /* @@ -527,8 +528,8 @@ gigaset_tty_open(struct tty_struct *tty) cs->dev = &cs->hw.ser->dev.dev; cs->hw.ser->tty = tty; - mutex_init(&cs->hw.ser->dead_mutex); atomic_set(&cs->hw.ser->refcnt, 1); + init_completion(&cs->hw.ser->dead_cmp); tty->disc_data = cs; @@ -536,14 +537,13 @@ gigaset_tty_open(struct tty_struct *tty) * startup system and notify the LL that we are ready to run */ if (startmode == SM_LOCKED) - atomic_set(&cs->mstate, MS_LOCKED); + cs->mstate = MS_LOCKED; if (!gigaset_start(cs)) { tasklet_kill(&cs->write_tasklet); goto error; } gig_dbg(DEBUG_INIT, "Startup of HLL done"); - mutex_lock(&cs->hw.ser->dead_mutex); return 0; error: @@ -577,7 +577,7 @@ gigaset_tty_close(struct tty_struct *tty) else { /* wait for running methods to finish */ if (!atomic_dec_and_test(&cs->hw.ser->refcnt)) - mutex_lock(&cs->hw.ser->dead_mutex); + wait_for_completion(&cs->hw.ser->dead_cmp); } /* stop operations */ @@ -714,8 +714,8 @@ gigaset_tty_receive(struct tty_struct *tty, const unsigned char *buf, return; } - tail = atomic_read(&inbuf->tail); - head = atomic_read(&inbuf->head); + tail = inbuf->tail; + head = inbuf->head; gig_dbg(DEBUG_INTR, "buffer state: %u -> %u, receive %u bytes", head, tail, count); @@ -742,7 +742,7 @@ gigaset_tty_receive(struct tty_struct *tty, const unsigned char *buf, } gig_dbg(DEBUG_INTR, "setting tail to %u", tail); - atomic_set(&inbuf->tail, tail); + inbuf->tail = tail; /* Everything was received .. Push data into handler */ gig_dbg(DEBUG_INTR, "%s-->BH", __func__); diff --git a/drivers/isdn/gigaset/usb-gigaset.c b/drivers/isdn/gigaset/usb-gigaset.c index ca4bee173cfb..77d20ab0cd4d 100644 --- a/drivers/isdn/gigaset/usb-gigaset.c +++ b/drivers/isdn/gigaset/usb-gigaset.c @@ -104,12 +104,17 @@ MODULE_DEVICE_TABLE(usb, gigaset_table); * flags per packet. */ +/* functions called if a device of this driver is connected/disconnected */ static int gigaset_probe(struct usb_interface *interface, const struct usb_device_id *id); static void gigaset_disconnect(struct usb_interface *interface); +/* functions called before/after suspend */ +static int gigaset_suspend(struct usb_interface *intf, pm_message_t message); +static int gigaset_resume(struct usb_interface *intf); +static int gigaset_pre_reset(struct usb_interface *intf); + static struct gigaset_driver *driver = NULL; -static struct cardstate *cardstate = NULL; /* usb specific object needed to register this driver with the usb subsystem */ static struct usb_driver gigaset_usb_driver = { @@ -117,12 +122,17 @@ static struct usb_driver gigaset_usb_driver = { .probe = gigaset_probe, .disconnect = gigaset_disconnect, .id_table = gigaset_table, + .suspend = gigaset_suspend, + .resume = gigaset_resume, + .reset_resume = gigaset_resume, + .pre_reset = gigaset_pre_reset, + .post_reset = gigaset_resume, }; struct usb_cardstate { struct usb_device *udev; /* usb device pointer */ struct usb_interface *interface; /* interface for this device */ - atomic_t busy; /* bulk output in progress */ + int busy; /* bulk output in progress */ /* Output buffer */ unsigned char *bulk_out_buffer; @@ -314,7 +324,7 @@ static void gigaset_modem_fill(unsigned long data) gig_dbg(DEBUG_OUTPUT, "modem_fill"); - if (atomic_read(&cs->hw.usb->busy)) { + if (cs->hw.usb->busy) { gig_dbg(DEBUG_OUTPUT, "modem_fill: busy"); return; } @@ -361,18 +371,13 @@ static void gigaset_read_int_callback(struct urb *urb) { struct inbuf_t *inbuf = urb->context; struct cardstate *cs = inbuf->cs; - int resubmit = 0; + int status = urb->status; int r; unsigned numbytes; unsigned char *src; unsigned long flags; - if (!urb->status) { - if (!cs->connected) { - err("%s: disconnected", __func__); /* should never happen */ - return; - } - + if (!status) { numbytes = urb->actual_length; if (numbytes) { @@ -389,28 +394,26 @@ static void gigaset_read_int_callback(struct urb *urb) } } else gig_dbg(DEBUG_INTR, "Received zero block length"); - resubmit = 1; } else { /* The urb might have been killed. */ - gig_dbg(DEBUG_ANY, "%s - nonzero read bulk status received: %d", - __func__, urb->status); - if (urb->status != -ENOENT) { /* not killed */ - if (!cs->connected) { - err("%s: disconnected", __func__); /* should never happen */ - return; - } - resubmit = 1; - } + gig_dbg(DEBUG_ANY, "%s - nonzero status received: %d", + __func__, status); + if (status == -ENOENT || status == -ESHUTDOWN) + /* killed or endpoint shutdown: don't resubmit */ + return; } - if (resubmit) { - spin_lock_irqsave(&cs->lock, flags); - r = cs->connected ? usb_submit_urb(urb, GFP_ATOMIC) : -ENODEV; + /* resubmit URB */ + spin_lock_irqsave(&cs->lock, flags); + if (!cs->connected) { spin_unlock_irqrestore(&cs->lock, flags); - if (r) - dev_err(cs->dev, "error %d when resubmitting urb.\n", - -r); + err("%s: disconnected", __func__); + return; } + r = usb_submit_urb(urb, GFP_ATOMIC); + spin_unlock_irqrestore(&cs->lock, flags); + if (r) + dev_err(cs->dev, "error %d resubmitting URB\n", -r); } @@ -418,19 +421,28 @@ static void gigaset_read_int_callback(struct urb *urb) static void gigaset_write_bulk_callback(struct urb *urb) { struct cardstate *cs = urb->context; + int status = urb->status; unsigned long flags; - if (urb->status) + switch (status) { + case 0: /* normal completion */ + break; + case -ENOENT: /* killed */ + gig_dbg(DEBUG_ANY, "%s: killed", __func__); + cs->hw.usb->busy = 0; + return; + default: dev_err(cs->dev, "bulk transfer failed (status %d)\n", - -urb->status); + -status); /* That's all we can do. Communication problems are handled by timeouts or network protocols. */ + } spin_lock_irqsave(&cs->lock, flags); if (!cs->connected) { err("%s: not connected", __func__); } else { - atomic_set(&cs->hw.usb->busy, 0); + cs->hw.usb->busy = 0; tasklet_schedule(&cs->write_tasklet); } spin_unlock_irqrestore(&cs->lock, flags); @@ -478,14 +490,14 @@ static int send_cb(struct cardstate *cs, struct cmdbuf_t *cb) cb->offset += count; cb->len -= count; - atomic_set(&ucs->busy, 1); + ucs->busy = 1; spin_lock_irqsave(&cs->lock, flags); status = cs->connected ? usb_submit_urb(ucs->bulk_out_urb, GFP_ATOMIC) : -ENODEV; spin_unlock_irqrestore(&cs->lock, flags); if (status) { - atomic_set(&ucs->busy, 0); + ucs->busy = 0; err("could not submit urb (error %d)\n", -status); cb->len = 0; /* skip urb => remove cb+wakeup @@ -504,7 +516,7 @@ static int gigaset_write_cmd(struct cardstate *cs, const unsigned char *buf, struct cmdbuf_t *cb; unsigned long flags; - gigaset_dbg_buffer(atomic_read(&cs->mstate) != MS_LOCKED ? + gigaset_dbg_buffer(cs->mstate != MS_LOCKED ? DEBUG_TRANSCMD : DEBUG_LOCKCMD, "CMD Transmit", len, buf); @@ -641,7 +653,7 @@ static int write_modem(struct cardstate *cs) count = min(bcs->tx_skb->len, (unsigned) ucs->bulk_out_size); skb_copy_from_linear_data(bcs->tx_skb, ucs->bulk_out_buffer, count); skb_pull(bcs->tx_skb, count); - atomic_set(&ucs->busy, 1); + ucs->busy = 1; gig_dbg(DEBUG_OUTPUT, "write_modem: send %d bytes", count); spin_lock_irqsave(&cs->lock, flags); @@ -659,7 +671,7 @@ static int write_modem(struct cardstate *cs) if (ret) { err("could not submit urb (error %d)\n", -ret); - atomic_set(&ucs->busy, 0); + ucs->busy = 0; } if (!bcs->tx_skb->len) { @@ -680,53 +692,44 @@ static int gigaset_probe(struct usb_interface *interface, { int retval; struct usb_device *udev = interface_to_usbdev(interface); - unsigned int ifnum; - struct usb_host_interface *hostif; + struct usb_host_interface *hostif = interface->cur_altsetting; struct cardstate *cs = NULL; struct usb_cardstate *ucs = NULL; struct usb_endpoint_descriptor *endpoint; int buffer_size; - int alt; - gig_dbg(DEBUG_ANY, - "%s: Check if device matches .. (Vendor: 0x%x, Product: 0x%x)", - __func__, le16_to_cpu(udev->descriptor.idVendor), - le16_to_cpu(udev->descriptor.idProduct)); - - retval = -ENODEV; //FIXME + gig_dbg(DEBUG_ANY, "%s: Check if device matches ...", __func__); /* See if the device offered us matches what we can accept */ if ((le16_to_cpu(udev->descriptor.idVendor) != USB_M105_VENDOR_ID) || - (le16_to_cpu(udev->descriptor.idProduct) != USB_M105_PRODUCT_ID)) + (le16_to_cpu(udev->descriptor.idProduct) != USB_M105_PRODUCT_ID)) { + gig_dbg(DEBUG_ANY, "device ID (0x%x, 0x%x) not for me - skip", + le16_to_cpu(udev->descriptor.idVendor), + le16_to_cpu(udev->descriptor.idProduct)); return -ENODEV; - - /* this starts to become ascii art... */ - hostif = interface->cur_altsetting; - alt = hostif->desc.bAlternateSetting; - ifnum = hostif->desc.bInterfaceNumber; // FIXME ? - - if (alt != 0 || ifnum != 0) { - dev_warn(&udev->dev, "ifnum %d, alt %d\n", ifnum, alt); + } + if (hostif->desc.bInterfaceNumber != 0) { + gig_dbg(DEBUG_ANY, "interface %d not for me - skip", + hostif->desc.bInterfaceNumber); + return -ENODEV; + } + if (hostif->desc.bAlternateSetting != 0) { + dev_notice(&udev->dev, "unsupported altsetting %d - skip", + hostif->desc.bAlternateSetting); return -ENODEV; } - - /* Reject application specific intefaces - * - */ if (hostif->desc.bInterfaceClass != 255) { - dev_info(&udev->dev, - "%s: Device matched but iface_desc[%d]->bInterfaceClass==%d!\n", - __func__, ifnum, hostif->desc.bInterfaceClass); + dev_notice(&udev->dev, "unsupported interface class %d - skip", + hostif->desc.bInterfaceClass); return -ENODEV; } dev_info(&udev->dev, "%s: Device matched ... !\n", __func__); - cs = gigaset_getunassignedcs(driver); - if (!cs) { - dev_warn(&udev->dev, "no free cardstate\n"); + /* allocate memory for our device state and intialize it */ + cs = gigaset_initcs(driver, 1, 1, 0, cidmode, GIGASET_MODULENAME); + if (!cs) return -ENODEV; - } ucs = cs->hw.usb; /* save off device structure ptrs for later use */ @@ -759,7 +762,7 @@ static int gigaset_probe(struct usb_interface *interface, endpoint = &hostif->endpoint[1].desc; - atomic_set(&ucs->busy, 0); + ucs->busy = 0; ucs->read_urb = usb_alloc_urb(0, GFP_KERNEL); if (!ucs->read_urb) { @@ -792,7 +795,7 @@ static int gigaset_probe(struct usb_interface *interface, /* tell common part that the device is ready */ if (startmode == SM_LOCKED) - atomic_set(&cs->mstate, MS_LOCKED); + cs->mstate = MS_LOCKED; if (!gigaset_start(cs)) { tasklet_kill(&cs->write_tasklet); @@ -813,7 +816,7 @@ error: usb_put_dev(ucs->udev); ucs->udev = NULL; ucs->interface = NULL; - gigaset_unassign(cs); + gigaset_freecs(cs); return retval; } @@ -824,6 +827,9 @@ static void gigaset_disconnect(struct usb_interface *interface) cs = usb_get_intfdata(interface); ucs = cs->hw.usb; + + dev_info(cs->dev, "disconnecting Gigaset USB adapter\n"); + usb_kill_urb(ucs->read_urb); gigaset_stop(cs); @@ -831,7 +837,7 @@ static void gigaset_disconnect(struct usb_interface *interface) usb_set_intfdata(interface, NULL); tasklet_kill(&cs->write_tasklet); - usb_kill_urb(ucs->bulk_out_urb); /* FIXME: only if active? */ + usb_kill_urb(ucs->bulk_out_urb); kfree(ucs->bulk_out_buffer); usb_free_urb(ucs->bulk_out_urb); @@ -844,7 +850,53 @@ static void gigaset_disconnect(struct usb_interface *interface) ucs->interface = NULL; ucs->udev = NULL; cs->dev = NULL; - gigaset_unassign(cs); + gigaset_freecs(cs); +} + +/* gigaset_suspend + * This function is called before the USB connection is suspended or reset. + */ +static int gigaset_suspend(struct usb_interface *intf, pm_message_t message) +{ + struct cardstate *cs = usb_get_intfdata(intf); + + /* stop activity */ + cs->connected = 0; /* prevent rescheduling */ + usb_kill_urb(cs->hw.usb->read_urb); + tasklet_kill(&cs->write_tasklet); + usb_kill_urb(cs->hw.usb->bulk_out_urb); + + gig_dbg(DEBUG_SUSPEND, "suspend complete"); + return 0; +} + +/* gigaset_resume + * This function is called after the USB connection has been resumed or reset. + */ +static int gigaset_resume(struct usb_interface *intf) +{ + struct cardstate *cs = usb_get_intfdata(intf); + int rc; + + /* resubmit interrupt URB */ + cs->connected = 1; + rc = usb_submit_urb(cs->hw.usb->read_urb, GFP_KERNEL); + if (rc) { + dev_err(cs->dev, "Could not submit read URB (error %d)\n", -rc); + return rc; + } + + gig_dbg(DEBUG_SUSPEND, "resume complete"); + return 0; +} + +/* gigaset_pre_reset + * This function is called before the USB connection is reset. + */ +static int gigaset_pre_reset(struct usb_interface *intf) +{ + /* same as suspend */ + return gigaset_suspend(intf, PMSG_ON); } static const struct gigaset_ops ops = { @@ -880,11 +932,6 @@ static int __init usb_gigaset_init(void) &ops, THIS_MODULE)) == NULL) goto error; - /* allocate memory for our device state and intialize it */ - cardstate = gigaset_initcs(driver, 1, 1, 0, cidmode, GIGASET_MODULENAME); - if (!cardstate) - goto error; - /* register this driver with the USB subsystem */ result = usb_register(&gigaset_usb_driver); if (result < 0) { @@ -897,9 +944,7 @@ static int __init usb_gigaset_init(void) info(DRIVER_DESC); return 0; -error: if (cardstate) - gigaset_freecs(cardstate); - cardstate = NULL; +error: if (driver) gigaset_freedriver(driver); driver = NULL; @@ -913,11 +958,16 @@ error: if (cardstate) */ static void __exit usb_gigaset_exit(void) { + int i; + gigaset_blockdriver(driver); /* => probe will fail * => no gigaset_start any more */ - gigaset_shutdown(cardstate); + /* stop all connected devices */ + for (i = 0; i < driver->minors; i++) + gigaset_shutdown(driver->cs + i); + /* from now on, no isdn callback should be possible */ /* deregister this driver with the USB subsystem */ @@ -925,8 +975,6 @@ static void __exit usb_gigaset_exit(void) /* this will call the disconnect-callback */ /* from now on, no disconnect/probe callback should be running */ - gigaset_freecs(cardstate); - cardstate = NULL; gigaset_freedriver(driver); driver = NULL; } diff --git a/drivers/isdn/hardware/eicon/debug.c b/drivers/isdn/hardware/eicon/debug.c index 0db9cc661e28..84318ec8d13e 100644 --- a/drivers/isdn/hardware/eicon/debug.c +++ b/drivers/isdn/hardware/eicon/debug.c @@ -1188,7 +1188,7 @@ int SuperTraceASSIGN (void* AdapterHandle, byte* data) { if ((features[0] & DIVA_XDI_EXTENDED_FEATURES_VALID) && (features[0] & DIVA_XDI_EXTENDED_FEATURE_MANAGEMENT_DMA)) { - dword rx_dma_magic; + dword uninitialized_var(rx_dma_magic); if ((pC->dma_handle = diva_get_dma_descriptor (pC->request, &rx_dma_magic)) >= 0) { pC->xbuffer[0] = LLI; pC->xbuffer[1] = 8; diff --git a/drivers/isdn/hardware/eicon/diva.c b/drivers/isdn/hardware/eicon/diva.c index ffa2afa77c2f..1403a5458e68 100644 --- a/drivers/isdn/hardware/eicon/diva.c +++ b/drivers/isdn/hardware/eicon/diva.c @@ -515,12 +515,11 @@ diva_xdi_read(void *adapter, void *os_handle, void __user *dst, irqreturn_t diva_os_irq_wrapper(int irq, void *context) { - diva_os_xdi_adapter_t *a = (diva_os_xdi_adapter_t *) context; + diva_os_xdi_adapter_t *a = context; diva_xdi_clear_interrupts_proc_t clear_int_proc; - if (!a || !a->xdi_adapter.diva_isr_handler) { + if (!a || !a->xdi_adapter.diva_isr_handler) return IRQ_NONE; - } if ((clear_int_proc = a->clear_interrupts_proc)) { (*clear_int_proc) (a); diff --git a/drivers/isdn/hardware/eicon/message.c b/drivers/isdn/hardware/eicon/message.c index b9177ca4369a..1ff98e7eb794 100644 --- a/drivers/isdn/hardware/eicon/message.c +++ b/drivers/isdn/hardware/eicon/message.c @@ -9027,7 +9027,7 @@ static byte AddInfo(byte **add_i, /* facility is a nested structure */ /* FTY can be more than once */ - if(esc_chi[0] && !(esc_chi[esc_chi[0]])&0x7f ) + if (esc_chi[0] && !(esc_chi[esc_chi[0]] & 0x7f)) { add_i[0] = (byte *)"\x02\x02\x00"; /* use neither b nor d channel */ } diff --git a/drivers/isdn/hisax/avm_pci.c b/drivers/isdn/hisax/avm_pci.c index 035d158779df..0f1db1f669b2 100644 --- a/drivers/isdn/hisax/avm_pci.c +++ b/drivers/isdn/hisax/avm_pci.c @@ -263,11 +263,7 @@ hdlc_empty_fifo(struct BCState *bcs, int count) outl(idx, cs->hw.avm.cfg_reg + 4); while (cnt < count) { #ifdef __powerpc__ -#ifdef CONFIG_APUS - *ptr++ = in_le32((unsigned *)(cs->hw.avm.isac +_IO_BASE)); -#else *ptr++ = in_be32((unsigned *)(cs->hw.avm.isac +_IO_BASE)); -#endif /* CONFIG_APUS */ #else *ptr++ = inl(cs->hw.avm.isac); #endif /* __powerpc__ */ @@ -328,11 +324,7 @@ hdlc_fill_fifo(struct BCState *bcs) if (cs->subtyp == AVM_FRITZ_PCI) { while (cnt<count) { #ifdef __powerpc__ -#ifdef CONFIG_APUS - out_le32((unsigned *)(cs->hw.avm.isac +_IO_BASE), *ptr++); -#else out_be32((unsigned *)(cs->hw.avm.isac +_IO_BASE), *ptr++); -#endif /* CONFIG_APUS */ #else outl(*ptr++, cs->hw.avm.isac); #endif /* __powerpc__ */ diff --git a/drivers/isdn/i4l/isdn_tty.c b/drivers/isdn/i4l/isdn_tty.c index 9cb6e5021adb..133eb18e65cc 100644 --- a/drivers/isdn/i4l/isdn_tty.c +++ b/drivers/isdn/i4l/isdn_tty.c @@ -1917,7 +1917,6 @@ isdn_tty_modem_init(void) info->owner = THIS_MODULE; #endif spin_lock_init(&info->readlock); - init_MUTEX(&info->write_sem); sprintf(info->last_cause, "0000"); sprintf(info->last_num, "none"); info->last_dir = 0; diff --git a/drivers/isdn/i4l/isdn_ttyfax.c b/drivers/isdn/i4l/isdn_ttyfax.c index a943d078bacc..f93de4a30355 100644 --- a/drivers/isdn/i4l/isdn_ttyfax.c +++ b/drivers/isdn/i4l/isdn_ttyfax.c @@ -834,7 +834,7 @@ isdn_tty_cmd_FCLASS2(char **p, modem_info * info) char *rp = &f->resolution; p[0] += 2; - if (!info->faxonline & 1) /* not outgoing connection */ + if (!(info->faxonline & 1)) /* not outgoing connection */ PARSE_ERROR1; for (i = 0; (((*p[0] >= '0') && (*p[0] <= '9')) || (*p[0] == ',')) && (i < 4); i++) { diff --git a/drivers/isdn/icn/icn.c b/drivers/isdn/icn/icn.c index 82d957bde299..bf7997abc4ac 100644 --- a/drivers/isdn/icn/icn.c +++ b/drivers/isdn/icn/icn.c @@ -1302,7 +1302,7 @@ icn_command(isdn_ctrl * c, icn_card * card) } break; case ISDN_CMD_DIAL: - if (!card->flags & ICN_FLAGS_RUNNING) + if (!(card->flags & ICN_FLAGS_RUNNING)) return -ENODEV; if (card->leased) break; @@ -1328,7 +1328,7 @@ icn_command(isdn_ctrl * c, icn_card * card) } break; case ISDN_CMD_ACCEPTD: - if (!card->flags & ICN_FLAGS_RUNNING) + if (!(card->flags & ICN_FLAGS_RUNNING)) return -ENODEV; if (c->arg < ICN_BCH) { a = c->arg + 1; @@ -1348,7 +1348,7 @@ icn_command(isdn_ctrl * c, icn_card * card) } break; case ISDN_CMD_ACCEPTB: - if (!card->flags & ICN_FLAGS_RUNNING) + if (!(card->flags & ICN_FLAGS_RUNNING)) return -ENODEV; if (c->arg < ICN_BCH) { a = c->arg + 1; @@ -1366,7 +1366,7 @@ icn_command(isdn_ctrl * c, icn_card * card) } break; case ISDN_CMD_HANGUP: - if (!card->flags & ICN_FLAGS_RUNNING) + if (!(card->flags & ICN_FLAGS_RUNNING)) return -ENODEV; if (c->arg < ICN_BCH) { a = c->arg + 1; @@ -1375,7 +1375,7 @@ icn_command(isdn_ctrl * c, icn_card * card) } break; case ISDN_CMD_SETEAZ: - if (!card->flags & ICN_FLAGS_RUNNING) + if (!(card->flags & ICN_FLAGS_RUNNING)) return -ENODEV; if (card->leased) break; @@ -1391,7 +1391,7 @@ icn_command(isdn_ctrl * c, icn_card * card) } break; case ISDN_CMD_CLREAZ: - if (!card->flags & ICN_FLAGS_RUNNING) + if (!(card->flags & ICN_FLAGS_RUNNING)) return -ENODEV; if (card->leased) break; @@ -1405,7 +1405,7 @@ icn_command(isdn_ctrl * c, icn_card * card) } break; case ISDN_CMD_SETL2: - if (!card->flags & ICN_FLAGS_RUNNING) + if (!(card->flags & ICN_FLAGS_RUNNING)) return -ENODEV; if ((c->arg & 255) < ICN_BCH) { a = c->arg; @@ -1424,7 +1424,7 @@ icn_command(isdn_ctrl * c, icn_card * card) } break; case ISDN_CMD_SETL3: - if (!card->flags & ICN_FLAGS_RUNNING) + if (!(card->flags & ICN_FLAGS_RUNNING)) return -ENODEV; return 0; default: @@ -1471,7 +1471,7 @@ if_writecmd(const u_char __user *buf, int len, int id, int channel) icn_card *card = icn_findcard(id); if (card) { - if (!card->flags & ICN_FLAGS_RUNNING) + if (!(card->flags & ICN_FLAGS_RUNNING)) return -ENODEV; return (icn_writecmd(buf, len, 1, card)); } @@ -1486,7 +1486,7 @@ if_readstatus(u_char __user *buf, int len, int id, int channel) icn_card *card = icn_findcard(id); if (card) { - if (!card->flags & ICN_FLAGS_RUNNING) + if (!(card->flags & ICN_FLAGS_RUNNING)) return -ENODEV; return (icn_readstatus(buf, len, card)); } @@ -1501,7 +1501,7 @@ if_sendbuf(int id, int channel, int ack, struct sk_buff *skb) icn_card *card = icn_findcard(id); if (card) { - if (!card->flags & ICN_FLAGS_RUNNING) + if (!(card->flags & ICN_FLAGS_RUNNING)) return -ENODEV; return (icn_sendbuf(channel, ack, skb, card)); } diff --git a/drivers/isdn/isdnloop/isdnloop.c b/drivers/isdn/isdnloop/isdnloop.c index bb92e3cd9334..655ef9a3f4df 100644 --- a/drivers/isdn/isdnloop/isdnloop.c +++ b/drivers/isdn/isdnloop/isdnloop.c @@ -1184,7 +1184,7 @@ isdnloop_command(isdn_ctrl * c, isdnloop_card * card) } break; case ISDN_CMD_DIAL: - if (!card->flags & ISDNLOOP_FLAGS_RUNNING) + if (!(card->flags & ISDNLOOP_FLAGS_RUNNING)) return -ENODEV; if (card->leased) break; @@ -1210,7 +1210,7 @@ isdnloop_command(isdn_ctrl * c, isdnloop_card * card) } break; case ISDN_CMD_ACCEPTD: - if (!card->flags & ISDNLOOP_FLAGS_RUNNING) + if (!(card->flags & ISDNLOOP_FLAGS_RUNNING)) return -ENODEV; if (c->arg < ISDNLOOP_BCH) { a = c->arg + 1; @@ -1238,7 +1238,7 @@ isdnloop_command(isdn_ctrl * c, isdnloop_card * card) } break; case ISDN_CMD_ACCEPTB: - if (!card->flags & ISDNLOOP_FLAGS_RUNNING) + if (!(card->flags & ISDNLOOP_FLAGS_RUNNING)) return -ENODEV; if (c->arg < ISDNLOOP_BCH) { a = c->arg + 1; @@ -1264,7 +1264,7 @@ isdnloop_command(isdn_ctrl * c, isdnloop_card * card) i = isdnloop_writecmd(cbuf, strlen(cbuf), 0, card); break; case ISDN_CMD_HANGUP: - if (!card->flags & ISDNLOOP_FLAGS_RUNNING) + if (!(card->flags & ISDNLOOP_FLAGS_RUNNING)) return -ENODEV; if (c->arg < ISDNLOOP_BCH) { a = c->arg + 1; @@ -1273,7 +1273,7 @@ isdnloop_command(isdn_ctrl * c, isdnloop_card * card) } break; case ISDN_CMD_SETEAZ: - if (!card->flags & ISDNLOOP_FLAGS_RUNNING) + if (!(card->flags & ISDNLOOP_FLAGS_RUNNING)) return -ENODEV; if (card->leased) break; @@ -1303,7 +1303,7 @@ isdnloop_command(isdn_ctrl * c, isdnloop_card * card) } break; case ISDN_CMD_SETL2: - if (!card->flags & ISDNLOOP_FLAGS_RUNNING) + if (!(card->flags & ISDNLOOP_FLAGS_RUNNING)) return -ENODEV; if ((c->arg & 255) < ISDNLOOP_BCH) { a = c->arg; @@ -1395,7 +1395,7 @@ if_readstatus(u_char __user *buf, int len, int id, int channel) isdnloop_card *card = isdnloop_findcard(id); if (card) { - if (!card->flags & ISDNLOOP_FLAGS_RUNNING) + if (!(card->flags & ISDNLOOP_FLAGS_RUNNING)) return -ENODEV; return (isdnloop_readstatus(buf, len, card)); } @@ -1410,7 +1410,7 @@ if_sendbuf(int id, int channel, int ack, struct sk_buff *skb) isdnloop_card *card = isdnloop_findcard(id); if (card) { - if (!card->flags & ISDNLOOP_FLAGS_RUNNING) + if (!(card->flags & ISDNLOOP_FLAGS_RUNNING)) return -ENODEV; /* ack request stored in skb scratch area */ *(skb->head) = ack; diff --git a/drivers/macintosh/mediabay.c b/drivers/macintosh/mediabay.c index de9ebbfbf122..936788272a5f 100644 --- a/drivers/macintosh/mediabay.c +++ b/drivers/macintosh/mediabay.c @@ -78,12 +78,14 @@ struct media_bay_info { int cached_gpio; int sleeping; struct semaphore lock; -#ifdef CONFIG_BLK_DEV_IDE +#ifdef CONFIG_BLK_DEV_IDE_PMAC void __iomem *cd_base; - int cd_index; int cd_irq; int cd_retry; #endif +#if defined(CONFIG_BLK_DEV_IDE_PMAC) || defined(CONFIG_MAC_FLOPPY) + int cd_index; +#endif }; #define MAX_BAYS 2 @@ -91,7 +93,7 @@ struct media_bay_info { static struct media_bay_info media_bays[MAX_BAYS]; int media_bay_count = 0; -#ifdef CONFIG_BLK_DEV_IDE +#ifdef CONFIG_BLK_DEV_IDE_PMAC /* check the busy bit in the media-bay ide interface (assumes the media-bay contains an ide device) */ #define MB_IDE_READY(i) ((readb(media_bays[i].cd_base + 0x70) & 0x80) == 0) @@ -401,7 +403,7 @@ static void poll_media_bay(struct media_bay_info* bay) set_mb_power(bay, id != MB_NO); bay->content_id = id; if (id == MB_NO) { -#ifdef CONFIG_BLK_DEV_IDE +#ifdef CONFIG_BLK_DEV_IDE_PMAC bay->cd_retry = 0; #endif printk(KERN_INFO "media bay %d is empty\n", bay->index); @@ -414,9 +416,9 @@ static void poll_media_bay(struct media_bay_info* bay) } } +#ifdef CONFIG_MAC_FLOPPY int check_media_bay(struct device_node *which_bay, int what) { -#ifdef CONFIG_BLK_DEV_IDE int i; for (i=0; i<media_bay_count; i++) @@ -426,14 +428,14 @@ int check_media_bay(struct device_node *which_bay, int what) media_bays[i].cd_index = -1; return -EINVAL; } -#endif /* CONFIG_BLK_DEV_IDE */ return -ENODEV; } EXPORT_SYMBOL(check_media_bay); +#endif /* CONFIG_MAC_FLOPPY */ +#ifdef CONFIG_BLK_DEV_IDE_PMAC int check_media_bay_by_base(unsigned long base, int what) { -#ifdef CONFIG_BLK_DEV_IDE int i; for (i=0; i<media_bay_count; i++) @@ -443,15 +445,13 @@ int check_media_bay_by_base(unsigned long base, int what) media_bays[i].cd_index = -1; return -EINVAL; } -#endif - + return -ENODEV; } int media_bay_set_ide_infos(struct device_node* which_bay, unsigned long base, - int irq, int index) + int irq, int index) { -#ifdef CONFIG_BLK_DEV_IDE int i; for (i=0; i<media_bay_count; i++) { @@ -483,10 +483,10 @@ int media_bay_set_ide_infos(struct device_node* which_bay, unsigned long base, return -ENODEV; } } -#endif /* CONFIG_BLK_DEV_IDE */ - + return -ENODEV; } +#endif /* CONFIG_BLK_DEV_IDE_PMAC */ static void media_bay_step(int i) { @@ -521,14 +521,13 @@ static void media_bay_step(int i) bay->state = mb_resetting; MBDBG("mediabay%d: waiting reset (kind:%d)\n", i, bay->content_id); break; - case mb_resetting: if (bay->content_id != MB_CD) { MBDBG("mediabay%d: bay is up (kind:%d)\n", i, bay->content_id); bay->state = mb_up; break; } -#ifdef CONFIG_BLK_DEV_IDE +#ifdef CONFIG_BLK_DEV_IDE_PMAC MBDBG("mediabay%d: waiting IDE reset (kind:%d)\n", i, bay->content_id); bay->ops->un_reset_ide(bay); bay->timer = msecs_to_jiffies(MB_IDE_WAIT); @@ -536,16 +535,14 @@ static void media_bay_step(int i) #else printk(KERN_DEBUG "media-bay %d is ide (not compiled in kernel)\n", i); set_mb_power(bay, 0); -#endif /* CONFIG_BLK_DEV_IDE */ +#endif /* CONFIG_BLK_DEV_IDE_PMAC */ break; - -#ifdef CONFIG_BLK_DEV_IDE +#ifdef CONFIG_BLK_DEV_IDE_PMAC case mb_ide_resetting: bay->timer = msecs_to_jiffies(MB_IDE_TIMEOUT); bay->state = mb_ide_waiting; MBDBG("mediabay%d: waiting IDE ready (kind:%d)\n", i, bay->content_id); break; - case mb_ide_waiting: if (bay->cd_base == NULL) { bay->timer = 0; @@ -587,11 +584,10 @@ static void media_bay_step(int i) bay->timer = 0; } break; -#endif /* CONFIG_BLK_DEV_IDE */ - +#endif /* CONFIG_BLK_DEV_IDE_PMAC */ case mb_powering_down: bay->state = mb_empty; -#ifdef CONFIG_BLK_DEV_IDE +#ifdef CONFIG_BLK_DEV_IDE_PMAC if (bay->cd_index >= 0) { printk(KERN_DEBUG "Unregistering mb %d ide, index:%d\n", i, bay->cd_index); @@ -607,7 +603,7 @@ static void media_bay_step(int i) bay->content_id = MB_NO; } } -#endif /* CONFIG_BLK_DEV_IDE */ +#endif /* CONFIG_BLK_DEV_IDE_PMAC */ MBDBG("mediabay%d: end of power down\n", i); break; } @@ -739,7 +735,7 @@ static int media_bay_resume(struct macio_dev *mdev) bay->last_value = bay->content_id; bay->value_count = msecs_to_jiffies(MB_STABLE_DELAY); bay->timer = msecs_to_jiffies(MB_POWER_DELAY); -#ifdef CONFIG_BLK_DEV_IDE +#ifdef CONFIG_BLK_DEV_IDE_PMAC bay->cd_retry = 0; #endif do { @@ -829,7 +825,7 @@ static int __init media_bay_init(void) for (i=0; i<MAX_BAYS; i++) { memset((char *)&media_bays[i], 0, sizeof(struct media_bay_info)); media_bays[i].content_id = -1; -#ifdef CONFIG_BLK_DEV_IDE +#ifdef CONFIG_BLK_DEV_IDE_PMAC media_bays[i].cd_index = -1; #endif } diff --git a/drivers/md/bitmap.c b/drivers/md/bitmap.c index 1b1ef3130e6e..a0585fb6da94 100644 --- a/drivers/md/bitmap.c +++ b/drivers/md/bitmap.c @@ -237,7 +237,7 @@ static struct page *read_sb_page(mddev_t *mddev, long offset, unsigned long inde if (!page) return ERR_PTR(-ENOMEM); - ITERATE_RDEV(mddev, rdev, tmp) { + rdev_for_each(rdev, tmp, mddev) { if (! test_bit(In_sync, &rdev->flags) || test_bit(Faulty, &rdev->flags)) continue; @@ -261,7 +261,7 @@ static int write_sb_page(struct bitmap *bitmap, struct page *page, int wait) struct list_head *tmp; mddev_t *mddev = bitmap->mddev; - ITERATE_RDEV(mddev, rdev, tmp) + rdev_for_each(rdev, tmp, mddev) if (test_bit(In_sync, &rdev->flags) && !test_bit(Faulty, &rdev->flags)) { int size = PAGE_SIZE; @@ -1348,14 +1348,38 @@ void bitmap_close_sync(struct bitmap *bitmap) */ sector_t sector = 0; int blocks; - if (!bitmap) return; + if (!bitmap) + return; while (sector < bitmap->mddev->resync_max_sectors) { bitmap_end_sync(bitmap, sector, &blocks, 0); -/* - if (sector < 500) printk("bitmap_close_sync: sec %llu blks %d\n", - (unsigned long long)sector, blocks); -*/ sector += blocks; + sector += blocks; + } +} + +void bitmap_cond_end_sync(struct bitmap *bitmap, sector_t sector) +{ + sector_t s = 0; + int blocks; + + if (!bitmap) + return; + if (sector == 0) { + bitmap->last_end_sync = jiffies; + return; + } + if (time_before(jiffies, (bitmap->last_end_sync + + bitmap->daemon_sleep * HZ))) + return; + wait_event(bitmap->mddev->recovery_wait, + atomic_read(&bitmap->mddev->recovery_active) == 0); + + sector &= ~((1ULL << CHUNK_BLOCK_SHIFT(bitmap)) - 1); + s = 0; + while (s < sector && s < bitmap->mddev->resync_max_sectors) { + bitmap_end_sync(bitmap, s, &blocks, 0); + s += blocks; } + bitmap->last_end_sync = jiffies; } static void bitmap_set_memory_bits(struct bitmap *bitmap, sector_t offset, int needed) @@ -1565,3 +1589,4 @@ EXPORT_SYMBOL(bitmap_start_sync); EXPORT_SYMBOL(bitmap_end_sync); EXPORT_SYMBOL(bitmap_unplug); EXPORT_SYMBOL(bitmap_close_sync); +EXPORT_SYMBOL(bitmap_cond_end_sync); diff --git a/drivers/md/faulty.c b/drivers/md/faulty.c index cf2ddce34118..d107ddceefcd 100644 --- a/drivers/md/faulty.c +++ b/drivers/md/faulty.c @@ -294,7 +294,7 @@ static int run(mddev_t *mddev) } conf->nfaults = 0; - ITERATE_RDEV(mddev, rdev, tmp) + rdev_for_each(rdev, tmp, mddev) conf->rdev = rdev; mddev->array_size = mddev->size; diff --git a/drivers/md/linear.c b/drivers/md/linear.c index 3dac1cfb8189..0b8511776b3e 100644 --- a/drivers/md/linear.c +++ b/drivers/md/linear.c @@ -122,7 +122,7 @@ static linear_conf_t *linear_conf(mddev_t *mddev, int raid_disks) cnt = 0; conf->array_size = 0; - ITERATE_RDEV(mddev,rdev,tmp) { + rdev_for_each(rdev, tmp, mddev) { int j = rdev->raid_disk; dev_info_t *disk = conf->disks + j; diff --git a/drivers/md/md.c b/drivers/md/md.c index c28a120b4161..5fc326d3970e 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -195,7 +195,7 @@ static DEFINE_SPINLOCK(all_mddevs_lock); * Any code which breaks out of this loop while own * a reference to the current mddev and must mddev_put it. */ -#define ITERATE_MDDEV(mddev,tmp) \ +#define for_each_mddev(mddev,tmp) \ \ for (({ spin_lock(&all_mddevs_lock); \ tmp = all_mddevs.next; \ @@ -275,6 +275,7 @@ static mddev_t * mddev_find(dev_t unit) spin_lock_init(&new->write_lock); init_waitqueue_head(&new->sb_wait); new->reshape_position = MaxSector; + new->resync_max = MaxSector; new->queue = blk_alloc_queue(GFP_KERNEL); if (!new->queue) { @@ -310,7 +311,7 @@ static mdk_rdev_t * find_rdev_nr(mddev_t *mddev, int nr) mdk_rdev_t * rdev; struct list_head *tmp; - ITERATE_RDEV(mddev,rdev,tmp) { + rdev_for_each(rdev, tmp, mddev) { if (rdev->desc_nr == nr) return rdev; } @@ -322,7 +323,7 @@ static mdk_rdev_t * find_rdev(mddev_t * mddev, dev_t dev) struct list_head *tmp; mdk_rdev_t *rdev; - ITERATE_RDEV(mddev,rdev,tmp) { + rdev_for_each(rdev, tmp, mddev) { if (rdev->bdev->bd_dev == dev) return rdev; } @@ -773,12 +774,16 @@ static int super_90_validate(mddev_t *mddev, mdk_rdev_t *rdev) __u64 ev1 = md_event(sb); rdev->raid_disk = -1; - rdev->flags = 0; + clear_bit(Faulty, &rdev->flags); + clear_bit(In_sync, &rdev->flags); + clear_bit(WriteMostly, &rdev->flags); + clear_bit(BarriersNotsupp, &rdev->flags); + if (mddev->raid_disks == 0) { mddev->major_version = 0; mddev->minor_version = sb->minor_version; mddev->patch_version = sb->patch_version; - mddev->persistent = ! sb->not_persistent; + mddev->external = 0; mddev->chunk_size = sb->chunk_size; mddev->ctime = sb->ctime; mddev->utime = sb->utime; @@ -904,7 +909,7 @@ static void super_90_sync(mddev_t *mddev, mdk_rdev_t *rdev) sb->size = mddev->size; sb->raid_disks = mddev->raid_disks; sb->md_minor = mddev->md_minor; - sb->not_persistent = !mddev->persistent; + sb->not_persistent = 0; sb->utime = mddev->utime; sb->state = 0; sb->events_hi = (mddev->events>>32); @@ -938,7 +943,7 @@ static void super_90_sync(mddev_t *mddev, mdk_rdev_t *rdev) sb->state |= (1<<MD_SB_BITMAP_PRESENT); sb->disks[0].state = (1<<MD_DISK_REMOVED); - ITERATE_RDEV(mddev,rdev2,tmp) { + rdev_for_each(rdev2, tmp, mddev) { mdp_disk_t *d; int desc_nr; if (rdev2->raid_disk >= 0 && test_bit(In_sync, &rdev2->flags) @@ -1153,11 +1158,15 @@ static int super_1_validate(mddev_t *mddev, mdk_rdev_t *rdev) __u64 ev1 = le64_to_cpu(sb->events); rdev->raid_disk = -1; - rdev->flags = 0; + clear_bit(Faulty, &rdev->flags); + clear_bit(In_sync, &rdev->flags); + clear_bit(WriteMostly, &rdev->flags); + clear_bit(BarriersNotsupp, &rdev->flags); + if (mddev->raid_disks == 0) { mddev->major_version = 1; mddev->patch_version = 0; - mddev->persistent = 1; + mddev->external = 0; mddev->chunk_size = le32_to_cpu(sb->chunksize) << 9; mddev->ctime = le64_to_cpu(sb->ctime) & ((1ULL << 32)-1); mddev->utime = le64_to_cpu(sb->utime) & ((1ULL << 32)-1); @@ -1286,7 +1295,7 @@ static void super_1_sync(mddev_t *mddev, mdk_rdev_t *rdev) } max_dev = 0; - ITERATE_RDEV(mddev,rdev2,tmp) + rdev_for_each(rdev2, tmp, mddev) if (rdev2->desc_nr+1 > max_dev) max_dev = rdev2->desc_nr+1; @@ -1295,7 +1304,7 @@ static void super_1_sync(mddev_t *mddev, mdk_rdev_t *rdev) for (i=0; i<max_dev;i++) sb->dev_roles[i] = cpu_to_le16(0xfffe); - ITERATE_RDEV(mddev,rdev2,tmp) { + rdev_for_each(rdev2, tmp, mddev) { i = rdev2->desc_nr; if (test_bit(Faulty, &rdev2->flags)) sb->dev_roles[i] = cpu_to_le16(0xfffe); @@ -1333,8 +1342,8 @@ static int match_mddev_units(mddev_t *mddev1, mddev_t *mddev2) struct list_head *tmp, *tmp2; mdk_rdev_t *rdev, *rdev2; - ITERATE_RDEV(mddev1,rdev,tmp) - ITERATE_RDEV(mddev2, rdev2, tmp2) + rdev_for_each(rdev, tmp, mddev1) + rdev_for_each(rdev2, tmp2, mddev2) if (rdev->bdev->bd_contains == rdev2->bdev->bd_contains) return 1; @@ -1401,7 +1410,7 @@ static int bind_rdev_to_array(mdk_rdev_t * rdev, mddev_t * mddev) goto fail; } list_add(&rdev->same_set, &mddev->disks); - bd_claim_by_disk(rdev->bdev, rdev, mddev->gendisk); + bd_claim_by_disk(rdev->bdev, rdev->bdev->bd_holder, mddev->gendisk); return 0; fail: @@ -1410,10 +1419,11 @@ static int bind_rdev_to_array(mdk_rdev_t * rdev, mddev_t * mddev) return err; } -static void delayed_delete(struct work_struct *ws) +static void md_delayed_delete(struct work_struct *ws) { mdk_rdev_t *rdev = container_of(ws, mdk_rdev_t, del_work); kobject_del(&rdev->kobj); + kobject_put(&rdev->kobj); } static void unbind_rdev_from_array(mdk_rdev_t * rdev) @@ -1432,7 +1442,8 @@ static void unbind_rdev_from_array(mdk_rdev_t * rdev) /* We need to delay this, otherwise we can deadlock when * writing to 'remove' to "dev/state" */ - INIT_WORK(&rdev->del_work, delayed_delete); + INIT_WORK(&rdev->del_work, md_delayed_delete); + kobject_get(&rdev->kobj); schedule_work(&rdev->del_work); } @@ -1441,7 +1452,7 @@ static void unbind_rdev_from_array(mdk_rdev_t * rdev) * otherwise reused by a RAID array (or any other kernel * subsystem), by bd_claiming the device. */ -static int lock_rdev(mdk_rdev_t *rdev, dev_t dev) +static int lock_rdev(mdk_rdev_t *rdev, dev_t dev, int shared) { int err = 0; struct block_device *bdev; @@ -1453,13 +1464,15 @@ static int lock_rdev(mdk_rdev_t *rdev, dev_t dev) __bdevname(dev, b)); return PTR_ERR(bdev); } - err = bd_claim(bdev, rdev); + err = bd_claim(bdev, shared ? (mdk_rdev_t *)lock_rdev : rdev); if (err) { printk(KERN_ERR "md: could not bd_claim %s.\n", bdevname(bdev, b)); blkdev_put(bdev); return err; } + if (!shared) + set_bit(AllReserved, &rdev->flags); rdev->bdev = bdev; return err; } @@ -1503,7 +1516,7 @@ static void export_array(mddev_t *mddev) struct list_head *tmp; mdk_rdev_t *rdev; - ITERATE_RDEV(mddev,rdev,tmp) { + rdev_for_each(rdev, tmp, mddev) { if (!rdev->mddev) { MD_BUG(); continue; @@ -1581,17 +1594,17 @@ static void md_print_devices(void) printk("md: **********************************\n"); printk("md: * <COMPLETE RAID STATE PRINTOUT> *\n"); printk("md: **********************************\n"); - ITERATE_MDDEV(mddev,tmp) { + for_each_mddev(mddev, tmp) { if (mddev->bitmap) bitmap_print_sb(mddev->bitmap); else printk("%s: ", mdname(mddev)); - ITERATE_RDEV(mddev,rdev,tmp2) + rdev_for_each(rdev, tmp2, mddev) printk("<%s>", bdevname(rdev->bdev,b)); printk("\n"); - ITERATE_RDEV(mddev,rdev,tmp2) + rdev_for_each(rdev, tmp2, mddev) print_rdev(rdev); } printk("md: **********************************\n"); @@ -1610,7 +1623,7 @@ static void sync_sbs(mddev_t * mddev, int nospares) mdk_rdev_t *rdev; struct list_head *tmp; - ITERATE_RDEV(mddev,rdev,tmp) { + rdev_for_each(rdev, tmp, mddev) { if (rdev->sb_events == mddev->events || (nospares && rdev->raid_disk < 0 && @@ -1696,18 +1709,20 @@ repeat: MD_BUG(); mddev->events --; } - sync_sbs(mddev, nospares); /* * do not write anything to disk if using * nonpersistent superblocks */ if (!mddev->persistent) { - clear_bit(MD_CHANGE_PENDING, &mddev->flags); + if (!mddev->external) + clear_bit(MD_CHANGE_PENDING, &mddev->flags); + spin_unlock_irq(&mddev->write_lock); wake_up(&mddev->sb_wait); return; } + sync_sbs(mddev, nospares); spin_unlock_irq(&mddev->write_lock); dprintk(KERN_INFO @@ -1715,7 +1730,7 @@ repeat: mdname(mddev),mddev->in_sync); bitmap_update_sb(mddev->bitmap); - ITERATE_RDEV(mddev,rdev,tmp) { + rdev_for_each(rdev, tmp, mddev) { char b[BDEVNAME_SIZE]; dprintk(KERN_INFO "md: "); if (rdev->sb_loaded != 1) @@ -1785,7 +1800,7 @@ static ssize_t state_show(mdk_rdev_t *rdev, char *page) { char *sep = ""; - int len=0; + size_t len = 0; if (test_bit(Faulty, &rdev->flags)) { len+= sprintf(page+len, "%sfaulty",sep); @@ -1887,20 +1902,45 @@ static ssize_t slot_store(mdk_rdev_t *rdev, const char *buf, size_t len) { char *e; + int err; + char nm[20]; int slot = simple_strtoul(buf, &e, 10); if (strncmp(buf, "none", 4)==0) slot = -1; else if (e==buf || (*e && *e!= '\n')) return -EINVAL; - if (rdev->mddev->pers) - /* Cannot set slot in active array (yet) */ - return -EBUSY; - if (slot >= rdev->mddev->raid_disks) - return -ENOSPC; - rdev->raid_disk = slot; - /* assume it is working */ - rdev->flags = 0; - set_bit(In_sync, &rdev->flags); + if (rdev->mddev->pers) { + /* Setting 'slot' on an active array requires also + * updating the 'rd%d' link, and communicating + * with the personality with ->hot_*_disk. + * For now we only support removing + * failed/spare devices. This normally happens automatically, + * but not when the metadata is externally managed. + */ + if (slot != -1) + return -EBUSY; + if (rdev->raid_disk == -1) + return -EEXIST; + /* personality does all needed checks */ + if (rdev->mddev->pers->hot_add_disk == NULL) + return -EINVAL; + err = rdev->mddev->pers-> + hot_remove_disk(rdev->mddev, rdev->raid_disk); + if (err) + return err; + sprintf(nm, "rd%d", rdev->raid_disk); + sysfs_remove_link(&rdev->mddev->kobj, nm); + set_bit(MD_RECOVERY_NEEDED, &rdev->mddev->recovery); + md_wakeup_thread(rdev->mddev->thread); + } else { + if (slot >= rdev->mddev->raid_disks) + return -ENOSPC; + rdev->raid_disk = slot; + /* assume it is working */ + clear_bit(Faulty, &rdev->flags); + clear_bit(WriteMostly, &rdev->flags); + set_bit(In_sync, &rdev->flags); + } return len; } @@ -1923,6 +1963,10 @@ offset_store(mdk_rdev_t *rdev, const char *buf, size_t len) return -EINVAL; if (rdev->mddev->pers) return -EBUSY; + if (rdev->size && rdev->mddev->external) + /* Must set offset before size, so overlap checks + * can be sane */ + return -EBUSY; rdev->data_offset = offset; return len; } @@ -1936,16 +1980,69 @@ rdev_size_show(mdk_rdev_t *rdev, char *page) return sprintf(page, "%llu\n", (unsigned long long)rdev->size); } +static int overlaps(sector_t s1, sector_t l1, sector_t s2, sector_t l2) +{ + /* check if two start/length pairs overlap */ + if (s1+l1 <= s2) + return 0; + if (s2+l2 <= s1) + return 0; + return 1; +} + static ssize_t rdev_size_store(mdk_rdev_t *rdev, const char *buf, size_t len) { char *e; unsigned long long size = simple_strtoull(buf, &e, 10); + unsigned long long oldsize = rdev->size; if (e==buf || (*e && *e != '\n')) return -EINVAL; if (rdev->mddev->pers) return -EBUSY; rdev->size = size; + if (size > oldsize && rdev->mddev->external) { + /* need to check that all other rdevs with the same ->bdev + * do not overlap. We need to unlock the mddev to avoid + * a deadlock. We have already changed rdev->size, and if + * we have to change it back, we will have the lock again. + */ + mddev_t *mddev; + int overlap = 0; + struct list_head *tmp, *tmp2; + + mddev_unlock(rdev->mddev); + for_each_mddev(mddev, tmp) { + mdk_rdev_t *rdev2; + + mddev_lock(mddev); + rdev_for_each(rdev2, tmp2, mddev) + if (test_bit(AllReserved, &rdev2->flags) || + (rdev->bdev == rdev2->bdev && + rdev != rdev2 && + overlaps(rdev->data_offset, rdev->size, + rdev2->data_offset, rdev2->size))) { + overlap = 1; + break; + } + mddev_unlock(mddev); + if (overlap) { + mddev_put(mddev); + break; + } + } + mddev_lock(rdev->mddev); + if (overlap) { + /* Someone else could have slipped in a size + * change here, but doing so is just silly. + * We put oldsize back because we *know* it is + * safe, and trust userspace not to race with + * itself + */ + rdev->size = oldsize; + return -EBUSY; + } + } if (size < rdev->mddev->size || rdev->mddev->size == 0) rdev->mddev->size = size; return len; @@ -1980,12 +2077,18 @@ rdev_attr_store(struct kobject *kobj, struct attribute *attr, { struct rdev_sysfs_entry *entry = container_of(attr, struct rdev_sysfs_entry, attr); mdk_rdev_t *rdev = container_of(kobj, mdk_rdev_t, kobj); + int rv; if (!entry->store) return -EIO; if (!capable(CAP_SYS_ADMIN)) return -EACCES; - return entry->store(rdev, page, length); + rv = mddev_lock(rdev->mddev); + if (!rv) { + rv = entry->store(rdev, page, length); + mddev_unlock(rdev->mddev); + } + return rv; } static void rdev_free(struct kobject *ko) @@ -2029,7 +2132,7 @@ static mdk_rdev_t *md_import_device(dev_t newdev, int super_format, int super_mi if ((err = alloc_disk_sb(rdev))) goto abort_free; - err = lock_rdev(rdev, newdev); + err = lock_rdev(rdev, newdev, super_format == -2); if (err) goto abort_free; @@ -2099,7 +2202,7 @@ static void analyze_sbs(mddev_t * mddev) char b[BDEVNAME_SIZE]; freshest = NULL; - ITERATE_RDEV(mddev,rdev,tmp) + rdev_for_each(rdev, tmp, mddev) switch (super_types[mddev->major_version]. load_super(rdev, freshest, mddev->minor_version)) { case 1: @@ -2120,7 +2223,7 @@ static void analyze_sbs(mddev_t * mddev) validate_super(mddev, freshest); i = 0; - ITERATE_RDEV(mddev,rdev,tmp) { + rdev_for_each(rdev, tmp, mddev) { if (rdev != freshest) if (super_types[mddev->major_version]. validate_super(mddev, rdev)) { @@ -2215,7 +2318,7 @@ level_show(mddev_t *mddev, char *page) static ssize_t level_store(mddev_t *mddev, const char *buf, size_t len) { - int rv = len; + ssize_t rv = len; if (mddev->pers) return -EBUSY; if (len == 0) @@ -2425,6 +2528,8 @@ array_state_show(mddev_t *mddev, char *page) case 0: if (mddev->in_sync) st = clean; + else if (test_bit(MD_CHANGE_CLEAN, &mddev->flags)) + st = write_pending; else if (mddev->safemode) st = active_idle; else @@ -2455,11 +2560,9 @@ array_state_store(mddev_t *mddev, const char *buf, size_t len) break; case clear: /* stopping an active array */ - if (mddev->pers) { - if (atomic_read(&mddev->active) > 1) - return -EBUSY; - err = do_md_stop(mddev, 0); - } + if (atomic_read(&mddev->active) > 1) + return -EBUSY; + err = do_md_stop(mddev, 0); break; case inactive: /* stopping an active array */ @@ -2467,7 +2570,8 @@ array_state_store(mddev_t *mddev, const char *buf, size_t len) if (atomic_read(&mddev->active) > 1) return -EBUSY; err = do_md_stop(mddev, 2); - } + } else + err = 0; /* already inactive */ break; case suspended: break; /* not supported yet */ @@ -2495,9 +2599,15 @@ array_state_store(mddev_t *mddev, const char *buf, size_t len) restart_array(mddev); spin_lock_irq(&mddev->write_lock); if (atomic_read(&mddev->writes_pending) == 0) { - mddev->in_sync = 1; - set_bit(MD_CHANGE_CLEAN, &mddev->flags); - } + if (mddev->in_sync == 0) { + mddev->in_sync = 1; + if (mddev->persistent) + set_bit(MD_CHANGE_CLEAN, + &mddev->flags); + } + err = 0; + } else + err = -EBUSY; spin_unlock_irq(&mddev->write_lock); } else { mddev->ro = 0; @@ -2508,7 +2618,8 @@ array_state_store(mddev_t *mddev, const char *buf, size_t len) case active: if (mddev->pers) { restart_array(mddev); - clear_bit(MD_CHANGE_CLEAN, &mddev->flags); + if (mddev->external) + clear_bit(MD_CHANGE_CLEAN, &mddev->flags); wake_up(&mddev->sb_wait); err = 0; } else { @@ -2574,7 +2685,9 @@ new_dev_store(mddev_t *mddev, const char *buf, size_t len) if (err < 0) goto out; } - } else + } else if (mddev->external) + rdev = md_import_device(dev, -2, -1); + else rdev = md_import_device(dev, -1, -1); if (IS_ERR(rdev)) @@ -2659,7 +2772,9 @@ __ATTR(component_size, S_IRUGO|S_IWUSR, size_show, size_store); /* Metdata version. - * This is either 'none' for arrays with externally managed metadata, + * This is one of + * 'none' for arrays with no metadata (good luck...) + * 'external' for arrays with externally managed metadata, * or N.M for internally known formats */ static ssize_t @@ -2668,6 +2783,8 @@ metadata_show(mddev_t *mddev, char *page) if (mddev->persistent) return sprintf(page, "%d.%d\n", mddev->major_version, mddev->minor_version); + else if (mddev->external) + return sprintf(page, "external:%s\n", mddev->metadata_type); else return sprintf(page, "none\n"); } @@ -2682,6 +2799,21 @@ metadata_store(mddev_t *mddev, const char *buf, size_t len) if (cmd_match(buf, "none")) { mddev->persistent = 0; + mddev->external = 0; + mddev->major_version = 0; + mddev->minor_version = 90; + return len; + } + if (strncmp(buf, "external:", 9) == 0) { + size_t namelen = len-9; + if (namelen >= sizeof(mddev->metadata_type)) + namelen = sizeof(mddev->metadata_type)-1; + strncpy(mddev->metadata_type, buf+9, namelen); + mddev->metadata_type[namelen] = 0; + if (namelen && mddev->metadata_type[namelen-1] == '\n') + mddev->metadata_type[--namelen] = 0; + mddev->persistent = 0; + mddev->external = 1; mddev->major_version = 0; mddev->minor_version = 90; return len; @@ -2698,6 +2830,7 @@ metadata_store(mddev_t *mddev, const char *buf, size_t len) mddev->major_version = major; mddev->minor_version = minor; mddev->persistent = 1; + mddev->external = 0; return len; } @@ -2865,6 +2998,43 @@ sync_completed_show(mddev_t *mddev, char *page) static struct md_sysfs_entry md_sync_completed = __ATTR_RO(sync_completed); static ssize_t +max_sync_show(mddev_t *mddev, char *page) +{ + if (mddev->resync_max == MaxSector) + return sprintf(page, "max\n"); + else + return sprintf(page, "%llu\n", + (unsigned long long)mddev->resync_max); +} +static ssize_t +max_sync_store(mddev_t *mddev, const char *buf, size_t len) +{ + if (strncmp(buf, "max", 3) == 0) + mddev->resync_max = MaxSector; + else { + char *ep; + unsigned long long max = simple_strtoull(buf, &ep, 10); + if (ep == buf || (*ep != 0 && *ep != '\n')) + return -EINVAL; + if (max < mddev->resync_max && + test_bit(MD_RECOVERY_RUNNING, &mddev->recovery)) + return -EBUSY; + + /* Must be a multiple of chunk_size */ + if (mddev->chunk_size) { + if (max & (sector_t)((mddev->chunk_size>>9)-1)) + return -EINVAL; + } + mddev->resync_max = max; + } + wake_up(&mddev->recovery_wait); + return len; +} + +static struct md_sysfs_entry md_max_sync = +__ATTR(sync_max, S_IRUGO|S_IWUSR, max_sync_show, max_sync_store); + +static ssize_t suspend_lo_show(mddev_t *mddev, char *page) { return sprintf(page, "%llu\n", (unsigned long long)mddev->suspend_lo); @@ -2974,6 +3144,7 @@ static struct attribute *md_redundancy_attrs[] = { &md_sync_max.attr, &md_sync_speed.attr, &md_sync_completed.attr, + &md_max_sync.attr, &md_suspend_lo.attr, &md_suspend_hi.attr, &md_bitmap.attr, @@ -3118,8 +3289,11 @@ static int do_md_run(mddev_t * mddev) /* * Analyze all RAID superblock(s) */ - if (!mddev->raid_disks) + if (!mddev->raid_disks) { + if (!mddev->persistent) + return -EINVAL; analyze_sbs(mddev); + } chunk_size = mddev->chunk_size; @@ -3143,7 +3317,7 @@ static int do_md_run(mddev_t * mddev) } /* devices must have minimum size of one chunk */ - ITERATE_RDEV(mddev,rdev,tmp) { + rdev_for_each(rdev, tmp, mddev) { if (test_bit(Faulty, &rdev->flags)) continue; if (rdev->size < chunk_size / 1024) { @@ -3170,7 +3344,7 @@ static int do_md_run(mddev_t * mddev) * the only valid external interface is through the md * device. */ - ITERATE_RDEV(mddev,rdev,tmp) { + rdev_for_each(rdev, tmp, mddev) { if (test_bit(Faulty, &rdev->flags)) continue; sync_blockdev(rdev->bdev); @@ -3236,8 +3410,8 @@ static int do_md_run(mddev_t * mddev) mdk_rdev_t *rdev2; struct list_head *tmp2; int warned = 0; - ITERATE_RDEV(mddev, rdev, tmp) { - ITERATE_RDEV(mddev, rdev2, tmp2) { + rdev_for_each(rdev, tmp, mddev) { + rdev_for_each(rdev2, tmp2, mddev) { if (rdev < rdev2 && rdev->bdev->bd_contains == rdev2->bdev->bd_contains) { @@ -3297,7 +3471,7 @@ static int do_md_run(mddev_t * mddev) mddev->safemode_delay = (200 * HZ)/1000 +1; /* 200 msec delay */ mddev->in_sync = 1; - ITERATE_RDEV(mddev,rdev,tmp) + rdev_for_each(rdev, tmp, mddev) if (rdev->raid_disk >= 0) { char nm[20]; sprintf(nm, "rd%d", rdev->raid_disk); @@ -3330,7 +3504,7 @@ static int do_md_run(mddev_t * mddev) if (mddev->degraded && !mddev->sync_thread) { struct list_head *rtmp; int spares = 0; - ITERATE_RDEV(mddev,rdev,rtmp) + rdev_for_each(rdev, rtmp, mddev) if (rdev->raid_disk >= 0 && !test_bit(In_sync, &rdev->flags) && !test_bit(Faulty, &rdev->flags)) @@ -3507,14 +3681,14 @@ static int do_md_stop(mddev_t * mddev, int mode) } mddev->bitmap_offset = 0; - ITERATE_RDEV(mddev,rdev,tmp) + rdev_for_each(rdev, tmp, mddev) if (rdev->raid_disk >= 0) { char nm[20]; sprintf(nm, "rd%d", rdev->raid_disk); sysfs_remove_link(&mddev->kobj, nm); } - /* make sure all delayed_delete calls have finished */ + /* make sure all md_delayed_delete calls have finished */ flush_scheduled_work(); export_array(mddev); @@ -3523,7 +3697,10 @@ static int do_md_stop(mddev_t * mddev, int mode) mddev->size = 0; mddev->raid_disks = 0; mddev->recovery_cp = 0; + mddev->resync_max = MaxSector; mddev->reshape_position = MaxSector; + mddev->external = 0; + mddev->persistent = 0; } else if (mddev->pers) printk(KERN_INFO "md: %s switched to read-only mode.\n", @@ -3546,7 +3723,7 @@ static void autorun_array(mddev_t *mddev) printk(KERN_INFO "md: running: "); - ITERATE_RDEV(mddev,rdev,tmp) { + rdev_for_each(rdev, tmp, mddev) { char b[BDEVNAME_SIZE]; printk("<%s>", bdevname(rdev->bdev,b)); } @@ -3589,7 +3766,7 @@ static void autorun_devices(int part) printk(KERN_INFO "md: considering %s ...\n", bdevname(rdev0->bdev,b)); INIT_LIST_HEAD(&candidates); - ITERATE_RDEV_PENDING(rdev,tmp) + rdev_for_each_list(rdev, tmp, pending_raid_disks) if (super_90_load(rdev, rdev0, 0) >= 0) { printk(KERN_INFO "md: adding %s ...\n", bdevname(rdev->bdev,b)); @@ -3632,7 +3809,8 @@ static void autorun_devices(int part) mddev_unlock(mddev); } else { printk(KERN_INFO "md: created %s\n", mdname(mddev)); - ITERATE_RDEV_GENERIC(candidates,rdev,tmp) { + mddev->persistent = 1; + rdev_for_each_list(rdev, tmp, candidates) { list_del_init(&rdev->same_set); if (bind_rdev_to_array(rdev, mddev)) export_rdev(rdev); @@ -3643,7 +3821,7 @@ static void autorun_devices(int part) /* on success, candidates will be empty, on error * it won't... */ - ITERATE_RDEV_GENERIC(candidates,rdev,tmp) + rdev_for_each_list(rdev, tmp, candidates) export_rdev(rdev); mddev_put(mddev); } @@ -3673,7 +3851,7 @@ static int get_array_info(mddev_t * mddev, void __user * arg) struct list_head *tmp; nr=working=active=failed=spare=0; - ITERATE_RDEV(mddev,rdev,tmp) { + rdev_for_each(rdev, tmp, mddev) { nr++; if (test_bit(Faulty, &rdev->flags)) failed++; @@ -3919,8 +4097,6 @@ static int add_new_disk(mddev_t * mddev, mdu_disk_info_t *info) else rdev->raid_disk = -1; - rdev->flags = 0; - if (rdev->raid_disk < mddev->raid_disks) if (info->state & (1<<MD_DISK_SYNC)) set_bit(In_sync, &rdev->flags); @@ -4165,13 +4341,15 @@ static int set_array_info(mddev_t * mddev, mdu_array_info_t *info) else mddev->recovery_cp = 0; mddev->persistent = ! info->not_persistent; + mddev->external = 0; mddev->layout = info->layout; mddev->chunk_size = info->chunk_size; mddev->max_disks = MD_SB_DISKS; - mddev->flags = 0; + if (mddev->persistent) + mddev->flags = 0; set_bit(MD_CHANGE_DEVS, &mddev->flags); mddev->default_bitmap_offset = MD_SB_BYTES >> 9; @@ -4213,7 +4391,7 @@ static int update_size(mddev_t *mddev, unsigned long size) */ if (mddev->sync_thread) return -EBUSY; - ITERATE_RDEV(mddev,rdev,tmp) { + rdev_for_each(rdev, tmp, mddev) { sector_t avail; avail = rdev->size * 2; @@ -4471,9 +4649,10 @@ static int md_ioctl(struct inode *inode, struct file *file, */ /* if we are not initialised yet, only ADD_NEW_DISK, STOP_ARRAY, * RUN_ARRAY, and GET_ and SET_BITMAP_FILE are allowed */ - if (!mddev->raid_disks && cmd != ADD_NEW_DISK && cmd != STOP_ARRAY - && cmd != RUN_ARRAY && cmd != SET_BITMAP_FILE - && cmd != GET_BITMAP_FILE) { + if ((!mddev->raid_disks && !mddev->external) + && cmd != ADD_NEW_DISK && cmd != STOP_ARRAY + && cmd != RUN_ARRAY && cmd != SET_BITMAP_FILE + && cmd != GET_BITMAP_FILE) { err = -ENODEV; goto abort_unlock; } @@ -4757,7 +4936,7 @@ static void status_unused(struct seq_file *seq) seq_printf(seq, "unused devices: "); - ITERATE_RDEV_PENDING(rdev,tmp) { + rdev_for_each_list(rdev, tmp, pending_raid_disks) { char b[BDEVNAME_SIZE]; i++; seq_printf(seq, "%s ", @@ -4953,7 +5132,7 @@ static int md_seq_show(struct seq_file *seq, void *v) } size = 0; - ITERATE_RDEV(mddev,rdev,tmp2) { + rdev_for_each(rdev, tmp2, mddev) { char b[BDEVNAME_SIZE]; seq_printf(seq, " %s[%d]", bdevname(rdev->bdev,b), rdev->desc_nr); @@ -4982,7 +5161,10 @@ static int md_seq_show(struct seq_file *seq, void *v) mddev->major_version, mddev->minor_version); } - } else + } else if (mddev->external) + seq_printf(seq, " super external:%s", + mddev->metadata_type); + else seq_printf(seq, " super non-persistent"); if (mddev->pers) { @@ -5106,7 +5288,7 @@ static int is_mddev_idle(mddev_t *mddev) long curr_events; idle = 1; - ITERATE_RDEV(mddev,rdev,tmp) { + rdev_for_each(rdev, tmp, mddev) { struct gendisk *disk = rdev->bdev->bd_contains->bd_disk; curr_events = disk_stat_read(disk, sectors[0]) + disk_stat_read(disk, sectors[1]) - @@ -5283,7 +5465,7 @@ void md_do_sync(mddev_t *mddev) set_bit(MD_RECOVERY_INTR, &mddev->recovery); goto skip; } - ITERATE_MDDEV(mddev2,tmp) { + for_each_mddev(mddev2, tmp) { if (mddev2 == mddev) continue; if (mddev2->curr_resync && @@ -5333,7 +5515,7 @@ void md_do_sync(mddev_t *mddev) /* recovery follows the physical size of devices */ max_sectors = mddev->size << 1; j = MaxSector; - ITERATE_RDEV(mddev,rdev,rtmp) + rdev_for_each(rdev, rtmp, mddev) if (rdev->raid_disk >= 0 && !test_bit(Faulty, &rdev->flags) && !test_bit(In_sync, &rdev->flags) && @@ -5381,8 +5563,16 @@ void md_do_sync(mddev_t *mddev) sector_t sectors; skipped = 0; + if (j >= mddev->resync_max) { + sysfs_notify(&mddev->kobj, NULL, "sync_completed"); + wait_event(mddev->recovery_wait, + mddev->resync_max > j + || kthread_should_stop()); + } + if (kthread_should_stop()) + goto interrupted; sectors = mddev->pers->sync_request(mddev, j, &skipped, - currspeed < speed_min(mddev)); + currspeed < speed_min(mddev)); if (sectors == 0) { set_bit(MD_RECOVERY_ERR, &mddev->recovery); goto out; @@ -5424,15 +5614,9 @@ void md_do_sync(mddev_t *mddev) } - if (kthread_should_stop()) { - /* - * got a signal, exit. - */ - printk(KERN_INFO - "md: md_do_sync() got signal ... exiting\n"); - set_bit(MD_RECOVERY_INTR, &mddev->recovery); - goto out; - } + if (kthread_should_stop()) + goto interrupted; + /* * this loop exits only if either when we are slower than @@ -5484,7 +5668,7 @@ void md_do_sync(mddev_t *mddev) } else { if (!test_bit(MD_RECOVERY_INTR, &mddev->recovery)) mddev->curr_resync = MaxSector; - ITERATE_RDEV(mddev,rdev,rtmp) + rdev_for_each(rdev, rtmp, mddev) if (rdev->raid_disk >= 0 && !test_bit(Faulty, &rdev->flags) && !test_bit(In_sync, &rdev->flags) && @@ -5496,9 +5680,22 @@ void md_do_sync(mddev_t *mddev) skip: mddev->curr_resync = 0; + mddev->resync_max = MaxSector; + sysfs_notify(&mddev->kobj, NULL, "sync_completed"); wake_up(&resync_wait); set_bit(MD_RECOVERY_DONE, &mddev->recovery); md_wakeup_thread(mddev->thread); + return; + + interrupted: + /* + * got a signal, exit. + */ + printk(KERN_INFO + "md: md_do_sync() got signal ... exiting\n"); + set_bit(MD_RECOVERY_INTR, &mddev->recovery); + goto out; + } EXPORT_SYMBOL_GPL(md_do_sync); @@ -5509,8 +5706,9 @@ static int remove_and_add_spares(mddev_t *mddev) struct list_head *rtmp; int spares = 0; - ITERATE_RDEV(mddev,rdev,rtmp) + rdev_for_each(rdev, rtmp, mddev) if (rdev->raid_disk >= 0 && + !mddev->external && (test_bit(Faulty, &rdev->flags) || ! test_bit(In_sync, &rdev->flags)) && atomic_read(&rdev->nr_pending)==0) { @@ -5524,7 +5722,7 @@ static int remove_and_add_spares(mddev_t *mddev) } if (mddev->degraded) { - ITERATE_RDEV(mddev,rdev,rtmp) + rdev_for_each(rdev, rtmp, mddev) if (rdev->raid_disk < 0 && !test_bit(Faulty, &rdev->flags)) { rdev->recovery_offset = 0; @@ -5589,7 +5787,7 @@ void md_check_recovery(mddev_t *mddev) } if ( ! ( - mddev->flags || + (mddev->flags && !mddev->external) || test_bit(MD_RECOVERY_NEEDED, &mddev->recovery) || test_bit(MD_RECOVERY_DONE, &mddev->recovery) || (mddev->safemode == 1) || @@ -5605,7 +5803,8 @@ void md_check_recovery(mddev_t *mddev) if (mddev->safemode && !atomic_read(&mddev->writes_pending) && !mddev->in_sync && mddev->recovery_cp == MaxSector) { mddev->in_sync = 1; - set_bit(MD_CHANGE_CLEAN, &mddev->flags); + if (mddev->persistent) + set_bit(MD_CHANGE_CLEAN, &mddev->flags); } if (mddev->safemode == 1) mddev->safemode = 0; @@ -5637,7 +5836,7 @@ void md_check_recovery(mddev_t *mddev) * information must be scrapped */ if (!mddev->degraded) - ITERATE_RDEV(mddev,rdev,rtmp) + rdev_for_each(rdev, rtmp, mddev) rdev->saved_raid_disk = -1; mddev->recovery = 0; @@ -5714,7 +5913,7 @@ static int md_notify_reboot(struct notifier_block *this, printk(KERN_INFO "md: stopping all md devices.\n"); - ITERATE_MDDEV(mddev,tmp) + for_each_mddev(mddev, tmp) if (mddev_trylock(mddev)) { do_md_stop (mddev, 1); mddev_unlock(mddev); @@ -5848,7 +6047,7 @@ static __exit void md_exit(void) unregister_reboot_notifier(&md_notifier); unregister_sysctl_table(raid_table_header); remove_proc_entry("mdstat", NULL); - ITERATE_MDDEV(mddev,tmp) { + for_each_mddev(mddev, tmp) { struct gendisk *disk = mddev->gendisk; if (!disk) continue; diff --git a/drivers/md/mktables.c b/drivers/md/mktables.c index adef299908cf..b61d5767aae7 100644 --- a/drivers/md/mktables.c +++ b/drivers/md/mktables.c @@ -1,13 +1,10 @@ -#ident "$Id: mktables.c,v 1.2 2002/12/12 22:41:27 hpa Exp $" -/* ----------------------------------------------------------------------- * +/* -*- linux-c -*- ------------------------------------------------------- * * - * Copyright 2002 H. Peter Anvin - All Rights Reserved + * Copyright 2002-2007 H. Peter Anvin - All Rights Reserved * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, Inc., 53 Temple Place Ste 330, - * Bostom MA 02111-1307, USA; either version 2 of the License, or - * (at your option) any later version; incorporated herein by reference. + * This file is part of the Linux kernel, and is made available under + * the terms of the GNU General Public License version 2 or (at your + * option) any later version; incorporated herein by reference. * * ----------------------------------------------------------------------- */ @@ -26,100 +23,98 @@ static uint8_t gfmul(uint8_t a, uint8_t b) { - uint8_t v = 0; - - while ( b ) { - if ( b & 1 ) v ^= a; - a = (a << 1) ^ (a & 0x80 ? 0x1d : 0); - b >>= 1; - } - return v; + uint8_t v = 0; + + while (b) { + if (b & 1) + v ^= a; + a = (a << 1) ^ (a & 0x80 ? 0x1d : 0); + b >>= 1; + } + + return v; } static uint8_t gfpow(uint8_t a, int b) { - uint8_t v = 1; - - b %= 255; - if ( b < 0 ) - b += 255; - - while ( b ) { - if ( b & 1 ) v = gfmul(v,a); - a = gfmul(a,a); - b >>= 1; - } - return v; + uint8_t v = 1; + + b %= 255; + if (b < 0) + b += 255; + + while (b) { + if (b & 1) + v = gfmul(v, a); + a = gfmul(a, a); + b >>= 1; + } + + return v; } int main(int argc, char *argv[]) { - int i, j, k; - uint8_t v; - uint8_t exptbl[256], invtbl[256]; - - printf("#include \"raid6.h\"\n"); - - /* Compute multiplication table */ - printf("\nconst u8 __attribute__((aligned(256)))\n" - "raid6_gfmul[256][256] =\n" - "{\n"); - for ( i = 0 ; i < 256 ; i++ ) { - printf("\t{\n"); - for ( j = 0 ; j < 256 ; j += 8 ) { - printf("\t\t"); - for ( k = 0 ; k < 8 ; k++ ) { - printf("0x%02x, ", gfmul(i,j+k)); - } - printf("\n"); - } - printf("\t},\n"); - } - printf("};\n"); - - /* Compute power-of-2 table (exponent) */ - v = 1; - printf("\nconst u8 __attribute__((aligned(256)))\n" - "raid6_gfexp[256] =\n" - "{\n"); - for ( i = 0 ; i < 256 ; i += 8 ) { - printf("\t"); - for ( j = 0 ; j < 8 ; j++ ) { - exptbl[i+j] = v; - printf("0x%02x, ", v); - v = gfmul(v,2); - if ( v == 1 ) v = 0; /* For entry 255, not a real entry */ - } - printf("\n"); - } - printf("};\n"); - - /* Compute inverse table x^-1 == x^254 */ - printf("\nconst u8 __attribute__((aligned(256)))\n" - "raid6_gfinv[256] =\n" - "{\n"); - for ( i = 0 ; i < 256 ; i += 8 ) { - printf("\t"); - for ( j = 0 ; j < 8 ; j++ ) { - invtbl[i+j] = v = gfpow(i+j,254); - printf("0x%02x, ", v); - } - printf("\n"); - } - printf("};\n"); - - /* Compute inv(2^x + 1) (exponent-xor-inverse) table */ - printf("\nconst u8 __attribute__((aligned(256)))\n" - "raid6_gfexi[256] =\n" - "{\n"); - for ( i = 0 ; i < 256 ; i += 8 ) { - printf("\t"); - for ( j = 0 ; j < 8 ; j++ ) { - printf("0x%02x, ", invtbl[exptbl[i+j]^1]); - } - printf("\n"); - } - printf("};\n\n"); - - return 0; + int i, j, k; + uint8_t v; + uint8_t exptbl[256], invtbl[256]; + + printf("#include \"raid6.h\"\n"); + + /* Compute multiplication table */ + printf("\nconst u8 __attribute__((aligned(256)))\n" + "raid6_gfmul[256][256] =\n" + "{\n"); + for (i = 0; i < 256; i++) { + printf("\t{\n"); + for (j = 0; j < 256; j += 8) { + printf("\t\t"); + for (k = 0; k < 8; k++) + printf("0x%02x,%c", gfmul(i, j + k), + (k == 7) ? '\n' : ' '); + } + printf("\t},\n"); + } + printf("};\n"); + + /* Compute power-of-2 table (exponent) */ + v = 1; + printf("\nconst u8 __attribute__((aligned(256)))\n" + "raid6_gfexp[256] =\n" "{\n"); + for (i = 0; i < 256; i += 8) { + printf("\t"); + for (j = 0; j < 8; j++) { + exptbl[i + j] = v; + printf("0x%02x,%c", v, (j == 7) ? '\n' : ' '); + v = gfmul(v, 2); + if (v == 1) + v = 0; /* For entry 255, not a real entry */ + } + } + printf("};\n"); + + /* Compute inverse table x^-1 == x^254 */ + printf("\nconst u8 __attribute__((aligned(256)))\n" + "raid6_gfinv[256] =\n" "{\n"); + for (i = 0; i < 256; i += 8) { + printf("\t"); + for (j = 0; j < 8; j++) { + invtbl[i + j] = v = gfpow(i + j, 254); + printf("0x%02x,%c", v, (j == 7) ? '\n' : ' '); + } + } + printf("};\n"); + + /* Compute inv(2^x + 1) (exponent-xor-inverse) table */ + printf("\nconst u8 __attribute__((aligned(256)))\n" + "raid6_gfexi[256] =\n" "{\n"); + for (i = 0; i < 256; i += 8) { + printf("\t"); + for (j = 0; j < 8; j++) + printf("0x%02x,%c", invtbl[exptbl[i + j] ^ 1], + (j == 7) ? '\n' : ' '); + } + printf("};\n"); + + return 0; } diff --git a/drivers/md/multipath.c b/drivers/md/multipath.c index eb631ebed686..3f299d835a2b 100644 --- a/drivers/md/multipath.c +++ b/drivers/md/multipath.c @@ -436,7 +436,7 @@ static int multipath_run (mddev_t *mddev) } conf->working_disks = 0; - ITERATE_RDEV(mddev,rdev,tmp) { + rdev_for_each(rdev, tmp, mddev) { disk_idx = rdev->raid_disk; if (disk_idx < 0 || disk_idx >= mddev->raid_disks) diff --git a/drivers/md/raid0.c b/drivers/md/raid0.c index f8e591708d1f..818b48284096 100644 --- a/drivers/md/raid0.c +++ b/drivers/md/raid0.c @@ -72,11 +72,11 @@ static int create_strip_zones (mddev_t *mddev) */ conf->nr_strip_zones = 0; - ITERATE_RDEV(mddev,rdev1,tmp1) { + rdev_for_each(rdev1, tmp1, mddev) { printk("raid0: looking at %s\n", bdevname(rdev1->bdev,b)); c = 0; - ITERATE_RDEV(mddev,rdev2,tmp2) { + rdev_for_each(rdev2, tmp2, mddev) { printk("raid0: comparing %s(%llu)", bdevname(rdev1->bdev,b), (unsigned long long)rdev1->size); @@ -124,7 +124,7 @@ static int create_strip_zones (mddev_t *mddev) cnt = 0; smallest = NULL; zone->dev = conf->devlist; - ITERATE_RDEV(mddev, rdev1, tmp1) { + rdev_for_each(rdev1, tmp1, mddev) { int j = rdev1->raid_disk; if (j < 0 || j >= mddev->raid_disks) { @@ -293,7 +293,7 @@ static int raid0_run (mddev_t *mddev) /* calculate array device size */ mddev->array_size = 0; - ITERATE_RDEV(mddev,rdev,tmp) + rdev_for_each(rdev, tmp, mddev) mddev->array_size += rdev->size; printk("raid0 : md_size is %llu blocks.\n", diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c index 4a69c416e045..5c7fef091cec 100644 --- a/drivers/md/raid1.c +++ b/drivers/md/raid1.c @@ -1684,6 +1684,7 @@ static sector_t sync_request(mddev_t *mddev, sector_t sector_nr, int *skipped, i if (!go_faster && conf->nr_waiting) msleep_interruptible(1000); + bitmap_cond_end_sync(mddev->bitmap, sector_nr); raise_barrier(conf); conf->next_resync = sector_nr; @@ -1766,6 +1767,8 @@ static sector_t sync_request(mddev_t *mddev, sector_t sector_nr, int *skipped, i return rv; } + if (max_sector > mddev->resync_max) + max_sector = mddev->resync_max; /* Don't do IO beyond here */ nr_sectors = 0; sync_blocks = 0; do { @@ -1884,7 +1887,7 @@ static int run(mddev_t *mddev) if (!conf->r1bio_pool) goto out_no_mem; - ITERATE_RDEV(mddev, rdev, tmp) { + rdev_for_each(rdev, tmp, mddev) { disk_idx = rdev->raid_disk; if (disk_idx >= mddev->raid_disks || disk_idx < 0) diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c index 5cdcc9386200..017f58113c33 100644 --- a/drivers/md/raid10.c +++ b/drivers/md/raid10.c @@ -1657,6 +1657,9 @@ static sector_t sync_request(mddev_t *mddev, sector_t sector_nr, int *skipped, i return (max_sector - sector_nr) + sectors_skipped; } + if (max_sector > mddev->resync_max) + max_sector = mddev->resync_max; /* Don't do IO beyond here */ + /* make sure whole request will fit in a chunk - if chunks * are meaningful */ @@ -1670,6 +1673,8 @@ static sector_t sync_request(mddev_t *mddev, sector_t sector_nr, int *skipped, i if (!go_faster && conf->nr_waiting) msleep_interruptible(1000); + bitmap_cond_end_sync(mddev->bitmap, sector_nr); + /* Again, very different code for resync and recovery. * Both must result in an r10bio with a list of bios that * have bi_end_io, bi_sector, bi_bdev set, @@ -2021,7 +2026,7 @@ static int run(mddev_t *mddev) goto out_free_conf; } - ITERATE_RDEV(mddev, rdev, tmp) { + rdev_for_each(rdev, tmp, mddev) { disk_idx = rdev->raid_disk; if (disk_idx >= mddev->raid_disks || disk_idx < 0) diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c index e8c8157b02fc..2d6f1a51359c 100644 --- a/drivers/md/raid5.c +++ b/drivers/md/raid5.c @@ -3159,7 +3159,8 @@ static void raid5_activate_delayed(raid5_conf_t *conf) atomic_inc(&conf->preread_active_stripes); list_add_tail(&sh->lru, &conf->handle_list); } - } + } else + blk_plug_device(conf->mddev->queue); } static void activate_bit_delay(raid5_conf_t *conf) @@ -3549,7 +3550,8 @@ static int make_request(struct request_queue *q, struct bio * bi) goto retry; } finish_wait(&conf->wait_for_overlap, &w); - handle_stripe(sh, NULL); + set_bit(STRIPE_HANDLE, &sh->state); + clear_bit(STRIPE_DELAYED, &sh->state); release_stripe(sh); } else { /* cannot get stripe for read-ahead, just give-up */ @@ -3698,6 +3700,25 @@ static sector_t reshape_request(mddev_t *mddev, sector_t sector_nr, int *skipped release_stripe(sh); first_sector += STRIPE_SECTORS; } + /* If this takes us to the resync_max point where we have to pause, + * then we need to write out the superblock. + */ + sector_nr += conf->chunk_size>>9; + if (sector_nr >= mddev->resync_max) { + /* Cannot proceed until we've updated the superblock... */ + wait_event(conf->wait_for_overlap, + atomic_read(&conf->reshape_stripes) == 0); + mddev->reshape_position = conf->expand_progress; + set_bit(MD_CHANGE_DEVS, &mddev->flags); + md_wakeup_thread(mddev->thread); + wait_event(mddev->sb_wait, + !test_bit(MD_CHANGE_DEVS, &mddev->flags) + || kthread_should_stop()); + spin_lock_irq(&conf->device_lock); + conf->expand_lo = mddev->reshape_position; + spin_unlock_irq(&conf->device_lock); + wake_up(&conf->wait_for_overlap); + } return conf->chunk_size>>9; } @@ -3734,6 +3755,12 @@ static inline sector_t sync_request(mddev_t *mddev, sector_t sector_nr, int *ski if (test_bit(MD_RECOVERY_RESHAPE, &mddev->recovery)) return reshape_request(mddev, sector_nr, skipped); + /* No need to check resync_max as we never do more than one + * stripe, and as resync_max will always be on a chunk boundary, + * if the check in md_do_sync didn't fire, there is no chance + * of overstepping resync_max here + */ + /* if there is too many failed drives and we are trying * to resync, then assert that we are finished, because there is * nothing we can do. @@ -3753,6 +3780,9 @@ static inline sector_t sync_request(mddev_t *mddev, sector_t sector_nr, int *ski return sync_blocks * STRIPE_SECTORS; /* keep things rounded to whole stripes */ } + + bitmap_cond_end_sync(mddev->bitmap, sector_nr); + pd_idx = stripe_to_pdidx(sector_nr, conf, raid_disks); sh = get_active_stripe(conf, sector_nr, raid_disks, pd_idx, 1); if (sh == NULL) { @@ -3864,7 +3894,7 @@ static int retry_aligned_read(raid5_conf_t *conf, struct bio *raid_bio) * During the scan, completed stripes are saved for us by the interrupt * handler, so that they will not have to wait for our next wakeup. */ -static void raid5d (mddev_t *mddev) +static void raid5d(mddev_t *mddev) { struct stripe_head *sh; raid5_conf_t *conf = mddev_to_conf(mddev); @@ -3889,12 +3919,6 @@ static void raid5d (mddev_t *mddev) activate_bit_delay(conf); } - if (list_empty(&conf->handle_list) && - atomic_read(&conf->preread_active_stripes) < IO_THRESHOLD && - !blk_queue_plugged(mddev->queue) && - !list_empty(&conf->delayed_list)) - raid5_activate_delayed(conf); - while ((bio = remove_bio_from_retry(conf))) { int ok; spin_unlock_irq(&conf->device_lock); @@ -4108,7 +4132,7 @@ static int run(mddev_t *mddev) pr_debug("raid5: run(%s) called.\n", mdname(mddev)); - ITERATE_RDEV(mddev,rdev,tmp) { + rdev_for_each(rdev, tmp, mddev) { raid_disk = rdev->raid_disk; if (raid_disk >= conf->raid_disks || raid_disk < 0) @@ -4521,7 +4545,7 @@ static int raid5_start_reshape(mddev_t *mddev) if (test_bit(MD_RECOVERY_RUNNING, &mddev->recovery)) return -EBUSY; - ITERATE_RDEV(mddev, rdev, rtmp) + rdev_for_each(rdev, rtmp, mddev) if (rdev->raid_disk < 0 && !test_bit(Faulty, &rdev->flags)) spares++; @@ -4543,7 +4567,7 @@ static int raid5_start_reshape(mddev_t *mddev) /* Add some new drives, as many as will fit. * We know there are enough to make the newly sized array work. */ - ITERATE_RDEV(mddev, rdev, rtmp) + rdev_for_each(rdev, rtmp, mddev) if (rdev->raid_disk < 0 && !test_bit(Faulty, &rdev->flags)) { if (raid5_add_disk(mddev, rdev)) { diff --git a/drivers/md/raid6test/test.c b/drivers/md/raid6test/test.c index 0d5cd57accd7..559cc41b2585 100644 --- a/drivers/md/raid6test/test.c +++ b/drivers/md/raid6test/test.c @@ -1,12 +1,10 @@ /* -*- linux-c -*- ------------------------------------------------------- * * - * Copyright 2002 H. Peter Anvin - All Rights Reserved + * Copyright 2002-2007 H. Peter Anvin - All Rights Reserved * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, Inc., 53 Temple Place Ste 330, - * Bostom MA 02111-1307, USA; either version 2 of the License, or - * (at your option) any later version; incorporated herein by reference. + * This file is part of the Linux kernel, and is made available under + * the terms of the GNU General Public License version 2 or (at your + * option) any later version; incorporated herein by reference. * * ----------------------------------------------------------------------- */ @@ -30,67 +28,87 @@ char *dataptrs[NDISKS]; char data[NDISKS][PAGE_SIZE]; char recovi[PAGE_SIZE], recovj[PAGE_SIZE]; -void makedata(void) +static void makedata(void) { int i, j; - for ( i = 0 ; i < NDISKS ; i++ ) { - for ( j = 0 ; j < PAGE_SIZE ; j++ ) { + for (i = 0; i < NDISKS; i++) { + for (j = 0; j < PAGE_SIZE; j++) data[i][j] = rand(); - } + dataptrs[i] = data[i]; } } +static char disk_type(int d) +{ + switch (d) { + case NDISKS-2: + return 'P'; + case NDISKS-1: + return 'Q'; + default: + return 'D'; + } +} + +static int test_disks(int i, int j) +{ + int erra, errb; + + memset(recovi, 0xf0, PAGE_SIZE); + memset(recovj, 0xba, PAGE_SIZE); + + dataptrs[i] = recovi; + dataptrs[j] = recovj; + + raid6_dual_recov(NDISKS, PAGE_SIZE, i, j, (void **)&dataptrs); + + erra = memcmp(data[i], recovi, PAGE_SIZE); + errb = memcmp(data[j], recovj, PAGE_SIZE); + + if (i < NDISKS-2 && j == NDISKS-1) { + /* We don't implement the DQ failure scenario, since it's + equivalent to a RAID-5 failure (XOR, then recompute Q) */ + erra = errb = 0; + } else { + printf("algo=%-8s faila=%3d(%c) failb=%3d(%c) %s\n", + raid6_call.name, + i, disk_type(i), + j, disk_type(j), + (!erra && !errb) ? "OK" : + !erra ? "ERRB" : + !errb ? "ERRA" : "ERRAB"); + } + + dataptrs[i] = data[i]; + dataptrs[j] = data[j]; + + return erra || errb; +} + int main(int argc, char *argv[]) { - const struct raid6_calls * const * algo; + const struct raid6_calls *const *algo; int i, j; - int erra, errb; + int err = 0; makedata(); - for ( algo = raid6_algos ; *algo ; algo++ ) { - if ( !(*algo)->valid || (*algo)->valid() ) { + for (algo = raid6_algos; *algo; algo++) { + if (!(*algo)->valid || (*algo)->valid()) { raid6_call = **algo; /* Nuke syndromes */ memset(data[NDISKS-2], 0xee, 2*PAGE_SIZE); /* Generate assumed good syndrome */ - raid6_call.gen_syndrome(NDISKS, PAGE_SIZE, (void **)&dataptrs); - - for ( i = 0 ; i < NDISKS-1 ; i++ ) { - for ( j = i+1 ; j < NDISKS ; j++ ) { - memset(recovi, 0xf0, PAGE_SIZE); - memset(recovj, 0xba, PAGE_SIZE); - - dataptrs[i] = recovi; - dataptrs[j] = recovj; - - raid6_dual_recov(NDISKS, PAGE_SIZE, i, j, (void **)&dataptrs); - - erra = memcmp(data[i], recovi, PAGE_SIZE); - errb = memcmp(data[j], recovj, PAGE_SIZE); - - if ( i < NDISKS-2 && j == NDISKS-1 ) { - /* We don't implement the DQ failure scenario, since it's - equivalent to a RAID-5 failure (XOR, then recompute Q) */ - } else { - printf("algo=%-8s faila=%3d(%c) failb=%3d(%c) %s\n", - raid6_call.name, - i, (i==NDISKS-2)?'P':'D', - j, (j==NDISKS-1)?'Q':(j==NDISKS-2)?'P':'D', - (!erra && !errb) ? "OK" : - !erra ? "ERRB" : - !errb ? "ERRA" : - "ERRAB"); - } - - dataptrs[i] = data[i]; - dataptrs[j] = data[j]; - } - } + raid6_call.gen_syndrome(NDISKS, PAGE_SIZE, + (void **)&dataptrs); + + for (i = 0; i < NDISKS-1; i++) + for (j = i+1; j < NDISKS; j++) + err += test_disks(i, j); } printf("\n"); } @@ -99,5 +117,8 @@ int main(int argc, char *argv[]) /* Pick the best algorithm test */ raid6_select_algo(); - return 0; + if (err) + printf("\n*** ERRORS FOUND ***\n"); + + return err; } diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile index 28ddd146c1c5..850b8c6f4577 100644 --- a/drivers/media/video/Makefile +++ b/drivers/media/video/Makefile @@ -22,7 +22,6 @@ obj-$(CONFIG_VIDEO_IR_I2C) += ir-kbd-i2c.o obj-$(CONFIG_VIDEO_TVAUDIO) += tvaudio.o obj-$(CONFIG_VIDEO_TDA7432) += tda7432.o obj-$(CONFIG_VIDEO_TDA9875) += tda9875.o -obj-$(CONFIG_SOUND_TVMIXER) += tvmixer.o obj-$(CONFIG_VIDEO_SAA6588) += saa6588.o obj-$(CONFIG_VIDEO_SAA5246A) += saa5246a.o diff --git a/drivers/media/video/tvmixer.c b/drivers/media/video/tvmixer.c deleted file mode 100644 index 9fa5b702e073..000000000000 --- a/drivers/media/video/tvmixer.c +++ /dev/null @@ -1,336 +0,0 @@ -/* - */ - -#include <linux/module.h> -#include <linux/kernel.h> -#include <linux/string.h> -#include <linux/timer.h> -#include <linux/delay.h> -#include <linux/errno.h> -#include <linux/slab.h> -#include <linux/i2c.h> -#include <linux/videodev.h> -#include <linux/init.h> -#include <linux/kdev_t.h> -#include <linux/sound.h> -#include <linux/soundcard.h> - -#include <asm/semaphore.h> -#include <asm/uaccess.h> - - -#define DEV_MAX 4 - -static int devnr = -1; -module_param(devnr, int, 0644); - -MODULE_AUTHOR("Gerd Knorr"); -MODULE_LICENSE("GPL"); - -/* ----------------------------------------------------------------------- */ - -struct TVMIXER { - struct i2c_client *dev; - int minor; - int count; -}; - -static struct TVMIXER devices[DEV_MAX]; - -static int tvmixer_adapters(struct i2c_adapter *adap); -static int tvmixer_clients(struct i2c_client *client); - -/* ----------------------------------------------------------------------- */ - -static int mix_to_v4l(int i) -{ - int r; - - r = ((i & 0xff) * 65536 + 50) / 100; - if (r > 65535) r = 65535; - if (r < 0) r = 0; - return r; -} - -static int v4l_to_mix(int i) -{ - int r; - - r = (i * 100 + 32768) / 65536; - if (r > 100) r = 100; - if (r < 0) r = 0; - return r | (r << 8); -} - -static int v4l_to_mix2(int l, int r) -{ - r = (r * 100 + 32768) / 65536; - if (r > 100) r = 100; - if (r < 0) r = 0; - l = (l * 100 + 32768) / 65536; - if (l > 100) l = 100; - if (l < 0) l = 0; - return (r << 8) | l; -} - -static int tvmixer_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) -{ - struct video_audio va; - int left,right,ret,val = 0; - struct TVMIXER *mix = file->private_data; - struct i2c_client *client = mix->dev; - void __user *argp = (void __user *)arg; - int __user *p = argp; - - if (NULL == client) - return -ENODEV; - - if (cmd == SOUND_MIXER_INFO) { - mixer_info info; - strlcpy(info.id, "tv card", sizeof(info.id)); - strlcpy(info.name, client->name, sizeof(info.name)); - info.modify_counter = 42 /* FIXME */; - if (copy_to_user(argp, &info, sizeof(info))) - return -EFAULT; - return 0; - } - if (cmd == SOUND_OLD_MIXER_INFO) { - _old_mixer_info info; - strlcpy(info.id, "tv card", sizeof(info.id)); - strlcpy(info.name, client->name, sizeof(info.name)); - if (copy_to_user(argp, &info, sizeof(info))) - return -EFAULT; - return 0; - } - if (cmd == OSS_GETVERSION) - return put_user(SOUND_VERSION, p); - - if (_SIOC_DIR(cmd) & _SIOC_WRITE) - if (get_user(val, p)) - return -EFAULT; - - /* read state */ - memset(&va,0,sizeof(va)); - client->driver->command(client,VIDIOCGAUDIO,&va); - - switch (cmd) { - case MIXER_READ(SOUND_MIXER_RECMASK): - case MIXER_READ(SOUND_MIXER_CAPS): - case MIXER_READ(SOUND_MIXER_RECSRC): - case MIXER_WRITE(SOUND_MIXER_RECSRC): - ret = 0; - break; - - case MIXER_READ(SOUND_MIXER_STEREODEVS): - ret = SOUND_MASK_VOLUME; - break; - case MIXER_READ(SOUND_MIXER_DEVMASK): - ret = SOUND_MASK_VOLUME; - if (va.flags & VIDEO_AUDIO_BASS) - ret |= SOUND_MASK_BASS; - if (va.flags & VIDEO_AUDIO_TREBLE) - ret |= SOUND_MASK_TREBLE; - break; - - case MIXER_WRITE(SOUND_MIXER_VOLUME): - left = mix_to_v4l(val); - right = mix_to_v4l(val >> 8); - va.volume = max(left,right); - va.balance = (32768*min(left,right)) / (va.volume ? va.volume : 1); - va.balance = (left<right) ? (65535-va.balance) : va.balance; - if (va.volume) - va.flags &= ~VIDEO_AUDIO_MUTE; - client->driver->command(client,VIDIOCSAUDIO,&va); - client->driver->command(client,VIDIOCGAUDIO,&va); - /* fall throuth */ - case MIXER_READ(SOUND_MIXER_VOLUME): - left = (min(65536 - va.balance,32768) * - va.volume) / 32768; - right = (min(va.balance,(u16)32768) * - va.volume) / 32768; - ret = v4l_to_mix2(left,right); - break; - - case MIXER_WRITE(SOUND_MIXER_BASS): - va.bass = mix_to_v4l(val); - client->driver->command(client,VIDIOCSAUDIO,&va); - client->driver->command(client,VIDIOCGAUDIO,&va); - /* fall throuth */ - case MIXER_READ(SOUND_MIXER_BASS): - ret = v4l_to_mix(va.bass); - break; - - case MIXER_WRITE(SOUND_MIXER_TREBLE): - va.treble = mix_to_v4l(val); - client->driver->command(client,VIDIOCSAUDIO,&va); - client->driver->command(client,VIDIOCGAUDIO,&va); - /* fall throuth */ - case MIXER_READ(SOUND_MIXER_TREBLE): - ret = v4l_to_mix(va.treble); - break; - - default: - return -EINVAL; - } - if (put_user(ret, p)) - return -EFAULT; - return 0; -} - -static int tvmixer_open(struct inode *inode, struct file *file) -{ - int i, minor = iminor(inode); - struct TVMIXER *mix = NULL; - struct i2c_client *client = NULL; - - for (i = 0; i < DEV_MAX; i++) { - if (devices[i].minor == minor) { - mix = devices+i; - client = mix->dev; - break; - } - } - - if (NULL == client) - return -ENODEV; - - /* lock bttv in memory while the mixer is in use */ - file->private_data = mix; - if (client->adapter->owner) - try_module_get(client->adapter->owner); - return 0; -} - -static int tvmixer_release(struct inode *inode, struct file *file) -{ - struct TVMIXER *mix = file->private_data; - struct i2c_client *client; - - client = mix->dev; - if (NULL == client) { - return -ENODEV; - } - - module_put(client->adapter->owner); - return 0; -} - -static struct i2c_driver driver = { - .driver = { - .name = "tvmixer", - }, - .id = I2C_DRIVERID_TVMIXER, - .detach_adapter = tvmixer_adapters, - .attach_adapter = tvmixer_adapters, - .detach_client = tvmixer_clients, -}; - -static const struct file_operations tvmixer_fops = { - .owner = THIS_MODULE, - .llseek = no_llseek, - .ioctl = tvmixer_ioctl, - .open = tvmixer_open, - .release = tvmixer_release, -}; - -/* ----------------------------------------------------------------------- */ - -static int tvmixer_adapters(struct i2c_adapter *adap) -{ - struct i2c_client *client; - - list_for_each_entry(client, &adap->clients, list) - tvmixer_clients(client); - return 0; -} - -static int tvmixer_clients(struct i2c_client *client) -{ - struct video_audio va; - int i,minor; - - if (!(client->adapter->class & I2C_CLASS_TV_ANALOG)) - return -1; - - /* unregister ?? */ - for (i = 0; i < DEV_MAX; i++) { - if (devices[i].dev == client) { - /* unregister */ - unregister_sound_mixer(devices[i].minor); - devices[i].dev = NULL; - devices[i].minor = -1; - printk("tvmixer: %s unregistered (#1)\n", - client->name); - return 0; - } - } - - /* look for a free slot */ - for (i = 0; i < DEV_MAX; i++) - if (NULL == devices[i].dev) - break; - if (i == DEV_MAX) { - printk(KERN_WARNING "tvmixer: DEV_MAX too small\n"); - return -1; - } - - /* audio chip with mixer ??? */ - if (NULL == client->driver->command) - return -1; - memset(&va,0,sizeof(va)); - if (0 != client->driver->command(client,VIDIOCGAUDIO,&va)) - return -1; - if (0 == (va.flags & VIDEO_AUDIO_VOLUME)) - return -1; - - /* everything is fine, register */ - if ((minor = register_sound_mixer(&tvmixer_fops,devnr)) < 0) { - printk(KERN_ERR "tvmixer: cannot allocate mixer device\n"); - return -1; - } - - devices[i].minor = minor; - devices[i].count = 0; - devices[i].dev = client; - printk("tvmixer: %s (%s) registered with minor %d\n", - client->name,client->adapter->name,minor); - - return 0; -} - -/* ----------------------------------------------------------------------- */ - -static int __init tvmixer_init_module(void) -{ - int i; - - for (i = 0; i < DEV_MAX; i++) - devices[i].minor = -1; - - return i2c_add_driver(&driver); -} - -static void __exit tvmixer_cleanup_module(void) -{ - int i; - - i2c_del_driver(&driver); - for (i = 0; i < DEV_MAX; i++) { - if (devices[i].minor != -1) { - unregister_sound_mixer(devices[i].minor); - printk("tvmixer: %s unregistered (#2)\n", - devices[i].dev->name); - } - } -} - -module_init(tvmixer_init_module); -module_exit(tvmixer_cleanup_module); - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * --------------------------------------------------------------------------- - * Local variables: - * c-basic-offset: 8 - * End: - */ diff --git a/drivers/misc/asus-laptop.c b/drivers/misc/asus-laptop.c index 7dce318df1bd..0846c33296bc 100644 --- a/drivers/misc/asus-laptop.c +++ b/drivers/misc/asus-laptop.c @@ -33,7 +33,6 @@ * Sam Lin - GPS support */ -#include <linux/autoconf.h> #include <linux/kernel.h> #include <linux/module.h> #include <linux/init.h> diff --git a/drivers/misc/fujitsu-laptop.c b/drivers/misc/fujitsu-laptop.c index c8d62c268b11..1cfd7f3f1294 100644 --- a/drivers/misc/fujitsu-laptop.c +++ b/drivers/misc/fujitsu-laptop.c @@ -50,7 +50,6 @@ #include <linux/dmi.h> #include <linux/backlight.h> #include <linux/platform_device.h> -#include <linux/autoconf.h> #define FUJITSU_DRIVER_VERSION "0.3" diff --git a/drivers/misc/lkdtm.c b/drivers/misc/lkdtm.c index 552b7957a92a..c884730c5eaf 100644 --- a/drivers/misc/lkdtm.c +++ b/drivers/misc/lkdtm.c @@ -129,27 +129,28 @@ module_param(cpoint_count, int, 0644); MODULE_PARM_DESC(cpoint_count, " Crash Point Count, number of times the "\ "crash point is to be hit to trigger action"); -unsigned int jp_do_irq(unsigned int irq) +static unsigned int jp_do_irq(unsigned int irq) { lkdtm_handler(); jprobe_return(); return 0; } -irqreturn_t jp_handle_irq_event(unsigned int irq, struct irqaction *action) +static irqreturn_t jp_handle_irq_event(unsigned int irq, + struct irqaction *action) { lkdtm_handler(); jprobe_return(); return 0; } -void jp_tasklet_action(struct softirq_action *a) +static void jp_tasklet_action(struct softirq_action *a) { lkdtm_handler(); jprobe_return(); } -void jp_ll_rw_block(int rw, int nr, struct buffer_head *bhs[]) +static void jp_ll_rw_block(int rw, int nr, struct buffer_head *bhs[]) { lkdtm_handler(); jprobe_return(); @@ -157,23 +158,24 @@ void jp_ll_rw_block(int rw, int nr, struct buffer_head *bhs[]) struct scan_control; -unsigned long jp_shrink_inactive_list(unsigned long max_scan, - struct zone *zone, struct scan_control *sc) +static unsigned long jp_shrink_inactive_list(unsigned long max_scan, + struct zone *zone, + struct scan_control *sc) { lkdtm_handler(); jprobe_return(); return 0; } -int jp_hrtimer_start(struct hrtimer *timer, ktime_t tim, - const enum hrtimer_mode mode) +static int jp_hrtimer_start(struct hrtimer *timer, ktime_t tim, + const enum hrtimer_mode mode) { lkdtm_handler(); jprobe_return(); return 0; } -int jp_scsi_dispatch_cmd(struct scsi_cmnd *cmd) +static int jp_scsi_dispatch_cmd(struct scsi_cmnd *cmd) { lkdtm_handler(); jprobe_return(); @@ -270,7 +272,7 @@ void lkdtm_handler(void) } } -int lkdtm_module_init(void) +static int __init lkdtm_module_init(void) { int ret; @@ -331,7 +333,7 @@ int lkdtm_module_init(void) return 0; } -void lkdtm_module_exit(void) +static void __exit lkdtm_module_exit(void) { unregister_jprobe(&lkdtm); printk(KERN_INFO "lkdtm : Crash point unregistered\n"); diff --git a/drivers/misc/msi-laptop.c b/drivers/misc/msi-laptop.c index 83679c762925..de898c6938f3 100644 --- a/drivers/misc/msi-laptop.c +++ b/drivers/misc/msi-laptop.c @@ -58,7 +58,6 @@ #include <linux/dmi.h> #include <linux/backlight.h> #include <linux/platform_device.h> -#include <linux/autoconf.h> #define MSI_DRIVER_VERSION "0.5" diff --git a/drivers/misc/phantom.c b/drivers/misc/phantom.c index cd221fd0fb94..7fa61e907e1c 100644 --- a/drivers/misc/phantom.c +++ b/drivers/misc/phantom.c @@ -25,7 +25,7 @@ #include <asm/atomic.h> #include <asm/io.h> -#define PHANTOM_VERSION "n0.9.7" +#define PHANTOM_VERSION "n0.9.8" #define PHANTOM_MAX_MINORS 8 @@ -456,8 +456,9 @@ static int phantom_resume(struct pci_dev *pdev) #endif static struct pci_device_id phantom_pci_tbl[] __devinitdata = { - { PCI_DEVICE(PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050), - .class = PCI_CLASS_BRIDGE_OTHER << 8, .class_mask = 0xffff00 }, + { .vendor = PCI_VENDOR_ID_PLX, .device = PCI_DEVICE_ID_PLX_9050, + .subvendor = PCI_VENDOR_ID_PLX, .subdevice = PCI_DEVICE_ID_PLX_9050, + .class = PCI_CLASS_BRIDGE_OTHER << 8, .class_mask = 0xffff00 }, { 0, } }; MODULE_DEVICE_TABLE(pci, phantom_pci_tbl); diff --git a/drivers/mtd/devices/block2mtd.c b/drivers/mtd/devices/block2mtd.c index be4b9948c762..eeaaa9dce6ef 100644 --- a/drivers/mtd/devices/block2mtd.c +++ b/drivers/mtd/devices/block2mtd.c @@ -4,7 +4,7 @@ * block2mtd.c - create an mtd from a block device * * Copyright (C) 2001,2002 Simon Evans <spse@secret.org.uk> - * Copyright (C) 2004-2006 Jörn Engel <joern@wh.fh-wedel.de> + * Copyright (C) 2004-2006 Joern Engel <joern@wh.fh-wedel.de> * * Licence: GPL */ @@ -485,5 +485,5 @@ module_init(block2mtd_init); module_exit(block2mtd_exit); MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Simon Evans <spse@secret.org.uk> and others"); +MODULE_AUTHOR("Joern Engel <joern@lazybastard.org>"); MODULE_DESCRIPTION("Emulate an MTD using a block device"); diff --git a/drivers/mtd/devices/phram.c b/drivers/mtd/devices/phram.c index 56cc1ca7ffd5..180298b92a7a 100644 --- a/drivers/mtd/devices/phram.c +++ b/drivers/mtd/devices/phram.c @@ -2,7 +2,7 @@ * $Id: phram.c,v 1.16 2005/11/07 11:14:25 gleixner Exp $ * * Copyright (c) ???? Jochen Schäuble <psionic@psionic.de> - * Copyright (c) 2003-2004 Jörn Engel <joern@wh.fh-wedel.de> + * Copyright (c) 2003-2004 Joern Engel <joern@wh.fh-wedel.de> * * Usage: * @@ -299,5 +299,5 @@ module_init(init_phram); module_exit(cleanup_phram); MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Jörn Engel <joern@wh.fh-wedel.de>"); +MODULE_AUTHOR("Joern Engel <joern@wh.fh-wedel.de>"); MODULE_DESCRIPTION("MTD driver for physical RAM"); diff --git a/drivers/mtd/maps/mtx-1_flash.c b/drivers/mtd/maps/mtx-1_flash.c index d884f2be28f6..2a8fde9b92f0 100644 --- a/drivers/mtd/maps/mtx-1_flash.c +++ b/drivers/mtd/maps/mtx-1_flash.c @@ -4,7 +4,7 @@ * $Id: mtx-1_flash.c,v 1.2 2005/11/07 11:14:27 gleixner Exp $ * * (C) 2005 Bruno Randolf <bruno.randolf@4g-systems.biz> - * (C) 2005 Jörn Engel <joern@wohnheim.fh-wedel.de> + * (C) 2005 Joern Engel <joern@wohnheim.fh-wedel.de> * */ diff --git a/drivers/parport/parport_pc.c b/drivers/parport/parport_pc.c index e9743d3efaf6..238628d3a854 100644 --- a/drivers/parport/parport_pc.c +++ b/drivers/parport/parport_pc.c @@ -1540,6 +1540,38 @@ static void __devinit detect_and_report_smsc (void) smsc_check(0x3f0,0x44); smsc_check(0x370,0x44); } + +static void __devinit detect_and_report_it87(void) +{ + u16 dev; + u8 r; + if (verbose_probing) + printk(KERN_DEBUG "IT8705 Super-IO detection, now testing port 2E ...\n"); + if (!request_region(0x2e, 1, __FUNCTION__)) + return; + outb(0x87, 0x2e); + outb(0x01, 0x2e); + outb(0x55, 0x2e); + outb(0x55, 0x2e); + outb(0x20, 0x2e); + dev = inb(0x2f) << 8; + outb(0x21, 0x2e); + dev |= inb(0x2f); + if (dev == 0x8712 || dev == 0x8705 || dev == 0x8715 || + dev == 0x8716 || dev == 0x8718 || dev == 0x8726) { + printk(KERN_INFO "IT%04X SuperIO detected.\n", dev); + outb(0x07, 0x2E); /* Parallel Port */ + outb(0x03, 0x2F); + outb(0xF0, 0x2E); /* BOOT 0x80 off */ + r = inb(0x2f); + outb(0xF0, 0x2E); + outb(r | 8, 0x2F); + outb(0x02, 0x2E); /* Lock */ + outb(0x02, 0x2F); + + release_region(0x2e, 1); + } +} #endif /* CONFIG_PARPORT_PC_SUPERIO */ static int get_superio_dma (struct parport *p) @@ -2767,6 +2799,7 @@ enum parport_pc_pci_cards { netmos_9755, netmos_9805, netmos_9815, + quatech_sppxp100, }; @@ -2843,6 +2876,7 @@ static struct parport_pc_pci { /* netmos_9755 */ { 2, { { 0, 1 }, { 2, 3 },} }, /* untested */ /* netmos_9805 */ { 1, { { 0, -1 }, } }, /* untested */ /* netmos_9815 */ { 2, { { 0, -1 }, { 2, -1 }, } }, /* untested */ + /* quatech_sppxp100 */ { 1, { { 0, 1 }, } }, }; static const struct pci_device_id parport_pc_pci_tbl[] = { @@ -2926,6 +2960,9 @@ static const struct pci_device_id parport_pc_pci_tbl[] = { PCI_ANY_ID, PCI_ANY_ID, 0, 0, netmos_9805 }, { PCI_VENDOR_ID_NETMOS, PCI_DEVICE_ID_NETMOS_9815, PCI_ANY_ID, PCI_ANY_ID, 0, 0, netmos_9815 }, + /* Quatech SPPXP-100 Parallel port PCI ExpressCard */ + { PCI_VENDOR_ID_QUATECH, PCI_DEVICE_ID_QUATECH_SPPXP_100, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, quatech_sppxp100 }, { 0, } /* terminate list */ }; MODULE_DEVICE_TABLE(pci,parport_pc_pci_tbl); @@ -3159,24 +3196,25 @@ static void __init parport_pc_find_ports (int autoirq, int autodma) int count = 0, err; #ifdef CONFIG_PARPORT_PC_SUPERIO - detect_and_report_winbond (); - detect_and_report_smsc (); + detect_and_report_it87(); + detect_and_report_winbond(); + detect_and_report_smsc(); #endif /* Onboard SuperIO chipsets that show themselves on the PCI bus. */ - count += parport_pc_init_superio (autoirq, autodma); + count += parport_pc_init_superio(autoirq, autodma); /* PnP ports, skip detection if SuperIO already found them */ if (!count) { - err = pnp_register_driver (&parport_pc_pnp_driver); + err = pnp_register_driver(&parport_pc_pnp_driver); if (!err) pnp_registered_parport = 1; } /* ISA ports and whatever (see asm/parport.h). */ - parport_pc_find_nonpci_ports (autoirq, autodma); + parport_pc_find_nonpci_ports(autoirq, autodma); - err = pci_register_driver (&parport_pc_pci_driver); + err = pci_register_driver(&parport_pc_pci_driver); if (!err) pci_registered_parport = 1; } diff --git a/drivers/parport/parport_serial.c b/drivers/parport/parport_serial.c index bd6ad8b38168..e2e95b36a603 100644 --- a/drivers/parport/parport_serial.c +++ b/drivers/parport/parport_serial.c @@ -77,7 +77,7 @@ static struct parport_pc_pci cards[] __devinitdata = { /* titan_110l */ { 1, { { 3, -1 }, } }, /* titan_210l */ { 1, { { 3, -1 }, } }, /* netmos_9xx5_combo */ { 1, { { 2, -1 }, }, netmos_parallel_init }, - /* netmos_9855 */ { 1, { { 0, -1 }, }, netmos_parallel_init }, + /* netmos_9855 */ { 1, { { 2, -1 }, }, netmos_parallel_init }, /* avlab_1s1p */ { 1, { { 1, 2}, } }, /* avlab_1s2p */ { 2, { { 1, 2}, { 3, 4 },} }, /* avlab_2s1p */ { 1, { { 2, 3}, } }, @@ -185,7 +185,7 @@ static struct pciserial_board pci_parport_serial_boards[] __devinitdata = { .uart_offset = 8, }, [netmos_9855] = { - .flags = FL_BASE2 | FL_BASE_BARS, + .flags = FL_BASE4 | FL_BASE_BARS, .num_ports = 1, .base_baud = 115200, .uart_offset = 8, diff --git a/drivers/pci/dmar.c b/drivers/pci/dmar.c index 91b2dc956be5..8ed26480371f 100644 --- a/drivers/pci/dmar.c +++ b/drivers/pci/dmar.c @@ -26,6 +26,7 @@ #include <linux/pci.h> #include <linux/dmar.h> #include "iova.h" +#include "intel-iommu.h" #undef PREFIX #define PREFIX "DMAR:" diff --git a/drivers/pci/intel-iommu.c b/drivers/pci/intel-iommu.c index 4e01df99681a..31fa6c92aa5e 100644 --- a/drivers/pci/intel-iommu.c +++ b/drivers/pci/intel-iommu.c @@ -1088,7 +1088,7 @@ static void dmar_init_reserved_ranges(void) int i; u64 addr, size; - init_iova_domain(&reserved_iova_list); + init_iova_domain(&reserved_iova_list, DMA_32BIT_PFN); /* IOAPIC ranges shouldn't be accessed by DMA */ iova = reserve_iova(&reserved_iova_list, IOVA_PFN(IOAPIC_RANGE_START), @@ -1142,7 +1142,7 @@ static int domain_init(struct dmar_domain *domain, int guest_width) int adjust_width, agaw; unsigned long sagaw; - init_iova_domain(&domain->iovad); + init_iova_domain(&domain->iovad, DMA_32BIT_PFN); spin_lock_init(&domain->mapping_lock); domain_reserve_special_ranges(domain); diff --git a/drivers/pci/intel-iommu.h b/drivers/pci/intel-iommu.h index 459ad1f9dc54..0e4862675ad2 100644 --- a/drivers/pci/intel-iommu.h +++ b/drivers/pci/intel-iommu.h @@ -23,10 +23,24 @@ #include <linux/types.h> #include <linux/msi.h> +#include <linux/sysdev.h> #include "iova.h" #include <linux/io.h> /* + * We need a fixed PAGE_SIZE of 4K irrespective of + * arch PAGE_SIZE for IOMMU page tables. + */ +#define PAGE_SHIFT_4K (12) +#define PAGE_SIZE_4K (1UL << PAGE_SHIFT_4K) +#define PAGE_MASK_4K (((u64)-1) << PAGE_SHIFT_4K) +#define PAGE_ALIGN_4K(addr) (((addr) + PAGE_SIZE_4K - 1) & PAGE_MASK_4K) + +#define IOVA_PFN(addr) ((addr) >> PAGE_SHIFT_4K) +#define DMA_32BIT_PFN IOVA_PFN(DMA_32BIT_MASK) +#define DMA_64BIT_PFN IOVA_PFN(DMA_64BIT_MASK) + +/* * Intel IOMMU register specification per version 1.0 public spec. */ diff --git a/drivers/pci/iova.c b/drivers/pci/iova.c index a84571c29360..8de7ab6c6d0c 100644 --- a/drivers/pci/iova.c +++ b/drivers/pci/iova.c @@ -9,19 +9,19 @@ #include "iova.h" void -init_iova_domain(struct iova_domain *iovad) +init_iova_domain(struct iova_domain *iovad, unsigned long pfn_32bit) { spin_lock_init(&iovad->iova_alloc_lock); spin_lock_init(&iovad->iova_rbtree_lock); iovad->rbroot = RB_ROOT; iovad->cached32_node = NULL; - + iovad->dma_32bit_pfn = pfn_32bit; } static struct rb_node * __get_cached_rbnode(struct iova_domain *iovad, unsigned long *limit_pfn) { - if ((*limit_pfn != DMA_32BIT_PFN) || + if ((*limit_pfn != iovad->dma_32bit_pfn) || (iovad->cached32_node == NULL)) return rb_last(&iovad->rbroot); else { @@ -37,7 +37,7 @@ static void __cached_rbnode_insert_update(struct iova_domain *iovad, unsigned long limit_pfn, struct iova *new) { - if (limit_pfn != DMA_32BIT_PFN) + if (limit_pfn != iovad->dma_32bit_pfn) return; iovad->cached32_node = &new->node; } diff --git a/drivers/pci/iova.h b/drivers/pci/iova.h index ae3028d5a941..d521b5b7319c 100644 --- a/drivers/pci/iova.h +++ b/drivers/pci/iova.h @@ -15,22 +15,9 @@ #include <linux/rbtree.h> #include <linux/dma-mapping.h> -/* - * We need a fixed PAGE_SIZE of 4K irrespective of - * arch PAGE_SIZE for IOMMU page tables. - */ -#define PAGE_SHIFT_4K (12) -#define PAGE_SIZE_4K (1UL << PAGE_SHIFT_4K) -#define PAGE_MASK_4K (((u64)-1) << PAGE_SHIFT_4K) -#define PAGE_ALIGN_4K(addr) (((addr) + PAGE_SIZE_4K - 1) & PAGE_MASK_4K) - /* IO virtual address start page frame number */ #define IOVA_START_PFN (1) -#define IOVA_PFN(addr) ((addr) >> PAGE_SHIFT_4K) -#define DMA_32BIT_PFN IOVA_PFN(DMA_32BIT_MASK) -#define DMA_64BIT_PFN IOVA_PFN(DMA_64BIT_MASK) - /* iova structure */ struct iova { struct rb_node node; @@ -44,6 +31,7 @@ struct iova_domain { spinlock_t iova_rbtree_lock; /* Lock to protect update of rbtree */ struct rb_root rbroot; /* iova domain rbtree root */ struct rb_node *cached32_node; /* Save last alloced node */ + unsigned long dma_32bit_pfn; }; struct iova *alloc_iova_mem(void); @@ -56,7 +44,7 @@ struct iova *alloc_iova(struct iova_domain *iovad, unsigned long size, struct iova *reserve_iova(struct iova_domain *iovad, unsigned long pfn_lo, unsigned long pfn_hi); void copy_reserved_iova(struct iova_domain *from, struct iova_domain *to); -void init_iova_domain(struct iova_domain *iovad); +void init_iova_domain(struct iova_domain *iovad, unsigned long pfn_32bit); struct iova *find_iova(struct iova_domain *iovad, unsigned long pfn); void put_iova_domain(struct iova_domain *iovad); diff --git a/drivers/pnp/driver.c b/drivers/pnp/driver.c index a262762c5b88..12a1645a2e43 100644 --- a/drivers/pnp/driver.c +++ b/drivers/pnp/driver.c @@ -161,8 +161,7 @@ static int pnp_bus_suspend(struct device *dev, pm_message_t state) return error; } - if (!(pnp_drv->flags & PNP_DRIVER_RES_DO_NOT_CHANGE) && - pnp_can_disable(pnp_dev)) { + if (pnp_can_disable(pnp_dev)) { error = pnp_stop_dev(pnp_dev); if (error) return error; @@ -185,14 +184,17 @@ static int pnp_bus_resume(struct device *dev) if (pnp_dev->protocol && pnp_dev->protocol->resume) pnp_dev->protocol->resume(pnp_dev); - if (!(pnp_drv->flags & PNP_DRIVER_RES_DO_NOT_CHANGE)) { + if (pnp_can_write(pnp_dev)) { error = pnp_start_dev(pnp_dev); if (error) return error; } - if (pnp_drv->resume) - return pnp_drv->resume(pnp_dev); + if (pnp_drv->resume) { + error = pnp_drv->resume(pnp_dev); + if (error) + return error; + } return 0; } diff --git a/drivers/pnp/interface.c b/drivers/pnp/interface.c index 31548044fdde..982658477a58 100644 --- a/drivers/pnp/interface.c +++ b/drivers/pnp/interface.c @@ -10,9 +10,12 @@ #include <linux/errno.h> #include <linux/list.h> #include <linux/types.h> +#include <linux/pnp.h> #include <linux/stat.h> #include <linux/ctype.h> #include <linux/slab.h> +#include <linux/mutex.h> + #include <asm/uaccess.h> #include "base.h" @@ -315,8 +318,6 @@ static ssize_t pnp_show_current_resources(struct device *dmdev, return ret; } -extern struct semaphore pnp_res_mutex; - static ssize_t pnp_set_current_resources(struct device *dmdev, struct device_attribute *attr, const char *ubuf, size_t count) @@ -361,10 +362,10 @@ pnp_set_current_resources(struct device *dmdev, struct device_attribute *attr, goto done; } if (!strnicmp(buf, "get", 3)) { - down(&pnp_res_mutex); + mutex_lock(&pnp_res_mutex); if (pnp_can_read(dev)) dev->protocol->get(dev, &dev->res); - up(&pnp_res_mutex); + mutex_unlock(&pnp_res_mutex); goto done; } if (!strnicmp(buf, "set", 3)) { @@ -373,7 +374,7 @@ pnp_set_current_resources(struct device *dmdev, struct device_attribute *attr, goto done; buf += 3; pnp_init_resource_table(&dev->res); - down(&pnp_res_mutex); + mutex_lock(&pnp_res_mutex); while (1) { while (isspace(*buf)) ++buf; @@ -455,7 +456,7 @@ pnp_set_current_resources(struct device *dmdev, struct device_attribute *attr, } break; } - up(&pnp_res_mutex); + mutex_unlock(&pnp_res_mutex); goto done; } diff --git a/drivers/pnp/manager.c b/drivers/pnp/manager.c index c6b3d4e63ccc..c28caf272c11 100644 --- a/drivers/pnp/manager.c +++ b/drivers/pnp/manager.c @@ -12,9 +12,10 @@ #include <linux/pnp.h> #include <linux/slab.h> #include <linux/bitmap.h> +#include <linux/mutex.h> #include "base.h" -DECLARE_MUTEX(pnp_res_mutex); +DEFINE_MUTEX(pnp_res_mutex); static int pnp_assign_port(struct pnp_dev *dev, struct pnp_port *rule, int idx) { @@ -297,7 +298,7 @@ static int pnp_assign_resources(struct pnp_dev *dev, int depnum) if (!pnp_can_configure(dev)) return -ENODEV; - down(&pnp_res_mutex); + mutex_lock(&pnp_res_mutex); pnp_clean_resource_table(&dev->res); /* start with a fresh slate */ if (dev->independent) { port = dev->independent->port; @@ -366,12 +367,12 @@ static int pnp_assign_resources(struct pnp_dev *dev, int depnum) } else if (dev->dependent) goto fail; - up(&pnp_res_mutex); + mutex_unlock(&pnp_res_mutex); return 1; fail: pnp_clean_resource_table(&dev->res); - up(&pnp_res_mutex); + mutex_unlock(&pnp_res_mutex); return 0; } @@ -396,7 +397,7 @@ int pnp_manual_config_dev(struct pnp_dev *dev, struct pnp_resource_table *res, return -ENOMEM; *bak = dev->res; - down(&pnp_res_mutex); + mutex_lock(&pnp_res_mutex); dev->res = *res; if (!(mode & PNP_CONFIG_FORCE)) { for (i = 0; i < PNP_MAX_PORT; i++) { @@ -416,14 +417,14 @@ int pnp_manual_config_dev(struct pnp_dev *dev, struct pnp_resource_table *res, goto fail; } } - up(&pnp_res_mutex); + mutex_unlock(&pnp_res_mutex); kfree(bak); return 0; fail: dev->res = *bak; - up(&pnp_res_mutex); + mutex_unlock(&pnp_res_mutex); kfree(bak); return -EINVAL; } @@ -513,7 +514,7 @@ int pnp_activate_dev(struct pnp_dev *dev) int error; if (dev->active) - return 0; /* the device is already active */ + return 0; /* ensure resources are allocated */ if (pnp_auto_config_dev(dev)) @@ -524,7 +525,7 @@ int pnp_activate_dev(struct pnp_dev *dev) return error; dev->active = 1; - return 1; + return 0; } /** @@ -538,7 +539,7 @@ int pnp_disable_dev(struct pnp_dev *dev) int error; if (!dev->active) - return 0; /* the device is already disabled */ + return 0; error = pnp_stop_dev(dev); if (error) @@ -547,11 +548,11 @@ int pnp_disable_dev(struct pnp_dev *dev) dev->active = 0; /* release the resources so that other devices can use them */ - down(&pnp_res_mutex); + mutex_lock(&pnp_res_mutex); pnp_clean_resource_table(&dev->res); - up(&pnp_res_mutex); + mutex_unlock(&pnp_res_mutex); - return 1; + return 0; } /** diff --git a/drivers/pnp/pnpacpi/rsparser.c b/drivers/pnp/pnpacpi/rsparser.c index 6b9840cce0f4..6aa231ef642d 100644 --- a/drivers/pnp/pnpacpi/rsparser.c +++ b/drivers/pnp/pnpacpi/rsparser.c @@ -391,8 +391,8 @@ acpi_status pnpacpi_parse_allocated_resource(acpi_handle handle, pnpacpi_allocated_resource, res); } -static void pnpacpi_parse_dma_option(struct pnp_option *option, - struct acpi_resource_dma *p) +static __init void pnpacpi_parse_dma_option(struct pnp_option *option, + struct acpi_resource_dma *p) { int i; struct pnp_dma *dma; @@ -411,8 +411,8 @@ static void pnpacpi_parse_dma_option(struct pnp_option *option, pnp_register_dma_resource(option, dma); } -static void pnpacpi_parse_irq_option(struct pnp_option *option, - struct acpi_resource_irq *p) +static __init void pnpacpi_parse_irq_option(struct pnp_option *option, + struct acpi_resource_irq *p) { int i; struct pnp_irq *irq; @@ -431,8 +431,8 @@ static void pnpacpi_parse_irq_option(struct pnp_option *option, pnp_register_irq_resource(option, irq); } -static void pnpacpi_parse_ext_irq_option(struct pnp_option *option, - struct acpi_resource_extended_irq *p) +static __init void pnpacpi_parse_ext_irq_option(struct pnp_option *option, + struct acpi_resource_extended_irq *p) { int i; struct pnp_irq *irq; @@ -451,8 +451,8 @@ static void pnpacpi_parse_ext_irq_option(struct pnp_option *option, pnp_register_irq_resource(option, irq); } -static void pnpacpi_parse_port_option(struct pnp_option *option, - struct acpi_resource_io *io) +static __init void pnpacpi_parse_port_option(struct pnp_option *option, + struct acpi_resource_io *io) { struct pnp_port *port; @@ -470,8 +470,8 @@ static void pnpacpi_parse_port_option(struct pnp_option *option, pnp_register_port_resource(option, port); } -static void pnpacpi_parse_fixed_port_option(struct pnp_option *option, - struct acpi_resource_fixed_io *io) +static __init void pnpacpi_parse_fixed_port_option(struct pnp_option *option, + struct acpi_resource_fixed_io *io) { struct pnp_port *port; @@ -487,8 +487,8 @@ static void pnpacpi_parse_fixed_port_option(struct pnp_option *option, pnp_register_port_resource(option, port); } -static void pnpacpi_parse_mem24_option(struct pnp_option *option, - struct acpi_resource_memory24 *p) +static __init void pnpacpi_parse_mem24_option(struct pnp_option *option, + struct acpi_resource_memory24 *p) { struct pnp_mem *mem; @@ -508,8 +508,8 @@ static void pnpacpi_parse_mem24_option(struct pnp_option *option, pnp_register_mem_resource(option, mem); } -static void pnpacpi_parse_mem32_option(struct pnp_option *option, - struct acpi_resource_memory32 *p) +static __init void pnpacpi_parse_mem32_option(struct pnp_option *option, + struct acpi_resource_memory32 *p) { struct pnp_mem *mem; @@ -529,8 +529,8 @@ static void pnpacpi_parse_mem32_option(struct pnp_option *option, pnp_register_mem_resource(option, mem); } -static void pnpacpi_parse_fixed_mem32_option(struct pnp_option *option, - struct acpi_resource_fixed_memory32 *p) +static __init void pnpacpi_parse_fixed_mem32_option(struct pnp_option *option, + struct acpi_resource_fixed_memory32 *p) { struct pnp_mem *mem; @@ -549,8 +549,8 @@ static void pnpacpi_parse_fixed_mem32_option(struct pnp_option *option, pnp_register_mem_resource(option, mem); } -static void pnpacpi_parse_address_option(struct pnp_option *option, - struct acpi_resource *r) +static __init void pnpacpi_parse_address_option(struct pnp_option *option, + struct acpi_resource *r) { struct acpi_resource_address64 addr, *p = &addr; acpi_status status; @@ -596,8 +596,8 @@ struct acpipnp_parse_option_s { struct pnp_dev *dev; }; -static acpi_status pnpacpi_option_resource(struct acpi_resource *res, - void *data) +static __init acpi_status pnpacpi_option_resource(struct acpi_resource *res, + void *data) { int priority = 0; struct acpipnp_parse_option_s *parse_data = data; @@ -696,8 +696,8 @@ static acpi_status pnpacpi_option_resource(struct acpi_resource *res, return AE_OK; } -acpi_status pnpacpi_parse_resource_option_data(acpi_handle handle, - struct pnp_dev * dev) +acpi_status __init pnpacpi_parse_resource_option_data(acpi_handle handle, + struct pnp_dev *dev) { acpi_status status; struct acpipnp_parse_option_s parse_data; diff --git a/drivers/pnp/pnpbios/core.c b/drivers/pnp/pnpbios/core.c index e33e03f71084..f7e67197a568 100644 --- a/drivers/pnp/pnpbios/core.c +++ b/drivers/pnp/pnpbios/core.c @@ -315,7 +315,7 @@ struct pnp_protocol pnpbios_protocol = { .disable = pnpbios_disable_resources, }; -static int insert_device(struct pnp_bios_node *node) +static int __init insert_device(struct pnp_bios_node *node) { struct list_head *pos; struct pnp_dev *dev; diff --git a/drivers/pnp/pnpbios/rsparser.c b/drivers/pnp/pnpbios/rsparser.c index 3fabf11b0027..caade3531416 100644 --- a/drivers/pnp/pnpbios/rsparser.c +++ b/drivers/pnp/pnpbios/rsparser.c @@ -262,8 +262,8 @@ len_err: * Resource Configuration Options */ -static void pnpbios_parse_mem_option(unsigned char *p, int size, - struct pnp_option *option) +static __init void pnpbios_parse_mem_option(unsigned char *p, int size, + struct pnp_option *option) { struct pnp_mem *mem; @@ -278,8 +278,8 @@ static void pnpbios_parse_mem_option(unsigned char *p, int size, pnp_register_mem_resource(option, mem); } -static void pnpbios_parse_mem32_option(unsigned char *p, int size, - struct pnp_option *option) +static __init void pnpbios_parse_mem32_option(unsigned char *p, int size, + struct pnp_option *option) { struct pnp_mem *mem; @@ -294,8 +294,8 @@ static void pnpbios_parse_mem32_option(unsigned char *p, int size, pnp_register_mem_resource(option, mem); } -static void pnpbios_parse_fixed_mem32_option(unsigned char *p, int size, - struct pnp_option *option) +static __init void pnpbios_parse_fixed_mem32_option(unsigned char *p, int size, + struct pnp_option *option) { struct pnp_mem *mem; @@ -309,7 +309,7 @@ static void pnpbios_parse_fixed_mem32_option(unsigned char *p, int size, pnp_register_mem_resource(option, mem); } -static void pnpbios_parse_irq_option(unsigned char *p, int size, +static __init void pnpbios_parse_irq_option(unsigned char *p, int size, struct pnp_option *option) { struct pnp_irq *irq; @@ -327,7 +327,7 @@ static void pnpbios_parse_irq_option(unsigned char *p, int size, pnp_register_irq_resource(option, irq); } -static void pnpbios_parse_dma_option(unsigned char *p, int size, +static __init void pnpbios_parse_dma_option(unsigned char *p, int size, struct pnp_option *option) { struct pnp_dma *dma; @@ -340,8 +340,8 @@ static void pnpbios_parse_dma_option(unsigned char *p, int size, pnp_register_dma_resource(option, dma); } -static void pnpbios_parse_port_option(unsigned char *p, int size, - struct pnp_option *option) +static __init void pnpbios_parse_port_option(unsigned char *p, int size, + struct pnp_option *option) { struct pnp_port *port; @@ -356,8 +356,8 @@ static void pnpbios_parse_port_option(unsigned char *p, int size, pnp_register_port_resource(option, port); } -static void pnpbios_parse_fixed_port_option(unsigned char *p, int size, - struct pnp_option *option) +static __init void pnpbios_parse_fixed_port_option(unsigned char *p, int size, + struct pnp_option *option) { struct pnp_port *port; @@ -371,9 +371,9 @@ static void pnpbios_parse_fixed_port_option(unsigned char *p, int size, pnp_register_port_resource(option, port); } -static unsigned char *pnpbios_parse_resource_option_data(unsigned char *p, - unsigned char *end, - struct pnp_dev *dev) +static __init unsigned char * +pnpbios_parse_resource_option_data(unsigned char *p, unsigned char *end, + struct pnp_dev *dev) { unsigned int len, tag; int priority = 0; @@ -781,7 +781,8 @@ len_err: * Core Parsing Functions */ -int pnpbios_parse_data_stream(struct pnp_dev *dev, struct pnp_bios_node *node) +int __init pnpbios_parse_data_stream(struct pnp_dev *dev, + struct pnp_bios_node *node) { unsigned char *p = (char *)node->data; unsigned char *end = (char *)(node->data + node->size); diff --git a/drivers/pnp/quirks.c b/drivers/pnp/quirks.c index e903b8c2b1fa..4065139753b6 100644 --- a/drivers/pnp/quirks.c +++ b/drivers/pnp/quirks.c @@ -17,6 +17,7 @@ #include <linux/slab.h> #include <linux/pnp.h> #include <linux/io.h> +#include <linux/dmi.h> #include <linux/kallsyms.h> #include "base.h" @@ -108,6 +109,46 @@ static void quirk_sb16audio_resources(struct pnp_dev *dev) "pnp: SB audio device quirk - increasing port range\n"); } +static void quirk_supermicro_h8dce_system(struct pnp_dev *dev) +{ + int i; + static struct dmi_system_id supermicro_h8dce[] = { + { + .ident = "Supermicro H8DCE", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Supermicro"), + DMI_MATCH(DMI_PRODUCT_NAME, "H8DCE"), + }, + }, + { } + }; + + if (!dmi_check_system(supermicro_h8dce)) + return; + + /* + * On the Supermicro H8DCE, there's a system device with resources + * that overlap BAR 6 of the built-in SATA PCI adapter. If the PNP + * system device claims them, the sata_nv driver won't be able to. + * More details at: + * https://bugzilla.redhat.com/show_bug.cgi?id=280641 + * https://bugzilla.redhat.com/show_bug.cgi?id=313491 + * http://lkml.org/lkml/2008/1/9/449 + * http://thread.gmane.org/gmane.linux.acpi.devel/27312 + */ + for (i = 0; i < PNP_MAX_MEM; i++) { + if (pnp_mem_valid(dev, i) && pnp_mem_len(dev, i) && + (pnp_mem_start(dev, i) & 0xdfef0000) == 0xdfef0000) { + dev_warn(&dev->dev, "disabling 0x%llx-0x%llx to prevent" + " conflict with sata_nv PCI device\n", + (unsigned long long) pnp_mem_start(dev, i), + (unsigned long long) (pnp_mem_start(dev, i) + + pnp_mem_len(dev, i) - 1)); + pnp_mem_flags(dev, i) = 0; + } + } +} + /* * PnP Quirks * Cards or devices that need some tweaking due to incomplete resource info @@ -128,6 +169,8 @@ static struct pnp_fixup pnp_fixups[] = { {"CTL0043", quirk_sb16audio_resources}, {"CTL0044", quirk_sb16audio_resources}, {"CTL0045", quirk_sb16audio_resources}, + {"PNP0c01", quirk_supermicro_h8dce_system}, + {"PNP0c02", quirk_supermicro_h8dce_system}, {""} }; diff --git a/drivers/ps3/ps3av.c b/drivers/ps3/ps3av.c index 87b3493d88e5..6f2f90ebb020 100644 --- a/drivers/ps3/ps3av.c +++ b/drivers/ps3/ps3av.c @@ -78,23 +78,21 @@ static const struct avset_video_mode { u32 aspect; u32 x; u32 y; - u32 interlace; - u32 freq; } video_mode_table[] = { { 0, }, /* auto */ - {YUV444, XRGB, PS3AV_CMD_VIDEO_VID_480I, A_N, 720, 480, 1, 60}, - {YUV444, XRGB, PS3AV_CMD_VIDEO_VID_480P, A_N, 720, 480, 0, 60}, - {YUV444, XRGB, PS3AV_CMD_VIDEO_VID_720P_60HZ, A_N, 1280, 720, 0, 60}, - {YUV444, XRGB, PS3AV_CMD_VIDEO_VID_1080I_60HZ, A_W, 1920, 1080, 1, 60}, - {YUV444, XRGB, PS3AV_CMD_VIDEO_VID_1080P_60HZ, A_W, 1920, 1080, 0, 60}, - {YUV444, XRGB, PS3AV_CMD_VIDEO_VID_576I, A_N, 720, 576, 1, 50}, - {YUV444, XRGB, PS3AV_CMD_VIDEO_VID_576P, A_N, 720, 576, 0, 50}, - {YUV444, XRGB, PS3AV_CMD_VIDEO_VID_720P_50HZ, A_N, 1280, 720, 0, 50}, - {YUV444, XRGB, PS3AV_CMD_VIDEO_VID_1080I_50HZ, A_W, 1920, 1080, 1, 50}, - {YUV444, XRGB, PS3AV_CMD_VIDEO_VID_1080P_50HZ, A_W, 1920, 1080, 0, 50}, - { RGB8, XRGB, PS3AV_CMD_VIDEO_VID_WXGA, A_W, 1280, 768, 0, 60}, - { RGB8, XRGB, PS3AV_CMD_VIDEO_VID_SXGA, A_N, 1280, 1024, 0, 60}, - { RGB8, XRGB, PS3AV_CMD_VIDEO_VID_WUXGA, A_W, 1920, 1200, 0, 60}, + {YUV444, XRGB, PS3AV_CMD_VIDEO_VID_480I, A_N, 720, 480}, + {YUV444, XRGB, PS3AV_CMD_VIDEO_VID_480P, A_N, 720, 480}, + {YUV444, XRGB, PS3AV_CMD_VIDEO_VID_720P_60HZ, A_N, 1280, 720}, + {YUV444, XRGB, PS3AV_CMD_VIDEO_VID_1080I_60HZ, A_W, 1920, 1080}, + {YUV444, XRGB, PS3AV_CMD_VIDEO_VID_1080P_60HZ, A_W, 1920, 1080}, + {YUV444, XRGB, PS3AV_CMD_VIDEO_VID_576I, A_N, 720, 576}, + {YUV444, XRGB, PS3AV_CMD_VIDEO_VID_576P, A_N, 720, 576}, + {YUV444, XRGB, PS3AV_CMD_VIDEO_VID_720P_50HZ, A_N, 1280, 720}, + {YUV444, XRGB, PS3AV_CMD_VIDEO_VID_1080I_50HZ, A_W, 1920, 1080}, + {YUV444, XRGB, PS3AV_CMD_VIDEO_VID_1080P_50HZ, A_W, 1920, 1080}, + { RGB8, XRGB, PS3AV_CMD_VIDEO_VID_WXGA, A_W, 1280, 768}, + { RGB8, XRGB, PS3AV_CMD_VIDEO_VID_SXGA, A_N, 1280, 1024}, + { RGB8, XRGB, PS3AV_CMD_VIDEO_VID_WUXGA, A_W, 1920, 1200}, }; /* supported CIDs */ @@ -544,7 +542,7 @@ static void ps3av_set_videomode_packet(u32 id) static void ps3av_set_videomode_cont(u32 id, u32 old_id) { - static int vesa = 0; + static int vesa; int res; /* video signal off */ @@ -554,9 +552,9 @@ static void ps3av_set_videomode_cont(u32 id, u32 old_id) * AV backend needs non-VESA mode setting at least one time * when VESA mode is used. */ - if (vesa == 0 && (id & PS3AV_MODE_MASK) >= 11) { + if (vesa == 0 && (id & PS3AV_MODE_MASK) >= PS3AV_MODE_WXGA) { /* vesa mode */ - ps3av_set_videomode_packet(2); /* 480P */ + ps3av_set_videomode_packet(PS3AV_MODE_480P); } vesa = 1; @@ -596,20 +594,21 @@ static const struct { unsigned mask : 19; unsigned id : 4; } ps3av_preferred_modes[] = { - { .mask = PS3AV_RESBIT_WUXGA << SHIFT_VESA, .id = 13 }, - { .mask = PS3AV_RESBIT_1920x1080P << SHIFT_60, .id = 5 }, - { .mask = PS3AV_RESBIT_1920x1080P << SHIFT_50, .id = 10 }, - { .mask = PS3AV_RESBIT_1920x1080I << SHIFT_60, .id = 4 }, - { .mask = PS3AV_RESBIT_1920x1080I << SHIFT_50, .id = 9 }, - { .mask = PS3AV_RESBIT_SXGA << SHIFT_VESA, .id = 12 }, - { .mask = PS3AV_RESBIT_WXGA << SHIFT_VESA, .id = 11 }, - { .mask = PS3AV_RESBIT_1280x720P << SHIFT_60, .id = 3 }, - { .mask = PS3AV_RESBIT_1280x720P << SHIFT_50, .id = 8 }, - { .mask = PS3AV_RESBIT_720x480P << SHIFT_60, .id = 2 }, - { .mask = PS3AV_RESBIT_720x576P << SHIFT_50, .id = 7 }, + { PS3AV_RESBIT_WUXGA << SHIFT_VESA, PS3AV_MODE_WUXGA }, + { PS3AV_RESBIT_1920x1080P << SHIFT_60, PS3AV_MODE_1080P60 }, + { PS3AV_RESBIT_1920x1080P << SHIFT_50, PS3AV_MODE_1080P50 }, + { PS3AV_RESBIT_1920x1080I << SHIFT_60, PS3AV_MODE_1080I60 }, + { PS3AV_RESBIT_1920x1080I << SHIFT_50, PS3AV_MODE_1080I50 }, + { PS3AV_RESBIT_SXGA << SHIFT_VESA, PS3AV_MODE_SXGA }, + { PS3AV_RESBIT_WXGA << SHIFT_VESA, PS3AV_MODE_WXGA }, + { PS3AV_RESBIT_1280x720P << SHIFT_60, PS3AV_MODE_720P60 }, + { PS3AV_RESBIT_1280x720P << SHIFT_50, PS3AV_MODE_720P50 }, + { PS3AV_RESBIT_720x480P << SHIFT_60, PS3AV_MODE_480P }, + { PS3AV_RESBIT_720x576P << SHIFT_50, PS3AV_MODE_576P }, }; -static int ps3av_resbit2id(u32 res_50, u32 res_60, u32 res_vesa) +static enum ps3av_mode_num ps3av_resbit2id(u32 res_50, u32 res_60, + u32 res_vesa) { unsigned int i; u32 res_all; @@ -638,9 +637,9 @@ static int ps3av_resbit2id(u32 res_50, u32 res_60, u32 res_vesa) return 0; } -static int ps3av_hdmi_get_id(struct ps3av_info_monitor *info) +static enum ps3av_mode_num ps3av_hdmi_get_id(struct ps3av_info_monitor *info) { - int id; + enum ps3av_mode_num id; if (safe_mode) return PS3AV_DEFAULT_HDMI_MODE_ID_REG_60; @@ -854,7 +853,7 @@ int ps3av_set_video_mode(u32 id) /* auto mode */ option = id & ~PS3AV_MODE_MASK; - if ((id & PS3AV_MODE_MASK) == 0) { + if ((id & PS3AV_MODE_MASK) == PS3AV_MODE_AUTO) { id = ps3av_auto_videomode(&ps3av->av_hw_conf); if (id < 1) { printk(KERN_ERR "%s: invalid id :%d\n", __func__, id); @@ -889,36 +888,6 @@ int ps3av_get_mode(void) EXPORT_SYMBOL_GPL(ps3av_get_mode); -int ps3av_get_scanmode(int id) -{ - int size; - - id = id & PS3AV_MODE_MASK; - size = ARRAY_SIZE(video_mode_table); - if (id > size - 1 || id < 0) { - printk(KERN_ERR "%s: invalid mode %d\n", __func__, id); - return -EINVAL; - } - return video_mode_table[id].interlace; -} - -EXPORT_SYMBOL_GPL(ps3av_get_scanmode); - -int ps3av_get_refresh_rate(int id) -{ - int size; - - id = id & PS3AV_MODE_MASK; - size = ARRAY_SIZE(video_mode_table); - if (id > size - 1 || id < 0) { - printk(KERN_ERR "%s: invalid mode %d\n", __func__, id); - return -EINVAL; - } - return video_mode_table[id].freq; -} - -EXPORT_SYMBOL_GPL(ps3av_get_refresh_rate); - /* get resolution by video_mode */ int ps3av_video_mode2res(u32 id, u32 *xres, u32 *yres) { @@ -990,7 +959,7 @@ static int ps3av_probe(struct ps3_system_bus_device *dev) return -ENOMEM; mutex_init(&ps3av->mutex); - ps3av->ps3av_mode = 0; + ps3av->ps3av_mode = PS3AV_MODE_AUTO; ps3av->dev = dev; INIT_WORK(&ps3av->work, ps3avd); diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig index 45e4b9648176..6402d699072b 100644 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig @@ -20,6 +20,10 @@ menuconfig RTC_CLASS if RTC_CLASS +if GEN_RTC || RTC +comment "Conflicting RTC option has been selected, check GEN_RTC and RTC" +endif + config RTC_HCTOSYS bool "Set system time from RTC on startup and resume" depends on RTC_CLASS = y @@ -49,7 +53,7 @@ config RTC_HCTOSYS_DEVICE If the clock you specify here is not battery backed, it may still be useful to reinitialize system time when resuming from system - sleep states. Do not specify an RTC here unless it stays powered + sleep states. Do not specify an RTC here unless it stays powered during all this system's supported sleep states. config RTC_DEBUG @@ -142,7 +146,7 @@ config RTC_DRV_DS1307 will be called rtc-ds1307. config RTC_DRV_DS1374 - tristate "Maxim/Dallas Semiconductor DS1374 Real Time Clock" + tristate "Dallas/Maxim DS1374" depends on RTC_CLASS && I2C help If you say yes here you get support for Dallas Semiconductor @@ -162,7 +166,7 @@ config RTC_DRV_DS1672 will be called rtc-ds1672. config RTC_DRV_MAX6900 - tristate "Maxim 6900" + tristate "Maxim MAX6900" help If you say yes here you will get support for the Maxim MAX6900 I2C RTC chip. @@ -180,10 +184,10 @@ config RTC_DRV_RS5C372 will be called rtc-rs5c372. config RTC_DRV_ISL1208 - tristate "Intersil 1208" + tristate "Intersil ISL1208" help If you say yes here you get support for the - Intersil 1208 RTC chip. + Intersil ISL1208 RTC chip. This driver can also be built as a module. If so, the module will be called rtc-isl1208. @@ -220,7 +224,7 @@ config RTC_DRV_PCF8583 will be called rtc-pcf8583. config RTC_DRV_M41T80 - tristate "ST M41T80 series RTC" + tristate "ST M41T80/81/82/83/84/85/87" help If you say Y here you will get support for the ST M41T80 RTC chips series. Currently following chips are @@ -252,23 +256,32 @@ comment "SPI RTC drivers" if SPI_MASTER -config RTC_DRV_RS5C348 - tristate "Ricoh RS5C348A/B" +config RTC_DRV_MAX6902 + tristate "Maxim MAX6902" help - If you say yes here you get support for the - Ricoh RS5C348A and RS5C348B RTC chips. + If you say yes here you will get support for the + Maxim MAX6902 SPI RTC chip. This driver can also be built as a module. If so, the module - will be called rtc-rs5c348. + will be called rtc-max6902. -config RTC_DRV_MAX6902 - tristate "Maxim 6902" +config RTC_DRV_R9701 + tristate "Epson RTC-9701JE" help If you say yes here you will get support for the - Maxim MAX6902 SPI RTC chip. + Epson RTC-9701JE SPI RTC chip. This driver can also be built as a module. If so, the module - will be called rtc-max6902. + will be called rtc-r9701. + +config RTC_DRV_RS5C348 + tristate "Ricoh RS5C348A/B" + help + If you say yes here you get support for the + Ricoh RS5C348A and RS5C348B RTC chips. + + This driver can also be built as a module. If so, the module + will be called rtc-rs5c348. endif # SPI_MASTER @@ -302,34 +315,50 @@ config RTC_DRV_DS1216 help If you say yes here you get support for the Dallas DS1216 RTC chips. -config RTC_DRV_DS1553 - tristate "Dallas DS1553" +config RTC_DRV_DS1302 + tristate "Dallas DS1302" + depends on SH_SECUREEDGE5410 + help + If you say yes here you get support for the Dallas DS1302 RTC chips. + +config RTC_DRV_DS1511 + tristate "Dallas DS1511" + depends on RTC_CLASS help If you say yes here you get support for the - Dallas DS1553 timekeeping chip. + Dallas DS1511 timekeeping/watchdog chip. This driver can also be built as a module. If so, the module - will be called rtc-ds1553. + will be called rtc-ds1511. -config RTC_DRV_STK17TA8 - tristate "Simtek STK17TA8" - depends on RTC_CLASS +config RTC_DRV_DS1553 + tristate "Maxim/Dallas DS1553" help If you say yes here you get support for the - Simtek STK17TA8 timekeeping chip. + Maxim/Dallas DS1553 timekeeping chip. This driver can also be built as a module. If so, the module - will be called rtc-stk17ta8. + will be called rtc-ds1553. config RTC_DRV_DS1742 - tristate "Dallas DS1742/1743" + tristate "Maxim/Dallas DS1742/1743" help If you say yes here you get support for the - Dallas DS1742/1743 timekeeping chip. + Maxim/Dallas DS1742/1743 timekeeping chip. This driver can also be built as a module. If so, the module will be called rtc-ds1742. +config RTC_DRV_STK17TA8 + tristate "Simtek STK17TA8" + depends on RTC_CLASS + help + If you say yes here you get support for the + Simtek STK17TA8 timekeeping chip. + + This driver can also be built as a module. If so, the module + will be called rtc-stk17ta8. + config RTC_DRV_M48T86 tristate "ST M48T86/Dallas DS12887" help @@ -440,10 +469,47 @@ config RTC_DRV_AT32AP700X AT32AP700x family processors. config RTC_DRV_AT91RM9200 - tristate "AT91RM9200" - depends on ARCH_AT91RM9200 - help - Driver for the Atmel AT91RM9200's internal RTC (Realtime Clock). + tristate "AT91RM9200 or AT91SAM9RL" + depends on ARCH_AT91RM9200 || ARCH_AT91SAM9RL + help + Driver for the internal RTC (Realtime Clock) module found on + Atmel AT91RM9200's and AT91SAM9RL chips. On SAM9RL chips + this is powered by the backup power supply. + +config RTC_DRV_AT91SAM9 + tristate "AT91SAM9x" + depends on ARCH_AT91 && !(ARCH_AT91RM9200 || ARCH_AT91X40) + help + RTC driver for the Atmel AT91SAM9x internal RTT (Real Time Timer). + These timers are powered by the backup power supply (such as a + small coin cell battery), but do not need to be used as RTCs. + + (On AT91SAM9rl chips you probably want to use the dedicated RTC + module and leave the RTT available for other uses.) + +config RTC_DRV_AT91SAM9_RTT + int + range 0 1 + default 0 + prompt "RTT module Number" if ARCH_AT91SAM9263 + depends on RTC_DRV_AT91SAM9 + help + More than one RTT module is available. You can choose which + one will be used as an RTC. The default of zero is normally + OK to use, though some systems use that for non-RTC purposes. + +config RTC_DRV_AT91SAM9_GPBR + int + range 0 3 if !ARCH_AT91SAM9263 + range 0 15 if ARCH_AT91SAM9263 + default 0 + prompt "Backup Register Number" + depends on RTC_DRV_AT91SAM9 + help + The RTC driver needs to use one of the General Purpose Backup + Registers (GPBRs) as well as the RTT. You can choose which one + will be used. The default of zero is normally OK to use, but + on some systems other software needs to use that register. config RTC_DRV_BFIN tristate "Blackfin On-Chip RTC" diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile index 465db4dd50b2..ec703f34ab86 100644 --- a/drivers/rtc/Makefile +++ b/drivers/rtc/Makefile @@ -19,11 +19,14 @@ rtc-core-$(CONFIG_RTC_INTF_SYSFS) += rtc-sysfs.o obj-$(CONFIG_RTC_DRV_AT32AP700X)+= rtc-at32ap700x.o obj-$(CONFIG_RTC_DRV_AT91RM9200)+= rtc-at91rm9200.o +obj-$(CONFIG_RTC_DRV_AT91SAM9) += rtc-at91sam9.o obj-$(CONFIG_RTC_DRV_BFIN) += rtc-bfin.o obj-$(CONFIG_RTC_DRV_CMOS) += rtc-cmos.o obj-$(CONFIG_RTC_DRV_DS1216) += rtc-ds1216.o +obj-$(CONFIG_RTC_DRV_DS1302) += rtc-ds1302.o obj-$(CONFIG_RTC_DRV_DS1307) += rtc-ds1307.o obj-$(CONFIG_RTC_DRV_DS1374) += rtc-ds1374.o +obj-$(CONFIG_RTC_DRV_DS1511) += rtc-ds1511.o obj-$(CONFIG_RTC_DRV_DS1553) += rtc-ds1553.o obj-$(CONFIG_RTC_DRV_DS1672) += rtc-ds1672.o obj-$(CONFIG_RTC_DRV_DS1742) += rtc-ds1742.o @@ -38,6 +41,7 @@ obj-$(CONFIG_RTC_DRV_OMAP) += rtc-omap.o obj-$(CONFIG_RTC_DRV_PCF8563) += rtc-pcf8563.o obj-$(CONFIG_RTC_DRV_PCF8583) += rtc-pcf8583.o obj-$(CONFIG_RTC_DRV_PL031) += rtc-pl031.o +obj-$(CONFIG_RTC_DRV_R9701) += rtc-r9701.o obj-$(CONFIG_RTC_DRV_RS5C313) += rtc-rs5c313.o obj-$(CONFIG_RTC_DRV_RS5C348) += rtc-rs5c348.o obj-$(CONFIG_RTC_DRV_RS5C372) += rtc-rs5c372.o diff --git a/drivers/rtc/rtc-at91sam9.c b/drivers/rtc/rtc-at91sam9.c new file mode 100644 index 000000000000..bbf10ecf416c --- /dev/null +++ b/drivers/rtc/rtc-at91sam9.c @@ -0,0 +1,520 @@ +/* + * "RTT as Real Time Clock" driver for AT91SAM9 SoC family + * + * (C) 2007 Michel Benoit + * + * Based on rtc-at91rm9200.c by Rick Bronson + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ + +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/platform_device.h> +#include <linux/time.h> +#include <linux/rtc.h> +#include <linux/interrupt.h> +#include <linux/ioctl.h> + +#include <asm/mach/time.h> +#include <asm/arch/board.h> +#include <asm/arch/at91_rtt.h> + + +/* + * This driver uses two configurable hardware resources that live in the + * AT91SAM9 backup power domain (intended to be powered at all times) + * to implement the Real Time Clock interfaces + * + * - A "Real-time Timer" (RTT) counts up in seconds from a base time. + * We can't assign the counter value (CRTV) ... but we can reset it. + * + * - One of the "General Purpose Backup Registers" (GPBRs) holds the + * base time, normally an offset from the beginning of the POSIX + * epoch (1970-Jan-1 00:00:00 UTC). Some systems also include the + * local timezone's offset. + * + * The RTC's value is the RTT counter plus that offset. The RTC's alarm + * is likewise a base (ALMV) plus that offset. + * + * Not all RTTs will be used as RTCs; some systems have multiple RTTs to + * choose from, or a "real" RTC module. All systems have multiple GPBR + * registers available, likewise usable for more than "RTC" support. + */ + +/* + * We store ALARM_DISABLED in ALMV to record that no alarm is set. + * It's also the reset value for that field. + */ +#define ALARM_DISABLED ((u32)~0) + + +struct sam9_rtc { + void __iomem *rtt; + struct rtc_device *rtcdev; + u32 imr; +}; + +#define rtt_readl(rtc, field) \ + __raw_readl((rtc)->rtt + AT91_RTT_ ## field) +#define rtt_writel(rtc, field, val) \ + __raw_writel((val), (rtc)->rtt + AT91_RTT_ ## field) + +#define gpbr_readl(rtc) \ + at91_sys_read(AT91_GPBR + 4 * CONFIG_RTC_DRV_AT91SAM9_GPBR) +#define gpbr_writel(rtc, val) \ + at91_sys_write(AT91_GPBR + 4 * CONFIG_RTC_DRV_AT91SAM9_GPBR, (val)) + +/* + * Read current time and date in RTC + */ +static int at91_rtc_readtime(struct device *dev, struct rtc_time *tm) +{ + struct sam9_rtc *rtc = dev_get_drvdata(dev); + u32 secs, secs2; + u32 offset; + + /* read current time offset */ + offset = gpbr_readl(rtc); + if (offset == 0) + return -EILSEQ; + + /* reread the counter to help sync the two clock domains */ + secs = rtt_readl(rtc, VR); + secs2 = rtt_readl(rtc, VR); + if (secs != secs2) + secs = rtt_readl(rtc, VR); + + rtc_time_to_tm(offset + secs, tm); + + dev_dbg(dev, "%s: %4d-%02d-%02d %02d:%02d:%02d\n", "readtime", + 1900 + tm->tm_year, tm->tm_mon, tm->tm_mday, + tm->tm_hour, tm->tm_min, tm->tm_sec); + + return 0; +} + +/* + * Set current time and date in RTC + */ +static int at91_rtc_settime(struct device *dev, struct rtc_time *tm) +{ + struct sam9_rtc *rtc = dev_get_drvdata(dev); + int err; + u32 offset, alarm, mr; + unsigned long secs; + + dev_dbg(dev, "%s: %4d-%02d-%02d %02d:%02d:%02d\n", "settime", + 1900 + tm->tm_year, tm->tm_mon, tm->tm_mday, + tm->tm_hour, tm->tm_min, tm->tm_sec); + + err = rtc_tm_to_time(tm, &secs); + if (err != 0) + return err; + + mr = rtt_readl(rtc, MR); + + /* disable interrupts */ + rtt_writel(rtc, MR, mr & ~(AT91_RTT_ALMIEN | AT91_RTT_RTTINCIEN)); + + /* read current time offset */ + offset = gpbr_readl(rtc); + + /* store the new base time in a battery backup register */ + secs += 1; + gpbr_writel(rtc, secs); + + /* adjust the alarm time for the new base */ + alarm = rtt_readl(rtc, AR); + if (alarm != ALARM_DISABLED) { + if (offset > secs) { + /* time jumped backwards, increase time until alarm */ + alarm += (offset - secs); + } else if ((alarm + offset) > secs) { + /* time jumped forwards, decrease time until alarm */ + alarm -= (secs - offset); + } else { + /* time jumped past the alarm, disable alarm */ + alarm = ALARM_DISABLED; + mr &= ~AT91_RTT_ALMIEN; + } + rtt_writel(rtc, AR, alarm); + } + + /* reset the timer, and re-enable interrupts */ + rtt_writel(rtc, MR, mr | AT91_RTT_RTTRST); + + return 0; +} + +static int at91_rtc_readalarm(struct device *dev, struct rtc_wkalrm *alrm) +{ + struct sam9_rtc *rtc = dev_get_drvdata(dev); + struct rtc_time *tm = &alrm->time; + u32 alarm = rtt_readl(rtc, AR); + u32 offset; + + offset = gpbr_readl(rtc); + if (offset == 0) + return -EILSEQ; + + memset(alrm, 0, sizeof(alrm)); + if (alarm != ALARM_DISABLED && offset != 0) { + rtc_time_to_tm(offset + alarm, tm); + + dev_dbg(dev, "%s: %4d-%02d-%02d %02d:%02d:%02d\n", "readalarm", + 1900 + tm->tm_year, tm->tm_mon, tm->tm_mday, + tm->tm_hour, tm->tm_min, tm->tm_sec); + + if (rtt_readl(rtc, MR) & AT91_RTT_ALMIEN) + alrm->enabled = 1; + } + + return 0; +} + +static int at91_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm) +{ + struct sam9_rtc *rtc = dev_get_drvdata(dev); + struct rtc_time *tm = &alrm->time; + unsigned long secs; + u32 offset; + u32 mr; + int err; + + err = rtc_tm_to_time(tm, &secs); + if (err != 0) + return err; + + offset = gpbr_readl(rtc); + if (offset == 0) { + /* time is not set */ + return -EILSEQ; + } + mr = rtt_readl(rtc, MR); + rtt_writel(rtc, MR, mr & ~AT91_RTT_ALMIEN); + + /* alarm in the past? finish and leave disabled */ + if (secs <= offset) { + rtt_writel(rtc, AR, ALARM_DISABLED); + return 0; + } + + /* else set alarm and maybe enable it */ + rtt_writel(rtc, AR, secs - offset); + if (alrm->enabled) + rtt_writel(rtc, MR, mr | AT91_RTT_ALMIEN); + + dev_dbg(dev, "%s: %4d-%02d-%02d %02d:%02d:%02d\n", "setalarm", + tm->tm_year, tm->tm_mon, tm->tm_mday, tm->tm_hour, + tm->tm_min, tm->tm_sec); + + return 0; +} + +/* + * Handle commands from user-space + */ +static int at91_rtc_ioctl(struct device *dev, unsigned int cmd, + unsigned long arg) +{ + struct sam9_rtc *rtc = dev_get_drvdata(dev); + int ret = 0; + u32 mr = rtt_readl(rtc, MR); + + dev_dbg(dev, "ioctl: cmd=%08x, arg=%08lx, mr %08x\n", cmd, arg, mr); + + switch (cmd) { + case RTC_AIE_OFF: /* alarm off */ + rtt_writel(rtc, MR, mr & ~AT91_RTT_ALMIEN); + break; + case RTC_AIE_ON: /* alarm on */ + rtt_writel(rtc, MR, mr | AT91_RTT_ALMIEN); + break; + case RTC_UIE_OFF: /* update off */ + rtt_writel(rtc, MR, mr & ~AT91_RTT_RTTINCIEN); + break; + case RTC_UIE_ON: /* update on */ + rtt_writel(rtc, MR, mr | AT91_RTT_RTTINCIEN); + break; + default: + ret = -ENOIOCTLCMD; + break; + } + + return ret; +} + +/* + * Provide additional RTC information in /proc/driver/rtc + */ +static int at91_rtc_proc(struct device *dev, struct seq_file *seq) +{ + struct sam9_rtc *rtc = dev_get_drvdata(dev); + u32 mr = mr = rtt_readl(rtc, MR); + + seq_printf(seq, "update_IRQ\t: %s\n", + (mr & AT91_RTT_RTTINCIEN) ? "yes" : "no"); + return 0; +} + +/* + * IRQ handler for the RTC + */ +static irqreturn_t at91_rtc_interrupt(int irq, void *_rtc) +{ + struct sam9_rtc *rtc = _rtc; + u32 sr, mr; + unsigned long events = 0; + + /* Shared interrupt may be for another device. Note: reading + * SR clears it, so we must only read it in this irq handler! + */ + mr = rtt_readl(rtc, MR) & (AT91_RTT_ALMIEN | AT91_RTT_RTTINCIEN); + sr = rtt_readl(rtc, SR) & mr; + if (!sr) + return IRQ_NONE; + + /* alarm status */ + if (sr & AT91_RTT_ALMS) + events |= (RTC_AF | RTC_IRQF); + + /* timer update/increment */ + if (sr & AT91_RTT_RTTINC) + events |= (RTC_UF | RTC_IRQF); + + rtc_update_irq(rtc->rtcdev, 1, events); + + pr_debug("%s: num=%ld, events=0x%02lx\n", __FUNCTION__, + events >> 8, events & 0x000000FF); + + return IRQ_HANDLED; +} + +static const struct rtc_class_ops at91_rtc_ops = { + .ioctl = at91_rtc_ioctl, + .read_time = at91_rtc_readtime, + .set_time = at91_rtc_settime, + .read_alarm = at91_rtc_readalarm, + .set_alarm = at91_rtc_setalarm, + .proc = at91_rtc_proc, +}; + +/* + * Initialize and install RTC driver + */ +static int __init at91_rtc_probe(struct platform_device *pdev) +{ + struct resource *r; + struct sam9_rtc *rtc; + int ret; + u32 mr; + + r = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!r) + return -ENODEV; + + rtc = kzalloc(sizeof *rtc, GFP_KERNEL); + if (!rtc) + return -ENOMEM; + + platform_set_drvdata(pdev, rtc); + rtc->rtt = (void __force __iomem *) (AT91_VA_BASE_SYS - AT91_BASE_SYS); + rtc->rtt += r->start; + + mr = rtt_readl(rtc, MR); + + /* unless RTT is counting at 1 Hz, re-initialize it */ + if ((mr & AT91_RTT_RTPRES) != AT91_SLOW_CLOCK) { + mr = AT91_RTT_RTTRST | (AT91_SLOW_CLOCK & AT91_RTT_RTPRES); + gpbr_writel(rtc, 0); + } + + /* disable all interrupts (same as on shutdown path) */ + mr &= ~(AT91_RTT_ALMIEN | AT91_RTT_RTTINCIEN); + rtt_writel(rtc, MR, mr); + + rtc->rtcdev = rtc_device_register(pdev->name, &pdev->dev, + &at91_rtc_ops, THIS_MODULE); + if (IS_ERR(rtc->rtcdev)) { + ret = PTR_ERR(rtc->rtcdev); + goto fail; + } + + /* register irq handler after we know what name we'll use */ + ret = request_irq(AT91_ID_SYS, at91_rtc_interrupt, + IRQF_DISABLED | IRQF_SHARED, + rtc->rtcdev->dev.bus_id, rtc); + if (ret) { + dev_dbg(&pdev->dev, "can't share IRQ %d?\n", AT91_ID_SYS); + rtc_device_unregister(rtc->rtcdev); + goto fail; + } + + /* NOTE: sam9260 rev A silicon has a ROM bug which resets the + * RTT on at least some reboots. If you have that chip, you must + * initialize the time from some external source like a GPS, wall + * clock, discrete RTC, etc + */ + + if (gpbr_readl(rtc) == 0) + dev_warn(&pdev->dev, "%s: SET TIME!\n", + rtc->rtcdev->dev.bus_id); + + return 0; + +fail: + platform_set_drvdata(pdev, NULL); + kfree(rtc); + return ret; +} + +/* + * Disable and remove the RTC driver + */ +static int __exit at91_rtc_remove(struct platform_device *pdev) +{ + struct sam9_rtc *rtc = platform_get_drvdata(pdev); + u32 mr = rtt_readl(rtc, MR); + + /* disable all interrupts */ + rtt_writel(rtc, MR, mr & ~(AT91_RTT_ALMIEN | AT91_RTT_RTTINCIEN)); + free_irq(AT91_ID_SYS, rtc); + + rtc_device_unregister(rtc->rtcdev); + + platform_set_drvdata(pdev, NULL); + kfree(rtc); + return 0; +} + +static void at91_rtc_shutdown(struct platform_device *pdev) +{ + struct sam9_rtc *rtc = platform_get_drvdata(pdev); + u32 mr = rtt_readl(rtc, MR); + + rtc->imr = mr & (AT91_RTT_ALMIEN | AT91_RTT_RTTINCIEN); + rtt_writel(rtc, MR, mr & ~rtc->imr); +} + +#ifdef CONFIG_PM + +/* AT91SAM9 RTC Power management control */ + +static int at91_rtc_suspend(struct platform_device *pdev, + pm_message_t state) +{ + struct sam9_rtc *rtc = platform_get_drvdata(pdev); + u32 mr = rtt_readl(rtc, MR); + + /* + * This IRQ is shared with DBGU and other hardware which isn't + * necessarily a wakeup event source. + */ + rtc->imr = mr & (AT91_RTT_ALMIEN | AT91_RTT_RTTINCIEN); + if (rtc->imr) { + if (device_may_wakeup(&pdev->dev) && (mr & AT91_RTT_ALMIEN)) { + enable_irq_wake(AT91_ID_SYS); + /* don't let RTTINC cause wakeups */ + if (mr & AT91_RTT_RTTINCIEN) + rtt_writel(rtc, MR, mr & ~AT91_RTT_RTTINCIEN); + } else + rtt_writel(rtc, MR, mr & ~rtc->imr); + } + + return 0; +} + +static int at91_rtc_resume(struct platform_device *pdev) +{ + struct sam9_rtc *rtc = platform_get_drvdata(pdev); + u32 mr; + + if (rtc->imr) { + if (device_may_wakeup(&pdev->dev)) + disable_irq_wake(AT91_ID_SYS); + mr = rtt_readl(rtc, MR); + rtt_writel(rtc, MR, mr | rtc->imr); + } + + return 0; +} +#else +#define at91_rtc_suspend NULL +#define at91_rtc_resume NULL +#endif + +static struct platform_driver at91_rtc_driver = { + .driver.name = "rtc-at91sam9", + .driver.owner = THIS_MODULE, + .remove = __exit_p(at91_rtc_remove), + .shutdown = at91_rtc_shutdown, + .suspend = at91_rtc_suspend, + .resume = at91_rtc_resume, +}; + +/* Chips can have more than one RTT module, and they can be used for more + * than just RTCs. So we can't just register as "the" RTT driver. + * + * A normal approach in such cases is to create a library to allocate and + * free the modules. Here we just use bus_find_device() as like such a + * library, binding directly ... no runtime "library" footprint is needed. + */ +static int __init at91_rtc_match(struct device *dev, void *v) +{ + struct platform_device *pdev = to_platform_device(dev); + int ret; + + /* continue searching if this isn't the RTT we need */ + if (strcmp("at91_rtt", pdev->name) != 0 + || pdev->id != CONFIG_RTC_DRV_AT91SAM9_RTT) + goto fail; + + /* else we found it ... but fail unless we can bind to the RTC driver */ + if (dev->driver) { + dev_dbg(dev, "busy, can't use as RTC!\n"); + goto fail; + } + dev->driver = &at91_rtc_driver.driver; + if (device_attach(dev) == 0) { + dev_dbg(dev, "can't attach RTC!\n"); + goto fail; + } + ret = at91_rtc_probe(pdev); + if (ret == 0) + return true; + + dev_dbg(dev, "RTC probe err %d!\n", ret); +fail: + return false; +} + +static int __init at91_rtc_init(void) +{ + int status; + struct device *rtc; + + status = platform_driver_register(&at91_rtc_driver); + if (status) + return status; + rtc = bus_find_device(&platform_bus_type, NULL, + NULL, at91_rtc_match); + if (!rtc) + platform_driver_unregister(&at91_rtc_driver); + return rtc ? 0 : -ENODEV; +} +module_init(at91_rtc_init); + +static void __exit at91_rtc_exit(void) +{ + platform_driver_unregister(&at91_rtc_driver); +} +module_exit(at91_rtc_exit); + + +MODULE_AUTHOR("Michel Benoit"); +MODULE_DESCRIPTION("RTC driver for Atmel AT91SAM9x"); +MODULE_LICENSE("GPL"); diff --git a/drivers/rtc/rtc-bfin.c b/drivers/rtc/rtc-bfin.c index 1aa709dda0d6..d90ba860d216 100644 --- a/drivers/rtc/rtc-bfin.c +++ b/drivers/rtc/rtc-bfin.c @@ -1,6 +1,6 @@ /* * Blackfin On-Chip Real Time Clock Driver - * Supports BF53[123]/BF53[467]/BF54[2489] + * Supports BF52[257]/BF53[123]/BF53[467]/BF54[24789] * * Copyright 2004-2007 Analog Devices Inc. * @@ -32,26 +32,25 @@ * writes to clear status registers complete immediately. */ -#include <linux/module.h> -#include <linux/kernel.h> #include <linux/bcd.h> -#include <linux/rtc.h> +#include <linux/completion.h> +#include <linux/delay.h> #include <linux/init.h> +#include <linux/interrupt.h> +#include <linux/kernel.h> +#include <linux/module.h> #include <linux/platform_device.h> +#include <linux/rtc.h> #include <linux/seq_file.h> -#include <linux/interrupt.h> -#include <linux/spinlock.h> -#include <linux/delay.h> #include <asm/blackfin.h> -#define stamp(fmt, args...) pr_debug("%s:%i: " fmt "\n", __FUNCTION__, __LINE__, ## args) -#define stampit() stamp("here i am") +#define dev_dbg_stamp(dev) dev_dbg(dev, "%s:%i: here i am\n", __func__, __LINE__) struct bfin_rtc { struct rtc_device *rtc_dev; struct rtc_time rtc_alarm; - spinlock_t lock; + u16 rtc_wrote_regs; }; /* Bit values for the ISTAT / ICTL registers */ @@ -72,7 +71,7 @@ struct bfin_rtc { #define SEC_BITS_OFF 0 /* Some helper functions to convert between the common RTC notion of time - * and the internal Blackfin notion that is stored in 32bits. + * and the internal Blackfin notion that is encoded in 32bits. */ static inline u32 rtc_time_to_bfin(unsigned long now) { @@ -97,7 +96,10 @@ static inline void rtc_bfin_to_tm(u32 rtc_bfin, struct rtc_time *tm) rtc_time_to_tm(rtc_bfin_to_time(rtc_bfin), tm); } -/* Wait for the previous write to a RTC register to complete. +/** + * bfin_rtc_sync_pending - make sure pending writes have complete + * + * Wait for the previous write to a RTC register to complete. * Unfortunately, we can't sleep here as that introduces a race condition when * turning on interrupt events. Consider this: * - process sets alarm @@ -112,188 +114,202 @@ static inline void rtc_bfin_to_tm(u32 rtc_bfin, struct rtc_time *tm) * If anyone can point out the obvious solution here, i'm listening :). This * shouldn't be an issue on an SMP or preempt system as this function should * only be called with the rtc lock held. + * + * Other options: + * - disable PREN so the sync happens at 32.768kHZ ... but this changes the + * inc rate for all RTC registers from 1HZ to 32.768kHZ ... + * - use the write complete IRQ */ -static void rtc_bfin_sync_pending(void) +/* +static void bfin_rtc_sync_pending_polled(void) { - stampit(); - while (!(bfin_read_RTC_ISTAT() & RTC_ISTAT_WRITE_COMPLETE)) { + while (!(bfin_read_RTC_ISTAT() & RTC_ISTAT_WRITE_COMPLETE)) if (!(bfin_read_RTC_ISTAT() & RTC_ISTAT_WRITE_PENDING)) break; - } bfin_write_RTC_ISTAT(RTC_ISTAT_WRITE_COMPLETE); } +*/ +static DECLARE_COMPLETION(bfin_write_complete); +static void bfin_rtc_sync_pending(struct device *dev) +{ + dev_dbg_stamp(dev); + while (bfin_read_RTC_ISTAT() & RTC_ISTAT_WRITE_PENDING) + wait_for_completion_timeout(&bfin_write_complete, HZ * 5); + dev_dbg_stamp(dev); +} -static void rtc_bfin_reset(struct bfin_rtc *rtc) +/** + * bfin_rtc_reset - set RTC to sane/known state + * + * Initialize the RTC. Enable pre-scaler to scale RTC clock + * to 1Hz and clear interrupt/status registers. + */ +static void bfin_rtc_reset(struct device *dev) { - /* Initialize the RTC. Enable pre-scaler to scale RTC clock - * to 1Hz and clear interrupt/status registers. */ - spin_lock_irq(&rtc->lock); - rtc_bfin_sync_pending(); + struct bfin_rtc *rtc = dev_get_drvdata(dev); + dev_dbg_stamp(dev); + bfin_rtc_sync_pending(dev); bfin_write_RTC_PREN(0x1); - bfin_write_RTC_ICTL(0); + bfin_write_RTC_ICTL(RTC_ISTAT_WRITE_COMPLETE); bfin_write_RTC_SWCNT(0); bfin_write_RTC_ALARM(0); bfin_write_RTC_ISTAT(0xFFFF); - spin_unlock_irq(&rtc->lock); + rtc->rtc_wrote_regs = 0; } +/** + * bfin_rtc_interrupt - handle interrupt from RTC + * + * Since we handle all RTC events here, we have to make sure the requested + * interrupt is enabled (in RTC_ICTL) as the event status register (RTC_ISTAT) + * always gets updated regardless of the interrupt being enabled. So when one + * even we care about (e.g. stopwatch) goes off, we don't want to turn around + * and say that other events have happened as well (e.g. second). We do not + * have to worry about pending writes to the RTC_ICTL register as interrupts + * only fire if they are enabled in the RTC_ICTL register. + */ static irqreturn_t bfin_rtc_interrupt(int irq, void *dev_id) { - struct platform_device *pdev = to_platform_device(dev_id); - struct bfin_rtc *rtc = platform_get_drvdata(pdev); + struct device *dev = dev_id; + struct bfin_rtc *rtc = dev_get_drvdata(dev); unsigned long events = 0; - u16 rtc_istat; - - stampit(); + bool write_complete = false; + u16 rtc_istat, rtc_ictl; - spin_lock_irq(&rtc->lock); + dev_dbg_stamp(dev); rtc_istat = bfin_read_RTC_ISTAT(); + rtc_ictl = bfin_read_RTC_ICTL(); - if (rtc_istat & (RTC_ISTAT_ALARM | RTC_ISTAT_ALARM_DAY)) { - bfin_write_RTC_ISTAT(RTC_ISTAT_ALARM | RTC_ISTAT_ALARM_DAY); - events |= RTC_AF | RTC_IRQF; + if (rtc_istat & RTC_ISTAT_WRITE_COMPLETE) { + bfin_write_RTC_ISTAT(RTC_ISTAT_WRITE_COMPLETE); + write_complete = true; + complete(&bfin_write_complete); } - if (rtc_istat & RTC_ISTAT_STOPWATCH) { - bfin_write_RTC_ISTAT(RTC_ISTAT_STOPWATCH); - events |= RTC_PF | RTC_IRQF; - bfin_write_RTC_SWCNT(rtc->rtc_dev->irq_freq); + if (rtc_ictl & (RTC_ISTAT_ALARM | RTC_ISTAT_ALARM_DAY)) { + if (rtc_istat & (RTC_ISTAT_ALARM | RTC_ISTAT_ALARM_DAY)) { + bfin_write_RTC_ISTAT(RTC_ISTAT_ALARM | RTC_ISTAT_ALARM_DAY); + events |= RTC_AF | RTC_IRQF; + } } - if (rtc_istat & RTC_ISTAT_SEC) { - bfin_write_RTC_ISTAT(RTC_ISTAT_SEC); - events |= RTC_UF | RTC_IRQF; + if (rtc_ictl & RTC_ISTAT_STOPWATCH) { + if (rtc_istat & RTC_ISTAT_STOPWATCH) { + bfin_write_RTC_ISTAT(RTC_ISTAT_STOPWATCH); + events |= RTC_PF | RTC_IRQF; + bfin_write_RTC_SWCNT(rtc->rtc_dev->irq_freq); + } } - rtc_update_irq(rtc->rtc_dev, 1, events); + if (rtc_ictl & RTC_ISTAT_SEC) { + if (rtc_istat & RTC_ISTAT_SEC) { + bfin_write_RTC_ISTAT(RTC_ISTAT_SEC); + events |= RTC_UF | RTC_IRQF; + } + } - spin_unlock_irq(&rtc->lock); + if (events) + rtc_update_irq(rtc->rtc_dev, 1, events); - return IRQ_HANDLED; + if (write_complete || events) + return IRQ_HANDLED; + else + return IRQ_NONE; } static int bfin_rtc_open(struct device *dev) { - struct bfin_rtc *rtc = dev_get_drvdata(dev); int ret; - stampit(); + dev_dbg_stamp(dev); - ret = request_irq(IRQ_RTC, bfin_rtc_interrupt, IRQF_DISABLED, "rtc-bfin", dev); - if (unlikely(ret)) { - dev_err(dev, "request RTC IRQ failed with %d\n", ret); - return ret; - } - - rtc_bfin_reset(rtc); + ret = request_irq(IRQ_RTC, bfin_rtc_interrupt, IRQF_SHARED, to_platform_device(dev)->name, dev); + if (!ret) + bfin_rtc_reset(dev); return ret; } static void bfin_rtc_release(struct device *dev) { - struct bfin_rtc *rtc = dev_get_drvdata(dev); - stampit(); - rtc_bfin_reset(rtc); + dev_dbg_stamp(dev); + bfin_rtc_reset(dev); free_irq(IRQ_RTC, dev); } +static void bfin_rtc_int_set(struct bfin_rtc *rtc, u16 rtc_int) +{ + bfin_write_RTC_ISTAT(rtc_int); + bfin_write_RTC_ICTL(bfin_read_RTC_ICTL() | rtc_int); +} +static void bfin_rtc_int_clear(struct bfin_rtc *rtc, u16 rtc_int) +{ + bfin_write_RTC_ICTL(bfin_read_RTC_ICTL() & rtc_int); +} +static void bfin_rtc_int_set_alarm(struct bfin_rtc *rtc) +{ + /* Blackfin has different bits for whether the alarm is + * more than 24 hours away. + */ + bfin_rtc_int_set(rtc, (rtc->rtc_alarm.tm_yday == -1 ? RTC_ISTAT_ALARM : RTC_ISTAT_ALARM_DAY)); +} static int bfin_rtc_ioctl(struct device *dev, unsigned int cmd, unsigned long arg) { struct bfin_rtc *rtc = dev_get_drvdata(dev); + int ret = 0; + + dev_dbg_stamp(dev); - stampit(); + bfin_rtc_sync_pending(dev); switch (cmd) { case RTC_PIE_ON: - stampit(); - spin_lock_irq(&rtc->lock); - rtc_bfin_sync_pending(); - bfin_write_RTC_ISTAT(RTC_ISTAT_STOPWATCH); + dev_dbg_stamp(dev); + bfin_rtc_int_set(rtc, RTC_ISTAT_STOPWATCH); bfin_write_RTC_SWCNT(rtc->rtc_dev->irq_freq); - bfin_write_RTC_ICTL(bfin_read_RTC_ICTL() | RTC_ISTAT_STOPWATCH); - spin_unlock_irq(&rtc->lock); - return 0; + break; case RTC_PIE_OFF: - stampit(); - spin_lock_irq(&rtc->lock); - rtc_bfin_sync_pending(); - bfin_write_RTC_SWCNT(0); - bfin_write_RTC_ICTL(bfin_read_RTC_ICTL() & ~RTC_ISTAT_STOPWATCH); - spin_unlock_irq(&rtc->lock); - return 0; + dev_dbg_stamp(dev); + bfin_rtc_int_clear(rtc, ~RTC_ISTAT_STOPWATCH); + break; case RTC_UIE_ON: - stampit(); - spin_lock_irq(&rtc->lock); - rtc_bfin_sync_pending(); - bfin_write_RTC_ISTAT(RTC_ISTAT_SEC); - bfin_write_RTC_ICTL(bfin_read_RTC_ICTL() | RTC_ISTAT_SEC); - spin_unlock_irq(&rtc->lock); - return 0; + dev_dbg_stamp(dev); + bfin_rtc_int_set(rtc, RTC_ISTAT_SEC); + break; case RTC_UIE_OFF: - stampit(); - spin_lock_irq(&rtc->lock); - rtc_bfin_sync_pending(); - bfin_write_RTC_ICTL(bfin_read_RTC_ICTL() & ~RTC_ISTAT_SEC); - spin_unlock_irq(&rtc->lock); - return 0; - - case RTC_AIE_ON: { - unsigned long rtc_alarm; - u16 which_alarm; - int ret = 0; - - stampit(); - - spin_lock_irq(&rtc->lock); - - rtc_bfin_sync_pending(); - if (rtc->rtc_alarm.tm_yday == -1) { - struct rtc_time now; - rtc_bfin_to_tm(bfin_read_RTC_STAT(), &now); - now.tm_sec = rtc->rtc_alarm.tm_sec; - now.tm_min = rtc->rtc_alarm.tm_min; - now.tm_hour = rtc->rtc_alarm.tm_hour; - ret = rtc_tm_to_time(&now, &rtc_alarm); - which_alarm = RTC_ISTAT_ALARM; - } else { - ret = rtc_tm_to_time(&rtc->rtc_alarm, &rtc_alarm); - which_alarm = RTC_ISTAT_ALARM_DAY; - } - if (ret == 0) { - bfin_write_RTC_ISTAT(which_alarm); - bfin_write_RTC_ALARM(rtc_time_to_bfin(rtc_alarm)); - bfin_write_RTC_ICTL(bfin_read_RTC_ICTL() | which_alarm); - } - - spin_unlock_irq(&rtc->lock); - - return ret; - } + dev_dbg_stamp(dev); + bfin_rtc_int_clear(rtc, ~RTC_ISTAT_SEC); + break; + + case RTC_AIE_ON: + dev_dbg_stamp(dev); + bfin_rtc_int_set_alarm(rtc); + break; case RTC_AIE_OFF: - stampit(); - spin_lock_irq(&rtc->lock); - rtc_bfin_sync_pending(); - bfin_write_RTC_ICTL(bfin_read_RTC_ICTL() & ~(RTC_ISTAT_ALARM | RTC_ISTAT_ALARM_DAY)); - spin_unlock_irq(&rtc->lock); - return 0; + dev_dbg_stamp(dev); + bfin_rtc_int_clear(rtc, ~(RTC_ISTAT_ALARM | RTC_ISTAT_ALARM_DAY)); + break; + + default: + dev_dbg_stamp(dev); + ret = -ENOIOCTLCMD; } - return -ENOIOCTLCMD; + return ret; } static int bfin_rtc_read_time(struct device *dev, struct rtc_time *tm) { struct bfin_rtc *rtc = dev_get_drvdata(dev); - stampit(); + dev_dbg_stamp(dev); + + if (rtc->rtc_wrote_regs & 0x1) + bfin_rtc_sync_pending(dev); - spin_lock_irq(&rtc->lock); - rtc_bfin_sync_pending(); rtc_bfin_to_tm(bfin_read_RTC_STAT(), tm); - spin_unlock_irq(&rtc->lock); return 0; } @@ -304,64 +320,79 @@ static int bfin_rtc_set_time(struct device *dev, struct rtc_time *tm) int ret; unsigned long now; - stampit(); - - spin_lock_irq(&rtc->lock); + dev_dbg_stamp(dev); ret = rtc_tm_to_time(tm, &now); if (ret == 0) { - rtc_bfin_sync_pending(); + if (rtc->rtc_wrote_regs & 0x1) + bfin_rtc_sync_pending(dev); bfin_write_RTC_STAT(rtc_time_to_bfin(now)); + rtc->rtc_wrote_regs = 0x1; } - spin_unlock_irq(&rtc->lock); - return ret; } static int bfin_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm) { struct bfin_rtc *rtc = dev_get_drvdata(dev); - stampit(); - memcpy(&alrm->time, &rtc->rtc_alarm, sizeof(struct rtc_time)); - alrm->pending = !!(bfin_read_RTC_ICTL() & (RTC_ISTAT_ALARM | RTC_ISTAT_ALARM_DAY)); + dev_dbg_stamp(dev); + alrm->time = rtc->rtc_alarm; + bfin_rtc_sync_pending(dev); + alrm->enabled = !!(bfin_read_RTC_ICTL() & (RTC_ISTAT_ALARM | RTC_ISTAT_ALARM_DAY)); return 0; } static int bfin_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) { struct bfin_rtc *rtc = dev_get_drvdata(dev); - stampit(); - memcpy(&rtc->rtc_alarm, &alrm->time, sizeof(struct rtc_time)); + unsigned long rtc_alarm; + + dev_dbg_stamp(dev); + + if (rtc_tm_to_time(&alrm->time, &rtc_alarm)) + return -EINVAL; + + rtc->rtc_alarm = alrm->time; + + bfin_rtc_sync_pending(dev); + bfin_write_RTC_ALARM(rtc_time_to_bfin(rtc_alarm)); + if (alrm->enabled) + bfin_rtc_int_set_alarm(rtc); + return 0; } static int bfin_rtc_proc(struct device *dev, struct seq_file *seq) { -#define yesno(x) (x ? "yes" : "no") +#define yesno(x) ((x) ? "yes" : "no") u16 ictl = bfin_read_RTC_ICTL(); - stampit(); - seq_printf(seq, "alarm_IRQ\t: %s\n", yesno(ictl & RTC_ISTAT_ALARM)); - seq_printf(seq, "wkalarm_IRQ\t: %s\n", yesno(ictl & RTC_ISTAT_ALARM_DAY)); - seq_printf(seq, "seconds_IRQ\t: %s\n", yesno(ictl & RTC_ISTAT_SEC)); - seq_printf(seq, "periodic_IRQ\t: %s\n", yesno(ictl & RTC_ISTAT_STOPWATCH)); -#ifdef DEBUG - seq_printf(seq, "RTC_STAT\t: 0x%08X\n", bfin_read_RTC_STAT()); - seq_printf(seq, "RTC_ICTL\t: 0x%04X\n", bfin_read_RTC_ICTL()); - seq_printf(seq, "RTC_ISTAT\t: 0x%04X\n", bfin_read_RTC_ISTAT()); - seq_printf(seq, "RTC_SWCNT\t: 0x%04X\n", bfin_read_RTC_SWCNT()); - seq_printf(seq, "RTC_ALARM\t: 0x%08X\n", bfin_read_RTC_ALARM()); - seq_printf(seq, "RTC_PREN\t: 0x%04X\n", bfin_read_RTC_PREN()); -#endif + dev_dbg_stamp(dev); + seq_printf(seq, + "alarm_IRQ\t: %s\n" + "wkalarm_IRQ\t: %s\n" + "seconds_IRQ\t: %s\n" + "periodic_IRQ\t: %s\n", + yesno(ictl & RTC_ISTAT_ALARM), + yesno(ictl & RTC_ISTAT_ALARM_DAY), + yesno(ictl & RTC_ISTAT_SEC), + yesno(ictl & RTC_ISTAT_STOPWATCH)); return 0; +#undef yesno } +/** + * bfin_irq_set_freq - make sure hardware supports requested freq + * @dev: pointer to RTC device structure + * @freq: requested frequency rate + * + * The Blackfin RTC can only generate periodic events at 1 per + * second (1 Hz), so reject any attempt at changing it. + */ static int bfin_irq_set_freq(struct device *dev, int freq) { - struct bfin_rtc *rtc = dev_get_drvdata(dev); - stampit(); - rtc->rtc_dev->irq_freq = freq; - return 0; + dev_dbg_stamp(dev); + return -ENOTTY; } static struct rtc_class_ops bfin_rtc_ops = { @@ -381,27 +412,24 @@ static int __devinit bfin_rtc_probe(struct platform_device *pdev) struct bfin_rtc *rtc; int ret = 0; - stampit(); + dev_dbg_stamp(&pdev->dev); rtc = kzalloc(sizeof(*rtc), GFP_KERNEL); if (unlikely(!rtc)) return -ENOMEM; - spin_lock_init(&rtc->lock); - rtc->rtc_dev = rtc_device_register(pdev->name, &pdev->dev, &bfin_rtc_ops, THIS_MODULE); if (unlikely(IS_ERR(rtc))) { ret = PTR_ERR(rtc->rtc_dev); goto err; } - rtc->rtc_dev->irq_freq = 0; - rtc->rtc_dev->max_user_freq = (2 << 16); /* stopwatch is an unsigned 16 bit reg */ + rtc->rtc_dev->irq_freq = 1; platform_set_drvdata(pdev, rtc); return 0; -err: + err: kfree(rtc); return ret; } @@ -428,7 +456,6 @@ static struct platform_driver bfin_rtc_driver = { static int __init bfin_rtc_init(void) { - stampit(); return platform_driver_register(&bfin_rtc_driver); } diff --git a/drivers/rtc/rtc-cmos.c b/drivers/rtc/rtc-cmos.c index 29cf1457ca10..e059f94c79eb 100644 --- a/drivers/rtc/rtc-cmos.c +++ b/drivers/rtc/rtc-cmos.c @@ -36,9 +36,24 @@ #include <linux/platform_device.h> #include <linux/mod_devicetable.h> +#ifdef CONFIG_HPET_EMULATE_RTC +#include <asm/hpet.h> +#endif + /* this is for "generic access to PC-style RTC" using CMOS_READ/CMOS_WRITE */ #include <asm-generic/rtc.h> +#ifndef CONFIG_HPET_EMULATE_RTC +#define is_hpet_enabled() 0 +#define hpet_set_alarm_time(hrs, min, sec) do { } while (0) +#define hpet_set_periodic_freq(arg) 0 +#define hpet_mask_rtc_irq_bit(arg) do { } while (0) +#define hpet_set_rtc_irq_bit(arg) do { } while (0) +#define hpet_rtc_timer_init() do { } while (0) +#define hpet_register_irq_handler(h) 0 +#define hpet_unregister_irq_handler(h) do { } while (0) +extern irqreturn_t hpet_rtc_interrupt(int irq, void *dev_id); +#endif struct cmos_rtc { struct rtc_device *rtc; @@ -199,6 +214,7 @@ static int cmos_set_alarm(struct device *dev, struct rtc_wkalrm *t) sec = t->time.tm_sec; sec = (sec < 60) ? BIN2BCD(sec) : 0xff; + hpet_set_alarm_time(t->time.tm_hour, t->time.tm_min, t->time.tm_sec); spin_lock_irq(&rtc_lock); /* next rtc irq must not be from previous alarm setting */ @@ -252,7 +268,8 @@ static int cmos_irq_set_freq(struct device *dev, int freq) f = 16 - f; spin_lock_irqsave(&rtc_lock, flags); - CMOS_WRITE(RTC_REF_CLCK_32KHZ | f, RTC_FREQ_SELECT); + if (!hpet_set_periodic_freq(freq)) + CMOS_WRITE(RTC_REF_CLCK_32KHZ | f, RTC_FREQ_SELECT); spin_unlock_irqrestore(&rtc_lock, flags); return 0; @@ -314,28 +331,37 @@ cmos_rtc_ioctl(struct device *dev, unsigned int cmd, unsigned long arg) switch (cmd) { case RTC_AIE_OFF: /* alarm off */ rtc_control &= ~RTC_AIE; + hpet_mask_rtc_irq_bit(RTC_AIE); break; case RTC_AIE_ON: /* alarm on */ rtc_control |= RTC_AIE; + hpet_set_rtc_irq_bit(RTC_AIE); break; case RTC_UIE_OFF: /* update off */ rtc_control &= ~RTC_UIE; + hpet_mask_rtc_irq_bit(RTC_UIE); break; case RTC_UIE_ON: /* update on */ rtc_control |= RTC_UIE; + hpet_set_rtc_irq_bit(RTC_UIE); break; case RTC_PIE_OFF: /* periodic off */ rtc_control &= ~RTC_PIE; + hpet_mask_rtc_irq_bit(RTC_PIE); break; case RTC_PIE_ON: /* periodic on */ rtc_control |= RTC_PIE; + hpet_set_rtc_irq_bit(RTC_PIE); break; } - CMOS_WRITE(rtc_control, RTC_CONTROL); + if (!is_hpet_enabled()) + CMOS_WRITE(rtc_control, RTC_CONTROL); + rtc_intr = CMOS_READ(RTC_INTR_FLAGS); rtc_intr &= (rtc_control & RTC_IRQMASK) | RTC_IRQF; if (is_intr(rtc_intr)) rtc_update_irq(cmos->rtc, 1, rtc_intr); + spin_unlock_irqrestore(&rtc_lock, flags); return 0; } @@ -393,15 +419,111 @@ static const struct rtc_class_ops cmos_rtc_ops = { /*----------------------------------------------------------------*/ +/* + * All these chips have at least 64 bytes of address space, shared by + * RTC registers and NVRAM. Most of those bytes of NVRAM are used + * by boot firmware. Modern chips have 128 or 256 bytes. + */ + +#define NVRAM_OFFSET (RTC_REG_D + 1) + +static ssize_t +cmos_nvram_read(struct kobject *kobj, struct bin_attribute *attr, + char *buf, loff_t off, size_t count) +{ + int retval; + + if (unlikely(off >= attr->size)) + return 0; + if ((off + count) > attr->size) + count = attr->size - off; + + spin_lock_irq(&rtc_lock); + for (retval = 0, off += NVRAM_OFFSET; count--; retval++, off++) + *buf++ = CMOS_READ(off); + spin_unlock_irq(&rtc_lock); + + return retval; +} + +static ssize_t +cmos_nvram_write(struct kobject *kobj, struct bin_attribute *attr, + char *buf, loff_t off, size_t count) +{ + struct cmos_rtc *cmos; + int retval; + + cmos = dev_get_drvdata(container_of(kobj, struct device, kobj)); + if (unlikely(off >= attr->size)) + return -EFBIG; + if ((off + count) > attr->size) + count = attr->size - off; + + /* NOTE: on at least PCs and Ataris, the boot firmware uses a + * checksum on part of the NVRAM data. That's currently ignored + * here. If userspace is smart enough to know what fields of + * NVRAM to update, updating checksums is also part of its job. + */ + spin_lock_irq(&rtc_lock); + for (retval = 0, off += NVRAM_OFFSET; count--; retval++, off++) { + /* don't trash RTC registers */ + if (off == cmos->day_alrm + || off == cmos->mon_alrm + || off == cmos->century) + buf++; + else + CMOS_WRITE(*buf++, off); + } + spin_unlock_irq(&rtc_lock); + + return retval; +} + +static struct bin_attribute nvram = { + .attr = { + .name = "nvram", + .mode = S_IRUGO | S_IWUSR, + .owner = THIS_MODULE, + }, + + .read = cmos_nvram_read, + .write = cmos_nvram_write, + /* size gets set up later */ +}; + +/*----------------------------------------------------------------*/ + static struct cmos_rtc cmos_rtc; static irqreturn_t cmos_interrupt(int irq, void *p) { u8 irqstat; + u8 rtc_control; spin_lock(&rtc_lock); - irqstat = CMOS_READ(RTC_INTR_FLAGS); - irqstat &= (CMOS_READ(RTC_CONTROL) & RTC_IRQMASK) | RTC_IRQF; + /* + * In this case it is HPET RTC interrupt handler + * calling us, with the interrupt information + * passed as arg1, instead of irq. + */ + if (is_hpet_enabled()) + irqstat = (unsigned long)irq & 0xF0; + else { + irqstat = CMOS_READ(RTC_INTR_FLAGS); + rtc_control = CMOS_READ(RTC_CONTROL); + irqstat &= (rtc_control & RTC_IRQMASK) | RTC_IRQF; + } + + /* All Linux RTC alarms should be treated as if they were oneshot. + * Similar code may be needed in system wakeup paths, in case the + * alarm woke the system. + */ + if (irqstat & RTC_AIE) { + rtc_control = CMOS_READ(RTC_CONTROL); + rtc_control &= ~RTC_AIE; + CMOS_WRITE(rtc_control, RTC_CONTROL); + CMOS_READ(RTC_INTR_FLAGS); + } spin_unlock(&rtc_lock); if (is_intr(irqstat)) { @@ -412,11 +534,9 @@ static irqreturn_t cmos_interrupt(int irq, void *p) } #ifdef CONFIG_PNP -#define is_pnp() 1 #define INITSECTION #else -#define is_pnp() 0 #define INITSECTION __init #endif @@ -426,6 +546,7 @@ cmos_do_probe(struct device *dev, struct resource *ports, int rtc_irq) struct cmos_rtc_board_info *info = dev->platform_data; int retval = 0; unsigned char rtc_control; + unsigned address_space; /* there can be only one ... */ if (cmos_rtc.dev) @@ -450,15 +571,36 @@ cmos_do_probe(struct device *dev, struct resource *ports, int rtc_irq) cmos_rtc.irq = rtc_irq; cmos_rtc.iomem = ports; + /* Heuristic to deduce NVRAM size ... do what the legacy NVRAM + * driver did, but don't reject unknown configs. Old hardware + * won't address 128 bytes, and for now we ignore the way newer + * chips can address 256 bytes (using two more i/o ports). + */ +#if defined(CONFIG_ATARI) + address_space = 64; +#elif defined(__i386__) || defined(__x86_64__) || defined(__arm__) + address_space = 128; +#else +#warning Assuming 128 bytes of RTC+NVRAM address space, not 64 bytes. + address_space = 128; +#endif + /* For ACPI systems extension info comes from the FADT. On others, * board specific setup provides it as appropriate. Systems where * the alarm IRQ isn't automatically a wakeup IRQ (like ACPI, and * some almost-clones) can provide hooks to make that behave. + * + * Note that ACPI doesn't preclude putting these registers into + * "extended" areas of the chip, including some that we won't yet + * expect CMOS_READ and friends to handle. */ if (info) { - cmos_rtc.day_alrm = info->rtc_day_alarm; - cmos_rtc.mon_alrm = info->rtc_mon_alarm; - cmos_rtc.century = info->rtc_century; + if (info->rtc_day_alarm && info->rtc_day_alarm < 128) + cmos_rtc.day_alrm = info->rtc_day_alarm; + if (info->rtc_mon_alarm && info->rtc_mon_alarm < 128) + cmos_rtc.mon_alrm = info->rtc_mon_alarm; + if (info->rtc_century && info->rtc_century < 128) + cmos_rtc.century = info->rtc_century; if (info->wake_on && info->wake_off) { cmos_rtc.wake_on = info->wake_on; @@ -485,8 +627,9 @@ cmos_do_probe(struct device *dev, struct resource *ports, int rtc_irq) * doesn't use 32KHz here ... for portability we might need to * do something about other clock frequencies. */ - CMOS_WRITE(RTC_REF_CLCK_32KHZ | 0x06, RTC_FREQ_SELECT); cmos_rtc.rtc->irq_freq = 1024; + if (!hpet_set_periodic_freq(cmos_rtc.rtc->irq_freq)) + CMOS_WRITE(RTC_REF_CLCK_32KHZ | 0x06, RTC_FREQ_SELECT); /* disable irqs. * @@ -509,19 +652,39 @@ cmos_do_probe(struct device *dev, struct resource *ports, int rtc_irq) goto cleanup1; } - if (is_valid_irq(rtc_irq)) - retval = request_irq(rtc_irq, cmos_interrupt, IRQF_DISABLED, - cmos_rtc.rtc->dev.bus_id, + if (is_valid_irq(rtc_irq)) { + irq_handler_t rtc_cmos_int_handler; + + if (is_hpet_enabled()) { + int err; + + rtc_cmos_int_handler = hpet_rtc_interrupt; + err = hpet_register_irq_handler(cmos_interrupt); + if (err != 0) { + printk(KERN_WARNING "hpet_register_irq_handler " + " failed in rtc_init()."); + goto cleanup1; + } + } else + rtc_cmos_int_handler = cmos_interrupt; + + retval = request_irq(rtc_irq, rtc_cmos_int_handler, + IRQF_DISABLED, cmos_rtc.rtc->dev.bus_id, cmos_rtc.rtc); - if (retval < 0) { - dev_dbg(dev, "IRQ %d is already in use\n", rtc_irq); - goto cleanup1; + if (retval < 0) { + dev_dbg(dev, "IRQ %d is already in use\n", rtc_irq); + goto cleanup1; + } } + hpet_rtc_timer_init(); - /* REVISIT optionally make 50 or 114 bytes NVRAM available, - * like rtc-ds1553, rtc-ds1742 ... this will often include - * registers for century, and day/month alarm. - */ + /* export at least the first block of NVRAM */ + nvram.size = address_space - NVRAM_OFFSET; + retval = sysfs_create_bin_file(&dev->kobj, &nvram); + if (retval < 0) { + dev_dbg(dev, "can't create nvram file? %d\n", retval); + goto cleanup2; + } pr_info("%s: alarms up to one %s%s\n", cmos_rtc.rtc->dev.bus_id, @@ -536,6 +699,9 @@ cmos_do_probe(struct device *dev, struct resource *ports, int rtc_irq) return 0; +cleanup2: + if (is_valid_irq(rtc_irq)) + free_irq(rtc_irq, cmos_rtc.rtc); cleanup1: cmos_rtc.dev = NULL; rtc_device_unregister(cmos_rtc.rtc); @@ -563,8 +729,12 @@ static void __exit cmos_do_remove(struct device *dev) cmos_do_shutdown(); - if (is_valid_irq(cmos->irq)) + sysfs_remove_bin_file(&dev->kobj, &nvram); + + if (is_valid_irq(cmos->irq)) { free_irq(cmos->irq, cmos->rtc); + hpet_unregister_irq_handler(cmos_interrupt); + } rtc_device_unregister(cmos->rtc); cmos->rtc = NULL; @@ -659,9 +829,12 @@ static int cmos_resume(struct device *dev) /*----------------------------------------------------------------*/ -/* The "CMOS" RTC normally lives on the platform_bus. On ACPI systems, - * the device node will always be created as a PNPACPI device. Plus - * pre-ACPI PCs probably list it in the PNPBIOS tables. +/* On non-x86 systems, a "CMOS" RTC lives most naturally on platform_bus. + * ACPI systems always list these as PNPACPI devices, and pre-ACPI PCs + * probably list them in similar PNPBIOS tables; so PNP is more common. + * + * We don't use legacy "poke at the hardware" probing. Ancient PCs that + * predate even PNPBIOS should set up platform_bus devices. */ #ifdef CONFIG_PNP diff --git a/drivers/rtc/rtc-dev.c b/drivers/rtc/rtc-dev.c index 025c60a17a4a..90dfa0df747a 100644 --- a/drivers/rtc/rtc-dev.c +++ b/drivers/rtc/rtc-dev.c @@ -246,6 +246,15 @@ static int rtc_dev_ioctl(struct inode *inode, struct file *file, /* if the driver does not provide the ioctl interface * or if that particular ioctl was not implemented * (-ENOIOCTLCMD), we will try to emulate here. + * + * Drivers *SHOULD NOT* provide ioctl implementations + * for these requests. Instead, provide methods to + * support the following code, so that the RTC's main + * features are accessible without using ioctls. + * + * RTC and alarm times will be in UTC, by preference, + * but dual-booting with MS-Windows implies RTCs must + * use the local wall clock time. */ switch (cmd) { diff --git a/drivers/rtc/rtc-ds1302.c b/drivers/rtc/rtc-ds1302.c new file mode 100644 index 000000000000..7b002ceeaa7d --- /dev/null +++ b/drivers/rtc/rtc-ds1302.c @@ -0,0 +1,262 @@ +/* + * Dallas DS1302 RTC Support + * + * Copyright (C) 2002 David McCullough + * Copyright (C) 2003 - 2007 Paul Mundt + * + * This file is subject to the terms and conditions of the GNU General Public + * License version 2. See the file "COPYING" in the main directory of + * this archive for more details. + */ +#include <linux/init.h> +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/platform_device.h> +#include <linux/time.h> +#include <linux/rtc.h> +#include <linux/spinlock.h> +#include <linux/io.h> +#include <linux/bcd.h> +#include <asm/rtc.h> + +#define DRV_NAME "rtc-ds1302" +#define DRV_VERSION "0.1.0" + +#define RTC_CMD_READ 0x81 /* Read command */ +#define RTC_CMD_WRITE 0x80 /* Write command */ + +#define RTC_ADDR_RAM0 0x20 /* Address of RAM0 */ +#define RTC_ADDR_TCR 0x08 /* Address of trickle charge register */ +#define RTC_ADDR_YEAR 0x06 /* Address of year register */ +#define RTC_ADDR_DAY 0x05 /* Address of day of week register */ +#define RTC_ADDR_MON 0x04 /* Address of month register */ +#define RTC_ADDR_DATE 0x03 /* Address of day of month register */ +#define RTC_ADDR_HOUR 0x02 /* Address of hour register */ +#define RTC_ADDR_MIN 0x01 /* Address of minute register */ +#define RTC_ADDR_SEC 0x00 /* Address of second register */ + +#define RTC_RESET 0x1000 +#define RTC_IODATA 0x0800 +#define RTC_SCLK 0x0400 + +#ifdef CONFIG_SH_SECUREEDGE5410 +#include <asm/snapgear.h> +#define set_dp(x) SECUREEDGE_WRITE_IOPORT(x, 0x1c00) +#define get_dp() SECUREEDGE_READ_IOPORT() +#else +#error "Add support for your platform" +#endif + +struct ds1302_rtc { + struct rtc_device *rtc_dev; + spinlock_t lock; +}; + +static void ds1302_sendbits(unsigned int val) +{ + int i; + + for (i = 8; (i); i--, val >>= 1) { + set_dp((get_dp() & ~RTC_IODATA) | ((val & 0x1) ? + RTC_IODATA : 0)); + set_dp(get_dp() | RTC_SCLK); /* clock high */ + set_dp(get_dp() & ~RTC_SCLK); /* clock low */ + } +} + +static unsigned int ds1302_recvbits(void) +{ + unsigned int val; + int i; + + for (i = 0, val = 0; (i < 8); i++) { + val |= (((get_dp() & RTC_IODATA) ? 1 : 0) << i); + set_dp(get_dp() | RTC_SCLK); /* clock high */ + set_dp(get_dp() & ~RTC_SCLK); /* clock low */ + } + + return val; +} + +static unsigned int ds1302_readbyte(unsigned int addr) +{ + unsigned int val; + + set_dp(get_dp() & ~(RTC_RESET | RTC_IODATA | RTC_SCLK)); + + set_dp(get_dp() | RTC_RESET); + ds1302_sendbits(((addr & 0x3f) << 1) | RTC_CMD_READ); + val = ds1302_recvbits(); + set_dp(get_dp() & ~RTC_RESET); + + return val; +} + +static void ds1302_writebyte(unsigned int addr, unsigned int val) +{ + set_dp(get_dp() & ~(RTC_RESET | RTC_IODATA | RTC_SCLK)); + set_dp(get_dp() | RTC_RESET); + ds1302_sendbits(((addr & 0x3f) << 1) | RTC_CMD_WRITE); + ds1302_sendbits(val); + set_dp(get_dp() & ~RTC_RESET); +} + +static int ds1302_rtc_read_time(struct device *dev, struct rtc_time *tm) +{ + struct ds1302_rtc *rtc = dev_get_drvdata(dev); + + spin_lock_irq(&rtc->lock); + + tm->tm_sec = BCD2BIN(ds1302_readbyte(RTC_ADDR_SEC)); + tm->tm_min = BCD2BIN(ds1302_readbyte(RTC_ADDR_MIN)); + tm->tm_hour = BCD2BIN(ds1302_readbyte(RTC_ADDR_HOUR)); + tm->tm_wday = BCD2BIN(ds1302_readbyte(RTC_ADDR_DAY)); + tm->tm_mday = BCD2BIN(ds1302_readbyte(RTC_ADDR_DATE)); + tm->tm_mon = BCD2BIN(ds1302_readbyte(RTC_ADDR_MON)) - 1; + tm->tm_year = BCD2BIN(ds1302_readbyte(RTC_ADDR_YEAR)); + + if (tm->tm_year < 70) + tm->tm_year += 100; + + spin_unlock_irq(&rtc->lock); + + dev_dbg(dev, "%s: tm is secs=%d, mins=%d, hours=%d, " + "mday=%d, mon=%d, year=%d, wday=%d\n", + __FUNCTION__, + tm->tm_sec, tm->tm_min, tm->tm_hour, + tm->tm_mday, tm->tm_mon + 1, tm->tm_year, tm->tm_wday); + + if (rtc_valid_tm(tm) < 0) + dev_err(dev, "invalid date\n"); + + return 0; +} + +static int ds1302_rtc_set_time(struct device *dev, struct rtc_time *tm) +{ + struct ds1302_rtc *rtc = dev_get_drvdata(dev); + + spin_lock_irq(&rtc->lock); + + /* Stop RTC */ + ds1302_writebyte(RTC_ADDR_SEC, ds1302_readbyte(RTC_ADDR_SEC) | 0x80); + + ds1302_writebyte(RTC_ADDR_SEC, BIN2BCD(tm->tm_sec)); + ds1302_writebyte(RTC_ADDR_MIN, BIN2BCD(tm->tm_min)); + ds1302_writebyte(RTC_ADDR_HOUR, BIN2BCD(tm->tm_hour)); + ds1302_writebyte(RTC_ADDR_DAY, BIN2BCD(tm->tm_wday)); + ds1302_writebyte(RTC_ADDR_DATE, BIN2BCD(tm->tm_mday)); + ds1302_writebyte(RTC_ADDR_MON, BIN2BCD(tm->tm_mon + 1)); + ds1302_writebyte(RTC_ADDR_YEAR, BIN2BCD(tm->tm_year % 100)); + + /* Start RTC */ + ds1302_writebyte(RTC_ADDR_SEC, ds1302_readbyte(RTC_ADDR_SEC) & ~0x80); + + spin_unlock_irq(&rtc->lock); + + return 0; +} + +static int ds1302_rtc_ioctl(struct device *dev, unsigned int cmd, + unsigned long arg) +{ + switch (cmd) { +#ifdef RTC_SET_CHARGE + case RTC_SET_CHARGE: + { + struct ds1302_rtc *rtc = dev_get_drvdata(dev); + int tcs_val; + + if (copy_from_user(&tcs_val, (int __user *)arg, sizeof(int))) + return -EFAULT; + + spin_lock_irq(&rtc->lock); + ds1302_writebyte(RTC_ADDR_TCR, (0xa0 | tcs_val * 0xf)); + spin_unlock_irq(&rtc->lock); + return 0; + } +#endif + } + + return -ENOIOCTLCMD; +} + +static struct rtc_class_ops ds1302_rtc_ops = { + .read_time = ds1302_rtc_read_time, + .set_time = ds1302_rtc_set_time, + .ioctl = ds1302_rtc_ioctl, +}; + +static int __devinit ds1302_rtc_probe(struct platform_device *pdev) +{ + struct ds1302_rtc *rtc; + int ret; + + /* Reset */ + set_dp(get_dp() & ~(RTC_RESET | RTC_IODATA | RTC_SCLK)); + + /* Write a magic value to the DS1302 RAM, and see if it sticks. */ + ds1302_writebyte(RTC_ADDR_RAM0, 0x42); + if (ds1302_readbyte(RTC_ADDR_RAM0) != 0x42) + return -ENODEV; + + rtc = kzalloc(sizeof(struct ds1302_rtc), GFP_KERNEL); + if (unlikely(!rtc)) + return -ENOMEM; + + spin_lock_init(&rtc->lock); + rtc->rtc_dev = rtc_device_register("ds1302", &pdev->dev, + &ds1302_rtc_ops, THIS_MODULE); + if (IS_ERR(rtc->rtc_dev)) { + ret = PTR_ERR(rtc->rtc_dev); + goto out; + } + + platform_set_drvdata(pdev, rtc); + + return 0; +out: + kfree(rtc); + return ret; +} + +static int __devexit ds1302_rtc_remove(struct platform_device *pdev) +{ + struct ds1302_rtc *rtc = platform_get_drvdata(pdev); + + if (likely(rtc->rtc_dev)) + rtc_device_unregister(rtc->rtc_dev); + + platform_set_drvdata(pdev, NULL); + + kfree(rtc); + + return 0; +} + +static struct platform_driver ds1302_platform_driver = { + .driver = { + .name = DRV_NAME, + .owner = THIS_MODULE, + }, + .probe = ds1302_rtc_probe, + .remove = __devexit_p(ds1302_rtc_remove), +}; + +static int __init ds1302_rtc_init(void) +{ + return platform_driver_register(&ds1302_platform_driver); +} + +static void __exit ds1302_rtc_exit(void) +{ + platform_driver_unregister(&ds1302_platform_driver); +} + +module_init(ds1302_rtc_init); +module_exit(ds1302_rtc_exit); + +MODULE_DESCRIPTION("Dallas DS1302 RTC driver"); +MODULE_VERSION(DRV_VERSION); +MODULE_AUTHOR("Paul Mundt, David McCullough"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/rtc/rtc-ds1307.c b/drivers/rtc/rtc-ds1307.c index bc1c7fe94ad3..f389a28720d2 100644 --- a/drivers/rtc/rtc-ds1307.c +++ b/drivers/rtc/rtc-ds1307.c @@ -256,7 +256,7 @@ ds1307_nvram_read(struct kobject *kobj, struct bin_attribute *attr, struct i2c_msg msg[2]; int result; - client = to_i2c_client(container_of(kobj, struct device, kobj)); + client = kobj_to_i2c_client(kobj); ds1307 = i2c_get_clientdata(client); if (unlikely(off >= NVRAM_SIZE)) @@ -294,7 +294,7 @@ ds1307_nvram_write(struct kobject *kobj, struct bin_attribute *attr, u8 buffer[NVRAM_SIZE + 1]; int ret; - client = to_i2c_client(container_of(kobj, struct device, kobj)); + client = kobj_to_i2c_client(kobj); if (unlikely(off >= NVRAM_SIZE)) return -EFBIG; @@ -412,11 +412,6 @@ read_rtc: */ tmp = ds1307->regs[DS1307_REG_SECS]; switch (ds1307->type) { - case ds_1340: - /* FIXME read register with DS1340_BIT_OSF, use that to - * trigger the "set time" warning (*after* restarting the - * oscillator!) instead of this weaker ds1307/m41t00 test. - */ case ds_1307: case m41t00: /* clock halted? turn it on, so clock can tick. */ @@ -440,6 +435,24 @@ read_rtc: goto read_rtc; } break; + case ds_1340: + /* clock halted? turn it on, so clock can tick. */ + if (tmp & DS1340_BIT_nEOSC) + i2c_smbus_write_byte_data(client, DS1307_REG_SECS, 0); + + tmp = i2c_smbus_read_byte_data(client, DS1340_REG_FLAG); + if (tmp < 0) { + pr_debug("read error %d\n", tmp); + err = -EIO; + goto exit_free; + } + + /* oscillator fault? clear flag, and warn */ + if (tmp & DS1340_BIT_OSF) { + i2c_smbus_write_byte_data(client, DS1340_REG_FLAG, 0); + dev_warn(&client->dev, "SET TIME!\n"); + } + break; case ds_1337: case ds_1339: break; diff --git a/drivers/rtc/rtc-ds1511.c b/drivers/rtc/rtc-ds1511.c new file mode 100644 index 000000000000..d74b8086fa31 --- /dev/null +++ b/drivers/rtc/rtc-ds1511.c @@ -0,0 +1,656 @@ +/* + * An rtc driver for the Dallas DS1511 + * + * Copyright (C) 2006 Atsushi Nemoto <anemo@mba.ocn.ne.jp> + * Copyright (C) 2007 Andrew Sharp <andy.sharp@onstor.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Real time clock driver for the Dallas 1511 chip, which also + * contains a watchdog timer. There is a tiny amount of code that + * platform code could use to mess with the watchdog device a little + * bit, but not a full watchdog driver. + */ + +#include <linux/bcd.h> +#include <linux/init.h> +#include <linux/kernel.h> +#include <linux/delay.h> +#include <linux/interrupt.h> +#include <linux/rtc.h> +#include <linux/platform_device.h> +#include <linux/io.h> + +#define DRV_VERSION "0.6" + +enum ds1511reg { + DS1511_SEC = 0x0, + DS1511_MIN = 0x1, + DS1511_HOUR = 0x2, + DS1511_DOW = 0x3, + DS1511_DOM = 0x4, + DS1511_MONTH = 0x5, + DS1511_YEAR = 0x6, + DS1511_CENTURY = 0x7, + DS1511_AM1_SEC = 0x8, + DS1511_AM2_MIN = 0x9, + DS1511_AM3_HOUR = 0xa, + DS1511_AM4_DATE = 0xb, + DS1511_WD_MSEC = 0xc, + DS1511_WD_SEC = 0xd, + DS1511_CONTROL_A = 0xe, + DS1511_CONTROL_B = 0xf, + DS1511_RAMADDR_LSB = 0x10, + DS1511_RAMDATA = 0x13 +}; + +#define DS1511_BLF1 0x80 +#define DS1511_BLF2 0x40 +#define DS1511_PRS 0x20 +#define DS1511_PAB 0x10 +#define DS1511_TDF 0x08 +#define DS1511_KSF 0x04 +#define DS1511_WDF 0x02 +#define DS1511_IRQF 0x01 +#define DS1511_TE 0x80 +#define DS1511_CS 0x40 +#define DS1511_BME 0x20 +#define DS1511_TPE 0x10 +#define DS1511_TIE 0x08 +#define DS1511_KIE 0x04 +#define DS1511_WDE 0x02 +#define DS1511_WDS 0x01 +#define DS1511_RAM_MAX 0xff + +#define RTC_CMD DS1511_CONTROL_B +#define RTC_CMD1 DS1511_CONTROL_A + +#define RTC_ALARM_SEC DS1511_AM1_SEC +#define RTC_ALARM_MIN DS1511_AM2_MIN +#define RTC_ALARM_HOUR DS1511_AM3_HOUR +#define RTC_ALARM_DATE DS1511_AM4_DATE + +#define RTC_SEC DS1511_SEC +#define RTC_MIN DS1511_MIN +#define RTC_HOUR DS1511_HOUR +#define RTC_DOW DS1511_DOW +#define RTC_DOM DS1511_DOM +#define RTC_MON DS1511_MONTH +#define RTC_YEAR DS1511_YEAR +#define RTC_CENTURY DS1511_CENTURY + +#define RTC_TIE DS1511_TIE +#define RTC_TE DS1511_TE + +struct rtc_plat_data { + struct rtc_device *rtc; + void __iomem *ioaddr; /* virtual base address */ + unsigned long baseaddr; /* physical base address */ + int size; /* amount of memory mapped */ + int irq; + unsigned int irqen; + int alrm_sec; + int alrm_min; + int alrm_hour; + int alrm_mday; +}; + +static DEFINE_SPINLOCK(ds1511_lock); + +static __iomem char *ds1511_base; +static u32 reg_spacing = 1; + + static noinline void +rtc_write(uint8_t val, uint32_t reg) +{ + writeb(val, ds1511_base + (reg * reg_spacing)); +} + + static inline void +rtc_write_alarm(uint8_t val, enum ds1511reg reg) +{ + rtc_write((val | 0x80), reg); +} + + static noinline uint8_t +rtc_read(enum ds1511reg reg) +{ + return readb(ds1511_base + (reg * reg_spacing)); +} + + static inline void +rtc_disable_update(void) +{ + rtc_write((rtc_read(RTC_CMD) & ~RTC_TE), RTC_CMD); +} + + static void +rtc_enable_update(void) +{ + rtc_write((rtc_read(RTC_CMD) | RTC_TE), RTC_CMD); +} + +/* + * #define DS1511_WDOG_RESET_SUPPORT + * + * Uncomment this if you want to use these routines in + * some platform code. + */ +#ifdef DS1511_WDOG_RESET_SUPPORT +/* + * just enough code to set the watchdog timer so that it + * will reboot the system + */ + void +ds1511_wdog_set(unsigned long deciseconds) +{ + /* + * the wdog timer can take 99.99 seconds + */ + deciseconds %= 10000; + /* + * set the wdog values in the wdog registers + */ + rtc_write(BIN2BCD(deciseconds % 100), DS1511_WD_MSEC); + rtc_write(BIN2BCD(deciseconds / 100), DS1511_WD_SEC); + /* + * set wdog enable and wdog 'steering' bit to issue a reset + */ + rtc_write(DS1511_WDE | DS1511_WDS, RTC_CMD); +} + + void +ds1511_wdog_disable(void) +{ + /* + * clear wdog enable and wdog 'steering' bits + */ + rtc_write(rtc_read(RTC_CMD) & ~(DS1511_WDE | DS1511_WDS), RTC_CMD); + /* + * clear the wdog counter + */ + rtc_write(0, DS1511_WD_MSEC); + rtc_write(0, DS1511_WD_SEC); +} +#endif + +/* + * set the rtc chip's idea of the time. + * stupidly, some callers call with year unmolested; + * and some call with year = year - 1900. thanks. + */ + int +ds1511_rtc_set_time(struct device *dev, struct rtc_time *rtc_tm) +{ + u8 mon, day, dow, hrs, min, sec, yrs, cen; + unsigned int flags; + + /* + * won't have to change this for a while + */ + if (rtc_tm->tm_year < 1900) { + rtc_tm->tm_year += 1900; + } + + if (rtc_tm->tm_year < 1970) { + return -EINVAL; + } + yrs = rtc_tm->tm_year % 100; + cen = rtc_tm->tm_year / 100; + mon = rtc_tm->tm_mon + 1; /* tm_mon starts at zero */ + day = rtc_tm->tm_mday; + dow = rtc_tm->tm_wday & 0x7; /* automatic BCD */ + hrs = rtc_tm->tm_hour; + min = rtc_tm->tm_min; + sec = rtc_tm->tm_sec; + + if ((mon > 12) || (day == 0)) { + return -EINVAL; + } + + if (day > rtc_month_days(rtc_tm->tm_mon, rtc_tm->tm_year)) { + return -EINVAL; + } + + if ((hrs >= 24) || (min >= 60) || (sec >= 60)) { + return -EINVAL; + } + + /* + * each register is a different number of valid bits + */ + sec = BIN2BCD(sec) & 0x7f; + min = BIN2BCD(min) & 0x7f; + hrs = BIN2BCD(hrs) & 0x3f; + day = BIN2BCD(day) & 0x3f; + mon = BIN2BCD(mon) & 0x1f; + yrs = BIN2BCD(yrs) & 0xff; + cen = BIN2BCD(cen) & 0xff; + + spin_lock_irqsave(&ds1511_lock, flags); + rtc_disable_update(); + rtc_write(cen, RTC_CENTURY); + rtc_write(yrs, RTC_YEAR); + rtc_write((rtc_read(RTC_MON) & 0xe0) | mon, RTC_MON); + rtc_write(day, RTC_DOM); + rtc_write(hrs, RTC_HOUR); + rtc_write(min, RTC_MIN); + rtc_write(sec, RTC_SEC); + rtc_write(dow, RTC_DOW); + rtc_enable_update(); + spin_unlock_irqrestore(&ds1511_lock, flags); + + return 0; +} + + int +ds1511_rtc_read_time(struct device *dev, struct rtc_time *rtc_tm) +{ + unsigned int century; + unsigned int flags; + + spin_lock_irqsave(&ds1511_lock, flags); + rtc_disable_update(); + + rtc_tm->tm_sec = rtc_read(RTC_SEC) & 0x7f; + rtc_tm->tm_min = rtc_read(RTC_MIN) & 0x7f; + rtc_tm->tm_hour = rtc_read(RTC_HOUR) & 0x3f; + rtc_tm->tm_mday = rtc_read(RTC_DOM) & 0x3f; + rtc_tm->tm_wday = rtc_read(RTC_DOW) & 0x7; + rtc_tm->tm_mon = rtc_read(RTC_MON) & 0x1f; + rtc_tm->tm_year = rtc_read(RTC_YEAR) & 0x7f; + century = rtc_read(RTC_CENTURY); + + rtc_enable_update(); + spin_unlock_irqrestore(&ds1511_lock, flags); + + rtc_tm->tm_sec = BCD2BIN(rtc_tm->tm_sec); + rtc_tm->tm_min = BCD2BIN(rtc_tm->tm_min); + rtc_tm->tm_hour = BCD2BIN(rtc_tm->tm_hour); + rtc_tm->tm_mday = BCD2BIN(rtc_tm->tm_mday); + rtc_tm->tm_wday = BCD2BIN(rtc_tm->tm_wday); + rtc_tm->tm_mon = BCD2BIN(rtc_tm->tm_mon); + rtc_tm->tm_year = BCD2BIN(rtc_tm->tm_year); + century = BCD2BIN(century) * 100; + + /* + * Account for differences between how the RTC uses the values + * and how they are defined in a struct rtc_time; + */ + century += rtc_tm->tm_year; + rtc_tm->tm_year = century - 1900; + + rtc_tm->tm_mon--; + + if (rtc_valid_tm(rtc_tm) < 0) { + dev_err(dev, "retrieved date/time is not valid.\n"); + rtc_time_to_tm(0, rtc_tm); + } + return 0; +} + +/* + * write the alarm register settings + * + * we only have the use to interrupt every second, otherwise + * known as the update interrupt, or the interrupt if the whole + * date/hours/mins/secs matches. the ds1511 has many more + * permutations, but the kernel doesn't. + */ + static void +ds1511_rtc_update_alarm(struct rtc_plat_data *pdata) +{ + unsigned long flags; + + spin_lock_irqsave(&pdata->rtc->irq_lock, flags); + rtc_write(pdata->alrm_mday < 0 || (pdata->irqen & RTC_UF) ? + 0x80 : BIN2BCD(pdata->alrm_mday) & 0x3f, + RTC_ALARM_DATE); + rtc_write(pdata->alrm_hour < 0 || (pdata->irqen & RTC_UF) ? + 0x80 : BIN2BCD(pdata->alrm_hour) & 0x3f, + RTC_ALARM_HOUR); + rtc_write(pdata->alrm_min < 0 || (pdata->irqen & RTC_UF) ? + 0x80 : BIN2BCD(pdata->alrm_min) & 0x7f, + RTC_ALARM_MIN); + rtc_write(pdata->alrm_sec < 0 || (pdata->irqen & RTC_UF) ? + 0x80 : BIN2BCD(pdata->alrm_sec) & 0x7f, + RTC_ALARM_SEC); + rtc_write(rtc_read(RTC_CMD) | (pdata->irqen ? RTC_TIE : 0), RTC_CMD); + rtc_read(RTC_CMD1); /* clear interrupts */ + spin_unlock_irqrestore(&pdata->rtc->irq_lock, flags); +} + + static int +ds1511_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) +{ + struct platform_device *pdev = to_platform_device(dev); + struct rtc_plat_data *pdata = platform_get_drvdata(pdev); + + if (pdata->irq < 0) { + return -EINVAL; + } + pdata->alrm_mday = alrm->time.tm_mday; + pdata->alrm_hour = alrm->time.tm_hour; + pdata->alrm_min = alrm->time.tm_min; + pdata->alrm_sec = alrm->time.tm_sec; + if (alrm->enabled) { + pdata->irqen |= RTC_AF; + } + ds1511_rtc_update_alarm(pdata); + return 0; +} + + static int +ds1511_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm) +{ + struct platform_device *pdev = to_platform_device(dev); + struct rtc_plat_data *pdata = platform_get_drvdata(pdev); + + if (pdata->irq < 0) { + return -EINVAL; + } + alrm->time.tm_mday = pdata->alrm_mday < 0 ? 0 : pdata->alrm_mday; + alrm->time.tm_hour = pdata->alrm_hour < 0 ? 0 : pdata->alrm_hour; + alrm->time.tm_min = pdata->alrm_min < 0 ? 0 : pdata->alrm_min; + alrm->time.tm_sec = pdata->alrm_sec < 0 ? 0 : pdata->alrm_sec; + alrm->enabled = (pdata->irqen & RTC_AF) ? 1 : 0; + return 0; +} + + static irqreturn_t +ds1511_interrupt(int irq, void *dev_id) +{ + struct platform_device *pdev = dev_id; + struct rtc_plat_data *pdata = platform_get_drvdata(pdev); + unsigned long events = RTC_IRQF; + + /* + * read and clear interrupt + */ + if (!(rtc_read(RTC_CMD1) & DS1511_IRQF)) { + return IRQ_NONE; + } + if (rtc_read(RTC_ALARM_SEC) & 0x80) { + events |= RTC_UF; + } else { + events |= RTC_AF; + } + rtc_update_irq(pdata->rtc, 1, events); + return IRQ_HANDLED; +} + + static void +ds1511_rtc_release(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct rtc_plat_data *pdata = platform_get_drvdata(pdev); + + if (pdata->irq >= 0) { + pdata->irqen = 0; + ds1511_rtc_update_alarm(pdata); + } +} + + static int +ds1511_rtc_ioctl(struct device *dev, unsigned int cmd, unsigned long arg) +{ + struct platform_device *pdev = to_platform_device(dev); + struct rtc_plat_data *pdata = platform_get_drvdata(pdev); + + if (pdata->irq < 0) { + return -ENOIOCTLCMD; /* fall back into rtc-dev's emulation */ + } + switch (cmd) { + case RTC_AIE_OFF: + pdata->irqen &= ~RTC_AF; + ds1511_rtc_update_alarm(pdata); + break; + case RTC_AIE_ON: + pdata->irqen |= RTC_AF; + ds1511_rtc_update_alarm(pdata); + break; + case RTC_UIE_OFF: + pdata->irqen &= ~RTC_UF; + ds1511_rtc_update_alarm(pdata); + break; + case RTC_UIE_ON: + pdata->irqen |= RTC_UF; + ds1511_rtc_update_alarm(pdata); + break; + default: + return -ENOIOCTLCMD; + } + return 0; +} + +static const struct rtc_class_ops ds1511_rtc_ops = { + .read_time = ds1511_rtc_read_time, + .set_time = ds1511_rtc_set_time, + .read_alarm = ds1511_rtc_read_alarm, + .set_alarm = ds1511_rtc_set_alarm, + .release = ds1511_rtc_release, + .ioctl = ds1511_rtc_ioctl, +}; + + static ssize_t +ds1511_nvram_read(struct kobject *kobj, struct bin_attribute *ba, + char *buf, loff_t pos, size_t size) +{ + ssize_t count; + + /* + * if count is more than one, turn on "burst" mode + * turn it off when you're done + */ + if (size > 1) { + rtc_write((rtc_read(RTC_CMD) | DS1511_BME), RTC_CMD); + } + if (pos > DS1511_RAM_MAX) { + pos = DS1511_RAM_MAX; + } + if (size + pos > DS1511_RAM_MAX + 1) { + size = DS1511_RAM_MAX - pos + 1; + } + rtc_write(pos, DS1511_RAMADDR_LSB); + for (count = 0; size > 0; count++, size--) { + *buf++ = rtc_read(DS1511_RAMDATA); + } + if (count > 1) { + rtc_write((rtc_read(RTC_CMD) & ~DS1511_BME), RTC_CMD); + } + return count; +} + + static ssize_t +ds1511_nvram_write(struct kobject *kobj, struct bin_attribute *bin_attr, + char *buf, loff_t pos, size_t size) +{ + ssize_t count; + + /* + * if count is more than one, turn on "burst" mode + * turn it off when you're done + */ + if (size > 1) { + rtc_write((rtc_read(RTC_CMD) | DS1511_BME), RTC_CMD); + } + if (pos > DS1511_RAM_MAX) { + pos = DS1511_RAM_MAX; + } + if (size + pos > DS1511_RAM_MAX + 1) { + size = DS1511_RAM_MAX - pos + 1; + } + rtc_write(pos, DS1511_RAMADDR_LSB); + for (count = 0; size > 0; count++, size--) { + rtc_write(*buf++, DS1511_RAMDATA); + } + if (count > 1) { + rtc_write((rtc_read(RTC_CMD) & ~DS1511_BME), RTC_CMD); + } + return count; +} + +static struct bin_attribute ds1511_nvram_attr = { + .attr = { + .name = "nvram", + .mode = S_IRUGO | S_IWUGO, + .owner = THIS_MODULE, + }, + .size = DS1511_RAM_MAX, + .read = ds1511_nvram_read, + .write = ds1511_nvram_write, +}; + + static int __devinit +ds1511_rtc_probe(struct platform_device *pdev) +{ + struct rtc_device *rtc; + struct resource *res; + struct rtc_plat_data *pdata = NULL; + int ret = 0; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) { + return -ENODEV; + } + pdata = kzalloc(sizeof(*pdata), GFP_KERNEL); + if (!pdata) { + return -ENOMEM; + } + pdata->irq = -1; + pdata->size = res->end - res->start + 1; + if (!request_mem_region(res->start, pdata->size, pdev->name)) { + ret = -EBUSY; + goto out; + } + pdata->baseaddr = res->start; + pdata->size = pdata->size; + ds1511_base = ioremap(pdata->baseaddr, pdata->size); + if (!ds1511_base) { + ret = -ENOMEM; + goto out; + } + pdata->ioaddr = ds1511_base; + pdata->irq = platform_get_irq(pdev, 0); + + /* + * turn on the clock and the crystal, etc. + */ + rtc_write(0, RTC_CMD); + rtc_write(0, RTC_CMD1); + /* + * clear the wdog counter + */ + rtc_write(0, DS1511_WD_MSEC); + rtc_write(0, DS1511_WD_SEC); + /* + * start the clock + */ + rtc_enable_update(); + + /* + * check for a dying bat-tree + */ + if (rtc_read(RTC_CMD1) & DS1511_BLF1) { + dev_warn(&pdev->dev, "voltage-low detected.\n"); + } + + /* + * if the platform has an interrupt in mind for this device, + * then by all means, set it + */ + if (pdata->irq >= 0) { + rtc_read(RTC_CMD1); + if (request_irq(pdata->irq, ds1511_interrupt, + IRQF_DISABLED | IRQF_SHARED, pdev->name, pdev) < 0) { + + dev_warn(&pdev->dev, "interrupt not available.\n"); + pdata->irq = -1; + } + } + + rtc = rtc_device_register(pdev->name, &pdev->dev, &ds1511_rtc_ops, + THIS_MODULE); + if (IS_ERR(rtc)) { + ret = PTR_ERR(rtc); + goto out; + } + pdata->rtc = rtc; + platform_set_drvdata(pdev, pdata); + ret = sysfs_create_bin_file(&pdev->dev.kobj, &ds1511_nvram_attr); + if (ret) { + goto out; + } + return 0; + out: + if (pdata->rtc) { + rtc_device_unregister(pdata->rtc); + } + if (pdata->irq >= 0) { + free_irq(pdata->irq, pdev); + } + if (ds1511_base) { + iounmap(ds1511_base); + ds1511_base = NULL; + } + if (pdata->baseaddr) { + release_mem_region(pdata->baseaddr, pdata->size); + } + + kfree(pdata); + return ret; +} + + static int __devexit +ds1511_rtc_remove(struct platform_device *pdev) +{ + struct rtc_plat_data *pdata = platform_get_drvdata(pdev); + + sysfs_remove_bin_file(&pdev->dev.kobj, &ds1511_nvram_attr); + rtc_device_unregister(pdata->rtc); + pdata->rtc = NULL; + if (pdata->irq >= 0) { + /* + * disable the alarm interrupt + */ + rtc_write(rtc_read(RTC_CMD) & ~RTC_TIE, RTC_CMD); + rtc_read(RTC_CMD1); + free_irq(pdata->irq, pdev); + } + iounmap(pdata->ioaddr); + ds1511_base = NULL; + release_mem_region(pdata->baseaddr, pdata->size); + kfree(pdata); + return 0; +} + +static struct platform_driver ds1511_rtc_driver = { + .probe = ds1511_rtc_probe, + .remove = __devexit_p(ds1511_rtc_remove), + .driver = { + .name = "ds1511", + .owner = THIS_MODULE, + }, +}; + + static int __init +ds1511_rtc_init(void) +{ + return platform_driver_register(&ds1511_rtc_driver); +} + + static void __exit +ds1511_rtc_exit(void) +{ + return platform_driver_unregister(&ds1511_rtc_driver); +} + +module_init(ds1511_rtc_init); +module_exit(ds1511_rtc_exit); + +MODULE_AUTHOR("Andrew Sharp <andy.sharp@onstor.com>"); +MODULE_DESCRIPTION("Dallas DS1511 RTC driver"); +MODULE_LICENSE("GPL"); +MODULE_VERSION(DRV_VERSION); diff --git a/drivers/rtc/rtc-pcf8583.c b/drivers/rtc/rtc-pcf8583.c index c973ba94c422..8b3997007506 100644 --- a/drivers/rtc/rtc-pcf8583.c +++ b/drivers/rtc/rtc-pcf8583.c @@ -163,27 +163,17 @@ static int pcf8583_read_mem(struct i2c_client *client, struct rtc_mem *mem) static int pcf8583_write_mem(struct i2c_client *client, struct rtc_mem *mem) { - unsigned char addr[1]; - struct i2c_msg msgs[2] = { - { - .addr = client->addr, - .flags = 0, - .len = 1, - .buf = addr, - }, { - .addr = client->addr, - .flags = I2C_M_NOSTART, - .len = mem->nr, - .buf = mem->data, - } - }; + unsigned char buf[9]; + int ret; - if (mem->loc < 8) + if (mem->loc < 8 || mem->nr > 8) return -EINVAL; - addr[0] = mem->loc; + buf[0] = mem->loc; + memcpy(buf + 1, mem->data, mem->nr); - return i2c_transfer(client->adapter, msgs, 2) == 2 ? 0 : -EIO; + ret = i2c_master_send(client, buf, mem->nr + 1); + return ret == mem->nr + 1 ? 0 : -EIO; } static int pcf8583_rtc_read_time(struct device *dev, struct rtc_time *tm) diff --git a/drivers/rtc/rtc-r9701.c b/drivers/rtc/rtc-r9701.c new file mode 100644 index 000000000000..a64626a82d0b --- /dev/null +++ b/drivers/rtc/rtc-r9701.c @@ -0,0 +1,178 @@ +/* + * Driver for Epson RTC-9701JE + * + * Copyright (C) 2008 Magnus Damm + * + * Based on rtc-max6902.c + * + * Copyright (C) 2006 8D Technologies inc. + * Copyright (C) 2004 Compulab Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include <linux/module.h> +#include <linux/version.h> +#include <linux/kernel.h> +#include <linux/platform_device.h> +#include <linux/device.h> +#include <linux/init.h> +#include <linux/rtc.h> +#include <linux/spi/spi.h> +#include <linux/bcd.h> +#include <linux/delay.h> +#include <linux/bitops.h> + +#define RSECCNT 0x00 /* Second Counter */ +#define RMINCNT 0x01 /* Minute Counter */ +#define RHRCNT 0x02 /* Hour Counter */ +#define RWKCNT 0x03 /* Week Counter */ +#define RDAYCNT 0x04 /* Day Counter */ +#define RMONCNT 0x05 /* Month Counter */ +#define RYRCNT 0x06 /* Year Counter */ +#define R100CNT 0x07 /* Y100 Counter */ +#define RMINAR 0x08 /* Minute Alarm */ +#define RHRAR 0x09 /* Hour Alarm */ +#define RWKAR 0x0a /* Week/Day Alarm */ +#define RTIMCNT 0x0c /* Interval Timer */ +#define REXT 0x0d /* Extension Register */ +#define RFLAG 0x0e /* RTC Flag Register */ +#define RCR 0x0f /* RTC Control Register */ + +static int write_reg(struct device *dev, int address, unsigned char data) +{ + struct spi_device *spi = to_spi_device(dev); + unsigned char buf[2]; + + buf[0] = address & 0x7f; + buf[1] = data; + + return spi_write(spi, buf, ARRAY_SIZE(buf)); +} + +static int read_regs(struct device *dev, unsigned char *regs, int no_regs) +{ + struct spi_device *spi = to_spi_device(dev); + u8 txbuf[1], rxbuf[1]; + int k, ret; + + ret = 0; + + for (k = 0; ret == 0 && k < no_regs; k++) { + txbuf[0] = 0x80 | regs[k]; + ret = spi_write_then_read(spi, txbuf, 1, rxbuf, 1); + regs[k] = rxbuf[0]; + } + + return ret; +} + +static int r9701_get_datetime(struct device *dev, struct rtc_time *dt) +{ + unsigned long time; + int ret; + unsigned char buf[] = { RSECCNT, RMINCNT, RHRCNT, + RDAYCNT, RMONCNT, RYRCNT }; + + ret = read_regs(dev, buf, ARRAY_SIZE(buf)); + if (ret) + return ret; + + memset(dt, 0, sizeof(*dt)); + + dt->tm_sec = BCD2BIN(buf[0]); /* RSECCNT */ + dt->tm_min = BCD2BIN(buf[1]); /* RMINCNT */ + dt->tm_hour = BCD2BIN(buf[2]); /* RHRCNT */ + + dt->tm_mday = BCD2BIN(buf[3]); /* RDAYCNT */ + dt->tm_mon = BCD2BIN(buf[4]) - 1; /* RMONCNT */ + dt->tm_year = BCD2BIN(buf[5]) + 100; /* RYRCNT */ + + /* the rtc device may contain illegal values on power up + * according to the data sheet. make sure they are valid. + */ + + return rtc_valid_tm(dt); +} + +static int r9701_set_datetime(struct device *dev, struct rtc_time *dt) +{ + int ret, year; + + year = dt->tm_year + 1900; + if (year >= 2100 || year < 2000) + return -EINVAL; + + ret = write_reg(dev, RHRCNT, BIN2BCD(dt->tm_hour)); + ret = ret ? ret : write_reg(dev, RMINCNT, BIN2BCD(dt->tm_min)); + ret = ret ? ret : write_reg(dev, RSECCNT, BIN2BCD(dt->tm_sec)); + ret = ret ? ret : write_reg(dev, RDAYCNT, BIN2BCD(dt->tm_mday)); + ret = ret ? ret : write_reg(dev, RMONCNT, BIN2BCD(dt->tm_mon + 1)); + ret = ret ? ret : write_reg(dev, RYRCNT, BIN2BCD(dt->tm_year - 100)); + ret = ret ? ret : write_reg(dev, RWKCNT, 1 << dt->tm_wday); + + return ret; +} + +static const struct rtc_class_ops r9701_rtc_ops = { + .read_time = r9701_get_datetime, + .set_time = r9701_set_datetime, +}; + +static int __devinit r9701_probe(struct spi_device *spi) +{ + struct rtc_device *rtc; + unsigned char tmp; + int res; + + rtc = rtc_device_register("r9701", + &spi->dev, &r9701_rtc_ops, THIS_MODULE); + if (IS_ERR(rtc)) + return PTR_ERR(rtc); + + dev_set_drvdata(&spi->dev, rtc); + + tmp = R100CNT; + res = read_regs(&spi->dev, &tmp, 1); + if (res || tmp != 0x20) { + rtc_device_unregister(rtc); + return res; + } + + return 0; +} + +static int __devexit r9701_remove(struct spi_device *spi) +{ + struct rtc_device *rtc = dev_get_drvdata(&spi->dev); + + rtc_device_unregister(rtc); + return 0; +} + +static struct spi_driver r9701_driver = { + .driver = { + .name = "rtc-r9701", + .owner = THIS_MODULE, + }, + .probe = r9701_probe, + .remove = __devexit_p(r9701_remove), +}; + +static __init int r9701_init(void) +{ + return spi_register_driver(&r9701_driver); +} +module_init(r9701_init); + +static __exit void r9701_exit(void) +{ + spi_unregister_driver(&r9701_driver); +} +module_exit(r9701_exit); + +MODULE_DESCRIPTION("r9701 spi RTC driver"); +MODULE_AUTHOR("Magnus Damm <damm@opensource.se>"); +MODULE_LICENSE("GPL"); diff --git a/drivers/rtc/rtc-s3c.c b/drivers/rtc/rtc-s3c.c index e2041b4d0c85..86766f1f2496 100644 --- a/drivers/rtc/rtc-s3c.c +++ b/drivers/rtc/rtc-s3c.c @@ -20,6 +20,7 @@ #include <linux/rtc.h> #include <linux/bcd.h> #include <linux/clk.h> +#include <linux/log2.h> #include <asm/hardware.h> #include <asm/uaccess.h> @@ -309,9 +310,7 @@ static int s3c_rtc_ioctl(struct device *dev, break; case RTC_IRQP_SET: - /* check for power of 2 */ - - if ((arg & (arg-1)) != 0 || arg < 1) { + if (!is_power_of_2(arg)) { ret = -EINVAL; goto exit; } diff --git a/drivers/rtc/rtc-sa1100.c b/drivers/rtc/rtc-sa1100.c index 2eb38520f0c8..ee253cc45de1 100644 --- a/drivers/rtc/rtc-sa1100.c +++ b/drivers/rtc/rtc-sa1100.c @@ -357,23 +357,15 @@ static int sa1100_rtc_remove(struct platform_device *pdev) #ifdef CONFIG_PM static int sa1100_rtc_suspend(struct platform_device *pdev, pm_message_t state) { - if (pdev->dev.power.power_state.event != state.event) { - if (state.event == PM_EVENT_SUSPEND && - device_may_wakeup(&pdev->dev)) - enable_irq_wake(IRQ_RTCAlrm); - - pdev->dev.power.power_state = state; - } + if (device_may_wakeup(&pdev->dev)) + enable_irq_wake(IRQ_RTCAlrm); return 0; } static int sa1100_rtc_resume(struct platform_device *pdev) { - if (pdev->dev.power.power_state.event != PM_EVENT_ON) { - if (device_may_wakeup(&pdev->dev)) - disable_irq_wake(IRQ_RTCAlrm); - pdev->dev.power.power_state = PMSG_ON; - } + if (device_may_wakeup(&pdev->dev)) + disable_irq_wake(IRQ_RTCAlrm); return 0; } #else diff --git a/drivers/rtc/rtc-sysfs.c b/drivers/rtc/rtc-sysfs.c index 2ae0e8304d3a..4d27ccc4fc06 100644 --- a/drivers/rtc/rtc-sysfs.c +++ b/drivers/rtc/rtc-sysfs.c @@ -17,6 +17,13 @@ /* device attributes */ +/* + * NOTE: RTC times displayed in sysfs use the RTC's timezone. That's + * ideally UTC. However, PCs that also boot to MS-Windows normally use + * the local time and change to match daylight savings time. That affects + * attributes including date, time, since_epoch, and wakealarm. + */ + static ssize_t rtc_sysfs_show_name(struct device *dev, struct device_attribute *attr, char *buf) @@ -113,13 +120,13 @@ rtc_sysfs_show_wakealarm(struct device *dev, struct device_attribute *attr, unsigned long alarm; struct rtc_wkalrm alm; - /* Don't show disabled alarms; but the RTC could leave the - * alarm enabled after it's already triggered. Alarms are - * conceptually one-shot, even though some common hardware - * (PCs) doesn't actually work that way. + /* Don't show disabled alarms. For uniformity, RTC alarms are + * conceptually one-shot, even though some common RTCs (on PCs) + * don't actually work that way. * - * REVISIT maybe we should require RTC implementations to - * disable the RTC alarm after it triggers, for uniformity. + * NOTE: RTC implementations where the alarm doesn't match an + * exact YYYY-MM-DD HH:MM[:SS] date *must* disable their RTC + * alarms after they trigger, to ensure one-shot semantics. */ retval = rtc_read_alarm(to_rtc_device(dev), &alm); if (retval == 0 && alm.enabled) { diff --git a/drivers/s390/sysinfo.c b/drivers/s390/sysinfo.c index 19343f9675c3..291ff6235fe2 100644 --- a/drivers/s390/sysinfo.c +++ b/drivers/s390/sysinfo.c @@ -422,7 +422,7 @@ void s390_adjust_jiffies(void) /* * calibrate the delay loop */ -void __init calibrate_delay(void) +void __cpuinit calibrate_delay(void) { s390_adjust_jiffies(); /* Print the good old Bogomips line .. */ diff --git a/drivers/scsi/a2091.c b/drivers/scsi/a2091.c index 23f27c9c9895..5ac3a3e8dfaf 100644 --- a/drivers/scsi/a2091.c +++ b/drivers/scsi/a2091.c @@ -46,8 +46,7 @@ static int dma_setup(struct scsi_cmnd *cmd, int dir_in) struct Scsi_Host *instance = cmd->device->host; /* don't allow DMA if the physical address is bad */ - if (addr & A2091_XFER_MASK || - (!dir_in && mm_end_of_chunk (addr, cmd->SCp.this_residual))) + if (addr & A2091_XFER_MASK) { HDATA(instance)->dma_bounce_len = (cmd->SCp.this_residual + 511) & ~0x1ff; diff --git a/drivers/scsi/a3000.c b/drivers/scsi/a3000.c index d7255c8bf281..3aeec963940b 100644 --- a/drivers/scsi/a3000.c +++ b/drivers/scsi/a3000.c @@ -54,8 +54,7 @@ static int dma_setup(struct scsi_cmnd *cmd, int dir_in) * end of a physical memory chunk, then allocate a bounce * buffer */ - if (addr & A3000_XFER_MASK || - (!dir_in && mm_end_of_chunk (addr, cmd->SCp.this_residual))) + if (addr & A3000_XFER_MASK) { HDATA(a3000_host)->dma_bounce_len = (cmd->SCp.this_residual + 511) & ~0x1ff; diff --git a/drivers/scsi/aic7xxx_old.c b/drivers/scsi/aic7xxx_old.c index 3bfd9296bbfa..93984c9dfe14 100644 --- a/drivers/scsi/aic7xxx_old.c +++ b/drivers/scsi/aic7xxx_old.c @@ -6472,7 +6472,7 @@ do_aic7xxx_isr(int irq, void *dev_id) unsigned long cpu_flags; struct aic7xxx_host *p; - p = (struct aic7xxx_host *)dev_id; + p = dev_id; if(!p) return IRQ_NONE; spin_lock_irqsave(p->host->host_lock, cpu_flags); diff --git a/drivers/scsi/gvp11.c b/drivers/scsi/gvp11.c index 37741e9b5c3b..91f85226d08f 100644 --- a/drivers/scsi/gvp11.c +++ b/drivers/scsi/gvp11.c @@ -54,8 +54,7 @@ static int dma_setup(struct scsi_cmnd *cmd, int dir_in) static int scsi_alloc_out_of_range = 0; /* use bounce buffer if the physical address is bad */ - if (addr & HDATA(cmd->device->host)->dma_xfer_mask || - (!dir_in && mm_end_of_chunk (addr, cmd->SCp.this_residual))) + if (addr & HDATA(cmd->device->host)->dma_xfer_mask) { HDATA(cmd->device->host)->dma_bounce_len = (cmd->SCp.this_residual + 511) & ~0x1ff; diff --git a/drivers/scsi/ibmvscsi/ibmvstgt.c b/drivers/scsi/ibmvscsi/ibmvstgt.c index d63f11e95abf..bd62131b97a1 100644 --- a/drivers/scsi/ibmvscsi/ibmvstgt.c +++ b/drivers/scsi/ibmvscsi/ibmvstgt.c @@ -539,9 +539,9 @@ out: srp_iu_put(iue); } -static irqreturn_t ibmvstgt_interrupt(int irq, void *data) +static irqreturn_t ibmvstgt_interrupt(int dummy, void *data) { - struct srp_target *target = (struct srp_target *) data; + struct srp_target *target = data; struct vio_port *vport = target_to_port(target); vio_disable_interrupts(vport->dma_dev); diff --git a/drivers/scsi/ide-scsi.c b/drivers/scsi/ide-scsi.c index 6c4f0f081785..68e5c632c5d5 100644 --- a/drivers/scsi/ide-scsi.c +++ b/drivers/scsi/ide-scsi.c @@ -287,7 +287,7 @@ static int idescsi_end_request(ide_drive_t *, int, int); static ide_startstop_t idescsi_atapi_error(ide_drive_t *drive, struct request *rq, u8 stat, u8 err) { - if (HWIF(drive)->INB(IDE_STATUS_REG) & (BUSY_STAT|DRQ_STAT)) + if (ide_read_status(drive) & (BUSY_STAT | DRQ_STAT)) /* force an abort */ HWIF(drive)->OUTB(WIN_IDLEIMMEDIATE,IDE_COMMAND_REG); @@ -423,7 +423,7 @@ static ide_startstop_t idescsi_pc_intr (ide_drive_t *drive) } /* Clear the interrupt */ - stat = drive->hwif->INB(IDE_STATUS_REG); + stat = ide_read_status(drive); if ((stat & DRQ_STAT) == 0) { /* No more interrupts */ diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig index 4fa7927997ad..6a44fb1dc167 100644 --- a/drivers/serial/Kconfig +++ b/drivers/serial/Kconfig @@ -877,15 +877,15 @@ config SERIAL_SUNHV systems. Say Y if you want to be able to use this device. config SERIAL_IP22_ZILOG - tristate "IP22 Zilog8530 serial support" - depends on SGI_IP22 + tristate "SGI Zilog8530 serial support" + depends on SGI_HAS_ZILOG select SERIAL_CORE help - This driver supports the Zilog8530 serial ports found on SGI IP22 + This driver supports the Zilog8530 serial ports found on SGI systems. Say Y or M if you want to be able to these serial ports. config SERIAL_IP22_ZILOG_CONSOLE - bool "Console on IP22 Zilog8530 serial port" + bool "Console on SGI Zilog8530 serial port" depends on SERIAL_IP22_ZILOG=y select SERIAL_CORE_CONSOLE @@ -1318,4 +1318,19 @@ config SERIAL_QE This driver supports the QE serial ports on Freescale embedded PowerPC that contain a QUICC Engine. +config SERIAL_SC26XX + tristate "SC2681/SC2692 serial port support" + depends on SNI_RM + select SERIAL_CORE + help + This is a driver for the onboard serial ports of + older RM400 machines. + +config SERIAL_SC26XX_CONSOLE + bool "Console on SC2681/SC2692 serial port" + depends on SERIAL_SC26XX + select SERIAL_CORE_CONSOLE + help + Support for Console on SC2681/SC2692 serial ports. + endmenu diff --git a/drivers/serial/Makefile b/drivers/serial/Makefile index 2dd41b4cc8db..640cfe44a56d 100644 --- a/drivers/serial/Makefile +++ b/drivers/serial/Makefile @@ -55,6 +55,7 @@ obj-$(CONFIG_SERIAL_M32R_SIO) += m32r_sio.o obj-$(CONFIG_SERIAL_MPSC) += mpsc.o obj-$(CONFIG_SERIAL_SB1250_DUART) += sb1250-duart.o obj-$(CONFIG_ETRAX_SERIAL) += crisv10.o +obj-$(CONFIG_SERIAL_SC26XX) += sc26xx.o obj-$(CONFIG_SERIAL_JSM) += jsm/ obj-$(CONFIG_SERIAL_TXX9) += serial_txx9.o obj-$(CONFIG_SERIAL_VR41XX) += vr41xx_siu.o diff --git a/drivers/serial/cpm_uart/cpm_uart_core.c b/drivers/serial/cpm_uart/cpm_uart_core.c index b5e4478de0e3..236af9d33851 100644 --- a/drivers/serial/cpm_uart/cpm_uart_core.c +++ b/drivers/serial/cpm_uart/cpm_uart_core.c @@ -380,7 +380,7 @@ static void cpm_uart_int_rx(struct uart_port *port) static irqreturn_t cpm_uart_int(int irq, void *data) { u8 events; - struct uart_port *port = (struct uart_port *)data; + struct uart_port *port = data; struct uart_cpm_port *pinfo = (struct uart_cpm_port *)port; smc_t __iomem *smcp = pinfo->smcp; scc_t __iomem *sccp = pinfo->sccp; diff --git a/drivers/serial/dz.c b/drivers/serial/dz.c index d31721f2744d..bbae5a220219 100644 --- a/drivers/serial/dz.c +++ b/drivers/serial/dz.c @@ -324,7 +324,7 @@ static inline void check_modem_status(struct dz_port *dport) */ static irqreturn_t dz_interrupt(int irq, void *dev) { - struct dz_port *dport = (struct dz_port *)dev; + struct dz_port *dport = dev; unsigned short status; /* get the reason why we just got an irq */ diff --git a/drivers/serial/imx.c b/drivers/serial/imx.c index dc1967176fe2..56af1f566a4c 100644 --- a/drivers/serial/imx.c +++ b/drivers/serial/imx.c @@ -308,7 +308,7 @@ static void imx_start_tx(struct uart_port *port) static irqreturn_t imx_rtsint(int irq, void *dev_id) { - struct imx_port *sport = (struct imx_port *)dev_id; + struct imx_port *sport = dev_id; unsigned int val = readl(sport->port.membase + USR1) & USR1_RTSS; unsigned long flags; @@ -324,7 +324,7 @@ static irqreturn_t imx_rtsint(int irq, void *dev_id) static irqreturn_t imx_txint(int irq, void *dev_id) { - struct imx_port *sport = (struct imx_port *)dev_id; + struct imx_port *sport = dev_id; struct circ_buf *xmit = &sport->port.info->xmit; unsigned long flags; diff --git a/drivers/serial/sc26xx.c b/drivers/serial/sc26xx.c new file mode 100644 index 000000000000..a350b6d2a181 --- /dev/null +++ b/drivers/serial/sc26xx.c @@ -0,0 +1,755 @@ +/* + * SC268xx.c: Serial driver for Philiphs SC2681/SC2692 devices. + * + * Copyright (C) 2006,2007 Thomas Bogendörfer (tsbogend@alpha.franken.de) + */ + +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/errno.h> +#include <linux/tty.h> +#include <linux/tty_flip.h> +#include <linux/major.h> +#include <linux/circ_buf.h> +#include <linux/serial.h> +#include <linux/sysrq.h> +#include <linux/console.h> +#include <linux/spinlock.h> +#include <linux/slab.h> +#include <linux/delay.h> +#include <linux/init.h> +#include <linux/platform_device.h> +#include <linux/irq.h> + +#if defined(CONFIG_MAGIC_SYSRQ) +#define SUPPORT_SYSRQ +#endif + +#include <linux/serial_core.h> + +#define SC26XX_MAJOR 204 +#define SC26XX_MINOR_START 205 +#define SC26XX_NR 2 + +struct uart_sc26xx_port { + struct uart_port port[2]; + u8 dsr_mask[2]; + u8 cts_mask[2]; + u8 dcd_mask[2]; + u8 ri_mask[2]; + u8 dtr_mask[2]; + u8 rts_mask[2]; + u8 imr; +}; + +/* register common to both ports */ +#define RD_ISR 0x14 +#define RD_IPR 0x34 + +#define WR_ACR 0x10 +#define WR_IMR 0x14 +#define WR_OPCR 0x34 +#define WR_OPR_SET 0x38 +#define WR_OPR_CLR 0x3C + +/* access common register */ +#define READ_SC(p, r) readb((p)->membase + RD_##r) +#define WRITE_SC(p, r, v) writeb((v), (p)->membase + WR_##r) + +/* register per port */ +#define RD_PORT_MRx 0x00 +#define RD_PORT_SR 0x04 +#define RD_PORT_RHR 0x0c + +#define WR_PORT_MRx 0x00 +#define WR_PORT_CSR 0x04 +#define WR_PORT_CR 0x08 +#define WR_PORT_THR 0x0c + +/* SR bits */ +#define SR_BREAK (1 << 7) +#define SR_FRAME (1 << 6) +#define SR_PARITY (1 << 5) +#define SR_OVERRUN (1 << 4) +#define SR_TXRDY (1 << 2) +#define SR_RXRDY (1 << 0) + +#define CR_RES_MR (1 << 4) +#define CR_RES_RX (2 << 4) +#define CR_RES_TX (3 << 4) +#define CR_STRT_BRK (6 << 4) +#define CR_STOP_BRK (7 << 4) +#define CR_DIS_TX (1 << 3) +#define CR_ENA_TX (1 << 2) +#define CR_DIS_RX (1 << 1) +#define CR_ENA_RX (1 << 0) + +/* ISR bits */ +#define ISR_RXRDYB (1 << 5) +#define ISR_TXRDYB (1 << 4) +#define ISR_RXRDYA (1 << 1) +#define ISR_TXRDYA (1 << 0) + +/* IMR bits */ +#define IMR_RXRDY (1 << 1) +#define IMR_TXRDY (1 << 0) + +/* access port register */ +static inline u8 read_sc_port(struct uart_port *p, u8 reg) +{ + return readb(p->membase + p->line * 0x20 + reg); +} + +static inline void write_sc_port(struct uart_port *p, u8 reg, u8 val) +{ + writeb(val, p->membase + p->line * 0x20 + reg); +} + +#define READ_SC_PORT(p, r) read_sc_port(p, RD_PORT_##r) +#define WRITE_SC_PORT(p, r, v) write_sc_port(p, WR_PORT_##r, v) + +static void sc26xx_enable_irq(struct uart_port *port, int mask) +{ + struct uart_sc26xx_port *up; + int line = port->line; + + port -= line; + up = container_of(port, struct uart_sc26xx_port, port[0]); + + up->imr |= mask << (line * 4); + WRITE_SC(port, IMR, up->imr); +} + +static void sc26xx_disable_irq(struct uart_port *port, int mask) +{ + struct uart_sc26xx_port *up; + int line = port->line; + + port -= line; + up = container_of(port, struct uart_sc26xx_port, port[0]); + + up->imr &= ~(mask << (line * 4)); + WRITE_SC(port, IMR, up->imr); +} + +static struct tty_struct *receive_chars(struct uart_port *port) +{ + struct tty_struct *tty = NULL; + int limit = 10000; + unsigned char ch; + char flag; + u8 status; + + if (port->info != NULL) /* Unopened serial console */ + tty = port->info->tty; + + while (limit-- > 0) { + status = READ_SC_PORT(port, SR); + if (!(status & SR_RXRDY)) + break; + ch = READ_SC_PORT(port, RHR); + + flag = TTY_NORMAL; + port->icount.rx++; + + if (unlikely(status & (SR_BREAK | SR_FRAME | + SR_PARITY | SR_OVERRUN))) { + if (status & SR_BREAK) { + status &= ~(SR_PARITY | SR_FRAME); + port->icount.brk++; + if (uart_handle_break(port)) + continue; + } else if (status & SR_PARITY) + port->icount.parity++; + else if (status & SR_FRAME) + port->icount.frame++; + if (status & SR_OVERRUN) + port->icount.overrun++; + + status &= port->read_status_mask; + if (status & SR_BREAK) + flag = TTY_BREAK; + else if (status & SR_PARITY) + flag = TTY_PARITY; + else if (status & SR_FRAME) + flag = TTY_FRAME; + } + + if (uart_handle_sysrq_char(port, ch)) + continue; + + if (status & port->ignore_status_mask) + continue; + + tty_insert_flip_char(tty, ch, flag); + } + return tty; +} + +static void transmit_chars(struct uart_port *port) +{ + struct circ_buf *xmit; + + if (!port->info) + return; + + xmit = &port->info->xmit; + if (uart_circ_empty(xmit) || uart_tx_stopped(port)) { + sc26xx_disable_irq(port, IMR_TXRDY); + return; + } + while (!uart_circ_empty(xmit)) { + if (!(READ_SC_PORT(port, SR) & SR_TXRDY)) + break; + + WRITE_SC_PORT(port, THR, xmit->buf[xmit->tail]); + xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); + port->icount.tx++; + } + if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) + uart_write_wakeup(port); +} + +static irqreturn_t sc26xx_interrupt(int irq, void *dev_id) +{ + struct uart_sc26xx_port *up = dev_id; + struct tty_struct *tty; + unsigned long flags; + u8 isr; + + spin_lock_irqsave(&up->port[0].lock, flags); + + tty = NULL; + isr = READ_SC(&up->port[0], ISR); + if (isr & ISR_TXRDYA) + transmit_chars(&up->port[0]); + if (isr & ISR_RXRDYA) + tty = receive_chars(&up->port[0]); + + spin_unlock(&up->port[0].lock); + + if (tty) + tty_flip_buffer_push(tty); + + spin_lock(&up->port[1].lock); + + tty = NULL; + if (isr & ISR_TXRDYB) + transmit_chars(&up->port[1]); + if (isr & ISR_RXRDYB) + tty = receive_chars(&up->port[1]); + + spin_unlock_irqrestore(&up->port[1].lock, flags); + + if (tty) + tty_flip_buffer_push(tty); + + return IRQ_HANDLED; +} + +/* port->lock is not held. */ +static unsigned int sc26xx_tx_empty(struct uart_port *port) +{ + return (READ_SC_PORT(port, SR) & SR_TXRDY) ? TIOCSER_TEMT : 0; +} + +/* port->lock held by caller. */ +static void sc26xx_set_mctrl(struct uart_port *port, unsigned int mctrl) +{ + struct uart_sc26xx_port *up; + int line = port->line; + + port -= line; + up = container_of(port, struct uart_sc26xx_port, port[0]); + + if (up->dtr_mask[line]) { + if (mctrl & TIOCM_DTR) + WRITE_SC(port, OPR_SET, up->dtr_mask[line]); + else + WRITE_SC(port, OPR_CLR, up->dtr_mask[line]); + } + if (up->rts_mask[line]) { + if (mctrl & TIOCM_RTS) + WRITE_SC(port, OPR_SET, up->rts_mask[line]); + else + WRITE_SC(port, OPR_CLR, up->rts_mask[line]); + } +} + +/* port->lock is held by caller and interrupts are disabled. */ +static unsigned int sc26xx_get_mctrl(struct uart_port *port) +{ + struct uart_sc26xx_port *up; + int line = port->line; + unsigned int mctrl = TIOCM_DSR | TIOCM_CTS | TIOCM_CAR; + u8 ipr; + + port -= line; + up = container_of(port, struct uart_sc26xx_port, port[0]); + ipr = READ_SC(port, IPR) ^ 0xff; + + if (up->dsr_mask[line]) { + mctrl &= ~TIOCM_DSR; + mctrl |= ipr & up->dsr_mask[line] ? TIOCM_DSR : 0; + } + if (up->cts_mask[line]) { + mctrl &= ~TIOCM_CTS; + mctrl |= ipr & up->cts_mask[line] ? TIOCM_CTS : 0; + } + if (up->dcd_mask[line]) { + mctrl &= ~TIOCM_CAR; + mctrl |= ipr & up->dcd_mask[line] ? TIOCM_CAR : 0; + } + if (up->ri_mask[line]) { + mctrl &= ~TIOCM_RNG; + mctrl |= ipr & up->ri_mask[line] ? TIOCM_RNG : 0; + } + return mctrl; +} + +/* port->lock held by caller. */ +static void sc26xx_stop_tx(struct uart_port *port) +{ + return; +} + +/* port->lock held by caller. */ +static void sc26xx_start_tx(struct uart_port *port) +{ + struct circ_buf *xmit = &port->info->xmit; + + while (!uart_circ_empty(xmit)) { + if (!(READ_SC_PORT(port, SR) & SR_TXRDY)) { + sc26xx_enable_irq(port, IMR_TXRDY); + break; + } + WRITE_SC_PORT(port, THR, xmit->buf[xmit->tail]); + xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); + port->icount.tx++; + } +} + +/* port->lock held by caller. */ +static void sc26xx_stop_rx(struct uart_port *port) +{ +} + +/* port->lock held by caller. */ +static void sc26xx_enable_ms(struct uart_port *port) +{ +} + +/* port->lock is not held. */ +static void sc26xx_break_ctl(struct uart_port *port, int break_state) +{ + if (break_state == -1) + WRITE_SC_PORT(port, CR, CR_STRT_BRK); + else + WRITE_SC_PORT(port, CR, CR_STOP_BRK); +} + +/* port->lock is not held. */ +static int sc26xx_startup(struct uart_port *port) +{ + sc26xx_disable_irq(port, IMR_TXRDY | IMR_RXRDY); + WRITE_SC(port, OPCR, 0); + + /* reset tx and rx */ + WRITE_SC_PORT(port, CR, CR_RES_RX); + WRITE_SC_PORT(port, CR, CR_RES_TX); + + /* start rx/tx */ + WRITE_SC_PORT(port, CR, CR_ENA_TX | CR_ENA_RX); + + /* enable irqs */ + sc26xx_enable_irq(port, IMR_RXRDY); + return 0; +} + +/* port->lock is not held. */ +static void sc26xx_shutdown(struct uart_port *port) +{ + /* disable interrupst */ + sc26xx_disable_irq(port, IMR_TXRDY | IMR_RXRDY); + + /* stop tx/rx */ + WRITE_SC_PORT(port, CR, CR_DIS_TX | CR_DIS_RX); +} + +/* port->lock is not held. */ +static void sc26xx_set_termios(struct uart_port *port, struct ktermios *termios, + struct ktermios *old) +{ + unsigned int baud = uart_get_baud_rate(port, termios, old, 0, 4000000); + unsigned int quot = uart_get_divisor(port, baud); + unsigned int iflag, cflag; + unsigned long flags; + u8 mr1, mr2, csr; + + spin_lock_irqsave(&port->lock, flags); + + while ((READ_SC_PORT(port, SR) & ((1 << 3) | (1 << 2))) != 0xc) + udelay(2); + + WRITE_SC_PORT(port, CR, CR_DIS_TX | CR_DIS_RX); + + iflag = termios->c_iflag; + cflag = termios->c_cflag; + + port->read_status_mask = SR_OVERRUN; + if (iflag & INPCK) + port->read_status_mask |= SR_PARITY | SR_FRAME; + if (iflag & (BRKINT | PARMRK)) + port->read_status_mask |= SR_BREAK; + + port->ignore_status_mask = 0; + if (iflag & IGNBRK) + port->ignore_status_mask |= SR_BREAK; + if ((cflag & CREAD) == 0) + port->ignore_status_mask |= SR_BREAK | SR_FRAME | + SR_PARITY | SR_OVERRUN; + + switch (cflag & CSIZE) { + case CS5: + mr1 = 0x00; + break; + case CS6: + mr1 = 0x01; + break; + case CS7: + mr1 = 0x02; + break; + default: + case CS8: + mr1 = 0x03; + break; + } + mr2 = 0x07; + if (cflag & CSTOPB) + mr2 = 0x0f; + if (cflag & PARENB) { + if (cflag & PARODD) + mr1 |= (1 << 2); + } else + mr1 |= (2 << 3); + + switch (baud) { + case 50: + csr = 0x00; + break; + case 110: + csr = 0x11; + break; + case 134: + csr = 0x22; + break; + case 200: + csr = 0x33; + break; + case 300: + csr = 0x44; + break; + case 600: + csr = 0x55; + break; + case 1200: + csr = 0x66; + break; + case 2400: + csr = 0x88; + break; + case 4800: + csr = 0x99; + break; + default: + case 9600: + csr = 0xbb; + break; + case 19200: + csr = 0xcc; + break; + } + + WRITE_SC_PORT(port, CR, CR_RES_MR); + WRITE_SC_PORT(port, MRx, mr1); + WRITE_SC_PORT(port, MRx, mr2); + + WRITE_SC(port, ACR, 0x80); + WRITE_SC_PORT(port, CSR, csr); + + /* reset tx and rx */ + WRITE_SC_PORT(port, CR, CR_RES_RX); + WRITE_SC_PORT(port, CR, CR_RES_TX); + + WRITE_SC_PORT(port, CR, CR_ENA_TX | CR_ENA_RX); + while ((READ_SC_PORT(port, SR) & ((1 << 3) | (1 << 2))) != 0xc) + udelay(2); + + /* XXX */ + uart_update_timeout(port, cflag, + (port->uartclk / (16 * quot))); + + spin_unlock_irqrestore(&port->lock, flags); +} + +static const char *sc26xx_type(struct uart_port *port) +{ + return "SC26XX"; +} + +static void sc26xx_release_port(struct uart_port *port) +{ +} + +static int sc26xx_request_port(struct uart_port *port) +{ + return 0; +} + +static void sc26xx_config_port(struct uart_port *port, int flags) +{ +} + +static int sc26xx_verify_port(struct uart_port *port, struct serial_struct *ser) +{ + return -EINVAL; +} + +static struct uart_ops sc26xx_ops = { + .tx_empty = sc26xx_tx_empty, + .set_mctrl = sc26xx_set_mctrl, + .get_mctrl = sc26xx_get_mctrl, + .stop_tx = sc26xx_stop_tx, + .start_tx = sc26xx_start_tx, + .stop_rx = sc26xx_stop_rx, + .enable_ms = sc26xx_enable_ms, + .break_ctl = sc26xx_break_ctl, + .startup = sc26xx_startup, + .shutdown = sc26xx_shutdown, + .set_termios = sc26xx_set_termios, + .type = sc26xx_type, + .release_port = sc26xx_release_port, + .request_port = sc26xx_request_port, + .config_port = sc26xx_config_port, + .verify_port = sc26xx_verify_port, +}; + +static struct uart_port *sc26xx_port; + +#ifdef CONFIG_SERIAL_SC26XX_CONSOLE +static void sc26xx_console_putchar(struct uart_port *port, char c) +{ + unsigned long flags; + int limit = 1000000; + + spin_lock_irqsave(&port->lock, flags); + + while (limit-- > 0) { + if (READ_SC_PORT(port, SR) & SR_TXRDY) { + WRITE_SC_PORT(port, THR, c); + break; + } + udelay(2); + } + + spin_unlock_irqrestore(&port->lock, flags); +} + +static void sc26xx_console_write(struct console *con, const char *s, unsigned n) +{ + struct uart_port *port = sc26xx_port; + int i; + + for (i = 0; i < n; i++) { + if (*s == '\n') + sc26xx_console_putchar(port, '\r'); + sc26xx_console_putchar(port, *s++); + } +} + +static int __init sc26xx_console_setup(struct console *con, char *options) +{ + struct uart_port *port = sc26xx_port; + int baud = 9600; + int bits = 8; + int parity = 'n'; + int flow = 'n'; + + if (port->type != PORT_SC26XX) + return -1; + + printk(KERN_INFO "Console: ttySC%d (SC26XX)\n", con->index); + if (options) + uart_parse_options(options, &baud, &parity, &bits, &flow); + + return uart_set_options(port, con, baud, parity, bits, flow); +} + +static struct uart_driver sc26xx_reg; +static struct console sc26xx_console = { + .name = "ttySC", + .write = sc26xx_console_write, + .device = uart_console_device, + .setup = sc26xx_console_setup, + .flags = CON_PRINTBUFFER, + .index = -1, + .data = &sc26xx_reg, +}; +#define SC26XX_CONSOLE &sc26xx_console +#else +#define SC26XX_CONSOLE NULL +#endif + +static struct uart_driver sc26xx_reg = { + .owner = THIS_MODULE, + .driver_name = "SC26xx", + .dev_name = "ttySC", + .major = SC26XX_MAJOR, + .minor = SC26XX_MINOR_START, + .nr = SC26XX_NR, + .cons = SC26XX_CONSOLE, +}; + +static u8 sc26xx_flags2mask(unsigned int flags, unsigned int bitpos) +{ + unsigned int bit = (flags >> bitpos) & 15; + + return bit ? (1 << (bit - 1)) : 0; +} + +static void __devinit sc26xx_init_masks(struct uart_sc26xx_port *up, + int line, unsigned int data) +{ + up->dtr_mask[line] = sc26xx_flags2mask(data, 0); + up->rts_mask[line] = sc26xx_flags2mask(data, 4); + up->dsr_mask[line] = sc26xx_flags2mask(data, 8); + up->cts_mask[line] = sc26xx_flags2mask(data, 12); + up->dcd_mask[line] = sc26xx_flags2mask(data, 16); + up->ri_mask[line] = sc26xx_flags2mask(data, 20); +} + +static int __devinit sc26xx_probe(struct platform_device *dev) +{ + struct resource *res; + struct uart_sc26xx_port *up; + unsigned int *sc26xx_data = dev->dev.platform_data; + int err; + + res = platform_get_resource(dev, IORESOURCE_MEM, 0); + if (!res) + return -ENODEV; + + up = kzalloc(sizeof *up, GFP_KERNEL); + if (unlikely(!up)) + return -ENOMEM; + + up->port[0].line = 0; + up->port[0].ops = &sc26xx_ops; + up->port[0].type = PORT_SC26XX; + up->port[0].uartclk = (29491200 / 16); /* arbitrary */ + + up->port[0].mapbase = res->start; + up->port[0].membase = ioremap_nocache(up->port[0].mapbase, 0x40); + up->port[0].iotype = UPIO_MEM; + up->port[0].irq = platform_get_irq(dev, 0); + + up->port[0].dev = &dev->dev; + + sc26xx_init_masks(up, 0, sc26xx_data[0]); + + sc26xx_port = &up->port[0]; + + up->port[1].line = 1; + up->port[1].ops = &sc26xx_ops; + up->port[1].type = PORT_SC26XX; + up->port[1].uartclk = (29491200 / 16); /* arbitrary */ + + up->port[1].mapbase = up->port[0].mapbase; + up->port[1].membase = up->port[0].membase; + up->port[1].iotype = UPIO_MEM; + up->port[1].irq = up->port[0].irq; + + up->port[1].dev = &dev->dev; + + sc26xx_init_masks(up, 1, sc26xx_data[1]); + + err = uart_register_driver(&sc26xx_reg); + if (err) + goto out_free_port; + + sc26xx_reg.tty_driver->name_base = sc26xx_reg.minor; + + err = uart_add_one_port(&sc26xx_reg, &up->port[0]); + if (err) + goto out_unregister_driver; + + err = uart_add_one_port(&sc26xx_reg, &up->port[1]); + if (err) + goto out_remove_port0; + + err = request_irq(up->port[0].irq, sc26xx_interrupt, 0, "sc26xx", up); + if (err) + goto out_remove_ports; + + dev_set_drvdata(&dev->dev, up); + return 0; + +out_remove_ports: + uart_remove_one_port(&sc26xx_reg, &up->port[1]); +out_remove_port0: + uart_remove_one_port(&sc26xx_reg, &up->port[0]); + +out_unregister_driver: + uart_unregister_driver(&sc26xx_reg); + +out_free_port: + kfree(up); + sc26xx_port = NULL; + return err; +} + + +static int __exit sc26xx_driver_remove(struct platform_device *dev) +{ + struct uart_sc26xx_port *up = dev_get_drvdata(&dev->dev); + + free_irq(up->port[0].irq, up); + + uart_remove_one_port(&sc26xx_reg, &up->port[0]); + uart_remove_one_port(&sc26xx_reg, &up->port[1]); + + uart_unregister_driver(&sc26xx_reg); + + kfree(up); + sc26xx_port = NULL; + + dev_set_drvdata(&dev->dev, NULL); + return 0; +} + +static struct platform_driver sc26xx_driver = { + .probe = sc26xx_probe, + .remove = __devexit_p(sc26xx_driver_remove), + .driver = { + .name = "SC26xx", + }, +}; + +static int __init sc26xx_init(void) +{ + return platform_driver_register(&sc26xx_driver); +} + +static void __exit sc26xx_exit(void) +{ + platform_driver_unregister(&sc26xx_driver); +} + +module_init(sc26xx_init); +module_exit(sc26xx_exit); + + +MODULE_AUTHOR("Thomas Bogendörfer"); +MODULE_DESCRIPTION("SC681/SC2692 serial driver"); +MODULE_VERSION("1.0"); +MODULE_LICENSE("GPL"); diff --git a/drivers/serial/uartlite.c b/drivers/serial/uartlite.c index 80943409edb0..bacf68dca01a 100644 --- a/drivers/serial/uartlite.c +++ b/drivers/serial/uartlite.c @@ -142,7 +142,7 @@ static int ulite_transmit(struct uart_port *port, int stat) static irqreturn_t ulite_isr(int irq, void *dev_id) { - struct uart_port *port = (struct uart_port *)dev_id; + struct uart_port *port = dev_id; int busy; do { diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig index aaaea81e412a..d8107890db15 100644 --- a/drivers/spi/Kconfig +++ b/drivers/spi/Kconfig @@ -144,10 +144,10 @@ config SPI_OMAP_UWIRE This hooks up to the MicroWire controller on OMAP1 chips. config SPI_OMAP24XX - tristate "McSPI driver for OMAP24xx" - depends on SPI_MASTER && ARCH_OMAP24XX + tristate "McSPI driver for OMAP24xx/OMAP34xx" + depends on SPI_MASTER && (ARCH_OMAP24XX || ARCH_OMAP34XX) help - SPI master controller for OMAP24xx Multichannel SPI + SPI master controller for OMAP24xx/OMAP34xx Multichannel SPI (McSPI) modules. config SPI_PXA2XX @@ -176,6 +176,13 @@ config SPI_S3C24XX_GPIO the inbuilt hardware cannot provide the transfer mode, or where the board is using non hardware connected pins. +config SPI_SH_SCI + tristate "SuperH SCI SPI controller" + depends on SPI_MASTER && SUPERH + select SPI_BITBANG + help + SPI driver for SuperH SCI blocks. + config SPI_TXX9 tristate "Toshiba TXx9 SPI controller" depends on SPI_MASTER && GENERIC_GPIO && CPU_TX49XX diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile index 41fbac45c323..7fca043ce723 100644 --- a/drivers/spi/Makefile +++ b/drivers/spi/Makefile @@ -27,6 +27,7 @@ obj-$(CONFIG_SPI_S3C24XX_GPIO) += spi_s3c24xx_gpio.o obj-$(CONFIG_SPI_S3C24XX) += spi_s3c24xx.o obj-$(CONFIG_SPI_TXX9) += spi_txx9.o obj-$(CONFIG_SPI_XILINX) += xilinx_spi.o +obj-$(CONFIG_SPI_SH_SCI) += spi_sh_sci.o # ... add above this line ... # SPI protocol drivers (device/link on bus) diff --git a/drivers/spi/atmel_spi.c b/drivers/spi/atmel_spi.c index ff10808183a3..293b7cab3e57 100644 --- a/drivers/spi/atmel_spi.c +++ b/drivers/spi/atmel_spi.c @@ -51,7 +51,9 @@ struct atmel_spi { u8 stopping; struct list_head queue; struct spi_transfer *current_transfer; - unsigned long remaining_bytes; + unsigned long current_remaining_bytes; + struct spi_transfer *next_transfer; + unsigned long next_remaining_bytes; void *buffer; dma_addr_t buffer_dma; @@ -121,6 +123,48 @@ static void cs_deactivate(struct atmel_spi *as, struct spi_device *spi) gpio_set_value(gpio, !active); } +static inline int atmel_spi_xfer_is_last(struct spi_message *msg, + struct spi_transfer *xfer) +{ + return msg->transfers.prev == &xfer->transfer_list; +} + +static inline int atmel_spi_xfer_can_be_chained(struct spi_transfer *xfer) +{ + return xfer->delay_usecs == 0 && !xfer->cs_change; +} + +static void atmel_spi_next_xfer_data(struct spi_master *master, + struct spi_transfer *xfer, + dma_addr_t *tx_dma, + dma_addr_t *rx_dma, + u32 *plen) +{ + struct atmel_spi *as = spi_master_get_devdata(master); + u32 len = *plen; + + /* use scratch buffer only when rx or tx data is unspecified */ + if (xfer->rx_buf) + *rx_dma = xfer->rx_dma + xfer->len - len; + else { + *rx_dma = as->buffer_dma; + if (len > BUFFER_SIZE) + len = BUFFER_SIZE; + } + if (xfer->tx_buf) + *tx_dma = xfer->tx_dma + xfer->len - len; + else { + *tx_dma = as->buffer_dma; + if (len > BUFFER_SIZE) + len = BUFFER_SIZE; + memset(as->buffer, 0, len); + dma_sync_single_for_device(&as->pdev->dev, + as->buffer_dma, len, DMA_TO_DEVICE); + } + + *plen = len; +} + /* * Submit next transfer for DMA. * lock is held, spi irq is blocked @@ -130,53 +174,78 @@ static void atmel_spi_next_xfer(struct spi_master *master, { struct atmel_spi *as = spi_master_get_devdata(master); struct spi_transfer *xfer; - u32 len; + u32 len, remaining, total; dma_addr_t tx_dma, rx_dma; - xfer = as->current_transfer; - if (!xfer || as->remaining_bytes == 0) { - if (xfer) - xfer = list_entry(xfer->transfer_list.next, - struct spi_transfer, transfer_list); - else - xfer = list_entry(msg->transfers.next, - struct spi_transfer, transfer_list); - as->remaining_bytes = xfer->len; - as->current_transfer = xfer; - } + if (!as->current_transfer) + xfer = list_entry(msg->transfers.next, + struct spi_transfer, transfer_list); + else if (!as->next_transfer) + xfer = list_entry(as->current_transfer->transfer_list.next, + struct spi_transfer, transfer_list); + else + xfer = NULL; - len = as->remaining_bytes; + if (xfer) { + len = xfer->len; + atmel_spi_next_xfer_data(master, xfer, &tx_dma, &rx_dma, &len); + remaining = xfer->len - len; - tx_dma = xfer->tx_dma + xfer->len - len; - rx_dma = xfer->rx_dma + xfer->len - len; + spi_writel(as, RPR, rx_dma); + spi_writel(as, TPR, tx_dma); - /* use scratch buffer only when rx or tx data is unspecified */ - if (!xfer->rx_buf) { - rx_dma = as->buffer_dma; - if (len > BUFFER_SIZE) - len = BUFFER_SIZE; - } - if (!xfer->tx_buf) { - tx_dma = as->buffer_dma; - if (len > BUFFER_SIZE) - len = BUFFER_SIZE; - memset(as->buffer, 0, len); - dma_sync_single_for_device(&as->pdev->dev, - as->buffer_dma, len, DMA_TO_DEVICE); + if (msg->spi->bits_per_word > 8) + len >>= 1; + spi_writel(as, RCR, len); + spi_writel(as, TCR, len); + + dev_dbg(&msg->spi->dev, + " start xfer %p: len %u tx %p/%08x rx %p/%08x\n", + xfer, xfer->len, xfer->tx_buf, xfer->tx_dma, + xfer->rx_buf, xfer->rx_dma); + } else { + xfer = as->next_transfer; + remaining = as->next_remaining_bytes; } - spi_writel(as, RPR, rx_dma); - spi_writel(as, TPR, tx_dma); + as->current_transfer = xfer; + as->current_remaining_bytes = remaining; - as->remaining_bytes -= len; - if (msg->spi->bits_per_word > 8) - len >>= 1; + if (remaining > 0) + len = remaining; + else if (!atmel_spi_xfer_is_last(msg, xfer) + && atmel_spi_xfer_can_be_chained(xfer)) { + xfer = list_entry(xfer->transfer_list.next, + struct spi_transfer, transfer_list); + len = xfer->len; + } else + xfer = NULL; - /* REVISIT: when xfer->delay_usecs == 0, the PDC "next transfer" - * mechanism might help avoid the IRQ latency between transfers - * (and improve the nCS0 errata handling on at91rm9200 chips) - * - * We're also waiting for ENDRX before we start the next + as->next_transfer = xfer; + + if (xfer) { + total = len; + atmel_spi_next_xfer_data(master, xfer, &tx_dma, &rx_dma, &len); + as->next_remaining_bytes = total - len; + + spi_writel(as, RNPR, rx_dma); + spi_writel(as, TNPR, tx_dma); + + if (msg->spi->bits_per_word > 8) + len >>= 1; + spi_writel(as, RNCR, len); + spi_writel(as, TNCR, len); + + dev_dbg(&msg->spi->dev, + " next xfer %p: len %u tx %p/%08x rx %p/%08x\n", + xfer, xfer->len, xfer->tx_buf, xfer->tx_dma, + xfer->rx_buf, xfer->rx_dma); + } else { + spi_writel(as, RNCR, 0); + spi_writel(as, TNCR, 0); + } + + /* REVISIT: We're waiting for ENDRX before we start the next * transfer because we need to handle some difficult timing * issues otherwise. If we wait for ENDTX in one transfer and * then starts waiting for ENDRX in the next, it's difficult @@ -186,17 +255,7 @@ static void atmel_spi_next_xfer(struct spi_master *master, * * It should be doable, though. Just not now... */ - spi_writel(as, TNCR, 0); - spi_writel(as, RNCR, 0); spi_writel(as, IER, SPI_BIT(ENDRX) | SPI_BIT(OVRES)); - - dev_dbg(&msg->spi->dev, - " start xfer %p: len %u tx %p/%08x rx %p/%08x imr %03x\n", - xfer, xfer->len, xfer->tx_buf, xfer->tx_dma, - xfer->rx_buf, xfer->rx_dma, spi_readl(as, IMR)); - - spi_writel(as, RCR, len); - spi_writel(as, TCR, len); spi_writel(as, PTCR, SPI_BIT(TXTEN) | SPI_BIT(RXTEN)); } @@ -294,6 +353,7 @@ atmel_spi_msg_done(struct spi_master *master, struct atmel_spi *as, spin_lock(&as->lock); as->current_transfer = NULL; + as->next_transfer = NULL; /* continue if needed */ if (list_empty(&as->queue) || as->stopping) @@ -377,7 +437,7 @@ atmel_spi_interrupt(int irq, void *dev_id) spi_writel(as, IDR, pending); - if (as->remaining_bytes == 0) { + if (as->current_remaining_bytes == 0) { msg->actual_length += xfer->len; if (!msg->is_dma_mapped) @@ -387,7 +447,7 @@ atmel_spi_interrupt(int irq, void *dev_id) if (xfer->delay_usecs) udelay(xfer->delay_usecs); - if (msg->transfers.prev == &xfer->transfer_list) { + if (atmel_spi_xfer_is_last(msg, xfer)) { /* report completed message */ atmel_spi_msg_done(master, as, msg, 0, xfer->cs_change); @@ -490,9 +550,14 @@ static int atmel_spi_setup(struct spi_device *spi) if (!(spi->mode & SPI_CPHA)) csr |= SPI_BIT(NCPHA); - /* TODO: DLYBS and DLYBCT */ - csr |= SPI_BF(DLYBS, 10); - csr |= SPI_BF(DLYBCT, 10); + /* DLYBS is mostly irrelevant since we manage chipselect using GPIOs. + * + * DLYBCT would add delays between words, slowing down transfers. + * It could potentially be useful to cope with DMA bottlenecks, but + * in those cases it's probably best to just use a lower bitrate. + */ + csr |= SPI_BF(DLYBS, 0); + csr |= SPI_BF(DLYBCT, 0); /* chipselect must have been muxed as GPIO (e.g. in board setup) */ npcs_pin = (unsigned int)spi->controller_data; diff --git a/drivers/spi/omap2_mcspi.c b/drivers/spi/omap2_mcspi.c index ea61724ae225..a6ba11afb03f 100644 --- a/drivers/spi/omap2_mcspi.c +++ b/drivers/spi/omap2_mcspi.c @@ -915,6 +915,28 @@ static u8 __initdata spi2_txdma_id[] = { OMAP24XX_DMA_SPI2_TX1, }; +#if defined(CONFIG_ARCH_OMAP2430) || defined(CONFIG_ARCH_OMAP34XX) +static u8 __initdata spi3_rxdma_id[] = { + OMAP24XX_DMA_SPI3_RX0, + OMAP24XX_DMA_SPI3_RX1, +}; + +static u8 __initdata spi3_txdma_id[] = { + OMAP24XX_DMA_SPI3_TX0, + OMAP24XX_DMA_SPI3_TX1, +}; +#endif + +#ifdef CONFIG_ARCH_OMAP3 +static u8 __initdata spi4_rxdma_id[] = { + OMAP34XX_DMA_SPI4_RX0, +}; + +static u8 __initdata spi4_txdma_id[] = { + OMAP34XX_DMA_SPI4_TX0, +}; +#endif + static int __init omap2_mcspi_probe(struct platform_device *pdev) { struct spi_master *master; @@ -935,7 +957,20 @@ static int __init omap2_mcspi_probe(struct platform_device *pdev) txdma_id = spi2_txdma_id; num_chipselect = 2; break; - /* REVISIT omap2430 has a third McSPI ... */ +#if defined(CONFIG_ARCH_OMAP2430) || defined(CONFIG_ARCH_OMAP3) + case 3: + rxdma_id = spi3_rxdma_id; + txdma_id = spi3_txdma_id; + num_chipselect = 2; + break; +#endif +#ifdef CONFIG_ARCH_OMAP3 + case 4: + rxdma_id = spi4_rxdma_id; + txdma_id = spi4_txdma_id; + num_chipselect = 1; + break; +#endif default: return -EINVAL; } diff --git a/drivers/spi/pxa2xx_spi.c b/drivers/spi/pxa2xx_spi.c index eb817b8eb024..365e0e355aea 100644 --- a/drivers/spi/pxa2xx_spi.c +++ b/drivers/spi/pxa2xx_spi.c @@ -1526,17 +1526,6 @@ static void pxa2xx_spi_shutdown(struct platform_device *pdev) } #ifdef CONFIG_PM -static int suspend_devices(struct device *dev, void *pm_message) -{ - pm_message_t *state = pm_message; - - if (dev->power.power_state.event != state->event) { - dev_warn(dev, "pm state does not match request\n"); - return -1; - } - - return 0; -} static int pxa2xx_spi_suspend(struct platform_device *pdev, pm_message_t state) { @@ -1544,12 +1533,6 @@ static int pxa2xx_spi_suspend(struct platform_device *pdev, pm_message_t state) struct ssp_device *ssp = drv_data->ssp; int status = 0; - /* Check all childern for current power state */ - if (device_for_each_child(&pdev->dev, &state, suspend_devices) != 0) { - dev_warn(&pdev->dev, "suspend aborted\n"); - return -1; - } - status = stop_queue(drv_data); if (status != 0) return status; diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index 682a6a48fec3..1ad12afc6ba0 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c @@ -18,7 +18,6 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -#include <linux/autoconf.h> #include <linux/kernel.h> #include <linux/device.h> #include <linux/init.h> @@ -77,39 +76,33 @@ static int spi_uevent(struct device *dev, struct kobj_uevent_env *env) #ifdef CONFIG_PM -/* - * NOTE: the suspend() method for an spi_master controller driver - * should verify that all its child devices are marked as suspended; - * suspend requests delivered through sysfs power/state files don't - * enforce such constraints. - */ static int spi_suspend(struct device *dev, pm_message_t message) { - int value; + int value = 0; struct spi_driver *drv = to_spi_driver(dev->driver); - if (!drv || !drv->suspend) - return 0; - /* suspend will stop irqs and dma; no more i/o */ - value = drv->suspend(to_spi_device(dev), message); - if (value == 0) - dev->power.power_state = message; + if (drv) { + if (drv->suspend) + value = drv->suspend(to_spi_device(dev), message); + else + dev_dbg(dev, "... can't suspend\n"); + } return value; } static int spi_resume(struct device *dev) { - int value; + int value = 0; struct spi_driver *drv = to_spi_driver(dev->driver); - if (!drv || !drv->resume) - return 0; - /* resume may restart the i/o queue */ - value = drv->resume(to_spi_device(dev)); - if (value == 0) - dev->power.power_state = PMSG_ON; + if (drv) { + if (drv->resume) + value = drv->resume(to_spi_device(dev)); + else + dev_dbg(dev, "... can't resume\n"); + } return value; } diff --git a/drivers/spi/spi_bfin5xx.c b/drivers/spi/spi_bfin5xx.c index 7ef39a6e8c06..d853fceb6bf0 100644 --- a/drivers/spi/spi_bfin5xx.c +++ b/drivers/spi/spi_bfin5xx.c @@ -1,37 +1,11 @@ /* - * File: drivers/spi/bfin5xx_spi.c - * Maintainer: - * Bryan Wu <bryan.wu@analog.com> - * Original Author: - * Luke Yang (Analog Devices Inc.) - * - * Created: March. 10th 2006 - * Description: SPI controller driver for Blackfin BF5xx - * Bugs: Enter bugs at http://blackfin.uclinux.org/ - * - * Modified: - * March 10, 2006 bfin5xx_spi.c Created. (Luke Yang) - * August 7, 2006 added full duplex mode (Axel Weiss & Luke Yang) - * July 17, 2007 add support for BF54x SPI0 controller (Bryan Wu) - * July 30, 2007 add platfrom_resource interface to support multi-port - * SPI controller (Bryan Wu) + * Blackfin On-Chip SPI Driver * * Copyright 2004-2007 Analog Devices Inc. * - * This program is free software ; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation ; either version 2, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY ; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * Enter bugs at http://blackfin.uclinux.org/ * - * You should have received a copy of the GNU General Public License - * along with this program ; see the file COPYING. - * If not, write to the Free Software Foundation, - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * Licensed under the GPL-2 or later. */ #include <linux/init.h> @@ -223,10 +197,9 @@ static void cs_deactive(struct driver_data *drv_data, struct chip_data *chip) #define MAX_SPI_SSEL 7 /* stop controller and re-config current chip*/ -static int restore_state(struct driver_data *drv_data) +static void restore_state(struct driver_data *drv_data) { struct chip_data *chip = drv_data->cur_chip; - int ret = 0; /* Clear status and disable clock */ write_STAT(drv_data, BIT_STAT_CLR); @@ -239,13 +212,6 @@ static int restore_state(struct driver_data *drv_data) bfin_spi_enable(drv_data); cs_active(drv_data, chip); - - if (ret) - dev_dbg(&drv_data->pdev->dev, - ": request chip select number %d failed\n", - chip->chip_select_num); - - return ret; } /* used to kick off transfer in rx mode */ @@ -286,32 +252,30 @@ static void u8_writer(struct driver_data *drv_data) dev_dbg(&drv_data->pdev->dev, "cr8-s is 0x%x\n", read_STAT(drv_data)); - /* poll for SPI completion before start */ - while (!(read_STAT(drv_data) & BIT_STAT_SPIF)) - cpu_relax(); - while (drv_data->tx < drv_data->tx_end) { write_TDBR(drv_data, (*(u8 *) (drv_data->tx))); while (read_STAT(drv_data) & BIT_STAT_TXS) cpu_relax(); ++drv_data->tx; } + + /* poll for SPI completion before return */ + while (!(read_STAT(drv_data) & BIT_STAT_SPIF)) + cpu_relax(); } static void u8_cs_chg_writer(struct driver_data *drv_data) { struct chip_data *chip = drv_data->cur_chip; - /* poll for SPI completion before start */ - while (!(read_STAT(drv_data) & BIT_STAT_SPIF)) - cpu_relax(); - while (drv_data->tx < drv_data->tx_end) { cs_active(drv_data, chip); write_TDBR(drv_data, (*(u8 *) (drv_data->tx))); while (read_STAT(drv_data) & BIT_STAT_TXS) cpu_relax(); + while (!(read_STAT(drv_data) & BIT_STAT_SPIF)) + cpu_relax(); cs_deactive(drv_data, chip); @@ -350,43 +314,28 @@ static void u8_cs_chg_reader(struct driver_data *drv_data) { struct chip_data *chip = drv_data->cur_chip; - /* poll for SPI completion before start */ - while (!(read_STAT(drv_data) & BIT_STAT_SPIF)) - cpu_relax(); - - /* clear TDBR buffer before read(else it will be shifted out) */ - write_TDBR(drv_data, 0xFFFF); + while (drv_data->rx < drv_data->rx_end) { + cs_active(drv_data, chip); + read_RDBR(drv_data); /* kick off */ - cs_active(drv_data, chip); - dummy_read(drv_data); + while (!(read_STAT(drv_data) & BIT_STAT_RXS)) + cpu_relax(); + while (!(read_STAT(drv_data) & BIT_STAT_SPIF)) + cpu_relax(); - while (drv_data->rx < drv_data->rx_end - 1) { + *(u8 *) (drv_data->rx) = read_SHAW(drv_data); cs_deactive(drv_data, chip); - while (!(read_STAT(drv_data) & BIT_STAT_RXS)) - cpu_relax(); - cs_active(drv_data, chip); - *(u8 *) (drv_data->rx) = read_RDBR(drv_data); ++drv_data->rx; } - cs_deactive(drv_data, chip); - - while (!(read_STAT(drv_data) & BIT_STAT_RXS)) - cpu_relax(); - *(u8 *) (drv_data->rx) = read_SHAW(drv_data); - ++drv_data->rx; } static void u8_duplex(struct driver_data *drv_data) { - /* poll for SPI completion before start */ - while (!(read_STAT(drv_data) & BIT_STAT_SPIF)) - cpu_relax(); - /* in duplex mode, clk is triggered by writing of TDBR */ while (drv_data->rx < drv_data->rx_end) { write_TDBR(drv_data, (*(u8 *) (drv_data->tx))); - while (read_STAT(drv_data) & BIT_STAT_TXS) + while (!(read_STAT(drv_data) & BIT_STAT_SPIF)) cpu_relax(); while (!(read_STAT(drv_data) & BIT_STAT_RXS)) cpu_relax(); @@ -400,15 +349,12 @@ static void u8_cs_chg_duplex(struct driver_data *drv_data) { struct chip_data *chip = drv_data->cur_chip; - /* poll for SPI completion before start */ - while (!(read_STAT(drv_data) & BIT_STAT_SPIF)) - cpu_relax(); - while (drv_data->rx < drv_data->rx_end) { cs_active(drv_data, chip); write_TDBR(drv_data, (*(u8 *) (drv_data->tx))); - while (read_STAT(drv_data) & BIT_STAT_TXS) + + while (!(read_STAT(drv_data) & BIT_STAT_SPIF)) cpu_relax(); while (!(read_STAT(drv_data) & BIT_STAT_RXS)) cpu_relax(); @@ -426,32 +372,30 @@ static void u16_writer(struct driver_data *drv_data) dev_dbg(&drv_data->pdev->dev, "cr16 is 0x%x\n", read_STAT(drv_data)); - /* poll for SPI completion before start */ - while (!(read_STAT(drv_data) & BIT_STAT_SPIF)) - cpu_relax(); - while (drv_data->tx < drv_data->tx_end) { write_TDBR(drv_data, (*(u16 *) (drv_data->tx))); while ((read_STAT(drv_data) & BIT_STAT_TXS)) cpu_relax(); drv_data->tx += 2; } + + /* poll for SPI completion before return */ + while (!(read_STAT(drv_data) & BIT_STAT_SPIF)) + cpu_relax(); } static void u16_cs_chg_writer(struct driver_data *drv_data) { struct chip_data *chip = drv_data->cur_chip; - /* poll for SPI completion before start */ - while (!(read_STAT(drv_data) & BIT_STAT_SPIF)) - cpu_relax(); - while (drv_data->tx < drv_data->tx_end) { cs_active(drv_data, chip); write_TDBR(drv_data, (*(u16 *) (drv_data->tx))); while ((read_STAT(drv_data) & BIT_STAT_TXS)) cpu_relax(); + while (!(read_STAT(drv_data) & BIT_STAT_SPIF)) + cpu_relax(); cs_deactive(drv_data, chip); @@ -519,14 +463,10 @@ static void u16_cs_chg_reader(struct driver_data *drv_data) static void u16_duplex(struct driver_data *drv_data) { - /* poll for SPI completion before start */ - while (!(read_STAT(drv_data) & BIT_STAT_SPIF)) - cpu_relax(); - /* in duplex mode, clk is triggered by writing of TDBR */ while (drv_data->tx < drv_data->tx_end) { write_TDBR(drv_data, (*(u16 *) (drv_data->tx))); - while (read_STAT(drv_data) & BIT_STAT_TXS) + while (!(read_STAT(drv_data) & BIT_STAT_SPIF)) cpu_relax(); while (!(read_STAT(drv_data) & BIT_STAT_RXS)) cpu_relax(); @@ -540,15 +480,11 @@ static void u16_cs_chg_duplex(struct driver_data *drv_data) { struct chip_data *chip = drv_data->cur_chip; - /* poll for SPI completion before start */ - while (!(read_STAT(drv_data) & BIT_STAT_SPIF)) - cpu_relax(); - while (drv_data->tx < drv_data->tx_end) { cs_active(drv_data, chip); write_TDBR(drv_data, (*(u16 *) (drv_data->tx))); - while (read_STAT(drv_data) & BIT_STAT_TXS) + while (!(read_STAT(drv_data) & BIT_STAT_SPIF)) cpu_relax(); while (!(read_STAT(drv_data) & BIT_STAT_RXS)) cpu_relax(); @@ -616,7 +552,7 @@ static void giveback(struct driver_data *drv_data) static irqreturn_t dma_irq_handler(int irq, void *dev_id) { - struct driver_data *drv_data = (struct driver_data *)dev_id; + struct driver_data *drv_data = dev_id; struct chip_data *chip = drv_data->cur_chip; struct spi_message *msg = drv_data->cur_msg; @@ -978,10 +914,7 @@ static void pump_messages(struct work_struct *work) /* Setup the SSP using the per chip configuration */ drv_data->cur_chip = spi_get_ctldata(drv_data->cur_msg->spi); - if (restore_state(drv_data)) { - spin_unlock_irqrestore(&drv_data->lock, flags); - return; - }; + restore_state(drv_data); list_del_init(&drv_data->cur_msg->queue); @@ -1187,7 +1120,7 @@ static int setup(struct spi_device *spi) if ((chip->chip_select_num > 0) && (chip->chip_select_num <= spi->master->num_chipselect)) peripheral_request(ssel[spi->master->bus_num] - [chip->chip_select_num-1], DRV_NAME); + [chip->chip_select_num-1], spi->modalias); cs_deactive(drv_data, chip); diff --git a/drivers/spi/spi_imx.c b/drivers/spi/spi_imx.c index 639963eb1ac1..1b0647124933 100644 --- a/drivers/spi/spi_imx.c +++ b/drivers/spi/spi_imx.c @@ -1686,17 +1686,6 @@ static void spi_imx_shutdown(struct platform_device *pdev) } #ifdef CONFIG_PM -static int suspend_devices(struct device *dev, void *pm_message) -{ - pm_message_t *state = pm_message; - - if (dev->power.power_state.event != state->event) { - dev_warn(dev, "pm state does not match request\n"); - return -1; - } - - return 0; -} static int spi_imx_suspend(struct platform_device *pdev, pm_message_t state) { diff --git a/drivers/spi/spi_s3c24xx.c b/drivers/spi/spi_s3c24xx.c index 89d6685a5ca4..6e834b8b9d27 100644 --- a/drivers/spi/spi_s3c24xx.c +++ b/drivers/spi/spi_s3c24xx.c @@ -237,10 +237,8 @@ static int __init s3c24xx_spi_probe(struct platform_device *pdev) { struct s3c24xx_spi *hw; struct spi_master *master; - struct spi_board_info *bi; struct resource *res; int err = 0; - int i; master = spi_alloc_master(&pdev->dev, sizeof(struct s3c24xx_spi)); if (master == NULL) { @@ -348,16 +346,6 @@ static int __init s3c24xx_spi_probe(struct platform_device *pdev) goto err_register; } - /* register all the devices associated */ - - bi = &hw->pdata->board_info[0]; - for (i = 0; i < hw->pdata->board_size; i++, bi++) { - dev_info(hw->dev, "registering %s\n", bi->modalias); - - bi->controller_data = hw; - spi_new_device(master, bi); - } - return 0; err_register: diff --git a/drivers/spi/spi_s3c24xx_gpio.c b/drivers/spi/spi_s3c24xx_gpio.c index 109d82c1abc0..82ae7d7eca38 100644 --- a/drivers/spi/spi_s3c24xx_gpio.c +++ b/drivers/spi/spi_s3c24xx_gpio.c @@ -100,7 +100,6 @@ static int s3c2410_spigpio_probe(struct platform_device *dev) struct spi_master *master; struct s3c2410_spigpio *sp; int ret; - int i; master = spi_alloc_master(&dev->dev, sizeof(struct s3c2410_spigpio)); if (master == NULL) { @@ -143,17 +142,6 @@ static int s3c2410_spigpio_probe(struct platform_device *dev) if (ret) goto err_no_bitbang; - /* register the chips to go with the board */ - - for (i = 0; i < sp->info->board_size; i++) { - dev_info(&dev->dev, "registering %p: %s\n", - &sp->info->board_info[i], - sp->info->board_info[i].modalias); - - sp->info->board_info[i].controller_data = sp; - spi_new_device(master, sp->info->board_info + i); - } - return 0; err_no_bitbang: diff --git a/drivers/spi/spi_sh_sci.c b/drivers/spi/spi_sh_sci.c new file mode 100644 index 000000000000..3dbe71b16d60 --- /dev/null +++ b/drivers/spi/spi_sh_sci.c @@ -0,0 +1,205 @@ +/* + * SH SCI SPI interface + * + * Copyright (c) 2008 Magnus Damm + * + * Based on S3C24XX GPIO based SPI driver, which is: + * Copyright (c) 2006 Ben Dooks + * Copyright (c) 2006 Simtec Electronics + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + */ + +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/delay.h> +#include <linux/spinlock.h> +#include <linux/workqueue.h> +#include <linux/platform_device.h> + +#include <linux/spi/spi.h> +#include <linux/spi/spi_bitbang.h> + +#include <asm/spi.h> +#include <asm/io.h> + +struct sh_sci_spi { + struct spi_bitbang bitbang; + + void __iomem *membase; + unsigned char val; + struct sh_spi_info *info; + struct platform_device *dev; +}; + +#define SCSPTR(sp) (sp->membase + 0x1c) +#define PIN_SCK (1 << 2) +#define PIN_TXD (1 << 0) +#define PIN_RXD PIN_TXD +#define PIN_INIT ((1 << 1) | (1 << 3) | PIN_SCK | PIN_TXD) + +static inline void setbits(struct sh_sci_spi *sp, int bits, int on) +{ + /* + * We are the only user of SCSPTR so no locking is required. + * Reading bit 2 and 0 in SCSPTR gives pin state as input. + * Writing the same bits sets the output value. + * This makes regular read-modify-write difficult so we + * use sp->val to keep track of the latest register value. + */ + + if (on) + sp->val |= bits; + else + sp->val &= ~bits; + + iowrite8(sp->val, SCSPTR(sp)); +} + +static inline void setsck(struct spi_device *dev, int on) +{ + setbits(spi_master_get_devdata(dev->master), PIN_SCK, on); +} + +static inline void setmosi(struct spi_device *dev, int on) +{ + setbits(spi_master_get_devdata(dev->master), PIN_TXD, on); +} + +static inline u32 getmiso(struct spi_device *dev) +{ + struct sh_sci_spi *sp = spi_master_get_devdata(dev->master); + + return (ioread8(SCSPTR(sp)) & PIN_RXD) ? 1 : 0; +} + +#define spidelay(x) ndelay(x) + +#define EXPAND_BITBANG_TXRX +#include <linux/spi/spi_bitbang.h> + +static u32 sh_sci_spi_txrx_mode0(struct spi_device *spi, + unsigned nsecs, u32 word, u8 bits) +{ + return bitbang_txrx_be_cpha0(spi, nsecs, 0, word, bits); +} + +static u32 sh_sci_spi_txrx_mode1(struct spi_device *spi, + unsigned nsecs, u32 word, u8 bits) +{ + return bitbang_txrx_be_cpha1(spi, nsecs, 0, word, bits); +} + +static u32 sh_sci_spi_txrx_mode2(struct spi_device *spi, + unsigned nsecs, u32 word, u8 bits) +{ + return bitbang_txrx_be_cpha0(spi, nsecs, 1, word, bits); +} + +static u32 sh_sci_spi_txrx_mode3(struct spi_device *spi, + unsigned nsecs, u32 word, u8 bits) +{ + return bitbang_txrx_be_cpha1(spi, nsecs, 1, word, bits); +} + +static void sh_sci_spi_chipselect(struct spi_device *dev, int value) +{ + struct sh_sci_spi *sp = spi_master_get_devdata(dev->master); + + if (sp->info && sp->info->chip_select) + (sp->info->chip_select)(sp->info, dev->chip_select, value); +} + +static int sh_sci_spi_probe(struct platform_device *dev) +{ + struct resource *r; + struct spi_master *master; + struct sh_sci_spi *sp; + int ret; + + master = spi_alloc_master(&dev->dev, sizeof(struct sh_sci_spi)); + if (master == NULL) { + dev_err(&dev->dev, "failed to allocate spi master\n"); + ret = -ENOMEM; + goto err0; + } + + sp = spi_master_get_devdata(master); + + platform_set_drvdata(dev, sp); + sp->info = dev->dev.platform_data; + + /* setup spi bitbang adaptor */ + sp->bitbang.master = spi_master_get(master); + sp->bitbang.master->bus_num = sp->info->bus_num; + sp->bitbang.master->num_chipselect = sp->info->num_chipselect; + sp->bitbang.chipselect = sh_sci_spi_chipselect; + + sp->bitbang.txrx_word[SPI_MODE_0] = sh_sci_spi_txrx_mode0; + sp->bitbang.txrx_word[SPI_MODE_1] = sh_sci_spi_txrx_mode1; + sp->bitbang.txrx_word[SPI_MODE_2] = sh_sci_spi_txrx_mode2; + sp->bitbang.txrx_word[SPI_MODE_3] = sh_sci_spi_txrx_mode3; + + r = platform_get_resource(dev, IORESOURCE_MEM, 0); + if (r == NULL) { + ret = -ENOENT; + goto err1; + } + sp->membase = ioremap(r->start, r->end - r->start + 1); + if (!sp->membase) { + ret = -ENXIO; + goto err1; + } + sp->val = ioread8(SCSPTR(sp)); + setbits(sp, PIN_INIT, 1); + + ret = spi_bitbang_start(&sp->bitbang); + if (!ret) + return 0; + + setbits(sp, PIN_INIT, 0); + iounmap(sp->membase); + err1: + spi_master_put(sp->bitbang.master); + err0: + return ret; +} + +static int sh_sci_spi_remove(struct platform_device *dev) +{ + struct sh_sci_spi *sp = platform_get_drvdata(dev); + + iounmap(sp->membase); + setbits(sp, PIN_INIT, 0); + spi_bitbang_stop(&sp->bitbang); + spi_master_put(sp->bitbang.master); + return 0; +} + +static struct platform_driver sh_sci_spi_drv = { + .probe = sh_sci_spi_probe, + .remove = sh_sci_spi_remove, + .driver = { + .name = "spi_sh_sci", + .owner = THIS_MODULE, + }, +}; + +static int __init sh_sci_spi_init(void) +{ + return platform_driver_register(&sh_sci_spi_drv); +} +module_init(sh_sci_spi_init); + +static void __exit sh_sci_spi_exit(void) +{ + platform_driver_unregister(&sh_sci_spi_drv); +} +module_exit(sh_sci_spi_exit); + +MODULE_DESCRIPTION("SH SCI SPI Driver"); +MODULE_AUTHOR("Magnus Damm <damm@opensource.se>"); +MODULE_LICENSE("GPL"); diff --git a/drivers/uio/uio.c b/drivers/uio/uio.c index cc246faa3590..2a77e9d42c68 100644 --- a/drivers/uio/uio.c +++ b/drivers/uio/uio.c @@ -417,30 +417,28 @@ static void uio_vma_close(struct vm_area_struct *vma) idev->vma_count--; } -static struct page *uio_vma_nopage(struct vm_area_struct *vma, - unsigned long address, int *type) +static int uio_vma_fault(struct vm_area_struct *vma, struct vm_fault *vmf) { struct uio_device *idev = vma->vm_private_data; - struct page* page = NOPAGE_SIGBUS; + struct page *page; int mi = uio_find_mem_index(vma); if (mi < 0) - return page; + return VM_FAULT_SIGBUS; if (idev->info->mem[mi].memtype == UIO_MEM_LOGICAL) page = virt_to_page(idev->info->mem[mi].addr); else page = vmalloc_to_page((void*)idev->info->mem[mi].addr); get_page(page); - if (type) - *type = VM_FAULT_MINOR; - return page; + vmf->page = page; + return 0; } static struct vm_operations_struct uio_vm_ops = { .open = uio_vma_open, .close = uio_vma_close, - .nopage = uio_vma_nopage, + .fault = uio_vma_fault, }; static int uio_mmap_physical(struct vm_area_struct *vma) diff --git a/drivers/video/atmel_lcdfb.c b/drivers/video/atmel_lcdfb.c index f8e711147501..fc65c02306dd 100644 --- a/drivers/video/atmel_lcdfb.c +++ b/drivers/video/atmel_lcdfb.c @@ -16,6 +16,7 @@ #include <linux/fb.h> #include <linux/init.h> #include <linux/delay.h> +#include <linux/backlight.h> #include <asm/arch/board.h> #include <asm/arch/cpu.h> @@ -69,6 +70,107 @@ static void atmel_lcdfb_update_dma2d(struct atmel_lcdfb_info *sinfo, } #endif +static const u32 contrast_ctr = ATMEL_LCDC_PS_DIV8 + | ATMEL_LCDC_POL_POSITIVE + | ATMEL_LCDC_ENA_PWMENABLE; + +#ifdef CONFIG_BACKLIGHT_ATMEL_LCDC + +/* some bl->props field just changed */ +static int atmel_bl_update_status(struct backlight_device *bl) +{ + struct atmel_lcdfb_info *sinfo = bl_get_data(bl); + int power = sinfo->bl_power; + int brightness = bl->props.brightness; + + /* REVISIT there may be a meaningful difference between + * fb_blank and power ... there seem to be some cases + * this doesn't handle correctly. + */ + if (bl->props.fb_blank != sinfo->bl_power) + power = bl->props.fb_blank; + else if (bl->props.power != sinfo->bl_power) + power = bl->props.power; + + if (brightness < 0 && power == FB_BLANK_UNBLANK) + brightness = lcdc_readl(sinfo, ATMEL_LCDC_CONTRAST_VAL); + else if (power != FB_BLANK_UNBLANK) + brightness = 0; + + lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_VAL, brightness); + lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_CTR, + brightness ? contrast_ctr : 0); + + bl->props.fb_blank = bl->props.power = sinfo->bl_power = power; + + return 0; +} + +static int atmel_bl_get_brightness(struct backlight_device *bl) +{ + struct atmel_lcdfb_info *sinfo = bl_get_data(bl); + + return lcdc_readl(sinfo, ATMEL_LCDC_CONTRAST_VAL); +} + +static struct backlight_ops atmel_lcdc_bl_ops = { + .update_status = atmel_bl_update_status, + .get_brightness = atmel_bl_get_brightness, +}; + +static void init_backlight(struct atmel_lcdfb_info *sinfo) +{ + struct backlight_device *bl; + + sinfo->bl_power = FB_BLANK_UNBLANK; + + if (sinfo->backlight) + return; + + bl = backlight_device_register("backlight", &sinfo->pdev->dev, + sinfo, &atmel_lcdc_bl_ops); + if (IS_ERR(sinfo->backlight)) { + dev_err(&sinfo->pdev->dev, "error %ld on backlight register\n", + PTR_ERR(bl)); + return; + } + sinfo->backlight = bl; + + bl->props.power = FB_BLANK_UNBLANK; + bl->props.fb_blank = FB_BLANK_UNBLANK; + bl->props.max_brightness = 0xff; + bl->props.brightness = atmel_bl_get_brightness(bl); +} + +static void exit_backlight(struct atmel_lcdfb_info *sinfo) +{ + if (sinfo->backlight) + backlight_device_unregister(sinfo->backlight); +} + +#else + +static void init_backlight(struct atmel_lcdfb_info *sinfo) +{ + dev_warn(&sinfo->pdev->dev, "backlight control is not available\n"); +} + +static void exit_backlight(struct atmel_lcdfb_info *sinfo) +{ +} + +#endif + +static void init_contrast(struct atmel_lcdfb_info *sinfo) +{ + /* have some default contrast/backlight settings */ + lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_CTR, contrast_ctr); + lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_VAL, ATMEL_LCDC_CVAL_DEFAULT); + + if (sinfo->lcdcon_is_backlight) + init_backlight(sinfo); +} + static struct fb_fix_screeninfo atmel_lcdfb_fix __initdata = { .type = FB_TYPE_PACKED_PIXELS, @@ -203,6 +305,26 @@ static int atmel_lcdfb_check_var(struct fb_var_screeninfo *var, var->transp.offset = var->transp.length = 0; var->xoffset = var->yoffset = 0; + /* Saturate vertical and horizontal timings at maximum values */ + var->vsync_len = min_t(u32, var->vsync_len, + (ATMEL_LCDC_VPW >> ATMEL_LCDC_VPW_OFFSET) + 1); + var->upper_margin = min_t(u32, var->upper_margin, + ATMEL_LCDC_VBP >> ATMEL_LCDC_VBP_OFFSET); + var->lower_margin = min_t(u32, var->lower_margin, + ATMEL_LCDC_VFP); + var->right_margin = min_t(u32, var->right_margin, + (ATMEL_LCDC_HFP >> ATMEL_LCDC_HFP_OFFSET) + 1); + var->hsync_len = min_t(u32, var->hsync_len, + (ATMEL_LCDC_HPW >> ATMEL_LCDC_HPW_OFFSET) + 1); + var->left_margin = min_t(u32, var->left_margin, + ATMEL_LCDC_HBP + 1); + + /* Some parameters can't be zero */ + var->vsync_len = max_t(u32, var->vsync_len, 1); + var->right_margin = max_t(u32, var->right_margin, 1); + var->hsync_len = max_t(u32, var->hsync_len, 1); + var->left_margin = max_t(u32, var->left_margin, 1); + switch (var->bits_per_pixel) { case 1: case 2: @@ -370,10 +492,6 @@ static int atmel_lcdfb_set_par(struct fb_info *info) /* Disable all interrupts */ lcdc_writel(sinfo, ATMEL_LCDC_IDR, ~0UL); - /* Set contrast */ - value = ATMEL_LCDC_PS_DIV8 | ATMEL_LCDC_POL_POSITIVE | ATMEL_LCDC_ENA_PWMENABLE; - lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_CTR, value); - lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_VAL, ATMEL_LCDC_CVAL_DEFAULT); /* ...wait for DMA engine to become idle... */ while (lcdc_readl(sinfo, ATMEL_LCDC_DMACON) & ATMEL_LCDC_DMABUSY) msleep(10); @@ -577,6 +695,7 @@ static int __init atmel_lcdfb_probe(struct platform_device *pdev) sinfo->default_monspecs = pdata_sinfo->default_monspecs; sinfo->atmel_lcdfb_power_control = pdata_sinfo->atmel_lcdfb_power_control; sinfo->guard_time = pdata_sinfo->guard_time; + sinfo->lcdcon_is_backlight = pdata_sinfo->lcdcon_is_backlight; } else { dev_err(dev, "cannot get default configuration\n"); goto free_info; @@ -670,6 +789,9 @@ static int __init atmel_lcdfb_probe(struct platform_device *pdev) goto release_mem; } + /* Initialize PWM for contrast or backlight ("off") */ + init_contrast(sinfo); + /* interrupt */ ret = request_irq(sinfo->irq_base, atmel_lcdfb_interrupt, 0, pdev->name, info); if (ret) { @@ -721,6 +843,7 @@ free_cmap: unregister_irqs: free_irq(sinfo->irq_base, info); unmap_mmio: + exit_backlight(sinfo); iounmap(sinfo->mmio); release_mem: release_mem_region(info->fix.mmio_start, info->fix.mmio_len); @@ -755,6 +878,7 @@ static int __exit atmel_lcdfb_remove(struct platform_device *pdev) if (!sinfo) return 0; + exit_backlight(sinfo); if (sinfo->atmel_lcdfb_power_control) sinfo->atmel_lcdfb_power_control(0); unregister_framebuffer(info); @@ -781,6 +905,9 @@ static int __exit atmel_lcdfb_remove(struct platform_device *pdev) static struct platform_driver atmel_lcdfb_driver = { .remove = __exit_p(atmel_lcdfb_remove), + +// FIXME need suspend, resume + .driver = { .name = "atmel_lcdfb", .owner = THIS_MODULE, diff --git a/drivers/video/backlight/Kconfig b/drivers/video/backlight/Kconfig index 9609a6c676be..924e2551044a 100644 --- a/drivers/video/backlight/Kconfig +++ b/drivers/video/backlight/Kconfig @@ -50,6 +50,19 @@ config BACKLIGHT_CLASS_DEVICE To have support for your specific LCD panel you will have to select the proper drivers which depend on this option. +config BACKLIGHT_ATMEL_LCDC + bool "Atmel LCDC Contrast-as-Backlight control" + depends on BACKLIGHT_CLASS_DEVICE && FB_ATMEL + default y if MACH_SAM9261EK || MACH_SAM9263EK + help + This provides a backlight control internal to the Atmel LCDC + driver. If the LCD "contrast control" on your board is wired + so it controls the backlight brightness, select this option to + export this as a PWM-based backlight control. + + If in doubt, it's safe to enable this option; it doesn't kick + in unless the board's description says it's wired that way. + config BACKLIGHT_CORGI tristate "Generic (aka Sharp Corgi) Backlight Driver" depends on BACKLIGHT_CLASS_DEVICE diff --git a/drivers/video/bf54x-lq043fb.c b/drivers/video/bf54x-lq043fb.c index c8e7427a0bc8..0ce791e6f79c 100644 --- a/drivers/video/bf54x-lq043fb.c +++ b/drivers/video/bf54x-lq043fb.c @@ -498,8 +498,7 @@ static struct lcd_device *lcd_dev; static irqreturn_t bfin_bf54x_irq_error(int irq, void *dev_id) { - - /*struct bfin_bf54xfb_info *info = (struct bfin_bf54xfb_info *)dev_id;*/ + /*struct bfin_bf54xfb_info *info = dev_id;*/ u16 status = bfin_read_EPPI0_STATUS(); diff --git a/drivers/video/console/bitblit.c b/drivers/video/console/bitblit.c index 308850df16fe..69864b1b3f9e 100644 --- a/drivers/video/console/bitblit.c +++ b/drivers/video/console/bitblit.c @@ -63,7 +63,7 @@ static void bit_clear(struct vc_data *vc, struct fb_info *info, int sy, int bgshift = (vc->vc_hi_font_mask) ? 13 : 12; struct fb_fillrect region; - region.color = attr_bgcol_ec(bgshift, vc); + region.color = attr_bgcol_ec(bgshift, vc, info); region.dx = sx * vc->vc_font.width; region.dy = sy * vc->vc_font.height; region.width = width * vc->vc_font.width; @@ -213,7 +213,7 @@ static void bit_clear_margins(struct vc_data *vc, struct fb_info *info, unsigned int bs = info->var.yres - bh; struct fb_fillrect region; - region.color = attr_bgcol_ec(bgshift, vc); + region.color = attr_bgcol_ec(bgshift, vc, info); region.rop = ROP_COPY; if (rw && !bottom_only) { diff --git a/drivers/video/console/fbcon.c b/drivers/video/console/fbcon.c index 0f32f4a00b2d..022282494d3f 100644 --- a/drivers/video/console/fbcon.c +++ b/drivers/video/console/fbcon.c @@ -84,7 +84,7 @@ #ifdef CONFIG_MAC #include <asm/macints.h> #endif -#if defined(__mc68000__) || defined(CONFIG_APUS) +#if defined(__mc68000__) #include <asm/machdep.h> #include <asm/setup.h> #endif @@ -147,7 +147,7 @@ static char fontname[40]; static int info_idx = -1; /* console rotation */ -static int rotate; +static int initial_rotation; static int fbcon_has_sysfs; static const struct consw fb_con; @@ -334,10 +334,7 @@ static inline int get_color(struct vc_data *vc, struct fb_info *info, switch (depth) { case 1: { - int col = ~(0xfff << (max(info->var.green.length, - max(info->var.red.length, - info->var.blue.length)))) & 0xff; - + int col = mono_col(info); /* 0 or 1 */ int fg = (info->fix.visual != FB_VISUAL_MONO01) ? col : 0; int bg = (info->fix.visual != FB_VISUAL_MONO01) ? 0 : col; @@ -537,9 +534,9 @@ static int __init fb_console_setup(char *this_opt) if (!strncmp(options, "rotate:", 7)) { options += 7; if (*options) - rotate = simple_strtoul(options, &options, 0); - if (rotate > 3) - rotate = 0; + initial_rotation = simple_strtoul(options, &options, 0); + if (initial_rotation > 3) + initial_rotation = 0; } } return 1; @@ -989,7 +986,7 @@ static const char *fbcon_startup(void) ops->graphics = 1; ops->cur_rotate = -1; info->fbcon_par = ops; - p->con_rotate = rotate; + p->con_rotate = initial_rotation; set_blitting_type(vc, info); if (info->fix.type != FB_TYPE_TEXT) { @@ -1176,7 +1173,7 @@ static void fbcon_init(struct vc_data *vc, int init) con_copy_unimap(vc, svc); ops = info->fbcon_par; - p->con_rotate = rotate; + p->con_rotate = initial_rotation; set_blitting_type(vc, info); cols = vc->vc_cols; @@ -2795,7 +2792,7 @@ static int fbcon_scrolldelta(struct vc_data *vc, int lines) { struct fb_info *info = registered_fb[con2fb_map[fg_console]]; struct fbcon_ops *ops = info->fbcon_par; - struct display *p = &fb_display[fg_console]; + struct display *disp = &fb_display[fg_console]; int offset, limit, scrollback_old; if (softback_top) { @@ -2833,7 +2830,7 @@ static int fbcon_scrolldelta(struct vc_data *vc, int lines) logo_shown = FBCON_LOGO_CANSHOW; } fbcon_cursor(vc, CM_ERASE | CM_SOFTBACK); - fbcon_redraw_softback(vc, p, lines); + fbcon_redraw_softback(vc, disp, lines); fbcon_cursor(vc, CM_DRAW | CM_SOFTBACK); return 0; } @@ -2855,9 +2852,9 @@ static int fbcon_scrolldelta(struct vc_data *vc, int lines) fbcon_cursor(vc, CM_ERASE); - offset = p->yscroll - scrollback_current; - limit = p->vrows; - switch (p->scrollmode) { + offset = disp->yscroll - scrollback_current; + limit = disp->vrows; + switch (disp->scrollmode) { case SCROLL_WRAP_MOVE: info->var.vmode |= FB_VMODE_YWRAP; break; diff --git a/drivers/video/console/fbcon.h b/drivers/video/console/fbcon.h index 8e6ef4bc7a5c..3706307e70ed 100644 --- a/drivers/video/console/fbcon.h +++ b/drivers/video/console/fbcon.h @@ -93,10 +93,6 @@ struct fbcon_ops { (((s) >> (fgshift)) & 0x0f) #define attr_bgcol(bgshift,s) \ (((s) >> (bgshift)) & 0x0f) -#define attr_bgcol_ec(bgshift,vc) \ - ((vc) ? (((vc)->vc_video_erase_char >> (bgshift)) & 0x0f) : 0) -#define attr_fgcol_ec(fgshift,vc) \ - ((vc) ? (((vc)->vc_video_erase_char >> (fgshift)) & 0x0f) : 0) /* Monochrome */ #define attr_bold(s) \ @@ -108,6 +104,49 @@ struct fbcon_ops { #define attr_blink(s) \ ((s) & 0x8000) +#define mono_col(info) \ + (~(0xfff << (max((info)->var.green.length, \ + max((info)->var.red.length, \ + (info)->var.blue.length)))) & 0xff) + +static inline int attr_col_ec(int shift, struct vc_data *vc, + struct fb_info *info, int is_fg) +{ + int is_mono01; + int col; + int fg; + int bg; + + if (!vc) + return 0; + + if (vc->vc_can_do_color) + return is_fg ? attr_fgcol(shift,vc->vc_video_erase_char) + : attr_bgcol(shift,vc->vc_video_erase_char); + + if (!info) + return 0; + + col = mono_col(info); + is_mono01 = info->fix.visual == FB_VISUAL_MONO01; + + if (attr_reverse(vc->vc_video_erase_char)) { + fg = is_mono01 ? col : 0; + bg = is_mono01 ? 0 : col; + } + else { + fg = is_mono01 ? 0 : col; + bg = is_mono01 ? col : 0; + } + + return is_fg ? fg : bg; +} + +#define attr_bgcol_ec(bgshift,vc,info) \ + attr_col_ec(bgshift,vc,info,0); +#define attr_fgcol_ec(fgshift,vc,info) \ + attr_col_ec(fgshift,vc,info,1); + /* Font */ #define REFCOUNT(fd) (((int *)(fd))[-1]) #define FNTSIZE(fd) (((int *)(fd))[-2]) diff --git a/drivers/video/console/fbcon_ccw.c b/drivers/video/console/fbcon_ccw.c index 825e6d6972a7..bdf913ecf001 100644 --- a/drivers/video/console/fbcon_ccw.c +++ b/drivers/video/console/fbcon_ccw.c @@ -84,7 +84,7 @@ static void ccw_clear(struct vc_data *vc, struct fb_info *info, int sy, int bgshift = (vc->vc_hi_font_mask) ? 13 : 12; u32 vyres = GETVYRES(ops->p->scrollmode, info); - region.color = attr_bgcol_ec(bgshift,vc); + region.color = attr_bgcol_ec(bgshift,vc,info); region.dx = sy * vc->vc_font.height; region.dy = vyres - ((sx + width) * vc->vc_font.width); region.height = width * vc->vc_font.width; @@ -198,7 +198,7 @@ static void ccw_clear_margins(struct vc_data *vc, struct fb_info *info, struct fb_fillrect region; int bgshift = (vc->vc_hi_font_mask) ? 13 : 12; - region.color = attr_bgcol_ec(bgshift,vc); + region.color = attr_bgcol_ec(bgshift,vc,info); region.rop = ROP_COPY; if (rw && !bottom_only) { diff --git a/drivers/video/console/fbcon_cw.c b/drivers/video/console/fbcon_cw.c index c637e6318803..a6819b9d1770 100644 --- a/drivers/video/console/fbcon_cw.c +++ b/drivers/video/console/fbcon_cw.c @@ -70,7 +70,7 @@ static void cw_clear(struct vc_data *vc, struct fb_info *info, int sy, int bgshift = (vc->vc_hi_font_mask) ? 13 : 12; u32 vxres = GETVXRES(ops->p->scrollmode, info); - region.color = attr_bgcol_ec(bgshift,vc); + region.color = attr_bgcol_ec(bgshift,vc,info); region.dx = vxres - ((sy + height) * vc->vc_font.height); region.dy = sx * vc->vc_font.width; region.height = width * vc->vc_font.width; @@ -182,7 +182,7 @@ static void cw_clear_margins(struct vc_data *vc, struct fb_info *info, struct fb_fillrect region; int bgshift = (vc->vc_hi_font_mask) ? 13 : 12; - region.color = attr_bgcol_ec(bgshift,vc); + region.color = attr_bgcol_ec(bgshift,vc,info); region.rop = ROP_COPY; if (rw && !bottom_only) { diff --git a/drivers/video/console/fbcon_ud.c b/drivers/video/console/fbcon_ud.c index 1473506df5d0..d9b5d6eb68a7 100644 --- a/drivers/video/console/fbcon_ud.c +++ b/drivers/video/console/fbcon_ud.c @@ -71,7 +71,7 @@ static void ud_clear(struct vc_data *vc, struct fb_info *info, int sy, u32 vyres = GETVYRES(ops->p->scrollmode, info); u32 vxres = GETVXRES(ops->p->scrollmode, info); - region.color = attr_bgcol_ec(bgshift,vc); + region.color = attr_bgcol_ec(bgshift,vc,info); region.dy = vyres - ((sy + height) * vc->vc_font.height); region.dx = vxres - ((sx + width) * vc->vc_font.width); region.width = width * vc->vc_font.width; @@ -228,7 +228,7 @@ static void ud_clear_margins(struct vc_data *vc, struct fb_info *info, struct fb_fillrect region; int bgshift = (vc->vc_hi_font_mask) ? 13 : 12; - region.color = attr_bgcol_ec(bgshift,vc); + region.color = attr_bgcol_ec(bgshift,vc,info); region.rop = ROP_COPY; if (rw && !bottom_only) { diff --git a/drivers/video/console/fonts.c b/drivers/video/console/fonts.c index 96979c377518..d0c03fd70871 100644 --- a/drivers/video/console/fonts.c +++ b/drivers/video/console/fonts.c @@ -15,7 +15,7 @@ #include <linux/module.h> #include <linux/types.h> #include <linux/string.h> -#if defined(__mc68000__) || defined(CONFIG_APUS) +#if defined(__mc68000__) #include <asm/setup.h> #endif #include <linux/font.h> @@ -120,7 +120,7 @@ const struct font_desc *get_default_font(int xres, int yres, u32 font_w, for(i=0; i<num_fonts; i++) { f = fonts[i]; c = f->pref; -#if defined(__mc68000__) || defined(CONFIG_APUS) +#if defined(__mc68000__) #ifdef CONFIG_FONT_PEARL_8x8 if (MACH_IS_AMIGA && f->idx == PEARL8x8_IDX) c = 100; diff --git a/drivers/video/console/tileblit.c b/drivers/video/console/tileblit.c index d981fe4d86c6..0056a41e5c35 100644 --- a/drivers/video/console/tileblit.c +++ b/drivers/video/console/tileblit.c @@ -40,8 +40,8 @@ static void tile_clear(struct vc_data *vc, struct fb_info *info, int sy, rect.index = vc->vc_video_erase_char & ((vc->vc_hi_font_mask) ? 0x1ff : 0xff); - rect.fg = attr_fgcol_ec(fgshift, vc); - rect.bg = attr_bgcol_ec(bgshift, vc); + rect.fg = attr_fgcol_ec(fgshift, vc, info); + rect.bg = attr_bgcol_ec(bgshift, vc, info); rect.sx = sx; rect.sy = sy; rect.width = width; diff --git a/drivers/video/console/vgacon.c b/drivers/video/console/vgacon.c index f65bcd314d54..6df29a62d720 100644 --- a/drivers/video/console/vgacon.c +++ b/drivers/video/console/vgacon.c @@ -1153,8 +1153,6 @@ static int vgacon_do_font_op(struct vgastate *state,char *arg,int set,int ch512) /* if 512 char mode is already enabled don't re-enable it. */ if ((set) && (ch512 != vga_512_chars)) { - int i; - /* attribute controller */ for (i = 0; i < MAX_NR_CONSOLES; i++) { struct vc_data *c = vc_cons[i].d; diff --git a/drivers/video/fb_defio.c b/drivers/video/fb_defio.c index a0c5d9d90d74..0f8cfb988c90 100644 --- a/drivers/video/fb_defio.c +++ b/drivers/video/fb_defio.c @@ -25,8 +25,8 @@ #include <linux/pagemap.h> /* this is to find and return the vmalloc-ed fb pages */ -static struct page* fb_deferred_io_nopage(struct vm_area_struct *vma, - unsigned long vaddr, int *type) +static int fb_deferred_io_fault(struct vm_area_struct *vma, + struct vm_fault *vmf) { unsigned long offset; struct page *page; @@ -34,18 +34,17 @@ static struct page* fb_deferred_io_nopage(struct vm_area_struct *vma, /* info->screen_base is in System RAM */ void *screen_base = (void __force *) info->screen_base; - offset = (vaddr - vma->vm_start) + (vma->vm_pgoff << PAGE_SHIFT); + offset = vmf->pgoff << PAGE_SHIFT; if (offset >= info->fix.smem_len) - return NOPAGE_SIGBUS; + return VM_FAULT_SIGBUS; page = vmalloc_to_page(screen_base + offset); if (!page) - return NOPAGE_OOM; + return VM_FAULT_SIGBUS; get_page(page); - if (type) - *type = VM_FAULT_MINOR; - return page; + vmf->page = page; + return 0; } int fb_deferred_io_fsync(struct file *file, struct dentry *dentry, int datasync) @@ -84,7 +83,7 @@ static int fb_deferred_io_mkwrite(struct vm_area_struct *vma, } static struct vm_operations_struct fb_deferred_io_vm_ops = { - .nopage = fb_deferred_io_nopage, + .fault = fb_deferred_io_fault, .page_mkwrite = fb_deferred_io_mkwrite, }; diff --git a/drivers/video/fb_draw.h b/drivers/video/fb_draw.h index cdafbe14ef1f..a2a0618d86a5 100644 --- a/drivers/video/fb_draw.h +++ b/drivers/video/fb_draw.h @@ -91,6 +91,7 @@ static inline unsigned long fb_rev_pixels_in_long(unsigned long val, val = comp(val >> 2, val << 2, REV_PIXELS_MASK2); if (bswapmask & 3) val = comp(val >> 4, val << 4, REV_PIXELS_MASK4); + return val; } static inline u32 fb_shifted_pixels_mask_u32(u32 index, u32 bswapmask) diff --git a/drivers/video/fbmon.c b/drivers/video/fbmon.c index 4ba9c0894416..052e18058498 100644 --- a/drivers/video/fbmon.c +++ b/drivers/video/fbmon.c @@ -4,7 +4,7 @@ * Copyright (C) 2002 James Simmons <jsimmons@users.sf.net> * * Credits: - * + * * The EDID Parser is a conglomeration from the following sources: * * 1. SciTech SNAP Graphics Architecture @@ -12,13 +12,13 @@ * * 2. XFree86 4.3.0, interpret_edid.c * Copyright 1998 by Egbert Eich <Egbert.Eich@Physik.TU-Darmstadt.DE> - * - * 3. John Fremlin <vii@users.sourceforge.net> and + * + * 3. John Fremlin <vii@users.sourceforge.net> and * Ani Joshi <ajoshi@unixbox.com> - * + * * Generalized Timing Formula is derived from: * - * GTF Spreadsheet by Andy Morrish (1/5/97) + * GTF Spreadsheet by Andy Morrish (1/5/97) * available at http://www.vesa.org * * This file is subject to the terms and conditions of the GNU General Public @@ -36,7 +36,7 @@ #endif #include "edid.h" -/* +/* * EDID parser */ @@ -160,8 +160,8 @@ static int check_edid(unsigned char *edid) for (i = 0; i < ARRAY_SIZE(brokendb); i++) { if (!strncmp(manufacturer, brokendb[i].manufacturer, 4) && brokendb[i].model == model) { - fix = brokendb[i].fix; - break; + fix = brokendb[i].fix; + break; } } @@ -323,7 +323,7 @@ static void get_dpms_capabilities(unsigned char flags, (flags & DPMS_SUSPEND) ? "yes" : "no", (flags & DPMS_STANDBY) ? "yes" : "no"); } - + static void get_chroma(unsigned char *block, struct fb_monspecs *specs) { int tmp; @@ -365,7 +365,7 @@ static void get_chroma(unsigned char *block, struct fb_monspecs *specs) tmp += 512; specs->chroma.bluey = tmp/1024; DPRINTK("BlueY: 0.%03d\n", specs->chroma.bluey); - + tmp = ((block[6] & (3 << 2)) >> 2) | (block[0xd] << 2); tmp *= 1000; tmp += 512; @@ -383,7 +383,7 @@ static void calc_mode_timings(int xres, int yres, int refresh, struct fb_videomode *mode) { struct fb_var_screeninfo *var; - + var = kzalloc(sizeof(struct fb_var_screeninfo), GFP_KERNEL); if (var) { @@ -451,11 +451,11 @@ static int get_est_timing(unsigned char *block, struct fb_videomode *mode) c = block[1]; if (c&0x80) { - mode[num++] = vesa_modes[9]; + mode[num++] = vesa_modes[9]; DPRINTK(" 800x600@72Hz\n"); } if (c&0x40) { - mode[num++] = vesa_modes[10]; + mode[num++] = vesa_modes[10]; DPRINTK(" 800x600@75Hz\n"); } if (c&0x20) { @@ -495,7 +495,7 @@ static int get_est_timing(unsigned char *block, struct fb_videomode *mode) static int get_std_timing(unsigned char *block, struct fb_videomode *mode) { int xres, yres = 0, refresh, ratio, i; - + xres = (block[0] + 31) * 8; if (xres <= 256) return 0; @@ -519,7 +519,7 @@ static int get_std_timing(unsigned char *block, struct fb_videomode *mode) DPRINTK(" %dx%d@%dHz\n", xres, yres, refresh); for (i = 0; i < VESA_MODEDB_SIZE; i++) { - if (vesa_modes[i].xres == xres && + if (vesa_modes[i].xres == xres && vesa_modes[i].yres == yres && vesa_modes[i].refresh == refresh) { *mode = vesa_modes[i]; @@ -536,13 +536,13 @@ static int get_dst_timing(unsigned char *block, { int j, num = 0; - for (j = 0; j < 6; j++, block+= STD_TIMING_DESCRIPTION_SIZE) + for (j = 0; j < 6; j++, block += STD_TIMING_DESCRIPTION_SIZE) num += get_std_timing(block, &mode[num]); return num; } -static void get_detailed_timing(unsigned char *block, +static void get_detailed_timing(unsigned char *block, struct fb_videomode *mode) { mode->xres = H_ACTIVE; @@ -553,7 +553,7 @@ static void get_detailed_timing(unsigned char *block, mode->right_margin = H_SYNC_OFFSET; mode->left_margin = (H_ACTIVE + H_BLANKING) - (H_ACTIVE + H_SYNC_OFFSET + H_SYNC_WIDTH); - mode->upper_margin = V_BLANKING - V_SYNC_OFFSET - + mode->upper_margin = V_BLANKING - V_SYNC_OFFSET - V_SYNC_WIDTH; mode->lower_margin = V_SYNC_OFFSET; mode->hsync_len = H_SYNC_WIDTH; @@ -597,7 +597,7 @@ static struct fb_videomode *fb_create_modedb(unsigned char *edid, int *dbsize) if (mode == NULL) return NULL; - if (edid == NULL || !edid_checksum(edid) || + if (edid == NULL || !edid_checksum(edid) || !edid_check_header(edid)) { kfree(mode); return NULL; @@ -632,7 +632,7 @@ static struct fb_videomode *fb_create_modedb(unsigned char *edid, int *dbsize) if (block[0] == 0x00 && block[1] == 0x00 && block[3] == 0xfa) num += get_dst_timing(block + 5, &mode[num]); } - + /* Yikes, EDID data is totally useless */ if (!num) { kfree(mode); @@ -686,7 +686,7 @@ static int fb_get_monitor_limits(unsigned char *edid, struct fb_monspecs *specs) /* estimate monitor limits based on modes supported */ if (retval) { struct fb_videomode *modes, *mode; - int num_modes, i, hz, hscan, pixclock; + int num_modes, hz, hscan, pixclock; int vtotal, htotal; modes = fb_create_modedb(edid, &num_modes); @@ -713,7 +713,7 @@ static int fb_get_monitor_limits(unsigned char *edid, struct fb_monspecs *specs) hscan = (pixclock + htotal / 2) / htotal; hscan = (hscan + 500) / 1000 * 1000; hz = (hscan + vtotal / 2) / vtotal; - + if (specs->dclkmax == 0 || specs->dclkmax < pixclock) specs->dclkmax = pixclock; @@ -966,8 +966,8 @@ void fb_edid_to_monspecs(unsigned char *edid, struct fb_monspecs *specs) DPRINTK("========================================\n"); } -/* - * VESA Generalized Timing Formula (GTF) +/* + * VESA Generalized Timing Formula (GTF) */ #define FLYBACK 550 @@ -996,7 +996,7 @@ struct __fb_timings { * @hfreq: horizontal freq * * DESCRIPTION: - * vblank = right_margin + vsync_len + left_margin + * vblank = right_margin + vsync_len + left_margin * * given: right_margin = 1 (V_FRONTPORCH) * vsync_len = 3 @@ -1010,12 +1010,12 @@ static u32 fb_get_vblank(u32 hfreq) { u32 vblank; - vblank = (hfreq * FLYBACK)/1000; + vblank = (hfreq * FLYBACK)/1000; vblank = (vblank + 500)/1000; return (vblank + V_FRONTPORCH); } -/** +/** * fb_get_hblank_by_freq - get horizontal blank time given hfreq * @hfreq: horizontal freq * @xres: horizontal resolution in pixels @@ -1031,7 +1031,7 @@ static u32 fb_get_vblank(u32 hfreq) * * where: C = ((offset - scale factor) * blank_scale) * -------------------------------------- + scale factor - * 256 + * 256 * M = blank_scale * gradient * */ @@ -1039,7 +1039,7 @@ static u32 fb_get_hblank_by_hfreq(u32 hfreq, u32 xres) { u32 c_val, m_val, duty_cycle, hblank; - c_val = (((H_OFFSET - H_SCALEFACTOR) * H_BLANKSCALE)/256 + + c_val = (((H_OFFSET - H_SCALEFACTOR) * H_BLANKSCALE)/256 + H_SCALEFACTOR) * 1000; m_val = (H_BLANKSCALE * H_GRADIENT)/256; m_val = (m_val * 1000000)/hfreq; @@ -1048,7 +1048,7 @@ static u32 fb_get_hblank_by_hfreq(u32 hfreq, u32 xres) return (hblank); } -/** +/** * fb_get_hblank_by_dclk - get horizontal blank time given pixelclock * @dclk: pixelclock in Hz * @xres: horizontal resolution in pixels @@ -1061,7 +1061,7 @@ static u32 fb_get_hblank_by_hfreq(u32 hfreq, u32 xres) * * duty cycle = percent of htotal assigned to inactive display * duty cycle = C - (M * h_period) - * + * * where: h_period = SQRT(100 - C + (0.4 * xres * M)/dclk) + C - 100 * ----------------------------------------------- * 2 * M @@ -1077,11 +1077,11 @@ static u32 fb_get_hblank_by_dclk(u32 dclk, u32 xres) h_period = 100 - C_VAL; h_period *= h_period; h_period += (M_VAL * xres * 2 * 1000)/(5 * dclk); - h_period *=10000; + h_period *= 10000; h_period = int_sqrt(h_period); h_period -= (100 - C_VAL) * 100; - h_period *= 1000; + h_period *= 1000; h_period /= 2 * M_VAL; duty_cycle = C_VAL * 1000 - (M_VAL * h_period)/100; @@ -1089,7 +1089,7 @@ static u32 fb_get_hblank_by_dclk(u32 dclk, u32 xres) hblank &= ~15; return (hblank); } - + /** * fb_get_hfreq - estimate hsync * @vfreq: vertical refresh rate @@ -1100,13 +1100,13 @@ static u32 fb_get_hblank_by_dclk(u32 dclk, u32 xres) * (yres + front_port) * vfreq * 1000000 * hfreq = ------------------------------------- * (1000000 - (vfreq * FLYBACK) - * + * */ static u32 fb_get_hfreq(u32 vfreq, u32 yres) { u32 divisor, hfreq; - + divisor = (1000000 - (vfreq * FLYBACK))/1000; hfreq = (yres + V_FRONTPORCH) * vfreq * 1000; return (hfreq/divisor); @@ -1117,7 +1117,7 @@ static void fb_timings_vfreq(struct __fb_timings *timings) timings->hfreq = fb_get_hfreq(timings->vfreq, timings->vactive); timings->vblank = fb_get_vblank(timings->hfreq); timings->vtotal = timings->vactive + timings->vblank; - timings->hblank = fb_get_hblank_by_hfreq(timings->hfreq, + timings->hblank = fb_get_hblank_by_hfreq(timings->hfreq, timings->hactive); timings->htotal = timings->hactive + timings->hblank; timings->dclk = timings->htotal * timings->hfreq; @@ -1128,7 +1128,7 @@ static void fb_timings_hfreq(struct __fb_timings *timings) timings->vblank = fb_get_vblank(timings->hfreq); timings->vtotal = timings->vactive + timings->vblank; timings->vfreq = timings->hfreq/timings->vtotal; - timings->hblank = fb_get_hblank_by_hfreq(timings->hfreq, + timings->hblank = fb_get_hblank_by_hfreq(timings->hfreq, timings->hactive); timings->htotal = timings->hactive + timings->hblank; timings->dclk = timings->htotal * timings->hfreq; @@ -1136,7 +1136,7 @@ static void fb_timings_hfreq(struct __fb_timings *timings) static void fb_timings_dclk(struct __fb_timings *timings) { - timings->hblank = fb_get_hblank_by_dclk(timings->dclk, + timings->hblank = fb_get_hblank_by_dclk(timings->dclk, timings->hactive); timings->htotal = timings->hactive + timings->hblank; timings->hfreq = timings->dclk/timings->htotal; @@ -1156,29 +1156,29 @@ static void fb_timings_dclk(struct __fb_timings *timings) * @info: pointer to fb_info * * DESCRIPTION: - * Calculates video mode based on monitor specs using VESA GTF. - * The GTF is best for VESA GTF compliant monitors but is + * Calculates video mode based on monitor specs using VESA GTF. + * The GTF is best for VESA GTF compliant monitors but is * specifically formulated to work for older monitors as well. * - * If @flag==0, the function will attempt to maximize the + * If @flag==0, the function will attempt to maximize the * refresh rate. Otherwise, it will calculate timings based on - * the flag and accompanying value. + * the flag and accompanying value. * - * If FB_IGNOREMON bit is set in @flags, monitor specs will be + * If FB_IGNOREMON bit is set in @flags, monitor specs will be * ignored and @var will be filled with the calculated timings. * * All calculations are based on the VESA GTF Spreadsheet * available at VESA's public ftp (http://www.vesa.org). - * + * * NOTES: * The timings generated by the GTF will be different from VESA * DMT. It might be a good idea to keep a table of standard * VESA modes as well. The GTF may also not work for some displays, * such as, and especially, analog TV. - * + * * REQUIRES: * A valid info->monspecs, otherwise 'safe numbers' will be used. - */ + */ int fb_get_mode(int flags, u32 val, struct fb_var_screeninfo *var, struct fb_info *info) { struct __fb_timings *timings; @@ -1191,7 +1191,7 @@ int fb_get_mode(int flags, u32 val, struct fb_var_screeninfo *var, struct fb_inf if (!timings) return -ENOMEM; - /* + /* * If monspecs are invalid, use values that are enough * for 640x480@60 */ @@ -1214,7 +1214,7 @@ int fb_get_mode(int flags, u32 val, struct fb_var_screeninfo *var, struct fb_inf timings->hactive = var->xres; timings->vactive = var->yres; - if (var->vmode & FB_VMODE_INTERLACED) { + if (var->vmode & FB_VMODE_INTERLACED) { timings->vactive /= 2; interlace = 2; } @@ -1250,9 +1250,9 @@ int fb_get_mode(int flags, u32 val, struct fb_var_screeninfo *var, struct fb_inf break; default: err = -EINVAL; - - } - + + } + if (err || (!(flags & FB_IGNOREMON) && (timings->vfreq < vfmin || timings->vfreq > vfmax || timings->hfreq < hfmin || timings->hfreq > hfmax || @@ -1269,7 +1269,7 @@ int fb_get_mode(int flags, u32 val, struct fb_var_screeninfo *var, struct fb_inf var->upper_margin = (timings->vblank * interlace)/dscan - (var->vsync_len + var->lower_margin); } - + kfree(timings); return err; } @@ -1291,7 +1291,7 @@ int fb_get_mode(int flags, u32 val, struct fb_var_screeninfo *var, return -EINVAL; } #endif /* CONFIG_FB_MODE_HELPERS */ - + /* * fb_validate_mode - validates var against monitor capabilities * @var: pointer to fb_var_screeninfo @@ -1309,7 +1309,7 @@ int fb_validate_mode(const struct fb_var_screeninfo *var, struct fb_info *info) u32 hfreq, vfreq, htotal, vtotal, pixclock; u32 hfmin, hfmax, vfmin, vfmax, dclkmin, dclkmax; - /* + /* * If monspecs are invalid, use values that are enough * for 640x480@60 */ @@ -1333,10 +1333,10 @@ int fb_validate_mode(const struct fb_var_screeninfo *var, struct fb_info *info) if (!var->pixclock) return -EINVAL; pixclock = PICOS2KHZ(var->pixclock) * 1000; - - htotal = var->xres + var->right_margin + var->hsync_len + + + htotal = var->xres + var->right_margin + var->hsync_len + var->left_margin; - vtotal = var->yres + var->lower_margin + var->vsync_len + + vtotal = var->yres + var->lower_margin + var->vsync_len + var->upper_margin; if (var->vmode & FB_VMODE_INTERLACED) @@ -1349,7 +1349,7 @@ int fb_validate_mode(const struct fb_var_screeninfo *var, struct fb_info *info) vfreq = hfreq/vtotal; - return (vfreq < vfmin || vfreq > vfmax || + return (vfreq < vfmin || vfreq > vfmax || hfreq < hfmin || hfreq > hfmax || pixclock < dclkmin || pixclock > dclkmax) ? -EINVAL : 0; diff --git a/drivers/video/geode/lxfb_core.c b/drivers/video/geode/lxfb_core.c index 583185fd7c94..eb6b88171538 100644 --- a/drivers/video/geode/lxfb_core.c +++ b/drivers/video/geode/lxfb_core.c @@ -34,7 +34,7 @@ static int fbsize; * we try to make it something sane - 640x480-60 is sane */ -const struct fb_videomode geode_modedb[] __initdata = { +static const struct fb_videomode geode_modedb[] __initdata = { /* 640x480-60 */ { NULL, 60, 640, 480, 39682, 48, 8, 25, 2, 88, 2, FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, diff --git a/drivers/video/hpfb.c b/drivers/video/hpfb.c index b18486ad8e17..2eb4fb159084 100644 --- a/drivers/video/hpfb.c +++ b/drivers/video/hpfb.c @@ -207,7 +207,8 @@ static struct fb_ops hpfb_ops = { #define HPFB_FBOMSB 0x5d /* Frame buffer offset */ #define HPFB_FBOLSB 0x5f -static int __init hpfb_init_one(unsigned long phys_base, unsigned long virt_base) +static int __devinit hpfb_init_one(unsigned long phys_base, + unsigned long virt_base) { unsigned long fboff, fb_width, fb_height, fb_start; diff --git a/drivers/video/i810/i810_main.c b/drivers/video/i810/i810_main.c index 1a7d7789d877..1d13dd099af8 100644 --- a/drivers/video/i810/i810_main.c +++ b/drivers/video/i810/i810_main.c @@ -1476,7 +1476,7 @@ static int i810fb_cursor(struct fb_info *info, struct fb_cursor *cursor) struct i810fb_par *par = info->par; u8 __iomem *mmio = par->mmio_start_virtual; - if (!par->dev_flags & LOCKUP) + if (!(par->dev_flags & LOCKUP)) return -ENXIO; if (cursor->image.width > 64 || cursor->image.height > 64) diff --git a/drivers/video/igafb.c b/drivers/video/igafb.c index b87ea21d3d78..3a81060137a2 100644 --- a/drivers/video/igafb.c +++ b/drivers/video/igafb.c @@ -400,6 +400,7 @@ int __init igafb_init(void) info = kzalloc(size, GFP_ATOMIC); if (!info) { printk("igafb_init: can't alloc fb_info\n"); + pci_dev_put(pdev); return -ENOMEM; } @@ -409,12 +410,14 @@ int __init igafb_init(void) if ((addr = pdev->resource[0].start) == 0) { printk("igafb_init: no memory start\n"); kfree(info); + pci_dev_put(pdev); return -ENXIO; } if ((info->screen_base = ioremap(addr, 1024*1024*2)) == 0) { printk("igafb_init: can't remap %lx[2M]\n", addr); kfree(info); + pci_dev_put(pdev); return -ENXIO; } @@ -449,6 +452,7 @@ int __init igafb_init(void) printk("igafb_init: can't remap %lx[4K]\n", igafb_fix.mmio_start); iounmap((void *)info->screen_base); kfree(info); + pci_dev_put(pdev); return -ENXIO; } @@ -466,6 +470,7 @@ int __init igafb_init(void) iounmap((void *)par->io_base); iounmap(info->screen_base); kfree(info); + pci_dev_put(pdev); return -ENOMEM; } diff --git a/drivers/video/intelfb/intelfbhw.c b/drivers/video/intelfb/intelfbhw.c index 5f6fb7d2c408..fa1fff553565 100644 --- a/drivers/video/intelfb/intelfbhw.c +++ b/drivers/video/intelfb/intelfbhw.c @@ -1971,7 +1971,7 @@ void intelfbhw_cursor_reset(struct intelfb_info *dinfo) static irqreturn_t intelfbhw_irq(int irq, void *dev_id) { u16 tmp; - struct intelfb_info *dinfo = (struct intelfb_info *)dev_id; + struct intelfb_info *dinfo = dev_id; spin_lock(&dinfo->int_lock); diff --git a/drivers/video/neofb.c b/drivers/video/neofb.c index 4b6a99b5be0d..5246b0402d76 100644 --- a/drivers/video/neofb.c +++ b/drivers/video/neofb.c @@ -2066,40 +2066,49 @@ static struct fb_info *__devinit neo_alloc_fb_info(struct pci_dev *dev, const st switch (info->fix.accel) { case FB_ACCEL_NEOMAGIC_NM2070: - sprintf(info->fix.id, "MagicGraph 128"); + snprintf(info->fix.id, sizeof(info->fix.id), + "MagicGraph 128"); break; case FB_ACCEL_NEOMAGIC_NM2090: - sprintf(info->fix.id, "MagicGraph 128V"); + snprintf(info->fix.id, sizeof(info->fix.id), + "MagicGraph 128V"); break; case FB_ACCEL_NEOMAGIC_NM2093: - sprintf(info->fix.id, "MagicGraph 128ZV"); + snprintf(info->fix.id, sizeof(info->fix.id), + "MagicGraph 128ZV"); break; case FB_ACCEL_NEOMAGIC_NM2097: - sprintf(info->fix.id, "MagicGraph 128ZV+"); + snprintf(info->fix.id, sizeof(info->fix.id), + "MagicGraph 128ZV+"); break; case FB_ACCEL_NEOMAGIC_NM2160: - sprintf(info->fix.id, "MagicGraph 128XD"); + snprintf(info->fix.id, sizeof(info->fix.id), + "MagicGraph 128XD"); break; case FB_ACCEL_NEOMAGIC_NM2200: - sprintf(info->fix.id, "MagicGraph 256AV"); + snprintf(info->fix.id, sizeof(info->fix.id), + "MagicGraph 256AV"); info->flags |= FBINFO_HWACCEL_IMAGEBLIT | FBINFO_HWACCEL_COPYAREA | FBINFO_HWACCEL_FILLRECT; break; case FB_ACCEL_NEOMAGIC_NM2230: - sprintf(info->fix.id, "MagicGraph 256AV+"); + snprintf(info->fix.id, sizeof(info->fix.id), + "MagicGraph 256AV+"); info->flags |= FBINFO_HWACCEL_IMAGEBLIT | FBINFO_HWACCEL_COPYAREA | FBINFO_HWACCEL_FILLRECT; break; case FB_ACCEL_NEOMAGIC_NM2360: - sprintf(info->fix.id, "MagicGraph 256ZX"); + snprintf(info->fix.id, sizeof(info->fix.id), + "MagicGraph 256ZX"); info->flags |= FBINFO_HWACCEL_IMAGEBLIT | FBINFO_HWACCEL_COPYAREA | FBINFO_HWACCEL_FILLRECT; break; case FB_ACCEL_NEOMAGIC_NM2380: - sprintf(info->fix.id, "MagicGraph 256XL+"); + snprintf(info->fix.id, sizeof(info->fix.id), + "MagicGraph 256XL+"); info->flags |= FBINFO_HWACCEL_IMAGEBLIT | FBINFO_HWACCEL_COPYAREA | FBINFO_HWACCEL_FILLRECT; diff --git a/drivers/video/nvidia/nvidia.c b/drivers/video/nvidia/nvidia.c index 30e14eb1f51e..74517b1b26a6 100644 --- a/drivers/video/nvidia/nvidia.c +++ b/drivers/video/nvidia/nvidia.c @@ -849,9 +849,27 @@ static int nvidiafb_check_var(struct fb_var_screeninfo *var, if (!mode_valid && info->monspecs.modedb_len) return -EINVAL; + /* + * If we're on a flat panel, check if the mode is outside of the + * panel dimensions. If so, cap it and try for the next best mode + * before bailing out. + */ if (par->fpWidth && par->fpHeight && (par->fpWidth < var->xres || - par->fpHeight < var->yres)) - return -EINVAL; + par->fpHeight < var->yres)) { + const struct fb_videomode *mode; + + var->xres = par->fpWidth; + var->yres = par->fpHeight; + + mode = fb_find_best_mode(var, &info->modelist); + if (!mode) { + printk(KERN_ERR PFX "mode out of range of flat " + "panel dimensions\n"); + return -EINVAL; + } + + fb_videomode_to_var(var, mode); + } if (var->yres_virtual < var->yres) var->yres_virtual = var->yres; diff --git a/drivers/video/pm2fb.c b/drivers/video/pm2fb.c index 5591dfb22b18..30181b593829 100644 --- a/drivers/video/pm2fb.c +++ b/drivers/video/pm2fb.c @@ -1159,6 +1159,11 @@ static void pm2fb_imageblit(struct fb_info *info, const struct fb_image *image) u32 fgx, bgx; const u32 *src = (const u32 *)image->data; u32 xres = (info->var.xres + 31) & ~31; + int raster_mode = 1; /* invert bits */ + +#ifdef __LITTLE_ENDIAN + raster_mode |= 3 << 7; /* reverse byte order */ +#endif if (info->state != FBINFO_STATE_RUNNING) return; @@ -1208,9 +1213,8 @@ static void pm2fb_imageblit(struct fb_info *info, const struct fb_image *image) pm2_WR(par, PM2R_RENDER, PM2F_RENDER_RECTANGLE | PM2F_INCREASE_X | PM2F_INCREASE_Y); - /* BitMapPackEachScanline & invert bits and byte order*/ - /* force background */ - pm2_WR(par, PM2R_RASTERIZER_MODE, (1 << 9) | 1 | (3 << 7)); + /* BitMapPackEachScanline */ + pm2_WR(par, PM2R_RASTERIZER_MODE, raster_mode | (1 << 9)); pm2_WR(par, PM2R_CONSTANT_COLOR, fgx); pm2_WR(par, PM2R_RENDER, PM2F_RENDER_RECTANGLE | @@ -1224,8 +1228,7 @@ static void pm2fb_imageblit(struct fb_info *info, const struct fb_image *image) PM2F_RENDER_RECTANGLE | PM2F_RENDER_FASTFILL | PM2F_INCREASE_X | PM2F_INCREASE_Y); - /* invert bits and byte order*/ - pm2_WR(par, PM2R_RASTERIZER_MODE, 1 | (3 << 7)); + pm2_WR(par, PM2R_RASTERIZER_MODE, raster_mode); pm2_WR(par, PM2R_FB_BLOCK_COLOR, fgx); pm2_WR(par, PM2R_RENDER, PM2F_RENDER_RECTANGLE | diff --git a/drivers/video/pm3fb.c b/drivers/video/pm3fb.c index 070659992c18..5dba8cdd0517 100644 --- a/drivers/video/pm3fb.c +++ b/drivers/video/pm3fb.c @@ -1227,7 +1227,7 @@ static struct fb_ops pm3fb_ops = { /* mmio register are already mapped when this function is called */ /* the pm3fb_fix.smem_start is also set */ -static unsigned long pm3fb_size_memory(struct pm3_par *par) +static unsigned long __devinit pm3fb_size_memory(struct pm3_par *par) { unsigned long memsize = 0; unsigned long tempBypass, i, temp1, temp2; diff --git a/drivers/video/pmag-aa-fb.c b/drivers/video/pmag-aa-fb.c index a864438b6008..6515ec11c16b 100644 --- a/drivers/video/pmag-aa-fb.c +++ b/drivers/video/pmag-aa-fb.c @@ -150,7 +150,7 @@ static int aafbcon_set_font(struct display *disp, int width, int height) { struct aafb_info *info = (struct aafb_info *)disp->fb_info; struct aafb_cursor *c = &info->cursor; - u8 fgc = ~attr_bgcol_ec(disp, disp->conp); + u8 fgc = ~attr_bgcol_ec(disp, disp->conp, &info->info); if (width > 64 || height > 64 || width < 0 || height < 0) return -EINVAL; diff --git a/drivers/video/ps3fb.c b/drivers/video/ps3fb.c index 044a423a72cb..dc3af1c78c56 100644 --- a/drivers/video/ps3fb.c +++ b/drivers/video/ps3fb.c @@ -57,8 +57,6 @@ #define GPU_ALIGN_UP(x) _ALIGN_UP((x), 64) #define GPU_MAX_LINE_LENGTH (65536 - 64) -#define PS3FB_FULL_MODE_BIT 0x80 - #define GPU_INTR_STATUS_VSYNC_0 0 /* vsync on head A */ #define GPU_INTR_STATUS_VSYNC_1 1 /* vsync on head B */ #define GPU_INTR_STATUS_FLIP_0 3 /* flip head A */ @@ -118,8 +116,6 @@ struct ps3fb_priv { unsigned int irq_no; u64 context_handle, memory_handle; - void *xdr_ea; - size_t xdr_size; struct gpu_driver_info *dinfo; u64 vblank_count; /* frame count */ @@ -136,42 +132,19 @@ static struct ps3fb_priv ps3fb; struct ps3fb_par { u32 pseudo_palette[16]; int mode_id, new_mode_id; - int res_index; unsigned int num_frames; /* num of frame buffers */ unsigned int width; unsigned int height; - unsigned long full_offset; /* start of fullscreen DDR fb */ - unsigned long fb_offset; /* start of actual DDR fb */ - unsigned long pan_offset; + unsigned int ddr_line_length; + unsigned int ddr_frame_size; + unsigned int xdr_frame_size; + unsigned int full_offset; /* start of fullscreen DDR fb */ + unsigned int fb_offset; /* start of actual DDR fb */ + unsigned int pan_offset; }; -struct ps3fb_res_table { - u32 xres; - u32 yres; - u32 xoff; - u32 yoff; - u32 type; -}; -#define PS3FB_RES_FULL 1 -static const struct ps3fb_res_table ps3fb_res[] = { - /* res_x,y margin_x,y full */ - { 720, 480, 72, 48 , 0}, - { 720, 576, 72, 58 , 0}, - { 1280, 720, 78, 38 , 0}, - { 1920, 1080, 116, 58 , 0}, - /* full mode */ - { 720, 480, 0, 0 , PS3FB_RES_FULL}, - { 720, 576, 0, 0 , PS3FB_RES_FULL}, - { 1280, 720, 0, 0 , PS3FB_RES_FULL}, - { 1920, 1080, 0, 0 , PS3FB_RES_FULL}, - /* vesa: normally full mode */ - { 1280, 768, 0, 0 , 0}, - { 1280, 1024, 0, 0 , 0}, - { 1920, 1200, 0, 0 , 0}, - { 0, 0, 0, 0 , 0} }; - -/* default resolution */ -#define GPU_RES_INDEX 0 /* 720 x 480 */ + +#define FIRST_NATIVE_MODE_INDEX 10 static const struct fb_videomode ps3fb_modedb[] = { /* 60 Hz broadcast modes (modes "1" to "5") */ @@ -211,7 +184,7 @@ static const struct fb_videomode ps3fb_modedb[] = { "720p", 50, 1124, 644, 13468, 298, 478, 57, 44, 80, 5, FB_SYNC_BROADCAST, FB_VMODE_NONINTERLACED }, { - /* 1080 */ + /* 1080i */ "1080i", 50, 1688, 964, 13468, 264, 600, 94, 62, 88, 5, FB_SYNC_BROADCAST, FB_VMODE_INTERLACED }, { @@ -220,24 +193,7 @@ static const struct fb_videomode ps3fb_modedb[] = { FB_SYNC_BROADCAST, FB_VMODE_NONINTERLACED }, - /* VESA modes (modes "11" to "13") */ - { - /* WXGA */ - "wxga", 60, 1280, 768, 12924, 160, 24, 29, 3, 136, 6, - 0, FB_VMODE_NONINTERLACED, - FB_MODE_IS_VESA - }, { - /* SXGA */ - "sxga", 60, 1280, 1024, 9259, 248, 48, 38, 1, 112, 3, - FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED, - FB_MODE_IS_VESA - }, { - /* WUXGA */ - "wuxga", 60, 1920, 1200, 6494, 80, 48, 26, 3, 32, 6, - FB_SYNC_HOR_HIGH_ACT, FB_VMODE_NONINTERLACED, - FB_MODE_IS_VESA - }, - + [FIRST_NATIVE_MODE_INDEX] = /* 60 Hz broadcast modes (full resolution versions of modes "1" to "5") */ { /* 480if */ @@ -276,12 +232,30 @@ static const struct fb_videomode ps3fb_modedb[] = { FB_SYNC_BROADCAST, FB_VMODE_NONINTERLACED }, { /* 1080if */ - "1080f", 50, 1920, 1080, 13468, 148, 484, 36, 4, 88, 5, + "1080if", 50, 1920, 1080, 13468, 148, 484, 36, 4, 88, 5, FB_SYNC_BROADCAST, FB_VMODE_INTERLACED }, { /* 1080pf */ "1080pf", 50, 1920, 1080, 6734, 148, 484, 36, 4, 88, 5, FB_SYNC_BROADCAST, FB_VMODE_NONINTERLACED + }, + + /* VESA modes (modes "11" to "13") */ + { + /* WXGA */ + "wxga", 60, 1280, 768, 12924, 160, 24, 29, 3, 136, 6, + 0, FB_VMODE_NONINTERLACED, + FB_MODE_IS_VESA + }, { + /* SXGA */ + "sxga", 60, 1280, 1024, 9259, 248, 48, 38, 1, 112, 3, + FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED, + FB_MODE_IS_VESA + }, { + /* WUXGA */ + "wuxga", 60, 1920, 1200, 6494, 80, 48, 26, 3, 32, 6, + FB_SYNC_HOR_HIGH_ACT, FB_VMODE_NONINTERLACED, + FB_MODE_IS_VESA } }; @@ -289,110 +263,188 @@ static const struct fb_videomode ps3fb_modedb[] = { #define HEAD_A #define HEAD_B -#define X_OFF(i) (ps3fb_res[i].xoff) /* left/right margin (pixel) */ -#define Y_OFF(i) (ps3fb_res[i].yoff) /* top/bottom margin (pixel) */ -#define WIDTH(i) (ps3fb_res[i].xres) /* width of FB */ -#define HEIGHT(i) (ps3fb_res[i].yres) /* height of FB */ #define BPP 4 /* number of bytes per pixel */ -/* Start of the virtual frame buffer (relative to fullscreen ) */ -#define VP_OFF(i) ((WIDTH(i) * Y_OFF(i) + X_OFF(i)) * BPP) - static int ps3fb_mode; module_param(ps3fb_mode, int, 0); static char *mode_option __devinitdata; -static int ps3fb_get_res_table(u32 xres, u32 yres, int mode) +static int ps3fb_cmp_mode(const struct fb_videomode *vmode, + const struct fb_var_screeninfo *var) { - int full_mode; - unsigned int i; - u32 x, y, f; - - full_mode = (mode & PS3FB_FULL_MODE_BIT) ? PS3FB_RES_FULL : 0; - for (i = 0;; i++) { - x = ps3fb_res[i].xres; - y = ps3fb_res[i].yres; - f = ps3fb_res[i].type; - - if (!x) { - pr_debug("ERROR: ps3fb_get_res_table()\n"); - return -1; - } + long xres, yres, left_margin, right_margin, upper_margin, lower_margin; + long dx, dy; + + /* maximum values */ + if (var->xres > vmode->xres || var->yres > vmode->yres || + var->pixclock > vmode->pixclock || + var->hsync_len > vmode->hsync_len || + var->vsync_len > vmode->vsync_len) + return -1; - if (full_mode == PS3FB_RES_FULL && f != PS3FB_RES_FULL) - continue; + /* progressive/interlaced must match */ + if ((var->vmode & FB_VMODE_MASK) != vmode->vmode) + return -1; - if (x == xres && (yres == 0 || y == yres)) - break; + /* minimum resolution */ + xres = max(var->xres, 1U); + yres = max(var->yres, 1U); + + /* minimum margins */ + left_margin = max(var->left_margin, vmode->left_margin); + right_margin = max(var->right_margin, vmode->right_margin); + upper_margin = max(var->upper_margin, vmode->upper_margin); + lower_margin = max(var->lower_margin, vmode->lower_margin); + + /* resolution + margins may not exceed native parameters */ + dx = ((long)vmode->left_margin + (long)vmode->xres + + (long)vmode->right_margin) - + (left_margin + xres + right_margin); + if (dx < 0) + return -1; - x = x - 2 * ps3fb_res[i].xoff; - y = y - 2 * ps3fb_res[i].yoff; - if (x == xres && (yres == 0 || y == yres)) - break; + dy = ((long)vmode->upper_margin + (long)vmode->yres + + (long)vmode->lower_margin) - + (upper_margin + yres + lower_margin); + if (dy < 0) + return -1; + + /* exact match */ + if (!dx && !dy) + return 0; + + /* resolution difference */ + return (vmode->xres - xres) * (vmode->yres - yres); +} + +static const struct fb_videomode *ps3fb_native_vmode(enum ps3av_mode_num id) +{ + return &ps3fb_modedb[FIRST_NATIVE_MODE_INDEX + id - 1]; +} + +static const struct fb_videomode *ps3fb_vmode(int id) +{ + u32 mode = id & PS3AV_MODE_MASK; + + if (mode < PS3AV_MODE_480I || mode > PS3AV_MODE_WUXGA) + return NULL; + + if (mode <= PS3AV_MODE_1080P50 && !(id & PS3AV_MODE_FULL)) { + /* Non-fullscreen broadcast mode */ + return &ps3fb_modedb[mode - 1]; } - return i; + + return ps3fb_native_vmode(mode); } -static unsigned int ps3fb_find_mode(const struct fb_var_screeninfo *var, +static unsigned int ps3fb_find_mode(struct fb_var_screeninfo *var, u32 *ddr_line_length, u32 *xdr_line_length) { - unsigned int i, mode; - - for (i = 0; i < ARRAY_SIZE(ps3fb_modedb); i++) - if (var->xres == ps3fb_modedb[i].xres && - var->yres == ps3fb_modedb[i].yres && - var->pixclock == ps3fb_modedb[i].pixclock && - var->hsync_len == ps3fb_modedb[i].hsync_len && - var->vsync_len == ps3fb_modedb[i].vsync_len && - var->left_margin == ps3fb_modedb[i].left_margin && - var->right_margin == ps3fb_modedb[i].right_margin && - var->upper_margin == ps3fb_modedb[i].upper_margin && - var->lower_margin == ps3fb_modedb[i].lower_margin && - var->sync == ps3fb_modedb[i].sync && - (var->vmode & FB_VMODE_MASK) == ps3fb_modedb[i].vmode) - goto found; - - pr_debug("ps3fb_find_mode: mode not found\n"); - return 0; + unsigned int id, best_id; + int diff, best_diff; + const struct fb_videomode *vmode; + long gap; + + best_id = 0; + best_diff = INT_MAX; + pr_debug("%s: wanted %u [%u] %u x %u [%u] %u\n", __func__, + var->left_margin, var->xres, var->right_margin, + var->upper_margin, var->yres, var->lower_margin); + for (id = PS3AV_MODE_480I; id <= PS3AV_MODE_WUXGA; id++) { + vmode = ps3fb_native_vmode(id); + diff = ps3fb_cmp_mode(vmode, var); + pr_debug("%s: mode %u: %u [%u] %u x %u [%u] %u: diff = %d\n", + __func__, id, vmode->left_margin, vmode->xres, + vmode->right_margin, vmode->upper_margin, + vmode->yres, vmode->lower_margin, diff); + if (diff < 0) + continue; + if (diff < best_diff) { + best_id = id; + if (!diff) + break; + best_diff = diff; + } + } -found: - /* Cropped broadcast modes use the full line length */ - *ddr_line_length = ps3fb_modedb[i < 10 ? i + 13 : i].xres * BPP; + if (!best_id) { + pr_debug("%s: no suitable mode found\n", __func__); + return 0; + } - if (ps3_compare_firmware_version(1, 9, 0) >= 0) { - *xdr_line_length = GPU_ALIGN_UP(max(var->xres, - var->xres_virtual) * BPP); - if (*xdr_line_length > GPU_MAX_LINE_LENGTH) - *xdr_line_length = GPU_MAX_LINE_LENGTH; - } else - *xdr_line_length = *ddr_line_length; + id = best_id; + vmode = ps3fb_native_vmode(id); - /* Full broadcast modes have the full mode bit set */ - mode = i > 12 ? (i - 12) | PS3FB_FULL_MODE_BIT : i + 1; + *ddr_line_length = vmode->xres * BPP; - pr_debug("ps3fb_find_mode: mode %u\n", mode); + /* minimum resolution */ + if (!var->xres) + var->xres = 1; + if (!var->yres) + var->yres = 1; - return mode; -} + /* minimum virtual resolution */ + if (var->xres_virtual < var->xres) + var->xres_virtual = var->xres; + if (var->yres_virtual < var->yres) + var->yres_virtual = var->yres; -static const struct fb_videomode *ps3fb_default_mode(int id) -{ - u32 mode = id & PS3AV_MODE_MASK; - u32 flags; + /* minimum margins */ + if (var->left_margin < vmode->left_margin) + var->left_margin = vmode->left_margin; + if (var->right_margin < vmode->right_margin) + var->right_margin = vmode->right_margin; + if (var->upper_margin < vmode->upper_margin) + var->upper_margin = vmode->upper_margin; + if (var->lower_margin < vmode->lower_margin) + var->lower_margin = vmode->lower_margin; + + /* extra margins */ + gap = ((long)vmode->left_margin + (long)vmode->xres + + (long)vmode->right_margin) - + ((long)var->left_margin + (long)var->xres + + (long)var->right_margin); + if (gap > 0) { + var->left_margin += gap/2; + var->right_margin += (gap+1)/2; + pr_debug("%s: rounded up H to %u [%u] %u\n", __func__, + var->left_margin, var->xres, var->right_margin); + } - if (mode < 1 || mode > 13) - return NULL; + gap = ((long)vmode->upper_margin + (long)vmode->yres + + (long)vmode->lower_margin) - + ((long)var->upper_margin + (long)var->yres + + (long)var->lower_margin); + if (gap > 0) { + var->upper_margin += gap/2; + var->lower_margin += (gap+1)/2; + pr_debug("%s: rounded up V to %u [%u] %u\n", __func__, + var->upper_margin, var->yres, var->lower_margin); + } + + /* fixed fields */ + var->pixclock = vmode->pixclock; + var->hsync_len = vmode->hsync_len; + var->vsync_len = vmode->vsync_len; + var->sync = vmode->sync; - flags = id & ~PS3AV_MODE_MASK; + if (ps3_compare_firmware_version(1, 9, 0) >= 0) { + *xdr_line_length = GPU_ALIGN_UP(var->xres_virtual * BPP); + if (*xdr_line_length > GPU_MAX_LINE_LENGTH) + *xdr_line_length = GPU_MAX_LINE_LENGTH; + } else + *xdr_line_length = *ddr_line_length; - if (mode <= 10 && flags & PS3FB_FULL_MODE_BIT) { - /* Full broadcast mode */ - return &ps3fb_modedb[mode + 12]; + if (vmode->sync & FB_SYNC_BROADCAST) { + /* Full broadcast modes have the full mode bit set */ + if (vmode->xres == var->xres && vmode->yres == var->yres) + id |= PS3AV_MODE_FULL; } - return &ps3fb_modedb[mode - 1]; + pr_debug("%s: mode %u\n", __func__, id); + return id; } static void ps3fb_sync_image(struct device *dev, u64 frame_offset, @@ -439,8 +491,7 @@ static void ps3fb_sync_image(struct device *dev, u64 frame_offset, static int ps3fb_sync(struct fb_info *info, u32 frame) { struct ps3fb_par *par = info->par; - int i, error = 0; - u32 ddr_line_length, xdr_line_length; + int error = 0; u64 ddr_base, xdr_base; if (frame > par->num_frames - 1) { @@ -450,16 +501,13 @@ static int ps3fb_sync(struct fb_info *info, u32 frame) goto out; } - i = par->res_index; - xdr_line_length = info->fix.line_length; - ddr_line_length = ps3fb_res[i].xres * BPP; - xdr_base = frame * info->var.yres_virtual * xdr_line_length; - ddr_base = frame * ps3fb_res[i].yres * ddr_line_length; + xdr_base = frame * par->xdr_frame_size; + ddr_base = frame * par->ddr_frame_size; ps3fb_sync_image(info->device, ddr_base + par->full_offset, ddr_base + par->fb_offset, xdr_base + par->pan_offset, - par->width, par->height, ddr_line_length, - xdr_line_length); + par->width, par->height, par->ddr_line_length, + info->fix.line_length); out: return error; @@ -498,22 +546,11 @@ static int ps3fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) u32 xdr_line_length, ddr_line_length; int mode; - dev_dbg(info->device, "var->xres:%u info->var.xres:%u\n", var->xres, - info->var.xres); - dev_dbg(info->device, "var->yres:%u info->var.yres:%u\n", var->yres, - info->var.yres); - - /* FIXME For now we do exact matches only */ mode = ps3fb_find_mode(var, &ddr_line_length, &xdr_line_length); if (!mode) return -EINVAL; /* Virtual screen */ - if (var->xres_virtual < var->xres) - var->xres_virtual = var->xres; - if (var->yres_virtual < var->yres) - var->yres_virtual = var->yres; - if (var->xres_virtual > xdr_line_length / BPP) { dev_dbg(info->device, "Horizontal virtual screen size too large\n"); @@ -559,7 +596,7 @@ static int ps3fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) } /* Memory limit */ - if (var->yres_virtual * xdr_line_length > ps3fb.xdr_size) { + if (var->yres_virtual * xdr_line_length > info->fix.smem_len) { dev_dbg(info->device, "Not enough memory\n"); return -ENOMEM; } @@ -578,39 +615,38 @@ static int ps3fb_set_par(struct fb_info *info) { struct ps3fb_par *par = info->par; unsigned int mode, ddr_line_length, xdr_line_length, lines, maxlines; - int i; - unsigned long offset; + unsigned int ddr_xoff, ddr_yoff, offset; + const struct fb_videomode *vmode; u64 dst; - dev_dbg(info->device, "xres:%d xv:%d yres:%d yv:%d clock:%d\n", - info->var.xres, info->var.xres_virtual, - info->var.yres, info->var.yres_virtual, info->var.pixclock); - mode = ps3fb_find_mode(&info->var, &ddr_line_length, &xdr_line_length); if (!mode) return -EINVAL; - i = ps3fb_get_res_table(info->var.xres, info->var.yres, mode); - par->res_index = i; + vmode = ps3fb_native_vmode(mode & PS3AV_MODE_MASK); - info->fix.smem_start = virt_to_abs(ps3fb.xdr_ea); - info->fix.smem_len = ps3fb.xdr_size; info->fix.xpanstep = info->var.xres_virtual > info->var.xres ? 1 : 0; info->fix.ypanstep = info->var.yres_virtual > info->var.yres ? 1 : 0; info->fix.line_length = xdr_line_length; - info->screen_base = (char __iomem *)ps3fb.xdr_ea; + par->ddr_line_length = ddr_line_length; + par->ddr_frame_size = vmode->yres * ddr_line_length; + par->xdr_frame_size = info->var.yres_virtual * xdr_line_length; - par->num_frames = ps3fb.xdr_size / - max(ps3fb_res[i].yres * ddr_line_length, - info->var.yres_virtual * xdr_line_length); + par->num_frames = info->fix.smem_len / + max(par->ddr_frame_size, par->xdr_frame_size); /* Keep the special bits we cannot set using fb_var_screeninfo */ par->new_mode_id = (par->new_mode_id & ~PS3AV_MODE_MASK) | mode; par->width = info->var.xres; par->height = info->var.yres; - offset = VP_OFF(i); + + /* Start of the virtual frame buffer (relative to fullscreen) */ + ddr_xoff = info->var.left_margin - vmode->left_margin; + ddr_yoff = info->var.upper_margin - vmode->upper_margin; + offset = ddr_yoff * ddr_line_length + ddr_xoff * BPP; + par->fb_offset = GPU_ALIGN_UP(offset); par->full_offset = par->fb_offset - offset; par->pan_offset = info->var.yoffset * xdr_line_length + @@ -625,16 +661,16 @@ static int ps3fb_set_par(struct fb_info *info) } /* Clear XDR frame buffer memory */ - memset(ps3fb.xdr_ea, 0, ps3fb.xdr_size); + memset((void __force *)info->screen_base, 0, info->fix.smem_len); /* Clear DDR frame buffer memory */ - lines = ps3fb_res[i].yres * par->num_frames; + lines = vmode->yres * par->num_frames; if (par->full_offset) lines++; - maxlines = ps3fb.xdr_size / ddr_line_length; + maxlines = info->fix.smem_len / ddr_line_length; for (dst = 0; lines; dst += maxlines * ddr_line_length) { unsigned int l = min(lines, maxlines); - ps3fb_sync_image(info->device, 0, dst, 0, ps3fb_res[i].xres, l, + ps3fb_sync_image(info->device, 0, dst, 0, vmode->xres, l, ddr_line_length, ddr_line_length); lines -= l; } @@ -797,7 +833,7 @@ static int ps3fb_ioctl(struct fb_info *info, unsigned int cmd, case PS3FB_IOCTL_SETMODE: { struct ps3fb_par *par = info->par; - const struct fb_videomode *mode; + const struct fb_videomode *vmode; struct fb_var_screeninfo var; if (copy_from_user(&val, argp, sizeof(val))) @@ -810,10 +846,10 @@ static int ps3fb_ioctl(struct fb_info *info, unsigned int cmd, } dev_dbg(info->device, "PS3FB_IOCTL_SETMODE:%x\n", val); retval = -EINVAL; - mode = ps3fb_default_mode(val); - if (mode) { + vmode = ps3fb_vmode(val); + if (vmode) { var = info->var; - fb_videomode_to_var(&var, mode); + fb_videomode_to_var(&var, vmode); acquire_console_sem(); info->flags |= FBINFO_MISC_USEREVENT; /* Force, in case only special bits changed */ @@ -975,10 +1011,9 @@ static int ps3fb_xdr_settings(u64 xdr_lpar, struct device *dev) __func__, status); return -ENXIO; } - dev_dbg(dev, - "video:%p xdr_ea:%p ioif:%lx lpar:%lx phys:%lx size:%lx\n", - ps3fb_videomemory.address, ps3fb.xdr_ea, GPU_IOIF, xdr_lpar, - virt_to_abs(ps3fb.xdr_ea), ps3fb_videomemory.size); + dev_dbg(dev, "video:%p ioif:%lx lpar:%lx size:%lx\n", + ps3fb_videomemory.address, GPU_IOIF, xdr_lpar, + ps3fb_videomemory.size); status = lv1_gpu_context_attribute(ps3fb.context_handle, L1GPU_CONTEXT_ATTRIBUTE_FB_SETUP, @@ -1055,14 +1090,14 @@ static int __devinit ps3fb_probe(struct ps3_system_bus_device *dev) struct fb_info *info; struct ps3fb_par *par; int retval = -ENOMEM; - u32 xres, yres; u64 ddr_lpar = 0; u64 lpar_dma_control = 0; u64 lpar_driver_info = 0; u64 lpar_reports = 0; u64 lpar_reports_size = 0; u64 xdr_lpar; - int status, res_index; + void *fb_start; + int status; struct task_struct *task; unsigned long max_ps3fb_size; @@ -1080,14 +1115,7 @@ static int __devinit ps3fb_probe(struct ps3_system_bus_device *dev) if (!ps3fb_mode) ps3fb_mode = ps3av_get_mode(); - dev_dbg(&dev->core, "ps3av_mode:%d\n", ps3fb_mode); - - if (ps3fb_mode > 0 && - !ps3av_video_mode2res(ps3fb_mode, &xres, &yres)) { - res_index = ps3fb_get_res_table(xres, yres, ps3fb_mode); - dev_dbg(&dev->core, "res_index:%d\n", res_index); - } else - res_index = GPU_RES_INDEX; + dev_dbg(&dev->core, "ps3fb_mode: %d\n", ps3fb_mode); atomic_set(&ps3fb.f_count, -1); /* fbcon opens ps3fb */ atomic_set(&ps3fb.ext_flip, 0); /* for flip with vsync */ @@ -1124,7 +1152,7 @@ static int __devinit ps3fb_probe(struct ps3_system_bus_device *dev) } /* vsync interrupt */ - ps3fb.dinfo = ioremap(lpar_driver_info, 128 * 1024); + ps3fb.dinfo = (void __force *)ioremap(lpar_driver_info, 128 * 1024); if (!ps3fb.dinfo) { dev_err(&dev->core, "%s: ioremap failed\n", __func__); goto err_gpu_context_free; @@ -1134,22 +1162,10 @@ static int __devinit ps3fb_probe(struct ps3_system_bus_device *dev) if (retval) goto err_iounmap_dinfo; - /* XDR frame buffer */ - ps3fb.xdr_ea = ps3fb_videomemory.address; - xdr_lpar = ps3_mm_phys_to_lpar(__pa(ps3fb.xdr_ea)); - /* Clear memory to prevent kernel info leakage into userspace */ - memset(ps3fb.xdr_ea, 0, ps3fb_videomemory.size); - - /* - * The GPU command buffer is at the start of video memory - * As we don't use the full command buffer, we can put the actual - * frame buffer at offset GPU_FB_START and save some precious XDR - * memory - */ - ps3fb.xdr_ea += GPU_FB_START; - ps3fb.xdr_size = ps3fb_videomemory.size - GPU_FB_START; + memset(ps3fb_videomemory.address, 0, ps3fb_videomemory.size); + xdr_lpar = ps3_mm_phys_to_lpar(__pa(ps3fb_videomemory.address)); retval = ps3fb_xdr_settings(xdr_lpar, &dev->core); if (retval) goto err_free_irq; @@ -1161,15 +1177,22 @@ static int __devinit ps3fb_probe(struct ps3_system_bus_device *dev) par = info->par; par->mode_id = ~ps3fb_mode; /* != ps3fb_mode, to trigger change */ par->new_mode_id = ps3fb_mode; - par->res_index = res_index; par->num_frames = 1; - info->screen_base = (char __iomem *)ps3fb.xdr_ea; info->fbops = &ps3fb_ops; - info->fix = ps3fb_fix; - info->fix.smem_start = virt_to_abs(ps3fb.xdr_ea); - info->fix.smem_len = ps3fb.xdr_size; + + /* + * The GPU command buffer is at the start of video memory + * As we don't use the full command buffer, we can put the actual + * frame buffer at offset GPU_FB_START and save some precious XDR + * memory + */ + fb_start = ps3fb_videomemory.address + GPU_FB_START; + info->screen_base = (char __force __iomem *)fb_start; + info->fix.smem_start = virt_to_abs(fb_start); + info->fix.smem_len = ps3fb_videomemory.size - GPU_FB_START; + info->pseudo_palette = par->pseudo_palette; info->flags = FBINFO_DEFAULT | FBINFO_READS_FAST | FBINFO_HWACCEL_XPAN | FBINFO_HWACCEL_YPAN; @@ -1180,7 +1203,7 @@ static int __devinit ps3fb_probe(struct ps3_system_bus_device *dev) if (!fb_find_mode(&info->var, info, mode_option, ps3fb_modedb, ARRAY_SIZE(ps3fb_modedb), - ps3fb_default_mode(par->new_mode_id), 32)) { + ps3fb_vmode(par->new_mode_id), 32)) { retval = -EINVAL; goto err_fb_dealloc; } @@ -1194,9 +1217,9 @@ static int __devinit ps3fb_probe(struct ps3_system_bus_device *dev) dev->core.driver_data = info; - dev_info(info->device, "%s %s, using %lu KiB of video memory\n", + dev_info(info->device, "%s %s, using %u KiB of video memory\n", dev_driver_string(info->dev), info->dev->bus_id, - ps3fb.xdr_size >> 10); + info->fix.smem_len >> 10); task = kthread_run(ps3fbd, info, DEVICE_NAME); if (IS_ERR(task)) { @@ -1219,7 +1242,7 @@ err_free_irq: free_irq(ps3fb.irq_no, &dev->core); ps3_irq_plug_destroy(ps3fb.irq_no); err_iounmap_dinfo: - iounmap((u8 __iomem *)ps3fb.dinfo); + iounmap((u8 __force __iomem *)ps3fb.dinfo); err_gpu_context_free: lv1_gpu_context_free(ps3fb.context_handle); err_gpu_memory_free: @@ -1254,7 +1277,7 @@ static int ps3fb_shutdown(struct ps3_system_bus_device *dev) framebuffer_release(info); info = dev->core.driver_data = NULL; } - iounmap((u8 __iomem *)ps3fb.dinfo); + iounmap((u8 __force __iomem *)ps3fb.dinfo); status = lv1_gpu_context_free(ps3fb.context_handle); if (status) diff --git a/drivers/video/s3c2410fb.c b/drivers/video/s3c2410fb.c index b3c31d9dc591..71fa6edb5c47 100644 --- a/drivers/video/s3c2410fb.c +++ b/drivers/video/s3c2410fb.c @@ -110,6 +110,11 @@ static int debug = 0; /* useful functions */ +static int is_s3c2412(struct s3c2410fb_info *fbi) +{ + return (fbi->drv_type == DRV_S3C2412); +} + /* s3c2410fb_set_lcdaddr * * initialise lcd controller address pointers @@ -501,7 +506,7 @@ static void schedule_palette_update(struct s3c2410fb_info *fbi, { unsigned long flags; unsigned long irqen; - void __iomem *regs = fbi->io; + void __iomem *irq_base = fbi->irq_base; local_irq_save(flags); @@ -511,9 +516,9 @@ static void schedule_palette_update(struct s3c2410fb_info *fbi, fbi->palette_ready = 1; /* enable IRQ */ - irqen = readl(regs + S3C2410_LCDINTMSK); + irqen = readl(irq_base + S3C24XX_LCDINTMSK); irqen &= ~S3C2410_LCDINT_FRSYNC; - writel(irqen, regs + S3C2410_LCDINTMSK); + writel(irqen, irq_base + S3C24XX_LCDINTMSK); } local_irq_restore(flags); @@ -594,15 +599,17 @@ static int s3c2410fb_setcolreg(unsigned regno, static int s3c2410fb_blank(int blank_mode, struct fb_info *info) { struct s3c2410fb_info *fbi = info->par; - void __iomem *regs = fbi->io; + void __iomem *tpal_reg = fbi->io; dprintk("blank(mode=%d, info=%p)\n", blank_mode, info); + tpal_reg += is_s3c2412(fbi) ? S3C2412_TPAL : S3C2410_TPAL; + if (blank_mode == FB_BLANK_UNBLANK) - writel(0x0, regs + S3C2410_TPAL); + writel(0x0, tpal_reg); else { dprintk("setting TPAL to output 0x000000\n"); - writel(S3C2410_TPAL_EN, regs + S3C2410_TPAL); + writel(S3C2410_TPAL_EN, tpal_reg); } return 0; @@ -663,7 +670,7 @@ static int __init s3c2410fb_map_video_memory(struct fb_info *info) dma_addr_t map_dma; unsigned map_size = PAGE_ALIGN(info->fix.smem_len); - dprintk("map_video_memory(fbi=%p)\n", fbi); + dprintk("map_video_memory(fbi=%p) map_size %u\n", fbi, map_size); info->screen_base = dma_alloc_writecombine(fbi->dev, map_size, &map_dma, GFP_KERNEL); @@ -672,7 +679,7 @@ static int __init s3c2410fb_map_video_memory(struct fb_info *info) /* prevent initial garbage on screen */ dprintk("map_video_memory: clear %p:%08x\n", info->screen_base, map_size); - memset(info->screen_base, 0xf0, map_size); + memset(info->screen_base, 0x00, map_size); info->fix.smem_start = map_dma; @@ -709,6 +716,16 @@ static int s3c2410fb_init_registers(struct fb_info *info) struct s3c2410fb_mach_info *mach_info = fbi->dev->platform_data; unsigned long flags; void __iomem *regs = fbi->io; + void __iomem *tpal; + void __iomem *lpcsel; + + if (is_s3c2412(fbi)) { + tpal = regs + S3C2412_TPAL; + lpcsel = regs + S3C2412_TCONSEL; + } else { + tpal = regs + S3C2410_TPAL; + lpcsel = regs + S3C2410_LPCSEL; + } /* Initialise LCD with values from haret */ @@ -724,12 +741,12 @@ static int s3c2410fb_init_registers(struct fb_info *info) local_irq_restore(flags); dprintk("LPCSEL = 0x%08lx\n", mach_info->lpcsel); - writel(mach_info->lpcsel, regs + S3C2410_LPCSEL); + writel(mach_info->lpcsel, lpcsel); - dprintk("replacing TPAL %08x\n", readl(regs + S3C2410_TPAL)); + dprintk("replacing TPAL %08x\n", readl(tpal)); /* ensure temporary palette disabled */ - writel(0x00, regs + S3C2410_TPAL); + writel(0x00, tpal); return 0; } @@ -763,15 +780,15 @@ static void s3c2410fb_write_palette(struct s3c2410fb_info *fbi) static irqreturn_t s3c2410fb_irq(int irq, void *dev_id) { struct s3c2410fb_info *fbi = dev_id; - void __iomem *regs = fbi->io; - unsigned long lcdirq = readl(regs + S3C2410_LCDINTPND); + void __iomem *irq_base = fbi->irq_base; + unsigned long lcdirq = readl(irq_base + S3C24XX_LCDINTPND); if (lcdirq & S3C2410_LCDINT_FRSYNC) { if (fbi->palette_ready) s3c2410fb_write_palette(fbi); - writel(S3C2410_LCDINT_FRSYNC, regs + S3C2410_LCDINTPND); - writel(S3C2410_LCDINT_FRSYNC, regs + S3C2410_LCDSRCPND); + writel(S3C2410_LCDINT_FRSYNC, irq_base + S3C24XX_LCDINTPND); + writel(S3C2410_LCDINT_FRSYNC, irq_base + S3C24XX_LCDSRCPND); } return IRQ_HANDLED; @@ -779,7 +796,8 @@ static irqreturn_t s3c2410fb_irq(int irq, void *dev_id) static char driver_name[] = "s3c2410fb"; -static int __init s3c2410fb_probe(struct platform_device *pdev) +static int __init s3c24xxfb_probe(struct platform_device *pdev, + enum s3c_drv_type drv_type) { struct s3c2410fb_info *info; struct s3c2410fb_display *display; @@ -799,6 +817,12 @@ static int __init s3c2410fb_probe(struct platform_device *pdev) return -EINVAL; } + if (mach_info->default_display >= mach_info->num_displays) { + dev_err(&pdev->dev, "default is %d but only %d displays\n", + mach_info->default_display, mach_info->num_displays); + return -EINVAL; + } + display = mach_info->displays + mach_info->default_display; irq = platform_get_irq(pdev, 0); @@ -815,6 +839,7 @@ static int __init s3c2410fb_probe(struct platform_device *pdev) info = fbinfo->par; info->dev = &pdev->dev; + info->drv_type = drv_type; res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (res == NULL) { @@ -838,6 +863,8 @@ static int __init s3c2410fb_probe(struct platform_device *pdev) goto release_mem; } + info->irq_base = info->io + ((drv_type == DRV_S3C2412) ? S3C2412_LCDINTBASE : S3C2410_LCDINTBASE); + dprintk("devinit\n"); strcpy(fbinfo->fix.id, driver_name); @@ -946,6 +973,16 @@ dealloc_fb: return ret; } +static int __init s3c2410fb_probe(struct platform_device *pdev) +{ + return s3c24xxfb_probe(pdev, DRV_S3C2410); +} + +static int __init s3c2412fb_probe(struct platform_device *pdev) +{ + return s3c24xxfb_probe(pdev, DRV_S3C2412); +} + /* s3c2410fb_stop_lcd * * shutdown the lcd controller @@ -1047,14 +1084,31 @@ static struct platform_driver s3c2410fb_driver = { }, }; +static struct platform_driver s3c2412fb_driver = { + .probe = s3c2412fb_probe, + .remove = s3c2410fb_remove, + .suspend = s3c2410fb_suspend, + .resume = s3c2410fb_resume, + .driver = { + .name = "s3c2412-lcd", + .owner = THIS_MODULE, + }, +}; + int __init s3c2410fb_init(void) { - return platform_driver_register(&s3c2410fb_driver); + int ret = platform_driver_register(&s3c2410fb_driver); + + if (ret == 0) + ret = platform_driver_register(&s3c2412fb_driver);; + + return ret; } static void __exit s3c2410fb_cleanup(void) { platform_driver_unregister(&s3c2410fb_driver); + platform_driver_unregister(&s3c2412fb_driver); } module_init(s3c2410fb_init); diff --git a/drivers/video/s3c2410fb.h b/drivers/video/s3c2410fb.h index 6ce5dc26c5f7..dbb73b95e2ef 100644 --- a/drivers/video/s3c2410fb.h +++ b/drivers/video/s3c2410fb.h @@ -25,13 +25,20 @@ #ifndef __S3C2410FB_H #define __S3C2410FB_H +enum s3c_drv_type { + DRV_S3C2410, + DRV_S3C2412, +}; + struct s3c2410fb_info { struct device *dev; struct clk *clk; struct resource *mem; void __iomem *io; + void __iomem *irq_base; + enum s3c_drv_type drv_type; struct s3c2410fb_hw regs; unsigned int palette_ready; diff --git a/drivers/video/sis/sis_main.c b/drivers/video/sis/sis_main.c index 93ae747440cb..73803624c131 100644 --- a/drivers/video/sis/sis_main.c +++ b/drivers/video/sis/sis_main.c @@ -427,7 +427,7 @@ sisfb_interpret_edid(struct sisfb_monitor *monitor, u8 *buffer) monitor->feature = buffer[0x18]; - if(!buffer[0x14] & 0x80) { + if(!(buffer[0x14] & 0x80)) { if(!(buffer[0x14] & 0x08)) { printk(KERN_INFO "sisfb: WARNING: Monitor does not support separate syncs\n"); @@ -4621,9 +4621,9 @@ sisfb_find_host_bridge(struct sis_video_info *ivideo, struct pci_dev *mypdev, while((pdev = pci_get_class(PCI_CLASS_BRIDGE_HOST, pdev))) { temp = pdev->vendor; - pci_dev_put(pdev); if(temp == pcivendor) { ret = 1; + pci_dev_put(pdev); break; } } diff --git a/drivers/video/sm501fb.c b/drivers/video/sm501fb.c index 58f200c69be3..e83dfba7e636 100644 --- a/drivers/video/sm501fb.c +++ b/drivers/video/sm501fb.c @@ -641,6 +641,7 @@ static void sm501fb_panel_power(struct sm501fb_info *fbi, int to) { unsigned long control; void __iomem *ctrl_reg = fbi->regs + SM501_DC_PANEL_CONTROL; + struct sm501_platdata_fbsub *pd = fbi->pdata->fb_pnl; control = readl(ctrl_reg); @@ -657,26 +658,34 @@ static void sm501fb_panel_power(struct sm501fb_info *fbi, int to) sm501fb_sync_regs(fbi); mdelay(10); - control |= SM501_DC_PANEL_CONTROL_BIAS; /* VBIASEN */ - writel(control, ctrl_reg); - sm501fb_sync_regs(fbi); - mdelay(10); - - control |= SM501_DC_PANEL_CONTROL_FPEN; - writel(control, ctrl_reg); + if (pd->flags & SM501FB_FLAG_PANEL_USE_VBIASEN) { + control |= SM501_DC_PANEL_CONTROL_BIAS; /* VBIASEN */ + writel(control, ctrl_reg); + sm501fb_sync_regs(fbi); + mdelay(10); + } + if (pd->flags & SM501FB_FLAG_PANEL_USE_FPEN) { + control |= SM501_DC_PANEL_CONTROL_FPEN; + writel(control, ctrl_reg); + sm501fb_sync_regs(fbi); + mdelay(10); + } } else if (!to && (control & SM501_DC_PANEL_CONTROL_VDD) != 0) { /* disable panel power */ + if (pd->flags & SM501FB_FLAG_PANEL_USE_FPEN) { + control &= ~SM501_DC_PANEL_CONTROL_FPEN; + writel(control, ctrl_reg); + sm501fb_sync_regs(fbi); + mdelay(10); + } - control &= ~SM501_DC_PANEL_CONTROL_FPEN; - writel(control, ctrl_reg); - sm501fb_sync_regs(fbi); - mdelay(10); - - control &= ~SM501_DC_PANEL_CONTROL_BIAS; - writel(control, ctrl_reg); - sm501fb_sync_regs(fbi); - mdelay(10); + if (pd->flags & SM501FB_FLAG_PANEL_USE_VBIASEN) { + control &= ~SM501_DC_PANEL_CONTROL_BIAS; + writel(control, ctrl_reg); + sm501fb_sync_regs(fbi); + mdelay(10); + } control &= ~SM501_DC_PANEL_CONTROL_DATA; writel(control, ctrl_reg); @@ -1267,6 +1276,7 @@ static int sm501fb_start(struct sm501fb_info *info, { struct resource *res; struct device *dev; + int k; int ret; info->dev = dev = &pdev->dev; @@ -1328,6 +1338,13 @@ static int sm501fb_start(struct sm501fb_info *info, info->fbmem_len = (res->end - res->start)+1; + /* clear framebuffer memory - avoids garbage data on unused fb */ + memset(info->fbmem, 0, info->fbmem_len); + + /* clear palette ram - undefined at power on */ + for (k = 0; k < (256 * 3); k++) + writel(0, info->regs + SM501_DC_PANEL_PALETTE + (k * 4)); + /* enable display controller */ sm501_unit_power(dev->parent, SM501_GATE_DISPLAY, 1); @@ -1681,6 +1698,15 @@ static int sm501fb_suspend_fb(struct sm501fb_info *info, if (par->screen.size == 0) return 0; + /* blank the relevant interface to ensure unit power minimised */ + (par->ops.fb_blank)(FB_BLANK_POWERDOWN, fbi); + + /* tell console/fb driver we are suspending */ + + acquire_console_sem(); + fb_set_suspend(fbi, 1); + release_console_sem(); + /* backup copies in case chip is powered down over suspend */ par->store_fb = vmalloc(par->screen.size); @@ -1700,12 +1726,6 @@ static int sm501fb_suspend_fb(struct sm501fb_info *info, memcpy_fromio(par->store_fb, par->screen.k_addr, par->screen.size); memcpy_fromio(par->store_cursor, par->cursor.k_addr, par->cursor.size); - /* blank the relevant interface to ensure unit power minimised */ - (par->ops.fb_blank)(FB_BLANK_POWERDOWN, fbi); - - acquire_console_sem(); - fb_set_suspend(fbi, 1); - release_console_sem(); return 0; diff --git a/drivers/video/tdfxfb.c b/drivers/video/tdfxfb.c index 057bdd593800..71e179ea5f95 100644 --- a/drivers/video/tdfxfb.c +++ b/drivers/video/tdfxfb.c @@ -1342,7 +1342,7 @@ out_err: } #ifndef MODULE -static void tdfxfb_setup(char *options) +static void __init tdfxfb_setup(char *options) { char *this_opt; diff --git a/drivers/video/uvesafb.c b/drivers/video/uvesafb.c index a14ef894d571..be27b9c1ed72 100644 --- a/drivers/video/uvesafb.c +++ b/drivers/video/uvesafb.c @@ -2003,12 +2003,12 @@ static void __devexit uvesafb_exit(void) module_exit(uvesafb_exit); -static inline int param_get_scroll(char *buffer, struct kernel_param *kp) +static int param_get_scroll(char *buffer, struct kernel_param *kp) { return 0; } -static inline int param_set_scroll(const char *val, struct kernel_param *kp) +static int param_set_scroll(const char *val, struct kernel_param *kp) { ypan = 0; @@ -2022,11 +2022,11 @@ static inline int param_set_scroll(const char *val, struct kernel_param *kp) return 0; } -#define param_check_scroll(name, p) __param_check(name, p, void); +#define param_check_scroll(name, p) __param_check(name, p, void) module_param_named(scroll, ypan, scroll, 0); MODULE_PARM_DESC(scroll, - "Scrolling mode, set to 'redraw', ''ypan' or 'ywrap'"); + "Scrolling mode, set to 'redraw', 'ypan', or 'ywrap'"); module_param_named(vgapal, pmi_setpal, invbool, 0); MODULE_PARM_DESC(vgapal, "Set palette using VGA registers"); module_param_named(pmipal, pmi_setpal, bool, 0); diff --git a/drivers/video/vermilion/vermilion.c b/drivers/video/vermilion/vermilion.c index 1c656667b937..2aa71eb67c2b 100644 --- a/drivers/video/vermilion/vermilion.c +++ b/drivers/video/vermilion/vermilion.c @@ -651,7 +651,7 @@ static int vmlfb_check_var_locked(struct fb_var_screeninfo *var, return -EINVAL; } - pitch = __ALIGN_MASK((var->xres * var->bits_per_pixel) >> 3, 0x3F); + pitch = ALIGN((var->xres * var->bits_per_pixel) >> 3, 0x40); mem = pitch * var->yres_virtual; if (mem > vinfo->vram_contig_size) { return -ENOMEM; @@ -785,8 +785,7 @@ static int vmlfb_set_par_locked(struct vml_info *vinfo) int clock; vinfo->bytes_per_pixel = var->bits_per_pixel >> 3; - vinfo->stride = - __ALIGN_MASK(var->xres_virtual * vinfo->bytes_per_pixel, 0x3F); + vinfo->stride = ALIGN(var->xres_virtual * vinfo->bytes_per_pixel, 0x40); info->fix.line_length = vinfo->stride; if (!subsys) diff --git a/drivers/virtio/virtio_balloon.c b/drivers/virtio/virtio_balloon.c index 622aece1acce..c8a4332d1132 100644 --- a/drivers/virtio/virtio_balloon.c +++ b/drivers/virtio/virtio_balloon.c @@ -23,6 +23,7 @@ #include <linux/swap.h> #include <linux/kthread.h> #include <linux/freezer.h> +#include <linux/delay.h> struct virtio_balloon { diff --git a/drivers/w1/masters/Kconfig b/drivers/w1/masters/Kconfig index 8236d447adf5..c4493091c655 100644 --- a/drivers/w1/masters/Kconfig +++ b/drivers/w1/masters/Kconfig @@ -42,5 +42,15 @@ config W1_MASTER_DS1WM in HP iPAQ devices like h5xxx, h2200, and ASIC3-based like hx4700. +config W1_MASTER_GPIO + tristate "GPIO 1-wire busmaster" + depends on GENERIC_GPIO + help + Say Y here if you want to communicate with your 1-wire devices using + GPIO pins. This driver uses the GPIO API to control the wire. + + This support is also available as a module. If so, the module + will be called w1-gpio.ko. + endmenu diff --git a/drivers/w1/masters/Makefile b/drivers/w1/masters/Makefile index 11551b328186..1420b5bbdda8 100644 --- a/drivers/w1/masters/Makefile +++ b/drivers/w1/masters/Makefile @@ -6,3 +6,4 @@ obj-$(CONFIG_W1_MASTER_MATROX) += matrox_w1.o obj-$(CONFIG_W1_MASTER_DS2490) += ds2490.o obj-$(CONFIG_W1_MASTER_DS2482) += ds2482.o obj-$(CONFIG_W1_MASTER_DS1WM) += ds1wm.o +obj-$(CONFIG_W1_MASTER_GPIO) += w1-gpio.o diff --git a/drivers/w1/masters/w1-gpio.c b/drivers/w1/masters/w1-gpio.c new file mode 100644 index 000000000000..9e1138a75e8b --- /dev/null +++ b/drivers/w1/masters/w1-gpio.c @@ -0,0 +1,124 @@ +/* + * w1-gpio - GPIO w1 bus master driver + * + * Copyright (C) 2007 Ville Syrjala <syrjala@sci.fi> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation. + */ + +#include <linux/init.h> +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/w1-gpio.h> + +#include "../w1.h" +#include "../w1_int.h" + +#include <asm/gpio.h> + +static void w1_gpio_write_bit_dir(void *data, u8 bit) +{ + struct w1_gpio_platform_data *pdata = data; + + if (bit) + gpio_direction_input(pdata->pin); + else + gpio_direction_output(pdata->pin, 0); +} + +static void w1_gpio_write_bit_val(void *data, u8 bit) +{ + struct w1_gpio_platform_data *pdata = data; + + gpio_set_value(pdata->pin, bit); +} + +static u8 w1_gpio_read_bit(void *data) +{ + struct w1_gpio_platform_data *pdata = data; + + return gpio_get_value(pdata->pin); +} + +static int __init w1_gpio_probe(struct platform_device *pdev) +{ + struct w1_bus_master *master; + struct w1_gpio_platform_data *pdata = pdev->dev.platform_data; + int err; + + if (!pdata) + return -ENXIO; + + master = kzalloc(sizeof(struct w1_bus_master), GFP_KERNEL); + if (!master) + return -ENOMEM; + + err = gpio_request(pdata->pin, "w1"); + if (err) + goto free_master; + + master->data = pdata; + master->read_bit = w1_gpio_read_bit; + + if (pdata->is_open_drain) { + gpio_direction_output(pdata->pin, 1); + master->write_bit = w1_gpio_write_bit_val; + } else { + gpio_direction_input(pdata->pin); + master->write_bit = w1_gpio_write_bit_dir; + } + + err = w1_add_master_device(master); + if (err) + goto free_gpio; + + platform_set_drvdata(pdev, master); + + return 0; + + free_gpio: + gpio_free(pdata->pin); + free_master: + kfree(master); + + return err; +} + +static int __exit w1_gpio_remove(struct platform_device *pdev) +{ + struct w1_bus_master *master = platform_get_drvdata(pdev); + struct w1_gpio_platform_data *pdata = pdev->dev.platform_data; + + w1_remove_master_device(master); + gpio_free(pdata->pin); + kfree(master); + + return 0; +} + +static struct platform_driver w1_gpio_driver = { + .driver = { + .name = "w1-gpio", + .owner = THIS_MODULE, + }, + .remove = __exit_p(w1_gpio_remove), +}; + +static int __init w1_gpio_init(void) +{ + return platform_driver_probe(&w1_gpio_driver, w1_gpio_probe); +} + +static void __exit w1_gpio_exit(void) +{ + platform_driver_unregister(&w1_gpio_driver); +} + +module_init(w1_gpio_init); +module_exit(w1_gpio_exit); + +MODULE_DESCRIPTION("GPIO w1 bus master driver"); +MODULE_AUTHOR("Ville Syrjala <syrjala@sci.fi>"); +MODULE_LICENSE("GPL"); diff --git a/drivers/w1/slaves/w1_therm.c b/drivers/w1/slaves/w1_therm.c index 112f4ec59035..fb28acaeed6c 100644 --- a/drivers/w1/slaves/w1_therm.c +++ b/drivers/w1/slaves/w1_therm.c @@ -92,6 +92,7 @@ struct w1_therm_family_converter int (*convert)(u8 rom[9]); }; +/* The return value is millidegrees Centigrade. */ static inline int w1_DS18B20_convert_temp(u8 rom[9]); static inline int w1_DS18S20_convert_temp(u8 rom[9]); @@ -113,7 +114,7 @@ static struct w1_therm_family_converter w1_therm_families[] = { static inline int w1_DS18B20_convert_temp(u8 rom[9]) { s16 t = (rom[1] << 8) | rom[0]; - t /= 16; + t = t*1000/16; return t; } diff --git a/drivers/w1/w1.c b/drivers/w1/w1.c index 33e50310e9e0..7293c9b11f91 100644 --- a/drivers/w1/w1.c +++ b/drivers/w1/w1.c @@ -675,7 +675,6 @@ static void w1_slave_found(void *data, u64 rn) struct w1_slave *sl; struct list_head *ent; struct w1_reg_num *tmp; - int family_found = 0; struct w1_master *dev; u64 rn_le = cpu_to_le64(rn); @@ -698,9 +697,6 @@ static void w1_slave_found(void *data, u64 rn) sl->reg_num.crc == tmp->crc) { set_bit(W1_SLAVE_ACTIVE, (long *)&sl->flags); break; - } else if (sl->reg_num.family == tmp->family) { - family_found = 1; - break; } slave_count++; diff --git a/fs/Kconfig b/fs/Kconfig index 987b5d7cb21a..ea5b35947623 100644 --- a/fs/Kconfig +++ b/fs/Kconfig @@ -1152,7 +1152,7 @@ config BEFS_DEBUG depends on BEFS_FS help If you say Y here, you can use the 'debug' mount option to enable - debugging output from the driver. + debugging output from the driver. config BFS_FS tristate "BFS file system support (EXPERIMENTAL)" @@ -1263,7 +1263,7 @@ config JFFS2_FS_XATTR Extended attributes are name:value pairs associated with inodes by the kernel or by users (see the attr(5) manual page, or visit <http://acl.bestbits.at/> for details). - + If unsure, say N. config JFFS2_FS_POSIX_ACL @@ -1274,10 +1274,10 @@ config JFFS2_FS_POSIX_ACL help Posix Access Control Lists (ACLs) support permissions for users and groups beyond the owner/group/world scheme. - + To learn more about Access Control Lists, visit the Posix ACLs for Linux website <http://acl.bestbits.at/>. - + If you don't know what Access Control Lists are, say N config JFFS2_FS_SECURITY @@ -1289,7 +1289,7 @@ config JFFS2_FS_SECURITY implemented by security modules like SELinux. This option enables an extended attribute handler for file security labels in the jffs2 filesystem. - + If you are not using a security module that requires using extended attributes for file security labels, say N. @@ -1835,7 +1835,7 @@ config RPCSEC_GSS_SPKM3 If unsure, say N. config SMB_FS - tristate "SMB file system support (to mount Windows shares etc.)" + tristate "SMB file system support (OBSOLETE, please use CIFS)" depends on INET select NLS help @@ -1858,8 +1858,8 @@ config SMB_FS General information about how to connect Linux, Windows machines and Macs is on the WWW at <http://www.eats.com/linux_mac_win.html>. - To compile the SMB support as a module, choose M here: the module will - be called smbfs. Most people say N, however. + To compile the SMB support as a module, choose M here: + the module will be called smbfs. Most people say N, however. config SMB_NLS_DEFAULT bool "Use a default NLS" @@ -1891,7 +1891,7 @@ config SMB_NLS_REMOTE smbmount from samba 2.2.0 or later supports this. config CIFS - tristate "CIFS support (advanced network filesystem for Samba, Window and other CIFS compliant servers)" + tristate "CIFS support (advanced network filesystem, SMBFS successor)" depends on INET select NLS help @@ -1949,16 +1949,16 @@ config CIFS_WEAK_PW_HASH LANMAN based servers such as OS/2 and Windows 95, but such mounts may be less secure than mounts using NTLM or more recent security mechanisms if you are on a public network. Unless you - have a need to access old SMB servers (and are on a private + have a need to access old SMB servers (and are on a private network) you probably want to say N. Even if this support is enabled in the kernel build, LANMAN authentication will not be used automatically. At runtime LANMAN mounts are disabled but can be set to required (or optional) either in /proc/fs/cifs (see fs/cifs/README for more detail) or via an - option on the mount command. This support is disabled by + option on the mount command. This support is disabled by default in order to reduce the possibility of a downgrade attack. - + If unsure, say N. config CIFS_XATTR @@ -1999,7 +1999,7 @@ config CIFS_DEBUG2 messages in some error paths, slowing performance. This option can be turned off unless you are debugging cifs problems. If unsure, say N. - + config CIFS_EXPERIMENTAL bool "CIFS Experimental Features (EXPERIMENTAL)" depends on CIFS && EXPERIMENTAL @@ -2090,7 +2090,7 @@ config CODA_FS_OLD_API However this new API is not backward compatible with older clients. If you really need to run the old Coda userspace cache manager then say Y. - + For most cases you probably want to say N. config AFS_FS diff --git a/fs/block_dev.c b/fs/block_dev.c index e48a630ae266..e63067d25cdb 100644 --- a/fs/block_dev.c +++ b/fs/block_dev.c @@ -534,7 +534,6 @@ void __init bdev_cache_init(void) if (err) panic("Cannot register bdev pseudo-fs"); bd_mnt = kern_mount(&bd_type); - err = PTR_ERR(bd_mnt); if (IS_ERR(bd_mnt)) panic("Cannot create bdev pseudo-fs"); blockdev_superblock = bd_mnt->mnt_sb; /* For writeback */ diff --git a/fs/compat.c b/fs/compat.c index 69baca5ad608..ee80ff341d37 100644 --- a/fs/compat.c +++ b/fs/compat.c @@ -2083,51 +2083,6 @@ long asmlinkage compat_sys_nfsservctl(int cmd, void *notused, void *notused2) #ifdef CONFIG_EPOLL -#ifdef CONFIG_HAS_COMPAT_EPOLL_EVENT -asmlinkage long compat_sys_epoll_ctl(int epfd, int op, int fd, - struct compat_epoll_event __user *event) -{ - long err = 0; - struct compat_epoll_event user; - struct epoll_event __user *kernel = NULL; - - if (event) { - if (copy_from_user(&user, event, sizeof(user))) - return -EFAULT; - kernel = compat_alloc_user_space(sizeof(struct epoll_event)); - err |= __put_user(user.events, &kernel->events); - err |= __put_user(user.data, &kernel->data); - } - - return err ? err : sys_epoll_ctl(epfd, op, fd, kernel); -} - - -asmlinkage long compat_sys_epoll_wait(int epfd, - struct compat_epoll_event __user *events, - int maxevents, int timeout) -{ - long i, ret, err = 0; - struct epoll_event __user *kbuf; - struct epoll_event ev; - - if ((maxevents <= 0) || - (maxevents > (INT_MAX / sizeof(struct epoll_event)))) - return -EINVAL; - kbuf = compat_alloc_user_space(sizeof(struct epoll_event) * maxevents); - ret = sys_epoll_wait(epfd, kbuf, maxevents, timeout); - for (i = 0; i < ret; i++) { - err |= __get_user(ev.events, &kbuf[i].events); - err |= __get_user(ev.data, &kbuf[i].data); - err |= __put_user(ev.events, &events->events); - err |= __put_user_unaligned(ev.data, &events->data); - events++; - } - - return err ? -EFAULT: ret; -} -#endif /* CONFIG_HAS_COMPAT_EPOLL_EVENT */ - #ifdef TIF_RESTORE_SIGMASK asmlinkage long compat_sys_epoll_pwait(int epfd, struct compat_epoll_event __user *events, @@ -2153,11 +2108,7 @@ asmlinkage long compat_sys_epoll_pwait(int epfd, sigprocmask(SIG_SETMASK, &ksigmask, &sigsaved); } -#ifdef CONFIG_HAS_COMPAT_EPOLL_EVENT - err = compat_sys_epoll_wait(epfd, events, maxevents, timeout); -#else err = sys_epoll_wait(epfd, events, maxevents, timeout); -#endif /* * If we changed the signal mask, we need to restore the original one. diff --git a/fs/dcache.c b/fs/dcache.c index d9ca1e5ceb92..44f6cf23b70e 100644 --- a/fs/dcache.c +++ b/fs/dcache.c @@ -89,7 +89,7 @@ static void d_free(struct dentry *dentry) if (dentry->d_op && dentry->d_op->d_release) dentry->d_op->d_release(dentry); /* if dentry was never inserted into hash, immediate free is OK */ - if (dentry->d_hash.pprev == NULL) + if (hlist_unhashed(&dentry->d_hash)) __d_free(dentry); else call_rcu(&dentry->d_u.d_rcu, d_callback); @@ -1408,9 +1408,6 @@ void d_delete(struct dentry * dentry) if (atomic_read(&dentry->d_count) == 1) { dentry_iput(dentry); fsnotify_nameremove(dentry, isdir); - - /* remove this and other inotify debug checks after 2.6.18 */ - dentry->d_flags &= ~DCACHE_INOTIFY_PARENT_WATCHED; return; } diff --git a/fs/dquot.c b/fs/dquot.c index cee7c6f428f0..def4e969df77 100644 --- a/fs/dquot.c +++ b/fs/dquot.c @@ -696,9 +696,8 @@ static int dqinit_needed(struct inode *inode, int type) /* This routine is guarded by dqonoff_mutex mutex */ static void add_dquot_ref(struct super_block *sb, int type) { - struct inode *inode; + struct inode *inode, *old_inode = NULL; -restart: spin_lock(&inode_lock); list_for_each_entry(inode, &sb->s_inodes, i_sb_list) { if (!atomic_read(&inode->i_writecount)) @@ -711,12 +710,18 @@ restart: __iget(inode); spin_unlock(&inode_lock); + iput(old_inode); sb->dq_op->initialize(inode, type); - iput(inode); - /* As we may have blocked we had better restart... */ - goto restart; + /* We hold a reference to 'inode' so it couldn't have been + * removed from s_inodes list while we dropped the inode_lock. + * We cannot iput the inode now as we can be holding the last + * reference and we cannot iput it under inode_lock. So we + * keep the reference and iput it later. */ + old_inode = inode; + spin_lock(&inode_lock); } spin_unlock(&inode_lock); + iput(old_inode); } /* Return 0 if dqput() won't block (note that 1 doesn't necessarily mean blocking) */ diff --git a/fs/ecryptfs/crypto.c b/fs/ecryptfs/crypto.c index f8ef0af919e7..a066e109ad9c 100644 --- a/fs/ecryptfs/crypto.c +++ b/fs/ecryptfs/crypto.c @@ -355,8 +355,11 @@ static int encrypt_scatterlist(struct ecryptfs_crypt_stat *crypt_stat, } /* Consider doing this once, when the file is opened */ mutex_lock(&crypt_stat->cs_tfm_mutex); - rc = crypto_blkcipher_setkey(crypt_stat->tfm, crypt_stat->key, - crypt_stat->key_size); + if (!(crypt_stat->flags & ECRYPTFS_KEY_SET)) { + rc = crypto_blkcipher_setkey(crypt_stat->tfm, crypt_stat->key, + crypt_stat->key_size); + crypt_stat->flags |= ECRYPTFS_KEY_SET; + } if (rc) { ecryptfs_printk(KERN_ERR, "Error setting key; rc = [%d]\n", rc); @@ -376,11 +379,10 @@ out: * * Convert an eCryptfs page index into a lower byte offset */ -void ecryptfs_lower_offset_for_extent(loff_t *offset, loff_t extent_num, - struct ecryptfs_crypt_stat *crypt_stat) +static void ecryptfs_lower_offset_for_extent(loff_t *offset, loff_t extent_num, + struct ecryptfs_crypt_stat *crypt_stat) { - (*offset) = ((crypt_stat->extent_size - * crypt_stat->num_header_extents_at_front) + (*offset) = (crypt_stat->num_header_bytes_at_front + (crypt_stat->extent_size * extent_num)); } @@ -842,15 +844,13 @@ void ecryptfs_set_default_sizes(struct ecryptfs_crypt_stat *crypt_stat) set_extent_mask_and_shift(crypt_stat); crypt_stat->iv_bytes = ECRYPTFS_DEFAULT_IV_BYTES; if (crypt_stat->flags & ECRYPTFS_METADATA_IN_XATTR) - crypt_stat->num_header_extents_at_front = 0; + crypt_stat->num_header_bytes_at_front = 0; else { if (PAGE_CACHE_SIZE <= ECRYPTFS_MINIMUM_HEADER_EXTENT_SIZE) - crypt_stat->num_header_extents_at_front = - (ECRYPTFS_MINIMUM_HEADER_EXTENT_SIZE - / crypt_stat->extent_size); + crypt_stat->num_header_bytes_at_front = + ECRYPTFS_MINIMUM_HEADER_EXTENT_SIZE; else - crypt_stat->num_header_extents_at_front = - (PAGE_CACHE_SIZE / crypt_stat->extent_size); + crypt_stat->num_header_bytes_at_front = PAGE_CACHE_SIZE; } } @@ -1128,7 +1128,7 @@ write_ecryptfs_flags(char *page_virt, struct ecryptfs_crypt_stat *crypt_stat, struct ecryptfs_cipher_code_str_map_elem { char cipher_str[16]; - u16 cipher_code; + u8 cipher_code; }; /* Add support for additional ciphers by adding elements here. The @@ -1152,10 +1152,10 @@ ecryptfs_cipher_code_str_map[] = { * * Returns zero on no match, or the cipher code on match */ -u16 ecryptfs_code_for_cipher_string(struct ecryptfs_crypt_stat *crypt_stat) +u8 ecryptfs_code_for_cipher_string(struct ecryptfs_crypt_stat *crypt_stat) { int i; - u16 code = 0; + u8 code = 0; struct ecryptfs_cipher_code_str_map_elem *map = ecryptfs_cipher_code_str_map; @@ -1187,7 +1187,7 @@ u16 ecryptfs_code_for_cipher_string(struct ecryptfs_crypt_stat *crypt_stat) * * Returns zero on success */ -int ecryptfs_cipher_code_to_string(char *str, u16 cipher_code) +int ecryptfs_cipher_code_to_string(char *str, u8 cipher_code) { int rc = 0; int i; @@ -1236,7 +1236,8 @@ ecryptfs_write_header_metadata(char *virt, header_extent_size = (u32)crypt_stat->extent_size; num_header_extents_at_front = - (u16)crypt_stat->num_header_extents_at_front; + (u16)(crypt_stat->num_header_bytes_at_front + / crypt_stat->extent_size); header_extent_size = cpu_to_be32(header_extent_size); memcpy(virt, &header_extent_size, 4); virt += 4; @@ -1311,40 +1312,16 @@ static int ecryptfs_write_headers_virt(char *page_virt, size_t *size, static int ecryptfs_write_metadata_to_contents(struct ecryptfs_crypt_stat *crypt_stat, struct dentry *ecryptfs_dentry, - char *page_virt) + char *virt) { - int current_header_page; - int header_pages; int rc; - rc = ecryptfs_write_lower(ecryptfs_dentry->d_inode, page_virt, - 0, PAGE_CACHE_SIZE); - if (rc) { + rc = ecryptfs_write_lower(ecryptfs_dentry->d_inode, virt, + 0, crypt_stat->num_header_bytes_at_front); + if (rc) printk(KERN_ERR "%s: Error attempting to write header " "information to lower file; rc = [%d]\n", __FUNCTION__, rc); - goto out; - } - header_pages = ((crypt_stat->extent_size - * crypt_stat->num_header_extents_at_front) - / PAGE_CACHE_SIZE); - memset(page_virt, 0, PAGE_CACHE_SIZE); - current_header_page = 1; - while (current_header_page < header_pages) { - loff_t offset; - - offset = (((loff_t)current_header_page) << PAGE_CACHE_SHIFT); - if ((rc = ecryptfs_write_lower(ecryptfs_dentry->d_inode, - page_virt, offset, - PAGE_CACHE_SIZE))) { - printk(KERN_ERR "%s: Error attempting to write header " - "information to lower file; rc = [%d]\n", - __FUNCTION__, rc); - goto out; - } - current_header_page++; - } -out: return rc; } @@ -1370,15 +1347,13 @@ ecryptfs_write_metadata_to_xattr(struct dentry *ecryptfs_dentry, * retrieved via a prompt. Exactly what happens at this point should * be policy-dependent. * - * TODO: Support header information spanning multiple pages - * * Returns zero on success; non-zero on error */ int ecryptfs_write_metadata(struct dentry *ecryptfs_dentry) { struct ecryptfs_crypt_stat *crypt_stat = &ecryptfs_inode_to_private(ecryptfs_dentry->d_inode)->crypt_stat; - char *page_virt; + char *virt; size_t size = 0; int rc = 0; @@ -1389,40 +1364,39 @@ int ecryptfs_write_metadata(struct dentry *ecryptfs_dentry) goto out; } } else { + printk(KERN_WARNING "%s: Encrypted flag not set\n", + __FUNCTION__); rc = -EINVAL; - ecryptfs_printk(KERN_WARNING, - "Called with crypt_stat->encrypted == 0\n"); goto out; } /* Released in this function */ - page_virt = kmem_cache_zalloc(ecryptfs_header_cache_0, GFP_USER); - if (!page_virt) { - ecryptfs_printk(KERN_ERR, "Out of memory\n"); + virt = kzalloc(crypt_stat->num_header_bytes_at_front, GFP_KERNEL); + if (!virt) { + printk(KERN_ERR "%s: Out of memory\n", __FUNCTION__); rc = -ENOMEM; goto out; } - rc = ecryptfs_write_headers_virt(page_virt, &size, crypt_stat, - ecryptfs_dentry); + rc = ecryptfs_write_headers_virt(virt, &size, crypt_stat, + ecryptfs_dentry); if (unlikely(rc)) { - ecryptfs_printk(KERN_ERR, "Error whilst writing headers\n"); - memset(page_virt, 0, PAGE_CACHE_SIZE); + printk(KERN_ERR "%s: Error whilst writing headers; rc = [%d]\n", + __FUNCTION__, rc); goto out_free; } if (crypt_stat->flags & ECRYPTFS_METADATA_IN_XATTR) rc = ecryptfs_write_metadata_to_xattr(ecryptfs_dentry, - crypt_stat, page_virt, - size); + crypt_stat, virt, size); else rc = ecryptfs_write_metadata_to_contents(crypt_stat, - ecryptfs_dentry, - page_virt); + ecryptfs_dentry, virt); if (rc) { - printk(KERN_ERR "Error writing metadata out to lower file; " - "rc = [%d]\n", rc); + printk(KERN_ERR "%s: Error writing metadata out to lower file; " + "rc = [%d]\n", __FUNCTION__, rc); goto out_free; } out_free: - kmem_cache_free(ecryptfs_header_cache_0, page_virt); + memset(virt, 0, crypt_stat->num_header_bytes_at_front); + kfree(virt); out: return rc; } @@ -1442,16 +1416,16 @@ static int parse_header_metadata(struct ecryptfs_crypt_stat *crypt_stat, virt += sizeof(u32); memcpy(&num_header_extents_at_front, virt, sizeof(u16)); num_header_extents_at_front = be16_to_cpu(num_header_extents_at_front); - crypt_stat->num_header_extents_at_front = - (int)num_header_extents_at_front; + crypt_stat->num_header_bytes_at_front = + (((size_t)num_header_extents_at_front + * (size_t)header_extent_size)); (*bytes_read) = (sizeof(u32) + sizeof(u16)); if ((validate_header_size == ECRYPTFS_VALIDATE_HEADER_SIZE) - && ((crypt_stat->extent_size - * crypt_stat->num_header_extents_at_front) + && (crypt_stat->num_header_bytes_at_front < ECRYPTFS_MINIMUM_HEADER_EXTENT_SIZE)) { rc = -EINVAL; - printk(KERN_WARNING "Invalid number of header extents: [%zd]\n", - crypt_stat->num_header_extents_at_front); + printk(KERN_WARNING "Invalid header size: [%zd]\n", + crypt_stat->num_header_bytes_at_front); } return rc; } @@ -1466,7 +1440,8 @@ static int parse_header_metadata(struct ecryptfs_crypt_stat *crypt_stat, */ static void set_default_header_data(struct ecryptfs_crypt_stat *crypt_stat) { - crypt_stat->num_header_extents_at_front = 2; + crypt_stat->num_header_bytes_at_front = + ECRYPTFS_MINIMUM_HEADER_EXTENT_SIZE; } /** @@ -1552,9 +1527,10 @@ int ecryptfs_read_xattr_region(char *page_virt, struct inode *ecryptfs_inode) size = ecryptfs_getxattr_lower(lower_dentry, ECRYPTFS_XATTR_NAME, page_virt, ECRYPTFS_DEFAULT_EXTENT_SIZE); if (size < 0) { - printk(KERN_ERR "Error attempting to read the [%s] " - "xattr from the lower file; return value = [%zd]\n", - ECRYPTFS_XATTR_NAME, size); + if (unlikely(ecryptfs_verbosity > 0)) + printk(KERN_INFO "Error attempting to read the [%s] " + "xattr from the lower file; return value = " + "[%zd]\n", ECRYPTFS_XATTR_NAME, size); rc = -EINVAL; goto out; } @@ -1802,7 +1778,7 @@ out: } struct kmem_cache *ecryptfs_key_tfm_cache; -struct list_head key_tfm_list; +static struct list_head key_tfm_list; struct mutex key_tfm_list_mutex; int ecryptfs_init_crypto(void) @@ -1812,6 +1788,11 @@ int ecryptfs_init_crypto(void) return 0; } +/** + * ecryptfs_destroy_crypto - free all cached key_tfms on key_tfm_list + * + * Called only at module unload time + */ int ecryptfs_destroy_crypto(void) { struct ecryptfs_key_tfm *key_tfm, *key_tfm_tmp; @@ -1835,6 +1816,8 @@ ecryptfs_add_new_key_tfm(struct ecryptfs_key_tfm **key_tfm, char *cipher_name, struct ecryptfs_key_tfm *tmp_tfm; int rc = 0; + BUG_ON(!mutex_is_locked(&key_tfm_list_mutex)); + tmp_tfm = kmem_cache_alloc(ecryptfs_key_tfm_cache, GFP_KERNEL); if (key_tfm != NULL) (*key_tfm) = tmp_tfm; @@ -1861,13 +1844,50 @@ ecryptfs_add_new_key_tfm(struct ecryptfs_key_tfm **key_tfm, char *cipher_name, (*key_tfm) = NULL; goto out; } - mutex_lock(&key_tfm_list_mutex); list_add(&tmp_tfm->key_tfm_list, &key_tfm_list); - mutex_unlock(&key_tfm_list_mutex); out: return rc; } +/** + * ecryptfs_tfm_exists - Search for existing tfm for cipher_name. + * @cipher_name: the name of the cipher to search for + * @key_tfm: set to corresponding tfm if found + * + * Searches for cached key_tfm matching @cipher_name + * Must be called with &key_tfm_list_mutex held + * Returns 1 if found, with @key_tfm set + * Returns 0 if not found, with @key_tfm set to NULL + */ +int ecryptfs_tfm_exists(char *cipher_name, struct ecryptfs_key_tfm **key_tfm) +{ + struct ecryptfs_key_tfm *tmp_key_tfm; + + BUG_ON(!mutex_is_locked(&key_tfm_list_mutex)); + + list_for_each_entry(tmp_key_tfm, &key_tfm_list, key_tfm_list) { + if (strcmp(tmp_key_tfm->cipher_name, cipher_name) == 0) { + if (key_tfm) + (*key_tfm) = tmp_key_tfm; + return 1; + } + } + if (key_tfm) + (*key_tfm) = NULL; + return 0; +} + +/** + * ecryptfs_get_tfm_and_mutex_for_cipher_name + * + * @tfm: set to cached tfm found, or new tfm created + * @tfm_mutex: set to mutex for cached tfm found, or new tfm created + * @cipher_name: the name of the cipher to search for and/or add + * + * Sets pointers to @tfm & @tfm_mutex matching @cipher_name. + * Searches for cached item first, and creates new if not found. + * Returns 0 on success, non-zero if adding new cipher failed + */ int ecryptfs_get_tfm_and_mutex_for_cipher_name(struct crypto_blkcipher **tfm, struct mutex **tfm_mutex, char *cipher_name) @@ -1877,22 +1897,17 @@ int ecryptfs_get_tfm_and_mutex_for_cipher_name(struct crypto_blkcipher **tfm, (*tfm) = NULL; (*tfm_mutex) = NULL; + mutex_lock(&key_tfm_list_mutex); - list_for_each_entry(key_tfm, &key_tfm_list, key_tfm_list) { - if (strcmp(key_tfm->cipher_name, cipher_name) == 0) { - (*tfm) = key_tfm->key_tfm; - (*tfm_mutex) = &key_tfm->key_tfm_mutex; - mutex_unlock(&key_tfm_list_mutex); + if (!ecryptfs_tfm_exists(cipher_name, &key_tfm)) { + rc = ecryptfs_add_new_key_tfm(&key_tfm, cipher_name, 0); + if (rc) { + printk(KERN_ERR "Error adding new key_tfm to list; " + "rc = [%d]\n", rc); goto out; } } mutex_unlock(&key_tfm_list_mutex); - rc = ecryptfs_add_new_key_tfm(&key_tfm, cipher_name, 0); - if (rc) { - printk(KERN_ERR "Error adding new key_tfm to list; rc = [%d]\n", - rc); - goto out; - } (*tfm) = key_tfm->key_tfm; (*tfm_mutex) = &key_tfm->key_tfm_mutex; out: diff --git a/fs/ecryptfs/ecryptfs_kernel.h b/fs/ecryptfs/ecryptfs_kernel.h index ce7a5d4aec36..5007f788da01 100644 --- a/fs/ecryptfs/ecryptfs_kernel.h +++ b/fs/ecryptfs/ecryptfs_kernel.h @@ -234,10 +234,11 @@ struct ecryptfs_crypt_stat { #define ECRYPTFS_KEY_VALID 0x00000080 #define ECRYPTFS_METADATA_IN_XATTR 0x00000100 #define ECRYPTFS_VIEW_AS_ENCRYPTED 0x00000200 +#define ECRYPTFS_KEY_SET 0x00000400 u32 flags; unsigned int file_version; size_t iv_bytes; - size_t num_header_extents_at_front; + size_t num_header_bytes_at_front; size_t extent_size; /* Data extent size; default is 4096 */ size_t key_size; size_t extent_shift; @@ -322,7 +323,6 @@ struct ecryptfs_key_tfm { unsigned char cipher_name[ECRYPTFS_MAX_CIPHER_NAME_SIZE + 1]; }; -extern struct list_head key_tfm_list; extern struct mutex key_tfm_list_mutex; /** @@ -521,11 +521,9 @@ extern struct kmem_cache *ecryptfs_file_info_cache; extern struct kmem_cache *ecryptfs_dentry_info_cache; extern struct kmem_cache *ecryptfs_inode_info_cache; extern struct kmem_cache *ecryptfs_sb_info_cache; -extern struct kmem_cache *ecryptfs_header_cache_0; extern struct kmem_cache *ecryptfs_header_cache_1; extern struct kmem_cache *ecryptfs_header_cache_2; extern struct kmem_cache *ecryptfs_xattr_cache; -extern struct kmem_cache *ecryptfs_lower_page_cache; extern struct kmem_cache *ecryptfs_key_record_cache; extern struct kmem_cache *ecryptfs_key_sig_cache; extern struct kmem_cache *ecryptfs_global_auth_tok_cache; @@ -562,8 +560,8 @@ int ecryptfs_read_and_validate_header_region(char *data, struct inode *ecryptfs_inode); int ecryptfs_read_and_validate_xattr_region(char *page_virt, struct dentry *ecryptfs_dentry); -u16 ecryptfs_code_for_cipher_string(struct ecryptfs_crypt_stat *crypt_stat); -int ecryptfs_cipher_code_to_string(char *str, u16 cipher_code); +u8 ecryptfs_code_for_cipher_string(struct ecryptfs_crypt_stat *crypt_stat); +int ecryptfs_cipher_code_to_string(char *str, u8 cipher_code); void ecryptfs_set_default_sizes(struct ecryptfs_crypt_stat *crypt_stat); int ecryptfs_generate_key_packet_set(char *dest_base, struct ecryptfs_crypt_stat *crypt_stat, @@ -576,8 +574,6 @@ int ecryptfs_truncate(struct dentry *dentry, loff_t new_length); int ecryptfs_inode_test(struct inode *inode, void *candidate_lower_inode); int ecryptfs_inode_set(struct inode *inode, void *lower_inode); void ecryptfs_init_inode(struct inode *inode, struct inode *lower_inode); -ssize_t ecryptfs_getxattr(struct dentry *dentry, const char *name, void *value, - size_t size); ssize_t ecryptfs_getxattr_lower(struct dentry *lower_dentry, const char *name, void *value, size_t size); @@ -623,6 +619,7 @@ ecryptfs_add_new_key_tfm(struct ecryptfs_key_tfm **key_tfm, char *cipher_name, size_t key_size); int ecryptfs_init_crypto(void); int ecryptfs_destroy_crypto(void); +int ecryptfs_tfm_exists(char *cipher_name, struct ecryptfs_key_tfm **key_tfm); int ecryptfs_get_tfm_and_mutex_for_cipher_name(struct crypto_blkcipher **tfm, struct mutex **tfm_mutex, char *cipher_name); @@ -631,8 +628,6 @@ int ecryptfs_keyring_auth_tok_for_sig(struct key **auth_tok_key, char *sig); int ecryptfs_write_zeros(struct file *file, pgoff_t index, int start, int num_zeros); -void ecryptfs_lower_offset_for_extent(loff_t *offset, loff_t extent_num, - struct ecryptfs_crypt_stat *crypt_stat); int ecryptfs_write_lower(struct inode *ecryptfs_inode, char *data, loff_t offset, size_t size); int ecryptfs_write_lower_page_segment(struct inode *ecryptfs_inode, @@ -646,8 +641,6 @@ int ecryptfs_read_lower_page_segment(struct page *page_for_ecryptfs, pgoff_t page_index, size_t offset_in_page, size_t size, struct inode *ecryptfs_inode); -int ecryptfs_read(char *data, loff_t offset, size_t size, - struct file *ecryptfs_file); struct page *ecryptfs_get_locked_page(struct file *file, loff_t index); #endif /* #ifndef ECRYPTFS_KERNEL_H */ diff --git a/fs/ecryptfs/file.c b/fs/ecryptfs/file.c index c98c4690a771..2b8f5ed4adea 100644 --- a/fs/ecryptfs/file.c +++ b/fs/ecryptfs/file.c @@ -209,9 +209,10 @@ static int ecryptfs_open(struct inode *inode, struct file *file) if (!(mount_crypt_stat->flags & ECRYPTFS_PLAINTEXT_PASSTHROUGH_ENABLED)) { rc = -EIO; - printk(KERN_WARNING "Attempt to read file that " + printk(KERN_WARNING "Either the lower file " "is not in a valid eCryptfs format, " - "and plaintext passthrough mode is not " + "or the key could not be retrieved. " + "Plaintext passthrough mode is not " "enabled; returning -EIO\n"); mutex_unlock(&crypt_stat->cs_mutex); goto out_free; diff --git a/fs/ecryptfs/inode.c b/fs/ecryptfs/inode.c index 5a719180983c..edd1e44e9d47 100644 --- a/fs/ecryptfs/inode.c +++ b/fs/ecryptfs/inode.c @@ -365,8 +365,7 @@ static struct dentry *ecryptfs_lookup(struct inode *dir, struct dentry *dentry, dentry->d_sb)->mount_crypt_stat; if (mount_crypt_stat->flags & ECRYPTFS_ENCRYPTED_VIEW_ENABLED) { if (crypt_stat->flags & ECRYPTFS_METADATA_IN_XATTR) - file_size = ((crypt_stat->extent_size - * crypt_stat->num_header_extents_at_front) + file_size = (crypt_stat->num_header_bytes_at_front + i_size_read(lower_dentry->d_inode)); else file_size = i_size_read(lower_dentry->d_inode); @@ -685,7 +684,7 @@ ecryptfs_put_link(struct dentry *dentry, struct nameidata *nd, void *ptr) * @crypt_stat: Crypt_stat associated with file * @upper_size: Size of the upper file * - * Calculate the requried size of the lower file based on the + * Calculate the required size of the lower file based on the * specified size of the upper file. This calculation is based on the * number of headers in the underlying file and the extent size. * @@ -697,8 +696,7 @@ upper_size_to_lower_size(struct ecryptfs_crypt_stat *crypt_stat, { loff_t lower_size; - lower_size = (crypt_stat->extent_size - * crypt_stat->num_header_extents_at_front); + lower_size = crypt_stat->num_header_bytes_at_front; if (upper_size != 0) { loff_t num_extents; @@ -875,11 +873,11 @@ static int ecryptfs_setattr(struct dentry *dentry, struct iattr *ia) if (!(mount_crypt_stat->flags & ECRYPTFS_PLAINTEXT_PASSTHROUGH_ENABLED)) { rc = -EIO; - printk(KERN_WARNING "Attempt to read file that " + printk(KERN_WARNING "Either the lower file " "is not in a valid eCryptfs format, " - "and plaintext passthrough mode is not " + "or the key could not be retrieved. " + "Plaintext passthrough mode is not " "enabled; returning -EIO\n"); - mutex_unlock(&crypt_stat->cs_mutex); goto out; } @@ -954,7 +952,7 @@ out: return rc; } -ssize_t +static ssize_t ecryptfs_getxattr(struct dentry *dentry, const char *name, void *value, size_t size) { diff --git a/fs/ecryptfs/keystore.c b/fs/ecryptfs/keystore.c index f458c1f35565..682b1b2482c2 100644 --- a/fs/ecryptfs/keystore.c +++ b/fs/ecryptfs/keystore.c @@ -189,7 +189,7 @@ out: } static int -parse_tag_65_packet(struct ecryptfs_session_key *session_key, u16 *cipher_code, +parse_tag_65_packet(struct ecryptfs_session_key *session_key, u8 *cipher_code, struct ecryptfs_message *msg) { size_t i = 0; @@ -275,7 +275,7 @@ out: static int -write_tag_66_packet(char *signature, size_t cipher_code, +write_tag_66_packet(char *signature, u8 cipher_code, struct ecryptfs_crypt_stat *crypt_stat, char **packet, size_t *packet_len) { @@ -428,7 +428,7 @@ static int decrypt_pki_encrypted_session_key(struct ecryptfs_auth_tok *auth_tok, struct ecryptfs_crypt_stat *crypt_stat) { - u16 cipher_code = 0; + u8 cipher_code = 0; struct ecryptfs_msg_ctx *msg_ctx; struct ecryptfs_message *msg = NULL; char *auth_tok_sig; @@ -1537,7 +1537,7 @@ write_tag_3_packet(char *dest, size_t *remaining_bytes, struct scatterlist dst_sg; struct scatterlist src_sg; struct mutex *tfm_mutex = NULL; - size_t cipher_code; + u8 cipher_code; size_t packet_size_length; size_t max_packet_size; struct ecryptfs_mount_crypt_stat *mount_crypt_stat = diff --git a/fs/ecryptfs/main.c b/fs/ecryptfs/main.c index 0249aa4ae181..778c420e4cac 100644 --- a/fs/ecryptfs/main.c +++ b/fs/ecryptfs/main.c @@ -117,7 +117,7 @@ void __ecryptfs_printk(const char *fmt, ...) * * Returns zero on success; non-zero otherwise */ -int ecryptfs_init_persistent_file(struct dentry *ecryptfs_dentry) +static int ecryptfs_init_persistent_file(struct dentry *ecryptfs_dentry) { struct ecryptfs_inode_info *inode_info = ecryptfs_inode_to_private(ecryptfs_dentry->d_inode); @@ -226,17 +226,15 @@ out: return rc; } -enum { ecryptfs_opt_sig, ecryptfs_opt_ecryptfs_sig, ecryptfs_opt_debug, - ecryptfs_opt_ecryptfs_debug, ecryptfs_opt_cipher, - ecryptfs_opt_ecryptfs_cipher, ecryptfs_opt_ecryptfs_key_bytes, +enum { ecryptfs_opt_sig, ecryptfs_opt_ecryptfs_sig, + ecryptfs_opt_cipher, ecryptfs_opt_ecryptfs_cipher, + ecryptfs_opt_ecryptfs_key_bytes, ecryptfs_opt_passthrough, ecryptfs_opt_xattr_metadata, ecryptfs_opt_encrypted_view, ecryptfs_opt_err }; static match_table_t tokens = { {ecryptfs_opt_sig, "sig=%s"}, {ecryptfs_opt_ecryptfs_sig, "ecryptfs_sig=%s"}, - {ecryptfs_opt_debug, "debug=%u"}, - {ecryptfs_opt_ecryptfs_debug, "ecryptfs_debug=%u"}, {ecryptfs_opt_cipher, "cipher=%s"}, {ecryptfs_opt_ecryptfs_cipher, "ecryptfs_cipher=%s"}, {ecryptfs_opt_ecryptfs_key_bytes, "ecryptfs_key_bytes=%u"}, @@ -313,7 +311,6 @@ static int ecryptfs_parse_options(struct super_block *sb, char *options) substring_t args[MAX_OPT_ARGS]; int token; char *sig_src; - char *debug_src; char *cipher_name_dst; char *cipher_name_src; char *cipher_key_bytes_src; @@ -341,16 +338,6 @@ static int ecryptfs_parse_options(struct super_block *sb, char *options) } sig_set = 1; break; - case ecryptfs_opt_debug: - case ecryptfs_opt_ecryptfs_debug: - debug_src = args[0].from; - ecryptfs_verbosity = - (int)simple_strtol(debug_src, &debug_src, - 0); - ecryptfs_printk(KERN_DEBUG, - "Verbosity set to [%d]" "\n", - ecryptfs_verbosity); - break; case ecryptfs_opt_cipher: case ecryptfs_opt_ecryptfs_cipher: cipher_name_src = args[0].from; @@ -423,9 +410,13 @@ static int ecryptfs_parse_options(struct super_block *sb, char *options) if (!cipher_key_bytes_set) { mount_crypt_stat->global_default_cipher_key_size = 0; } - rc = ecryptfs_add_new_key_tfm( - NULL, mount_crypt_stat->global_default_cipher_name, - mount_crypt_stat->global_default_cipher_key_size); + mutex_lock(&key_tfm_list_mutex); + if (!ecryptfs_tfm_exists(mount_crypt_stat->global_default_cipher_name, + NULL)) + rc = ecryptfs_add_new_key_tfm( + NULL, mount_crypt_stat->global_default_cipher_name, + mount_crypt_stat->global_default_cipher_key_size); + mutex_unlock(&key_tfm_list_mutex); if (rc) { printk(KERN_ERR "Error attempting to initialize cipher with " "name = [%s] and key size = [%td]; rc = [%d]\n", @@ -654,11 +645,6 @@ static struct ecryptfs_cache_info { .size = sizeof(struct ecryptfs_sb_info), }, { - .cache = &ecryptfs_header_cache_0, - .name = "ecryptfs_headers_0", - .size = PAGE_CACHE_SIZE, - }, - { .cache = &ecryptfs_header_cache_1, .name = "ecryptfs_headers_1", .size = PAGE_CACHE_SIZE, @@ -821,6 +807,10 @@ static int __init ecryptfs_init(void) "rc = [%d]\n", rc); goto out_release_messaging; } + if (ecryptfs_verbosity > 0) + printk(KERN_CRIT "eCryptfs verbosity set to %d. Secret values " + "will be written to the syslog!\n", ecryptfs_verbosity); + goto out; out_release_messaging: ecryptfs_release_messaging(ecryptfs_transport); diff --git a/fs/ecryptfs/mmap.c b/fs/ecryptfs/mmap.c index 0535412d8c64..dc74b186145d 100644 --- a/fs/ecryptfs/mmap.c +++ b/fs/ecryptfs/mmap.c @@ -34,8 +34,6 @@ #include <linux/scatterlist.h> #include "ecryptfs_kernel.h" -struct kmem_cache *ecryptfs_lower_page_cache; - /** * ecryptfs_get_locked_page * @@ -102,13 +100,14 @@ static void set_header_info(char *page_virt, struct ecryptfs_crypt_stat *crypt_stat) { size_t written; - int save_num_header_extents_at_front = - crypt_stat->num_header_extents_at_front; + size_t save_num_header_bytes_at_front = + crypt_stat->num_header_bytes_at_front; - crypt_stat->num_header_extents_at_front = 1; + crypt_stat->num_header_bytes_at_front = + ECRYPTFS_MINIMUM_HEADER_EXTENT_SIZE; ecryptfs_write_header_metadata(page_virt + 20, crypt_stat, &written); - crypt_stat->num_header_extents_at_front = - save_num_header_extents_at_front; + crypt_stat->num_header_bytes_at_front = + save_num_header_bytes_at_front; } /** @@ -134,8 +133,11 @@ ecryptfs_copy_up_encrypted_with_header(struct page *page, loff_t view_extent_num = ((((loff_t)page->index) * num_extents_per_page) + extent_num_in_page); + size_t num_header_extents_at_front = + (crypt_stat->num_header_bytes_at_front + / crypt_stat->extent_size); - if (view_extent_num < crypt_stat->num_header_extents_at_front) { + if (view_extent_num < num_header_extents_at_front) { /* This is a header extent */ char *page_virt; @@ -157,9 +159,8 @@ ecryptfs_copy_up_encrypted_with_header(struct page *page, } else { /* This is an encrypted data extent */ loff_t lower_offset = - ((view_extent_num - - crypt_stat->num_header_extents_at_front) - * crypt_stat->extent_size); + ((view_extent_num * crypt_stat->extent_size) + - crypt_stat->num_header_bytes_at_front); rc = ecryptfs_read_lower_page_segment( page, (lower_offset >> PAGE_CACHE_SHIFT), diff --git a/fs/ecryptfs/read_write.c b/fs/ecryptfs/read_write.c index 948f57624c05..0c4928623bbc 100644 --- a/fs/ecryptfs/read_write.c +++ b/fs/ecryptfs/read_write.c @@ -293,6 +293,7 @@ int ecryptfs_read_lower_page_segment(struct page *page_for_ecryptfs, return rc; } +#if 0 /** * ecryptfs_read * @data: The virtual address into which to write the data read (and @@ -371,3 +372,4 @@ int ecryptfs_read(char *data, loff_t offset, size_t size, out: return rc; } +#endif /* 0 */ diff --git a/fs/ecryptfs/super.c b/fs/ecryptfs/super.c index 4859c4eecd65..c27ac2b358a1 100644 --- a/fs/ecryptfs/super.c +++ b/fs/ecryptfs/super.c @@ -156,32 +156,38 @@ static void ecryptfs_clear_inode(struct inode *inode) /** * ecryptfs_show_options * - * Prints the directory we are currently mounted over. - * Returns zero on success; non-zero otherwise + * Prints the mount options for a given superblock. + * Returns zero; does not fail. */ static int ecryptfs_show_options(struct seq_file *m, struct vfsmount *mnt) { struct super_block *sb = mnt->mnt_sb; - struct dentry *lower_root_dentry = ecryptfs_dentry_to_lower(sb->s_root); - struct vfsmount *lower_mnt = ecryptfs_dentry_to_lower_mnt(sb->s_root); - char *tmp_page; - char *path; - int rc = 0; - - tmp_page = (char *)__get_free_page(GFP_KERNEL); - if (!tmp_page) { - rc = -ENOMEM; - goto out; - } - path = d_path(lower_root_dentry, lower_mnt, tmp_page, PAGE_SIZE); - if (IS_ERR(path)) { - rc = PTR_ERR(path); - goto out; + struct ecryptfs_mount_crypt_stat *mount_crypt_stat = + &ecryptfs_superblock_to_private(sb)->mount_crypt_stat; + struct ecryptfs_global_auth_tok *walker; + + mutex_lock(&mount_crypt_stat->global_auth_tok_list_mutex); + list_for_each_entry(walker, + &mount_crypt_stat->global_auth_tok_list, + mount_crypt_stat_list) { + seq_printf(m, ",ecryptfs_sig=%s", walker->sig); } - seq_printf(m, ",dir=%s", path); - free_page((unsigned long)tmp_page); -out: - return rc; + mutex_unlock(&mount_crypt_stat->global_auth_tok_list_mutex); + + seq_printf(m, ",ecryptfs_cipher=%s", + mount_crypt_stat->global_default_cipher_name); + + if (mount_crypt_stat->global_default_cipher_key_size) + seq_printf(m, ",ecryptfs_key_bytes=%zd", + mount_crypt_stat->global_default_cipher_key_size); + if (mount_crypt_stat->flags & ECRYPTFS_PLAINTEXT_PASSTHROUGH_ENABLED) + seq_printf(m, ",ecryptfs_passthrough"); + if (mount_crypt_stat->flags & ECRYPTFS_XATTR_METADATA_ENABLED) + seq_printf(m, ",ecryptfs_xattr_metadata"); + if (mount_crypt_stat->flags & ECRYPTFS_ENCRYPTED_VIEW_ENABLED) + seq_printf(m, ",ecryptfs_encrypted_view"); + + return 0; } const struct super_operations ecryptfs_sops = { diff --git a/fs/eventfd.c b/fs/eventfd.c index 2ce19c000d2a..a9f130cd50ac 100644 --- a/fs/eventfd.c +++ b/fs/eventfd.c @@ -15,6 +15,7 @@ #include <linux/spinlock.h> #include <linux/anon_inodes.h> #include <linux/eventfd.h> +#include <linux/syscalls.h> struct eventfd_ctx { wait_queue_head_t wqh; diff --git a/fs/ext2/balloc.c b/fs/ext2/balloc.c index 377ad172d74b..e7b2bafa1dd9 100644 --- a/fs/ext2/balloc.c +++ b/fs/ext2/balloc.c @@ -69,9 +69,53 @@ struct ext2_group_desc * ext2_get_group_desc(struct super_block * sb, return desc + offset; } +static int ext2_valid_block_bitmap(struct super_block *sb, + struct ext2_group_desc *desc, + unsigned int block_group, + struct buffer_head *bh) +{ + ext2_grpblk_t offset; + ext2_grpblk_t next_zero_bit; + ext2_fsblk_t bitmap_blk; + ext2_fsblk_t group_first_block; + + group_first_block = ext2_group_first_block_no(sb, block_group); + + /* check whether block bitmap block number is set */ + bitmap_blk = le32_to_cpu(desc->bg_block_bitmap); + offset = bitmap_blk - group_first_block; + if (!ext2_test_bit(offset, bh->b_data)) + /* bad block bitmap */ + goto err_out; + + /* check whether the inode bitmap block number is set */ + bitmap_blk = le32_to_cpu(desc->bg_inode_bitmap); + offset = bitmap_blk - group_first_block; + if (!ext2_test_bit(offset, bh->b_data)) + /* bad block bitmap */ + goto err_out; + + /* check whether the inode table block number is set */ + bitmap_blk = le32_to_cpu(desc->bg_inode_table); + offset = bitmap_blk - group_first_block; + next_zero_bit = ext2_find_next_zero_bit(bh->b_data, + offset + EXT2_SB(sb)->s_itb_per_group, + offset); + if (next_zero_bit >= offset + EXT2_SB(sb)->s_itb_per_group) + /* good bitmap for inode tables */ + return 1; + +err_out: + ext2_error(sb, __FUNCTION__, + "Invalid block bitmap - " + "block_group = %d, block = %lu", + block_group, bitmap_blk); + return 0; +} + /* - * Read the bitmap for a given block_group, reading into the specified - * slot in the superblock's bitmap cache. + * Read the bitmap for a given block_group,and validate the + * bits for block/inode/inode tables are set in the bitmaps * * Return buffer_head on success or NULL in case of failure. */ @@ -80,17 +124,36 @@ read_block_bitmap(struct super_block *sb, unsigned int block_group) { struct ext2_group_desc * desc; struct buffer_head * bh = NULL; - - desc = ext2_get_group_desc (sb, block_group, NULL); + ext2_fsblk_t bitmap_blk; + + desc = ext2_get_group_desc(sb, block_group, NULL); if (!desc) - goto error_out; - bh = sb_bread(sb, le32_to_cpu(desc->bg_block_bitmap)); - if (!bh) - ext2_error (sb, "read_block_bitmap", + return NULL; + bitmap_blk = le32_to_cpu(desc->bg_block_bitmap); + bh = sb_getblk(sb, bitmap_blk); + if (unlikely(!bh)) { + ext2_error(sb, __FUNCTION__, + "Cannot read block bitmap - " + "block_group = %d, block_bitmap = %u", + block_group, le32_to_cpu(desc->bg_block_bitmap)); + return NULL; + } + if (likely(bh_uptodate_or_lock(bh))) + return bh; + + if (bh_submit_read(bh) < 0) { + brelse(bh); + ext2_error(sb, __FUNCTION__, "Cannot read block bitmap - " "block_group = %d, block_bitmap = %u", block_group, le32_to_cpu(desc->bg_block_bitmap)); -error_out: + return NULL; + } + if (!ext2_valid_block_bitmap(sb, desc, block_group, bh)) { + brelse(bh); + return NULL; + } + return bh; } @@ -474,11 +537,13 @@ do_more: in_range (block, le32_to_cpu(desc->bg_inode_table), sbi->s_itb_per_group) || in_range (block + count - 1, le32_to_cpu(desc->bg_inode_table), - sbi->s_itb_per_group)) + sbi->s_itb_per_group)) { ext2_error (sb, "ext2_free_blocks", "Freeing blocks in system zones - " "Block = %lu, count = %lu", block, count); + goto error_return; + } for (i = 0, group_freed = 0; i < count; i++) { if (!ext2_clear_bit_atomic(sb_bgl_lock(sbi, block_group), @@ -1250,8 +1315,8 @@ retry_alloc: smp_rmb(); /* - * Now search the rest of the groups. We assume that - * i and gdp correctly point to the last group visited. + * Now search the rest of the groups. We assume that + * group_no and gdp correctly point to the last group visited. */ for (bgi = 0; bgi < ngroups; bgi++) { group_no++; @@ -1311,11 +1376,13 @@ allocated: in_range(ret_block, le32_to_cpu(gdp->bg_inode_table), EXT2_SB(sb)->s_itb_per_group) || in_range(ret_block + num - 1, le32_to_cpu(gdp->bg_inode_table), - EXT2_SB(sb)->s_itb_per_group)) + EXT2_SB(sb)->s_itb_per_group)) { ext2_error(sb, "ext2_new_blocks", "Allocating block in system zone - " "blocks from "E2FSBLK", length %lu", ret_block, num); + goto out; + } performed_allocation = 1; @@ -1466,9 +1533,6 @@ int ext2_bg_has_super(struct super_block *sb, int group) */ unsigned long ext2_bg_num_gdb(struct super_block *sb, int group) { - if (EXT2_HAS_RO_COMPAT_FEATURE(sb,EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER)&& - !ext2_group_sparse(group)) - return 0; - return EXT2_SB(sb)->s_gdb_count; + return ext2_bg_has_super(sb, group) ? EXT2_SB(sb)->s_gdb_count : 0; } diff --git a/fs/ext2/dir.c b/fs/ext2/dir.c index d868e26c15eb..8dededd80fe2 100644 --- a/fs/ext2/dir.c +++ b/fs/ext2/dir.c @@ -703,7 +703,7 @@ const struct file_operations ext2_dir_operations = { .llseek = generic_file_llseek, .read = generic_read_dir, .readdir = ext2_readdir, - .ioctl = ext2_ioctl, + .unlocked_ioctl = ext2_ioctl, #ifdef CONFIG_COMPAT .compat_ioctl = ext2_compat_ioctl, #endif diff --git a/fs/ext2/ext2.h b/fs/ext2/ext2.h index c87ae29c19cb..bb9948cdd50f 100644 --- a/fs/ext2/ext2.h +++ b/fs/ext2/ext2.h @@ -139,8 +139,7 @@ int __ext2_write_begin(struct file *file, struct address_space *mapping, struct page **pagep, void **fsdata); /* ioctl.c */ -extern int ext2_ioctl (struct inode *, struct file *, unsigned int, - unsigned long); +extern long ext2_ioctl(struct file *, unsigned int, unsigned long); extern long ext2_compat_ioctl(struct file *, unsigned int, unsigned long); /* namei.c */ diff --git a/fs/ext2/file.c b/fs/ext2/file.c index c051798459a1..5f2fa9c36293 100644 --- a/fs/ext2/file.c +++ b/fs/ext2/file.c @@ -48,7 +48,7 @@ const struct file_operations ext2_file_operations = { .write = do_sync_write, .aio_read = generic_file_aio_read, .aio_write = generic_file_aio_write, - .ioctl = ext2_ioctl, + .unlocked_ioctl = ext2_ioctl, #ifdef CONFIG_COMPAT .compat_ioctl = ext2_compat_ioctl, #endif @@ -65,7 +65,7 @@ const struct file_operations ext2_xip_file_operations = { .llseek = generic_file_llseek, .read = xip_file_read, .write = xip_file_write, - .ioctl = ext2_ioctl, + .unlocked_ioctl = ext2_ioctl, #ifdef CONFIG_COMPAT .compat_ioctl = ext2_compat_ioctl, #endif diff --git a/fs/ext2/inode.c b/fs/ext2/inode.c index b1ab32ab5a77..03978ec2a91c 100644 --- a/fs/ext2/inode.c +++ b/fs/ext2/inode.c @@ -286,15 +286,12 @@ static unsigned long ext2_find_near(struct inode *inode, Indirect *ind) * ext2_find_goal - find a prefered place for allocation. * @inode: owner * @block: block we want - * @chain: chain of indirect blocks * @partial: pointer to the last triple within a chain * * Returns preferred place for a block (the goal). */ -static inline int ext2_find_goal(struct inode *inode, - long block, - Indirect chain[4], +static inline int ext2_find_goal(struct inode *inode, long block, Indirect *partial) { struct ext2_block_alloc_info *block_i; @@ -569,7 +566,6 @@ static void ext2_splice_branch(struct inode *inode, * * `handle' can be NULL if create == 0. * - * The BKL may not be held on entry here. Be sure to take it early. * return > 0, # of blocks mapped or allocated. * return = 0, if plain lookup failed. * return < 0, error case. @@ -639,7 +635,7 @@ reread: if (S_ISREG(inode->i_mode) && (!ei->i_block_alloc_info)) ext2_init_block_alloc_info(inode); - goal = ext2_find_goal(inode, iblock, chain, partial); + goal = ext2_find_goal(inode, iblock, partial); /* the number of blocks need to allocate for [d,t]indirect blocks */ indirect_blks = (chain + depth) - partial - 1; diff --git a/fs/ext2/ioctl.c b/fs/ext2/ioctl.c index 320b2cb3d4d2..b8ea11fee5c6 100644 --- a/fs/ext2/ioctl.c +++ b/fs/ext2/ioctl.c @@ -17,9 +17,9 @@ #include <asm/uaccess.h> -int ext2_ioctl (struct inode * inode, struct file * filp, unsigned int cmd, - unsigned long arg) +long ext2_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) { + struct inode *inode = filp->f_dentry->d_inode; struct ext2_inode_info *ei = EXT2_I(inode); unsigned int flags; unsigned short rsv_window_size; @@ -141,9 +141,6 @@ int ext2_ioctl (struct inode * inode, struct file * filp, unsigned int cmd, #ifdef CONFIG_COMPAT long ext2_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { - struct inode *inode = file->f_path.dentry->d_inode; - int ret; - /* These are just misnamed, they actually get/put from/to user an int */ switch (cmd) { case EXT2_IOC32_GETFLAGS: @@ -161,9 +158,6 @@ long ext2_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg) default: return -ENOIOCTLCMD; } - lock_kernel(); - ret = ext2_ioctl(inode, file, cmd, (unsigned long) compat_ptr(arg)); - unlock_kernel(); - return ret; + return ext2_ioctl(file, cmd, (unsigned long) compat_ptr(arg)); } #endif diff --git a/fs/ext2/super.c b/fs/ext2/super.c index 6abaf75163f0..1ba18b72d43a 100644 --- a/fs/ext2/super.c +++ b/fs/ext2/super.c @@ -234,16 +234,16 @@ static int ext2_show_options(struct seq_file *seq, struct vfsmount *vfs) le16_to_cpu(es->s_def_resgid) != EXT2_DEF_RESGID) { seq_printf(seq, ",resgid=%u", sbi->s_resgid); } - if (test_opt(sb, ERRORS_CONT)) { + if (test_opt(sb, ERRORS_RO)) { int def_errors = le16_to_cpu(es->s_errors); if (def_errors == EXT2_ERRORS_PANIC || - def_errors == EXT2_ERRORS_RO) { - seq_puts(seq, ",errors=continue"); + def_errors == EXT2_ERRORS_CONTINUE) { + seq_puts(seq, ",errors=remount-ro"); } } - if (test_opt(sb, ERRORS_RO)) - seq_puts(seq, ",errors=remount-ro"); + if (test_opt(sb, ERRORS_CONT)) + seq_puts(seq, ",errors=continue"); if (test_opt(sb, ERRORS_PANIC)) seq_puts(seq, ",errors=panic"); if (test_opt(sb, NO_UID32)) @@ -617,27 +617,24 @@ static int ext2_setup_super (struct super_block * sb, return res; } -static int ext2_check_descriptors (struct super_block * sb) +static int ext2_check_descriptors(struct super_block *sb) { int i; - int desc_block = 0; struct ext2_sb_info *sbi = EXT2_SB(sb); unsigned long first_block = le32_to_cpu(sbi->s_es->s_first_data_block); unsigned long last_block; - struct ext2_group_desc * gdp = NULL; ext2_debug ("Checking group descriptors"); - for (i = 0; i < sbi->s_groups_count; i++) - { + for (i = 0; i < sbi->s_groups_count; i++) { + struct ext2_group_desc *gdp = ext2_get_group_desc(sb, i, NULL); + if (i == sbi->s_groups_count - 1) last_block = le32_to_cpu(sbi->s_es->s_blocks_count) - 1; else last_block = first_block + (EXT2_BLOCKS_PER_GROUP(sb) - 1); - if ((i % EXT2_DESC_PER_BLOCK(sb)) == 0) - gdp = (struct ext2_group_desc *) sbi->s_group_desc[desc_block++]->b_data; if (le32_to_cpu(gdp->bg_block_bitmap) < first_block || le32_to_cpu(gdp->bg_block_bitmap) > last_block) { @@ -667,7 +664,6 @@ static int ext2_check_descriptors (struct super_block * sb) return 0; } first_block += EXT2_BLOCKS_PER_GROUP(sb); - gdp++; } return 1; } @@ -820,10 +816,10 @@ static int ext2_fill_super(struct super_block *sb, void *data, int silent) if (le16_to_cpu(sbi->s_es->s_errors) == EXT2_ERRORS_PANIC) set_opt(sbi->s_mount_opt, ERRORS_PANIC); - else if (le16_to_cpu(sbi->s_es->s_errors) == EXT2_ERRORS_RO) - set_opt(sbi->s_mount_opt, ERRORS_RO); - else + else if (le16_to_cpu(sbi->s_es->s_errors) == EXT2_ERRORS_CONTINUE) set_opt(sbi->s_mount_opt, ERRORS_CONT); + else + set_opt(sbi->s_mount_opt, ERRORS_RO); sbi->s_resuid = le16_to_cpu(es->s_def_resuid); sbi->s_resgid = le16_to_cpu(es->s_def_resgid); @@ -868,8 +864,7 @@ static int ext2_fill_super(struct super_block *sb, void *data, int silent) blocksize = BLOCK_SIZE << le32_to_cpu(sbi->s_es->s_log_block_size); - if ((ext2_use_xip(sb)) && ((blocksize != PAGE_SIZE) || - (sb->s_blocksize != blocksize))) { + if (ext2_use_xip(sb) && blocksize != PAGE_SIZE) { if (!silent) printk("XIP: Unsupported blocksize\n"); goto failed_mount; diff --git a/fs/ext3/balloc.c b/fs/ext3/balloc.c index a8ba7e831278..a75713031105 100644 --- a/fs/ext3/balloc.c +++ b/fs/ext3/balloc.c @@ -80,13 +80,57 @@ struct ext3_group_desc * ext3_get_group_desc(struct super_block * sb, return desc + offset; } +static int ext3_valid_block_bitmap(struct super_block *sb, + struct ext3_group_desc *desc, + unsigned int block_group, + struct buffer_head *bh) +{ + ext3_grpblk_t offset; + ext3_grpblk_t next_zero_bit; + ext3_fsblk_t bitmap_blk; + ext3_fsblk_t group_first_block; + + group_first_block = ext3_group_first_block_no(sb, block_group); + + /* check whether block bitmap block number is set */ + bitmap_blk = le32_to_cpu(desc->bg_block_bitmap); + offset = bitmap_blk - group_first_block; + if (!ext3_test_bit(offset, bh->b_data)) + /* bad block bitmap */ + goto err_out; + + /* check whether the inode bitmap block number is set */ + bitmap_blk = le32_to_cpu(desc->bg_inode_bitmap); + offset = bitmap_blk - group_first_block; + if (!ext3_test_bit(offset, bh->b_data)) + /* bad block bitmap */ + goto err_out; + + /* check whether the inode table block number is set */ + bitmap_blk = le32_to_cpu(desc->bg_inode_table); + offset = bitmap_blk - group_first_block; + next_zero_bit = ext3_find_next_zero_bit(bh->b_data, + offset + EXT3_SB(sb)->s_itb_per_group, + offset); + if (next_zero_bit >= offset + EXT3_SB(sb)->s_itb_per_group) + /* good bitmap for inode tables */ + return 1; + +err_out: + ext3_error(sb, __FUNCTION__, + "Invalid block bitmap - " + "block_group = %d, block = %lu", + block_group, bitmap_blk); + return 0; +} + /** * read_block_bitmap() * @sb: super block * @block_group: given block group * - * Read the bitmap for a given block_group, reading into the specified - * slot in the superblock's bitmap cache. + * Read the bitmap for a given block_group,and validate the + * bits for block/inode/inode tables are set in the bitmaps * * Return buffer_head on success or NULL in case of failure. */ @@ -95,17 +139,35 @@ read_block_bitmap(struct super_block *sb, unsigned int block_group) { struct ext3_group_desc * desc; struct buffer_head * bh = NULL; + ext3_fsblk_t bitmap_blk; - desc = ext3_get_group_desc (sb, block_group, NULL); + desc = ext3_get_group_desc(sb, block_group, NULL); if (!desc) - goto error_out; - bh = sb_bread(sb, le32_to_cpu(desc->bg_block_bitmap)); - if (!bh) - ext3_error (sb, "read_block_bitmap", + return NULL; + bitmap_blk = le32_to_cpu(desc->bg_block_bitmap); + bh = sb_getblk(sb, bitmap_blk); + if (unlikely(!bh)) { + ext3_error(sb, __FUNCTION__, "Cannot read block bitmap - " "block_group = %d, block_bitmap = %u", block_group, le32_to_cpu(desc->bg_block_bitmap)); -error_out: + return NULL; + } + if (likely(bh_uptodate_or_lock(bh))) + return bh; + + if (bh_submit_read(bh) < 0) { + brelse(bh); + ext3_error(sb, __FUNCTION__, + "Cannot read block bitmap - " + "block_group = %d, block_bitmap = %u", + block_group, le32_to_cpu(desc->bg_block_bitmap)); + return NULL; + } + if (!ext3_valid_block_bitmap(sb, desc, block_group, bh)) { + brelse(bh); + return NULL; + } return bh; } /* @@ -468,11 +530,13 @@ do_more: in_range (block, le32_to_cpu(desc->bg_inode_table), sbi->s_itb_per_group) || in_range (block + count - 1, le32_to_cpu(desc->bg_inode_table), - sbi->s_itb_per_group)) + sbi->s_itb_per_group)) { ext3_error (sb, "ext3_free_blocks", "Freeing blocks in system zones - " "Block = "E3FSBLK", count = %lu", block, count); + goto error_return; + } /* * We are about to start releasing blocks in the bitmap, @@ -1508,7 +1572,7 @@ retry_alloc: /* * Now search the rest of the groups. We assume that - * i and gdp correctly point to the last group visited. + * group_no and gdp correctly point to the last group visited. */ for (bgi = 0; bgi < ngroups; bgi++) { group_no++; @@ -1575,11 +1639,13 @@ allocated: in_range(ret_block, le32_to_cpu(gdp->bg_inode_table), EXT3_SB(sb)->s_itb_per_group) || in_range(ret_block + num - 1, le32_to_cpu(gdp->bg_inode_table), - EXT3_SB(sb)->s_itb_per_group)) + EXT3_SB(sb)->s_itb_per_group)) { ext3_error(sb, "ext3_new_block", "Allocating block in system zone - " "blocks from "E3FSBLK", length %lu", ret_block, num); + goto out; + } performed_allocation = 1; @@ -1782,11 +1848,7 @@ static unsigned long ext3_bg_num_gdb_meta(struct super_block *sb, int group) static unsigned long ext3_bg_num_gdb_nometa(struct super_block *sb, int group) { - if (EXT3_HAS_RO_COMPAT_FEATURE(sb, - EXT3_FEATURE_RO_COMPAT_SPARSE_SUPER) && - !ext3_group_sparse(group)) - return 0; - return EXT3_SB(sb)->s_gdb_count; + return ext3_bg_has_super(sb, group) ? EXT3_SB(sb)->s_gdb_count : 0; } /** diff --git a/fs/ext3/inode.c b/fs/ext3/inode.c index 077535439288..8a9ce2d09bde 100644 --- a/fs/ext3/inode.c +++ b/fs/ext3/inode.c @@ -439,16 +439,14 @@ static ext3_fsblk_t ext3_find_near(struct inode *inode, Indirect *ind) * ext3_find_goal - find a prefered place for allocation. * @inode: owner * @block: block we want - * @chain: chain of indirect blocks * @partial: pointer to the last triple within a chain - * @goal: place to store the result. * * Normally this function find the prefered place for block allocation, - * stores it in *@goal and returns zero. + * returns it. */ static ext3_fsblk_t ext3_find_goal(struct inode *inode, long block, - Indirect chain[4], Indirect *partial) + Indirect *partial) { struct ext3_block_alloc_info *block_i; @@ -884,7 +882,7 @@ int ext3_get_blocks_handle(handle_t *handle, struct inode *inode, if (S_ISREG(inode->i_mode) && (!ei->i_block_alloc_info)) ext3_init_block_alloc_info(inode); - goal = ext3_find_goal(inode, iblock, chain, partial); + goal = ext3_find_goal(inode, iblock, partial); /* the number of blocks need to allocate for [d,t]indirect blocks */ indirect_blks = (chain + depth) - partial - 1; @@ -941,55 +939,45 @@ out: return err; } -#define DIO_CREDITS (EXT3_RESERVE_TRANS_BLOCKS + 32) +/* Maximum number of blocks we map for direct IO at once. */ +#define DIO_MAX_BLOCKS 4096 +/* + * Number of credits we need for writing DIO_MAX_BLOCKS: + * We need sb + group descriptor + bitmap + inode -> 4 + * For B blocks with A block pointers per block we need: + * 1 (triple ind.) + (B/A/A + 2) (doubly ind.) + (B/A + 2) (indirect). + * If we plug in 4096 for B and 256 for A (for 1KB block size), we get 25. + */ +#define DIO_CREDITS 25 static int ext3_get_block(struct inode *inode, sector_t iblock, struct buffer_head *bh_result, int create) { handle_t *handle = ext3_journal_current_handle(); - int ret = 0; + int ret = 0, started = 0; unsigned max_blocks = bh_result->b_size >> inode->i_blkbits; - if (!create) - goto get_block; /* A read */ - - if (max_blocks == 1) - goto get_block; /* A single block get */ - - if (handle->h_transaction->t_state == T_LOCKED) { - /* - * Huge direct-io writes can hold off commits for long - * periods of time. Let this commit run. - */ - ext3_journal_stop(handle); - handle = ext3_journal_start(inode, DIO_CREDITS); - if (IS_ERR(handle)) + if (create && !handle) { /* Direct IO write... */ + if (max_blocks > DIO_MAX_BLOCKS) + max_blocks = DIO_MAX_BLOCKS; + handle = ext3_journal_start(inode, DIO_CREDITS + + 2 * EXT3_QUOTA_TRANS_BLOCKS(inode->i_sb)); + if (IS_ERR(handle)) { ret = PTR_ERR(handle); - goto get_block; - } - - if (handle->h_buffer_credits <= EXT3_RESERVE_TRANS_BLOCKS) { - /* - * Getting low on buffer credits... - */ - ret = ext3_journal_extend(handle, DIO_CREDITS); - if (ret > 0) { - /* - * Couldn't extend the transaction. Start a new one. - */ - ret = ext3_journal_restart(handle, DIO_CREDITS); + goto out; } + started = 1; } -get_block: - if (ret == 0) { - ret = ext3_get_blocks_handle(handle, inode, iblock, + ret = ext3_get_blocks_handle(handle, inode, iblock, max_blocks, bh_result, create, 0); - if (ret > 0) { - bh_result->b_size = (ret << inode->i_blkbits); - ret = 0; - } + if (ret > 0) { + bh_result->b_size = (ret << inode->i_blkbits); + ret = 0; } + if (started) + ext3_journal_stop(handle); +out: return ret; } @@ -1680,7 +1668,8 @@ static int ext3_releasepage(struct page *page, gfp_t wait) * if the machine crashes during the write. * * If the O_DIRECT write is intantiating holes inside i_size and the machine - * crashes then stale disk data _may_ be exposed inside the file. + * crashes then stale disk data _may_ be exposed inside the file. But current + * VFS code falls back into buffered path in that case so we are safe. */ static ssize_t ext3_direct_IO(int rw, struct kiocb *iocb, const struct iovec *iov, loff_t offset, @@ -1689,7 +1678,7 @@ static ssize_t ext3_direct_IO(int rw, struct kiocb *iocb, struct file *file = iocb->ki_filp; struct inode *inode = file->f_mapping->host; struct ext3_inode_info *ei = EXT3_I(inode); - handle_t *handle = NULL; + handle_t *handle; ssize_t ret; int orphan = 0; size_t count = iov_length(iov, nr_segs); @@ -1697,17 +1686,21 @@ static ssize_t ext3_direct_IO(int rw, struct kiocb *iocb, if (rw == WRITE) { loff_t final_size = offset + count; - handle = ext3_journal_start(inode, DIO_CREDITS); - if (IS_ERR(handle)) { - ret = PTR_ERR(handle); - goto out; - } if (final_size > inode->i_size) { + /* Credits for sb + inode write */ + handle = ext3_journal_start(inode, 2); + if (IS_ERR(handle)) { + ret = PTR_ERR(handle); + goto out; + } ret = ext3_orphan_add(handle, inode); - if (ret) - goto out_stop; + if (ret) { + ext3_journal_stop(handle); + goto out; + } orphan = 1; ei->i_disksize = inode->i_size; + ext3_journal_stop(handle); } } @@ -1715,18 +1708,21 @@ static ssize_t ext3_direct_IO(int rw, struct kiocb *iocb, offset, nr_segs, ext3_get_block, NULL); - /* - * Reacquire the handle: ext3_get_block() can restart the transaction - */ - handle = ext3_journal_current_handle(); - -out_stop: - if (handle) { + if (orphan) { int err; - if (orphan && inode->i_nlink) + /* Credits for sb + inode write */ + handle = ext3_journal_start(inode, 2); + if (IS_ERR(handle)) { + /* This is really bad luck. We've written the data + * but cannot extend i_size. Bail out and pretend + * the write failed... */ + ret = PTR_ERR(handle); + goto out; + } + if (inode->i_nlink) ext3_orphan_del(handle, inode); - if (orphan && ret > 0) { + if (ret > 0) { loff_t end = offset + ret; if (end > inode->i_size) { ei->i_disksize = end; diff --git a/fs/ext3/namei.c b/fs/ext3/namei.c index 4ab6f76e63d0..92b83b004dd8 100644 --- a/fs/ext3/namei.c +++ b/fs/ext3/namei.c @@ -860,14 +860,10 @@ static struct buffer_head * ext3_find_entry (struct dentry *dentry, int nblocks, i, err; struct inode *dir = dentry->d_parent->d_inode; int namelen; - const u8 *name; - unsigned blocksize; *res_dir = NULL; sb = dir->i_sb; - blocksize = sb->s_blocksize; namelen = dentry->d_name.len; - name = dentry->d_name.name; if (namelen > EXT3_NAME_LEN) return NULL; if (is_dx(dir)) { diff --git a/fs/ext3/super.c b/fs/ext3/super.c index f3675cc630e9..343677e8c350 100644 --- a/fs/ext3/super.c +++ b/fs/ext3/super.c @@ -575,16 +575,16 @@ static int ext3_show_options(struct seq_file *seq, struct vfsmount *vfs) le16_to_cpu(es->s_def_resgid) != EXT3_DEF_RESGID) { seq_printf(seq, ",resgid=%u", sbi->s_resgid); } - if (test_opt(sb, ERRORS_CONT)) { + if (test_opt(sb, ERRORS_RO)) { int def_errors = le16_to_cpu(es->s_errors); if (def_errors == EXT3_ERRORS_PANIC || - def_errors == EXT3_ERRORS_RO) { - seq_puts(seq, ",errors=continue"); + def_errors == EXT3_ERRORS_CONTINUE) { + seq_puts(seq, ",errors=remount-ro"); } } - if (test_opt(sb, ERRORS_RO)) - seq_puts(seq, ",errors=remount-ro"); + if (test_opt(sb, ERRORS_CONT)) + seq_puts(seq, ",errors=continue"); if (test_opt(sb, ERRORS_PANIC)) seq_puts(seq, ",errors=panic"); if (test_opt(sb, NO_UID32)) @@ -1252,28 +1252,24 @@ static int ext3_setup_super(struct super_block *sb, struct ext3_super_block *es, } /* Called at mount-time, super-block is locked */ -static int ext3_check_descriptors (struct super_block * sb) +static int ext3_check_descriptors(struct super_block *sb) { struct ext3_sb_info *sbi = EXT3_SB(sb); ext3_fsblk_t first_block = le32_to_cpu(sbi->s_es->s_first_data_block); ext3_fsblk_t last_block; - struct ext3_group_desc * gdp = NULL; - int desc_block = 0; int i; ext3_debug ("Checking group descriptors"); - for (i = 0; i < sbi->s_groups_count; i++) - { + for (i = 0; i < sbi->s_groups_count; i++) { + struct ext3_group_desc *gdp = ext3_get_group_desc(sb, i, NULL); + if (i == sbi->s_groups_count - 1) last_block = le32_to_cpu(sbi->s_es->s_blocks_count) - 1; else last_block = first_block + (EXT3_BLOCKS_PER_GROUP(sb) - 1); - if ((i % EXT3_DESC_PER_BLOCK(sb)) == 0) - gdp = (struct ext3_group_desc *) - sbi->s_group_desc[desc_block++]->b_data; if (le32_to_cpu(gdp->bg_block_bitmap) < first_block || le32_to_cpu(gdp->bg_block_bitmap) > last_block) { @@ -1306,7 +1302,6 @@ static int ext3_check_descriptors (struct super_block * sb) return 0; } first_block += EXT3_BLOCKS_PER_GROUP(sb); - gdp++; } sbi->s_es->s_free_blocks_count=cpu_to_le32(ext3_count_free_blocks(sb)); @@ -1583,10 +1578,10 @@ static int ext3_fill_super (struct super_block *sb, void *data, int silent) if (le16_to_cpu(sbi->s_es->s_errors) == EXT3_ERRORS_PANIC) set_opt(sbi->s_mount_opt, ERRORS_PANIC); - else if (le16_to_cpu(sbi->s_es->s_errors) == EXT3_ERRORS_RO) - set_opt(sbi->s_mount_opt, ERRORS_RO); - else + else if (le16_to_cpu(sbi->s_es->s_errors) == EXT3_ERRORS_CONTINUE) set_opt(sbi->s_mount_opt, ERRORS_CONT); + else + set_opt(sbi->s_mount_opt, ERRORS_RO); sbi->s_resuid = le16_to_cpu(es->s_def_resuid); sbi->s_resgid = le16_to_cpu(es->s_def_resgid); diff --git a/fs/ext4/balloc.c b/fs/ext4/balloc.c index ac75ea953d83..0737e05ba3dd 100644 --- a/fs/ext4/balloc.c +++ b/fs/ext4/balloc.c @@ -1700,7 +1700,7 @@ retry_alloc: /* * Now search the rest of the groups. We assume that - * i and gdp correctly point to the last group visited. + * group_no and gdp correctly point to the last group visited. */ for (bgi = 0; bgi < ngroups; bgi++) { group_no++; @@ -2011,11 +2011,7 @@ static unsigned long ext4_bg_num_gdb_meta(struct super_block *sb, static unsigned long ext4_bg_num_gdb_nometa(struct super_block *sb, ext4_group_t group) { - if (EXT4_HAS_RO_COMPAT_FEATURE(sb, - EXT4_FEATURE_RO_COMPAT_SPARSE_SUPER) && - !ext4_group_sparse(group)) - return 0; - return EXT4_SB(sb)->s_gdb_count; + return ext4_bg_has_super(sb, group) ? EXT4_SB(sb)->s_gdb_count : 0; } /** diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c index 05c4145dd27d..0e9055cf700e 100644 --- a/fs/ext4/inode.c +++ b/fs/ext4/inode.c @@ -429,16 +429,13 @@ static ext4_fsblk_t ext4_find_near(struct inode *inode, Indirect *ind) * ext4_find_goal - find a prefered place for allocation. * @inode: owner * @block: block we want - * @chain: chain of indirect blocks * @partial: pointer to the last triple within a chain - * @goal: place to store the result. * * Normally this function find the prefered place for block allocation, - * stores it in *@goal and returns zero. + * returns it. */ - static ext4_fsblk_t ext4_find_goal(struct inode *inode, ext4_lblk_t block, - Indirect chain[4], Indirect *partial) + Indirect *partial) { struct ext4_block_alloc_info *block_i; @@ -839,7 +836,7 @@ int ext4_get_blocks_handle(handle_t *handle, struct inode *inode, if (S_ISREG(inode->i_mode) && (!ei->i_block_alloc_info)) ext4_init_block_alloc_info(inode); - goal = ext4_find_goal(inode, iblock, chain, partial); + goal = ext4_find_goal(inode, iblock, partial); /* the number of blocks need to allocate for [d,t]indirect blocks */ indirect_blks = (chain + depth) - partial - 1; diff --git a/fs/ext4/super.c b/fs/ext4/super.c index 055a0cd0168e..c89bb8797765 100644 --- a/fs/ext4/super.c +++ b/fs/ext4/super.c @@ -1458,7 +1458,7 @@ int ext4_group_desc_csum_verify(struct ext4_sb_info *sbi, __u32 block_group, } /* Called at mount-time, super-block is locked */ -static int ext4_check_descriptors (struct super_block * sb) +static int ext4_check_descriptors(struct super_block *sb) { struct ext4_sb_info *sbi = EXT4_SB(sb); ext4_fsblk_t first_block = le32_to_cpu(sbi->s_es->s_first_data_block); @@ -1466,8 +1466,6 @@ static int ext4_check_descriptors (struct super_block * sb) ext4_fsblk_t block_bitmap; ext4_fsblk_t inode_bitmap; ext4_fsblk_t inode_table; - struct ext4_group_desc * gdp = NULL; - int desc_block = 0; int flexbg_flag = 0; ext4_group_t i; @@ -1476,17 +1474,15 @@ static int ext4_check_descriptors (struct super_block * sb) ext4_debug ("Checking group descriptors"); - for (i = 0; i < sbi->s_groups_count; i++) - { + for (i = 0; i < sbi->s_groups_count; i++) { + struct ext4_group_desc *gdp = ext4_get_group_desc(sb, i, NULL); + if (i == sbi->s_groups_count - 1 || flexbg_flag) last_block = ext4_blocks_count(sbi->s_es) - 1; else last_block = first_block + (EXT4_BLOCKS_PER_GROUP(sb) - 1); - if ((i % EXT4_DESC_PER_BLOCK(sb)) == 0) - gdp = (struct ext4_group_desc *) - sbi->s_group_desc[desc_block++]->b_data; block_bitmap = ext4_block_bitmap(sb, gdp); if (block_bitmap < first_block || block_bitmap > last_block) { @@ -1524,8 +1520,6 @@ static int ext4_check_descriptors (struct super_block * sb) } if (!flexbg_flag) first_block += EXT4_BLOCKS_PER_GROUP(sb); - gdp = (struct ext4_group_desc *) - ((__u8 *)gdp + EXT4_DESC_SIZE(sb)); } ext4_free_blocks_count_set(sbi->s_es, ext4_count_free_blocks(sb)); diff --git a/fs/fat/file.c b/fs/fat/file.c index 69a83b59dce8..c614175876e0 100644 --- a/fs/fat/file.c +++ b/fs/fat/file.c @@ -155,6 +155,42 @@ out: return err; } +static int check_mode(const struct msdos_sb_info *sbi, mode_t mode) +{ + mode_t req = mode & ~S_IFMT; + + /* + * Of the r and x bits, all (subject to umask) must be present. Of the + * w bits, either all (subject to umask) or none must be present. + */ + + if (S_ISREG(mode)) { + req &= ~sbi->options.fs_fmask; + + if ((req & (S_IRUGO | S_IXUGO)) != + ((S_IRUGO | S_IXUGO) & ~sbi->options.fs_fmask)) + return -EPERM; + + if ((req & S_IWUGO) != 0 && + (req & S_IWUGO) != (S_IWUGO & ~sbi->options.fs_fmask)) + return -EPERM; + } else if (S_ISDIR(mode)) { + req &= ~sbi->options.fs_dmask; + + if ((req & (S_IRUGO | S_IXUGO)) != + ((S_IRUGO | S_IXUGO) & ~sbi->options.fs_dmask)) + return -EPERM; + + if ((req & S_IWUGO) != 0 && + (req & S_IWUGO) != (S_IWUGO & ~sbi->options.fs_dmask)) + return -EPERM; + } else { + return -EPERM; + } + + return 0; +} + int fat_notify_change(struct dentry *dentry, struct iattr *attr) { struct msdos_sb_info *sbi = MSDOS_SB(dentry->d_sb); @@ -186,9 +222,7 @@ int fat_notify_change(struct dentry *dentry, struct iattr *attr) if (((attr->ia_valid & ATTR_UID) && (attr->ia_uid != sbi->options.fs_uid)) || ((attr->ia_valid & ATTR_GID) && - (attr->ia_gid != sbi->options.fs_gid)) || - ((attr->ia_valid & ATTR_MODE) && - (attr->ia_mode & ~MSDOS_VALID_MODE))) + (attr->ia_gid != sbi->options.fs_gid))) error = -EPERM; if (error) { @@ -196,6 +230,13 @@ int fat_notify_change(struct dentry *dentry, struct iattr *attr) error = 0; goto out; } + + if (attr->ia_valid & ATTR_MODE) { + error = check_mode(sbi, attr->ia_mode); + if (error != 0 && !sbi->options.quiet) + goto out; + } + error = inode_setattr(inode, attr); if (error) goto out; diff --git a/fs/fat/inode.c b/fs/fat/inode.c index 920a576e1c25..24c0aaa5ae80 100644 --- a/fs/fat/inode.c +++ b/fs/fat/inode.c @@ -1295,10 +1295,8 @@ int fat_fill_super(struct super_block *sb, void *data, int silent, fsinfo = (struct fat_boot_fsinfo *)fsinfo_bh->b_data; if (!IS_FSINFO(fsinfo)) { - printk(KERN_WARNING - "FAT: Did not find valid FSINFO signature.\n" - " Found signature1 0x%08x signature2 0x%08x" - " (sector = %lu)\n", + printk(KERN_WARNING "FAT: Invalid FSINFO signature: " + "0x%08x, 0x%08x (sector = %lu)\n", le32_to_cpu(fsinfo->signature1), le32_to_cpu(fsinfo->signature2), sbi->fsinfo_sector); diff --git a/fs/fat/misc.c b/fs/fat/misc.c index 308f2b6b5026..61f23511eacf 100644 --- a/fs/fat/misc.c +++ b/fs/fat/misc.c @@ -55,9 +55,8 @@ void fat_clusters_flush(struct super_block *sb) fsinfo = (struct fat_boot_fsinfo *)bh->b_data; /* Sanity check */ if (!IS_FSINFO(fsinfo)) { - printk(KERN_ERR "FAT: Did not find valid FSINFO signature.\n" - " Found signature1 0x%08x signature2 0x%08x" - " (sector = %lu)\n", + printk(KERN_ERR "FAT: Invalid FSINFO signature: " + "0x%08x, 0x%08x (sector = %lu)\n", le32_to_cpu(fsinfo->signature1), le32_to_cpu(fsinfo->signature2), sbi->fsinfo_sector); diff --git a/fs/file.c b/fs/file.c index c5575de01113..5110acb1c9ef 100644 --- a/fs/file.c +++ b/fs/file.c @@ -24,6 +24,8 @@ struct fdtable_defer { struct fdtable *next; }; +int sysctl_nr_open __read_mostly = 1024*1024; + /* * We use this list to defer free fdtables that have vmalloced * sets/arrays. By keeping a per-cpu list, we avoid having to embed @@ -147,8 +149,8 @@ static struct fdtable * alloc_fdtable(unsigned int nr) nr /= (1024 / sizeof(struct file *)); nr = roundup_pow_of_two(nr + 1); nr *= (1024 / sizeof(struct file *)); - if (nr > NR_OPEN) - nr = NR_OPEN; + if (nr > sysctl_nr_open) + nr = sysctl_nr_open; fdt = kmalloc(sizeof(struct fdtable), GFP_KERNEL); if (!fdt) @@ -233,7 +235,7 @@ int expand_files(struct files_struct *files, int nr) if (nr < fdt->max_fds) return 0; /* Can we expand? */ - if (nr >= NR_OPEN) + if (nr >= sysctl_nr_open) return -EMFILE; /* All good, so we try */ diff --git a/fs/fs-writeback.c b/fs/fs-writeback.c index 0b3064079fa5..db80ce9eb1d0 100644 --- a/fs/fs-writeback.c +++ b/fs/fs-writeback.c @@ -515,8 +515,7 @@ writeback_inodes(struct writeback_control *wbc) might_sleep(); spin_lock(&sb_lock); restart: - sb = sb_entry(super_blocks.prev); - for (; sb != sb_entry(&super_blocks); sb = sb_entry(sb->s_list.prev)) { + list_for_each_entry_reverse(sb, &super_blocks, s_list) { if (sb_has_dirty_inodes(sb)) { /* we're making our own get_super here */ sb->s_count++; @@ -581,10 +580,8 @@ static void set_sb_syncing(int val) { struct super_block *sb; spin_lock(&sb_lock); - sb = sb_entry(super_blocks.prev); - for (; sb != sb_entry(&super_blocks); sb = sb_entry(sb->s_list.prev)) { + list_for_each_entry_reverse(sb, &super_blocks, s_list) sb->s_syncing = val; - } spin_unlock(&sb_lock); } diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c index db534bcde45f..af639807524e 100644 --- a/fs/fuse/dev.c +++ b/fs/fuse/dev.c @@ -201,6 +201,55 @@ void fuse_put_request(struct fuse_conn *fc, struct fuse_req *req) } } +static unsigned len_args(unsigned numargs, struct fuse_arg *args) +{ + unsigned nbytes = 0; + unsigned i; + + for (i = 0; i < numargs; i++) + nbytes += args[i].size; + + return nbytes; +} + +static u64 fuse_get_unique(struct fuse_conn *fc) +{ + fc->reqctr++; + /* zero is special */ + if (fc->reqctr == 0) + fc->reqctr = 1; + + return fc->reqctr; +} + +static void queue_request(struct fuse_conn *fc, struct fuse_req *req) +{ + req->in.h.unique = fuse_get_unique(fc); + req->in.h.len = sizeof(struct fuse_in_header) + + len_args(req->in.numargs, (struct fuse_arg *) req->in.args); + list_add_tail(&req->list, &fc->pending); + req->state = FUSE_REQ_PENDING; + if (!req->waiting) { + req->waiting = 1; + atomic_inc(&fc->num_waiting); + } + wake_up(&fc->waitq); + kill_fasync(&fc->fasync, SIGIO, POLL_IN); +} + +static void flush_bg_queue(struct fuse_conn *fc) +{ + while (fc->active_background < FUSE_MAX_BACKGROUND && + !list_empty(&fc->bg_queue)) { + struct fuse_req *req; + + req = list_entry(fc->bg_queue.next, struct fuse_req, list); + list_del(&req->list); + fc->active_background++; + queue_request(fc, req); + } +} + /* * This function is called when a request is finished. Either a reply * has arrived or it was aborted (and not yet sent) or some error @@ -229,6 +278,8 @@ static void request_end(struct fuse_conn *fc, struct fuse_req *req) clear_bdi_congested(&fc->bdi, WRITE); } fc->num_background--; + fc->active_background--; + flush_bg_queue(fc); } spin_unlock(&fc->lock); wake_up(&req->waitq); @@ -320,42 +371,6 @@ static void request_wait_answer(struct fuse_conn *fc, struct fuse_req *req) } } -static unsigned len_args(unsigned numargs, struct fuse_arg *args) -{ - unsigned nbytes = 0; - unsigned i; - - for (i = 0; i < numargs; i++) - nbytes += args[i].size; - - return nbytes; -} - -static u64 fuse_get_unique(struct fuse_conn *fc) - { - fc->reqctr++; - /* zero is special */ - if (fc->reqctr == 0) - fc->reqctr = 1; - - return fc->reqctr; -} - -static void queue_request(struct fuse_conn *fc, struct fuse_req *req) -{ - req->in.h.unique = fuse_get_unique(fc); - req->in.h.len = sizeof(struct fuse_in_header) + - len_args(req->in.numargs, (struct fuse_arg *) req->in.args); - list_add_tail(&req->list, &fc->pending); - req->state = FUSE_REQ_PENDING; - if (!req->waiting) { - req->waiting = 1; - atomic_inc(&fc->num_waiting); - } - wake_up(&fc->waitq); - kill_fasync(&fc->fasync, SIGIO, POLL_IN); -} - void request_send(struct fuse_conn *fc, struct fuse_req *req) { req->isreply = 1; @@ -375,20 +390,26 @@ void request_send(struct fuse_conn *fc, struct fuse_req *req) spin_unlock(&fc->lock); } +static void request_send_nowait_locked(struct fuse_conn *fc, + struct fuse_req *req) +{ + req->background = 1; + fc->num_background++; + if (fc->num_background == FUSE_MAX_BACKGROUND) + fc->blocked = 1; + if (fc->num_background == FUSE_CONGESTION_THRESHOLD) { + set_bdi_congested(&fc->bdi, READ); + set_bdi_congested(&fc->bdi, WRITE); + } + list_add_tail(&req->list, &fc->bg_queue); + flush_bg_queue(fc); +} + static void request_send_nowait(struct fuse_conn *fc, struct fuse_req *req) { spin_lock(&fc->lock); if (fc->connected) { - req->background = 1; - fc->num_background++; - if (fc->num_background == FUSE_MAX_BACKGROUND) - fc->blocked = 1; - if (fc->num_background == FUSE_CONGESTION_THRESHOLD) { - set_bdi_congested(&fc->bdi, READ); - set_bdi_congested(&fc->bdi, WRITE); - } - - queue_request(fc, req); + request_send_nowait_locked(fc, req); spin_unlock(&fc->lock); } else { req->out.h.error = -ENOTCONN; diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c index 80d2f5292cf9..f56f91bd38be 100644 --- a/fs/fuse/dir.c +++ b/fs/fuse/dir.c @@ -416,6 +416,7 @@ static int fuse_create_open(struct inode *dir, struct dentry *entry, int mode, fuse_put_request(fc, forget_req); d_instantiate(entry, inode); fuse_change_entry_timeout(entry, &outentry); + fuse_invalidate_attr(dir); file = lookup_instantiate_filp(nd, entry, generic_file_open); if (IS_ERR(file)) { ff->fh = outopen.fh; diff --git a/fs/fuse/file.c b/fs/fuse/file.c index bb05d227cf30..676b0bc8a86d 100644 --- a/fs/fuse/file.c +++ b/fs/fuse/file.c @@ -77,8 +77,8 @@ static struct fuse_file *fuse_file_get(struct fuse_file *ff) static void fuse_release_end(struct fuse_conn *fc, struct fuse_req *req) { - dput(req->dentry); - mntput(req->vfsmount); + dput(req->misc.release.dentry); + mntput(req->misc.release.vfsmount); fuse_put_request(fc, req); } @@ -86,7 +86,8 @@ static void fuse_file_put(struct fuse_file *ff) { if (atomic_dec_and_test(&ff->count)) { struct fuse_req *req = ff->reserved_req; - struct fuse_conn *fc = get_fuse_conn(req->dentry->d_inode); + struct inode *inode = req->misc.release.dentry->d_inode; + struct fuse_conn *fc = get_fuse_conn(inode); req->end = fuse_release_end; request_send_background(fc, req); kfree(ff); @@ -137,7 +138,7 @@ int fuse_open_common(struct inode *inode, struct file *file, int isdir) void fuse_release_fill(struct fuse_file *ff, u64 nodeid, int flags, int opcode) { struct fuse_req *req = ff->reserved_req; - struct fuse_release_in *inarg = &req->misc.release_in; + struct fuse_release_in *inarg = &req->misc.release.in; inarg->fh = ff->fh; inarg->flags = flags; @@ -153,13 +154,14 @@ int fuse_release_common(struct inode *inode, struct file *file, int isdir) struct fuse_file *ff = file->private_data; if (ff) { struct fuse_conn *fc = get_fuse_conn(inode); + struct fuse_req *req = ff->reserved_req; fuse_release_fill(ff, get_node_id(inode), file->f_flags, isdir ? FUSE_RELEASEDIR : FUSE_RELEASE); /* Hold vfsmount and dentry until release is finished */ - ff->reserved_req->vfsmount = mntget(file->f_path.mnt); - ff->reserved_req->dentry = dget(file->f_path.dentry); + req->misc.release.vfsmount = mntget(file->f_path.mnt); + req->misc.release.dentry = dget(file->f_path.dentry); spin_lock(&fc->lock); list_del(&ff->write_entry); diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h index 3ab8a3048e8b..67aaf6ee38ea 100644 --- a/fs/fuse/fuse_i.h +++ b/fs/fuse/fuse_i.h @@ -215,7 +215,11 @@ struct fuse_req { /** Data for asynchronous requests */ union { struct fuse_forget_in forget_in; - struct fuse_release_in release_in; + struct { + struct fuse_release_in in; + struct vfsmount *vfsmount; + struct dentry *dentry; + } release; struct fuse_init_in init_in; struct fuse_init_out init_out; struct fuse_read_in read_in; @@ -238,12 +242,6 @@ struct fuse_req { /** File used in the request (or NULL) */ struct fuse_file *ff; - /** vfsmount used in release */ - struct vfsmount *vfsmount; - - /** dentry used in release */ - struct dentry *dentry; - /** Request completion callback */ void (*end)(struct fuse_conn *, struct fuse_req *); @@ -298,6 +296,12 @@ struct fuse_conn { /** Number of requests currently in the background */ unsigned num_background; + /** Number of background requests currently queued for userspace */ + unsigned active_background; + + /** The list of background requests set aside for later queuing */ + struct list_head bg_queue; + /** Pending interrupts */ struct list_head interrupts; diff --git a/fs/fuse/inode.c b/fs/fuse/inode.c index e5e80d1a4687..c90f633d0b57 100644 --- a/fs/fuse/inode.c +++ b/fs/fuse/inode.c @@ -465,6 +465,7 @@ static struct fuse_conn *new_conn(void) INIT_LIST_HEAD(&fc->processing); INIT_LIST_HEAD(&fc->io); INIT_LIST_HEAD(&fc->interrupts); + INIT_LIST_HEAD(&fc->bg_queue); atomic_set(&fc->num_waiting, 0); fc->bdi.ra_pages = (VM_MAX_READAHEAD * 1024) / PAGE_CACHE_SIZE; fc->bdi.unplug_io_fn = default_unplug_io_fn; diff --git a/fs/hfs/bfind.c b/fs/hfs/bfind.c index f8452a0eab56..4129cdb3f0d8 100644 --- a/fs/hfs/bfind.c +++ b/fs/hfs/bfind.c @@ -52,9 +52,9 @@ int __hfs_brec_find(struct hfs_bnode *bnode, struct hfs_find_data *fd) rec = (e + b) / 2; len = hfs_brec_lenoff(bnode, rec, &off); keylen = hfs_brec_keylen(bnode, rec); - if (keylen == HFS_BAD_KEYLEN) { + if (keylen == 0) { res = -EINVAL; - goto done; + goto fail; } hfs_bnode_read(bnode, fd->key, off, keylen); cmpval = bnode->tree->keycmp(fd->key, fd->search_key); @@ -71,9 +71,9 @@ int __hfs_brec_find(struct hfs_bnode *bnode, struct hfs_find_data *fd) if (rec != e && e >= 0) { len = hfs_brec_lenoff(bnode, e, &off); keylen = hfs_brec_keylen(bnode, e); - if (keylen == HFS_BAD_KEYLEN) { + if (keylen == 0) { res = -EINVAL; - goto done; + goto fail; } hfs_bnode_read(bnode, fd->key, off, keylen); } @@ -83,6 +83,7 @@ done: fd->keylength = keylen; fd->entryoffset = off + keylen; fd->entrylength = len - keylen; +fail: return res; } @@ -206,7 +207,7 @@ int hfs_brec_goto(struct hfs_find_data *fd, int cnt) len = hfs_brec_lenoff(bnode, fd->record, &off); keylen = hfs_brec_keylen(bnode, fd->record); - if (keylen == HFS_BAD_KEYLEN) { + if (keylen == 0) { res = -EINVAL; goto out; } diff --git a/fs/hfs/brec.c b/fs/hfs/brec.c index 8626ee375ea8..878bf25dbc6a 100644 --- a/fs/hfs/brec.c +++ b/fs/hfs/brec.c @@ -49,14 +49,14 @@ u16 hfs_brec_keylen(struct hfs_bnode *node, u16 rec) if (retval > node->tree->max_key_len + 2) { printk(KERN_ERR "hfs: keylen %d too large\n", retval); - retval = HFS_BAD_KEYLEN; + retval = 0; } } else { retval = (hfs_bnode_read_u8(node, recoff) | 1) + 1; if (retval > node->tree->max_key_len + 1) { printk(KERN_ERR "hfs: keylen %d too large\n", retval); - retval = HFS_BAD_KEYLEN; + retval = 0; } } } diff --git a/fs/hfs/btree.c b/fs/hfs/btree.c index 110dd3515dc8..24cf6fc43021 100644 --- a/fs/hfs/btree.c +++ b/fs/hfs/btree.c @@ -81,15 +81,23 @@ struct hfs_btree *hfs_btree_open(struct super_block *sb, u32 id, btree_keycmp ke goto fail_page; if (!tree->node_count) goto fail_page; - if ((id == HFS_EXT_CNID) && (tree->max_key_len != HFS_MAX_EXT_KEYLEN)) { - printk(KERN_ERR "hfs: invalid extent max_key_len %d\n", - tree->max_key_len); - goto fail_page; - } - if ((id == HFS_CAT_CNID) && (tree->max_key_len != HFS_MAX_CAT_KEYLEN)) { - printk(KERN_ERR "hfs: invalid catalog max_key_len %d\n", - tree->max_key_len); - goto fail_page; + switch (id) { + case HFS_EXT_CNID: + if (tree->max_key_len != HFS_MAX_EXT_KEYLEN) { + printk(KERN_ERR "hfs: invalid extent max_key_len %d\n", + tree->max_key_len); + goto fail_page; + } + break; + case HFS_CAT_CNID: + if (tree->max_key_len != HFS_MAX_CAT_KEYLEN) { + printk(KERN_ERR "hfs: invalid catalog max_key_len %d\n", + tree->max_key_len); + goto fail_page; + } + break; + default: + BUG(); } tree->node_size_shift = ffs(size) - 1; diff --git a/fs/hfs/hfs.h b/fs/hfs/hfs.h index c6aae61adfe6..6f194d0768b6 100644 --- a/fs/hfs/hfs.h +++ b/fs/hfs/hfs.h @@ -28,8 +28,6 @@ #define HFS_MAX_NAMELEN 128 #define HFS_MAX_VALENCE 32767U -#define HFS_BAD_KEYLEN 0xFF - /* Meanings of the drAtrb field of the MDB, * Reference: _Inside Macintosh: Files_ p. 2-61 */ diff --git a/fs/hfs/super.c b/fs/hfs/super.c index 16cbd902f8b9..32de44ed0021 100644 --- a/fs/hfs/super.c +++ b/fs/hfs/super.c @@ -6,7 +6,7 @@ * This file may be distributed under the terms of the GNU General Public License. * * This file contains hfs_read_super(), some of the super_ops and - * init_module() and cleanup_module(). The remaining super_ops are in + * init_hfs_fs() and exit_hfs_fs(). The remaining super_ops are in * inode.c since they deal with inodes. * * Based on the minix file system code, (C) 1991, 1992 by Linus Torvalds diff --git a/fs/inotify.c b/fs/inotify.c index 2c5b92152876..690e72595e6e 100644 --- a/fs/inotify.c +++ b/fs/inotify.c @@ -168,20 +168,14 @@ static void set_dentry_child_flags(struct inode *inode, int watched) struct dentry *child; list_for_each_entry(child, &alias->d_subdirs, d_u.d_child) { - if (!child->d_inode) { - WARN_ON(child->d_flags & DCACHE_INOTIFY_PARENT_WATCHED); + if (!child->d_inode) continue; - } + spin_lock(&child->d_lock); - if (watched) { - WARN_ON(child->d_flags & - DCACHE_INOTIFY_PARENT_WATCHED); + if (watched) child->d_flags |= DCACHE_INOTIFY_PARENT_WATCHED; - } else { - WARN_ON(!(child->d_flags & - DCACHE_INOTIFY_PARENT_WATCHED)); - child->d_flags&=~DCACHE_INOTIFY_PARENT_WATCHED; - } + else + child->d_flags &=~DCACHE_INOTIFY_PARENT_WATCHED; spin_unlock(&child->d_lock); } } @@ -253,7 +247,6 @@ void inotify_d_instantiate(struct dentry *entry, struct inode *inode) if (!inode) return; - WARN_ON(entry->d_flags & DCACHE_INOTIFY_PARENT_WATCHED); spin_lock(&entry->d_lock); parent = entry->d_parent; if (parent->d_inode && inotify_inode_watched(parent->d_inode)) @@ -627,6 +620,7 @@ s32 inotify_add_watch(struct inotify_handle *ih, struct inotify_watch *watch, struct inode *inode, u32 mask) { int ret = 0; + int newly_watched; /* don't allow invalid bits: we don't want flags set */ mask &= IN_ALL_EVENTS | IN_ONESHOT; @@ -653,12 +647,18 @@ s32 inotify_add_watch(struct inotify_handle *ih, struct inotify_watch *watch, */ watch->inode = igrab(inode); - if (!inotify_inode_watched(inode)) - set_dentry_child_flags(inode, 1); - /* Add the watch to the handle's and the inode's list */ + newly_watched = !inotify_inode_watched(inode); list_add(&watch->h_list, &ih->watches); list_add(&watch->i_list, &inode->inotify_watches); + /* + * Set child flags _after_ adding the watch, so there is no race + * windows where newly instantiated children could miss their parent's + * watched flag. + */ + if (newly_watched) + set_dentry_child_flags(inode, 1); + out: mutex_unlock(&ih->mutex); mutex_unlock(&inode->inotify_mutex); diff --git a/fs/inotify_user.c b/fs/inotify_user.c index 5e009331c01f..a336c9709f3c 100644 --- a/fs/inotify_user.c +++ b/fs/inotify_user.c @@ -79,6 +79,7 @@ struct inotify_device { atomic_t count; /* reference count */ struct user_struct *user; /* user who opened this dev */ struct inotify_handle *ih; /* inotify handle */ + struct fasync_struct *fa; /* async notification */ unsigned int queue_size; /* size of the queue (bytes) */ unsigned int event_count; /* number of pending events */ unsigned int max_events; /* maximum number of events */ @@ -248,6 +249,19 @@ inotify_dev_get_event(struct inotify_device *dev) } /* + * inotify_dev_get_last_event - return the last event in the given dev's queue + * + * Caller must hold dev->ev_mutex. + */ +static inline struct inotify_kernel_event * +inotify_dev_get_last_event(struct inotify_device *dev) +{ + if (list_empty(&dev->events)) + return NULL; + return list_entry(dev->events.prev, struct inotify_kernel_event, list); +} + +/* * inotify_dev_queue_event - event handler registered with core inotify, adds * a new event to the given device * @@ -273,7 +287,7 @@ static void inotify_dev_queue_event(struct inotify_watch *w, u32 wd, u32 mask, put_inotify_watch(w); /* final put */ /* coalescing: drop this event if it is a dupe of the previous */ - last = inotify_dev_get_event(dev); + last = inotify_dev_get_last_event(dev); if (last && last->event.mask == mask && last->event.wd == wd && last->event.cookie == cookie) { const char *lastname = last->name; @@ -302,6 +316,7 @@ static void inotify_dev_queue_event(struct inotify_watch *w, u32 wd, u32 mask, dev->queue_size += sizeof(struct inotify_event) + kevent->event.len; list_add_tail(&kevent->list, &dev->events); wake_up_interruptible(&dev->wq); + kill_fasync(&dev->fa, SIGIO, POLL_IN); out: mutex_unlock(&dev->ev_mutex); @@ -490,6 +505,13 @@ static ssize_t inotify_read(struct file *file, char __user *buf, return ret; } +static int inotify_fasync(int fd, struct file *file, int on) +{ + struct inotify_device *dev = file->private_data; + + return fasync_helper(fd, file, on, &dev->fa) >= 0 ? 0 : -EIO; +} + static int inotify_release(struct inode *ignored, struct file *file) { struct inotify_device *dev = file->private_data; @@ -502,6 +524,9 @@ static int inotify_release(struct inode *ignored, struct file *file) inotify_dev_event_dequeue(dev); mutex_unlock(&dev->ev_mutex); + if (file->f_flags & FASYNC) + inotify_fasync(-1, file, 0); + /* free this device: the put matching the get in inotify_init() */ put_inotify_dev(dev); @@ -530,6 +555,7 @@ static long inotify_ioctl(struct file *file, unsigned int cmd, static const struct file_operations inotify_fops = { .poll = inotify_poll, .read = inotify_read, + .fasync = inotify_fasync, .release = inotify_release, .unlocked_ioctl = inotify_ioctl, .compat_ioctl = inotify_ioctl, @@ -577,6 +603,7 @@ asmlinkage long sys_inotify_init(void) goto out_free_dev; } dev->ih = ih; + dev->fa = NULL; filp->f_op = &inotify_fops; filp->f_path.mnt = mntget(inotify_mnt); diff --git a/fs/jbd/journal.c b/fs/jbd/journal.c index 5d14243499d4..3943a8905eb2 100644 --- a/fs/jbd/journal.c +++ b/fs/jbd/journal.c @@ -1457,7 +1457,7 @@ static const char *journal_dev_name(journal_t *journal, char *buffer) * Aborts hard --- we mark the abort as occurred, but do _nothing_ else, * and don't attempt to make any other journal updates. */ -void __journal_abort_hard(journal_t *journal) +static void __journal_abort_hard(journal_t *journal) { transaction_t *transaction; char b[BDEVNAME_SIZE]; diff --git a/fs/jbd/recovery.c b/fs/jbd/recovery.c index c5d9694b6a2f..2b8edf4d6eaa 100644 --- a/fs/jbd/recovery.c +++ b/fs/jbd/recovery.c @@ -354,7 +354,7 @@ static int do_one_pass(journal_t *journal, struct buffer_head * obh; struct buffer_head * nbh; - cond_resched(); /* We're under lock_kernel() */ + cond_resched(); /* If we already know where to stop the log traversal, * check right now that we haven't gone past the end of diff --git a/fs/jbd2/recovery.c b/fs/jbd2/recovery.c index 921680663fa2..d36356f7d222 100644 --- a/fs/jbd2/recovery.c +++ b/fs/jbd2/recovery.c @@ -397,7 +397,7 @@ static int do_one_pass(journal_t *journal, struct buffer_head * obh; struct buffer_head * nbh; - cond_resched(); /* We're under lock_kernel() */ + cond_resched(); /* If we already know where to stop the log traversal, * check right now that we haven't gone past the end of diff --git a/fs/namei.c b/fs/namei.c index 73e2e665817a..241cff423653 100644 --- a/fs/namei.c +++ b/fs/namei.c @@ -2188,6 +2188,7 @@ int vfs_unlink(struct inode *dir, struct dentry *dentry) /* We don't d_delete() NFS sillyrenamed files--they still exist. */ if (!error && !(dentry->d_flags & DCACHE_NFSFS_RENAMED)) { + fsnotify_link_count(dentry->d_inode); d_delete(dentry); } @@ -2360,7 +2361,7 @@ int vfs_link(struct dentry *old_dentry, struct inode *dir, struct dentry *new_de error = dir->i_op->link(old_dentry, dir, new_dentry); mutex_unlock(&old_dentry->d_inode->i_mutex); if (!error) - fsnotify_create(dir, new_dentry); + fsnotify_link(dir, old_dentry->d_inode, new_dentry); return error; } diff --git a/fs/namespace.c b/fs/namespace.c index 61bf376e29e8..e9c10cd01e13 100644 --- a/fs/namespace.c +++ b/fs/namespace.c @@ -25,18 +25,21 @@ #include <linux/security.h> #include <linux/mount.h> #include <linux/ramfs.h> +#include <linux/log2.h> #include <asm/uaccess.h> #include <asm/unistd.h> #include "pnode.h" #include "internal.h" +#define HASH_SHIFT ilog2(PAGE_SIZE / sizeof(struct list_head)) +#define HASH_SIZE (1UL << HASH_SHIFT) + /* spinlock for vfsmount related operations, inplace of dcache_lock */ __cacheline_aligned_in_smp DEFINE_SPINLOCK(vfsmount_lock); static int event; static struct list_head *mount_hashtable __read_mostly; -static int hash_mask __read_mostly, hash_bits __read_mostly; static struct kmem_cache *mnt_cache __read_mostly; static struct rw_semaphore namespace_sem; @@ -48,8 +51,8 @@ static inline unsigned long hash(struct vfsmount *mnt, struct dentry *dentry) { unsigned long tmp = ((unsigned long)mnt / L1_CACHE_BYTES); tmp += ((unsigned long)dentry / L1_CACHE_BYTES); - tmp = tmp + (tmp >> hash_bits); - return tmp & hash_mask; + tmp = tmp + (tmp >> HASH_SHIFT); + return tmp & (HASH_SIZE - 1); } struct vfsmount *alloc_vfsmnt(const char *name) @@ -1813,9 +1816,7 @@ static void __init init_mount_tree(void) void __init mnt_init(void) { - struct list_head *d; - unsigned int nr_hash; - int i; + unsigned u; int err; init_rwsem(&namespace_sem); @@ -1828,35 +1829,11 @@ void __init mnt_init(void) if (!mount_hashtable) panic("Failed to allocate mount hash table\n"); - /* - * Find the power-of-two list-heads that can fit into the allocation.. - * We don't guarantee that "sizeof(struct list_head)" is necessarily - * a power-of-two. - */ - nr_hash = PAGE_SIZE / sizeof(struct list_head); - hash_bits = 0; - do { - hash_bits++; - } while ((nr_hash >> hash_bits) != 0); - hash_bits--; + printk("Mount-cache hash table entries: %lu\n", HASH_SIZE); + + for (u = 0; u < HASH_SIZE; u++) + INIT_LIST_HEAD(&mount_hashtable[u]); - /* - * Re-calculate the actual number of entries and the mask - * from the number of bits we can fit. - */ - nr_hash = 1UL << hash_bits; - hash_mask = nr_hash - 1; - - printk("Mount-cache hash table entries: %d\n", nr_hash); - - /* And initialize the newly allocated array */ - d = mount_hashtable; - i = nr_hash; - do { - INIT_LIST_HEAD(d); - d++; - i--; - } while (i); err = sysfs_init(); if (err) printk(KERN_WARNING "%s: sysfs_init error: %d\n", diff --git a/fs/ncpfs/inode.c b/fs/ncpfs/inode.c index e1cb70c643f8..eff1f18d034f 100644 --- a/fs/ncpfs/inode.c +++ b/fs/ncpfs/inode.c @@ -987,7 +987,7 @@ static struct file_system_type ncp_fs_type = { static int __init init_ncp_fs(void) { int err; - DPRINTK("ncpfs: init_module called\n"); + DPRINTK("ncpfs: init_ncp_fs called\n"); err = init_inodecache(); if (err) @@ -1004,7 +1004,7 @@ out1: static void __exit exit_ncp_fs(void) { - DPRINTK("ncpfs: cleanup_module called\n"); + DPRINTK("ncpfs: exit_ncp_fs called\n"); unregister_filesystem(&ncp_fs_type); destroy_inodecache(); } diff --git a/fs/partitions/Kconfig b/fs/partitions/Kconfig index a99acd8de353..cb5f0a3f1b03 100644 --- a/fs/partitions/Kconfig +++ b/fs/partitions/Kconfig @@ -198,7 +198,7 @@ config LDM_DEBUG config SGI_PARTITION bool "SGI partition support" if PARTITION_ADVANCED - default y if (SGI_IP22 || SGI_IP27 || ((MACH_JAZZ || SNI_RM) && !CPU_LITTLE_ENDIAN)) + default y if DEFAULT_SGI_PARTITION help Say Y here if you would like to be able to read the hard disk partition table format used by SGI machines. diff --git a/fs/pnode.c b/fs/pnode.c index 89940f243fc2..05ba692bc540 100644 --- a/fs/pnode.c +++ b/fs/pnode.c @@ -83,6 +83,8 @@ void change_mnt_propagation(struct vfsmount *mnt, int type) mnt->mnt_master = NULL; if (type == MS_UNBINDABLE) mnt->mnt_flags |= MNT_UNBINDABLE; + else + mnt->mnt_flags &= ~MNT_UNBINDABLE; } } diff --git a/fs/proc/proc_misc.c b/fs/proc/proc_misc.c index 51288db37a0c..2686592dbcb2 100644 --- a/fs/proc/proc_misc.c +++ b/fs/proc/proc_misc.c @@ -29,6 +29,7 @@ #include <linux/mm.h> #include <linux/mmzone.h> #include <linux/pagemap.h> +#include <linux/interrupt.h> #include <linux/swap.h> #include <linux/slab.h> #include <linux/smp.h> @@ -64,7 +65,6 @@ */ extern int get_hardware_list(char *); extern int get_stram_list(char *); -extern int get_filesystem_list(char *); extern int get_exec_domain_list(char *); extern int get_dma_list(char *); @@ -84,10 +84,15 @@ static int loadavg_read_proc(char *page, char **start, off_t off, { int a, b, c; int len; + unsigned long seq; + + do { + seq = read_seqbegin(&xtime_lock); + a = avenrun[0] + (FIXED_1/200); + b = avenrun[1] + (FIXED_1/200); + c = avenrun[2] + (FIXED_1/200); + } while (read_seqretry(&xtime_lock, seq)); - a = avenrun[0] + (FIXED_1/200); - b = avenrun[1] + (FIXED_1/200); - c = avenrun[2] + (FIXED_1/200); len = sprintf(page,"%d.%02d %d.%02d %d.%02d %ld/%d %d\n", LOAD_INT(a), LOAD_FRAC(a), LOAD_INT(b), LOAD_FRAC(b), @@ -599,7 +604,6 @@ static void int_seq_stop(struct seq_file *f, void *v) } -extern int show_interrupts(struct seq_file *f, void *v); /* In arch code */ static struct seq_operations int_seq_ops = { .start = int_seq_start, .next = int_seq_next, diff --git a/fs/reiserfs/prints.c b/fs/reiserfs/prints.c index 5e7388b32d02..740bb8c0c1ae 100644 --- a/fs/reiserfs/prints.c +++ b/fs/reiserfs/prints.c @@ -575,6 +575,8 @@ void print_block(struct buffer_head *bh, ...) //int print_mode, int first, int l printk ("Block %llu contains unformatted data\n", (unsigned long long)bh->b_blocknr); + + va_end(args); } static char print_tb_buf[2048]; diff --git a/fs/reiserfs/xattr.c b/fs/reiserfs/xattr.c index 1597f6b649e0..a5bd23ce0e46 100644 --- a/fs/reiserfs/xattr.c +++ b/fs/reiserfs/xattr.c @@ -1084,7 +1084,7 @@ ssize_t reiserfs_listxattr(struct dentry * dentry, char *buffer, size_t size) } /* This is the implementation for the xattr plugin infrastructure */ -static struct list_head xattr_handlers = LIST_HEAD_INIT(xattr_handlers); +static LIST_HEAD(xattr_handlers); static DEFINE_RWLOCK(handler_lock); static struct reiserfs_xattr_handler *find_xattr_handler_prefix(const char diff --git a/fs/select.c b/fs/select.c index 47f47925aea2..5633fe980781 100644 --- a/fs/select.c +++ b/fs/select.c @@ -739,7 +739,7 @@ asmlinkage long sys_poll(struct pollfd __user *ufds, unsigned int nfds, timeout_jiffies = -1; else #endif - timeout_jiffies = msecs_to_jiffies(timeout_msecs); + timeout_jiffies = msecs_to_jiffies(timeout_msecs) + 1; } else { /* Infinite (< 0) or no (0) timeout */ timeout_jiffies = timeout_msecs; diff --git a/fs/signalfd.c b/fs/signalfd.c index 2d3e107da2d3..cb2b63ae0bf4 100644 --- a/fs/signalfd.c +++ b/fs/signalfd.c @@ -27,6 +27,7 @@ #include <linux/list.h> #include <linux/anon_inodes.h> #include <linux/signalfd.h> +#include <linux/syscalls.h> struct signalfd_ctx { sigset_t sigmask; diff --git a/fs/smbfs/inode.c b/fs/smbfs/inode.c index 9416ead0c7aa..4e5c22ca802e 100644 --- a/fs/smbfs/inode.c +++ b/fs/smbfs/inode.c @@ -500,6 +500,13 @@ static int smb_fill_super(struct super_block *sb, void *raw_data, int silent) struct smb_fattr root; int ver; void *mem; + static int warn_count; + + if (warn_count < 5) { + warn_count++; + printk(KERN_EMERG "smbfs is deprecated and will be removed" + "from the 2.6.27 kernel. Please migrate to cifs\n"); + } if (!raw_data) goto out_no_data; diff --git a/fs/smbfs/sock.c b/fs/smbfs/sock.c index e48bd8235a8e..e37fe4deebd0 100644 --- a/fs/smbfs/sock.c +++ b/fs/smbfs/sock.c @@ -329,9 +329,8 @@ smb_receive(struct smb_sb_info *server, struct smb_request *req) msg.msg_control = NULL; /* Dont repeat bytes and count available bufferspace */ - rlen = smb_move_iov(&p, &num, iov, req->rq_bytes_recvd); - if (req->rq_rlen < rlen) - rlen = req->rq_rlen; + rlen = min_t(int, smb_move_iov(&p, &num, iov, req->rq_bytes_recvd), + (req->rq_rlen - req->rq_bytes_recvd)); result = kernel_recvmsg(sock, &msg, p, num, rlen, flags); diff --git a/fs/utimes.c b/fs/utimes.c index b9912ecbee24..e5588cd8530e 100644 --- a/fs/utimes.c +++ b/fs/utimes.c @@ -6,6 +6,7 @@ #include <linux/sched.h> #include <linux/stat.h> #include <linux/utime.h> +#include <linux/syscalls.h> #include <asm/uaccess.h> #include <asm/unistd.h> diff --git a/include/asm-arm/arch-s3c2410/regs-lcd.h b/include/asm-arm/arch-s3c2410/regs-lcd.h index 76fe5f693426..bd854845697f 100644 --- a/include/asm-arm/arch-s3c2410/regs-lcd.h +++ b/include/asm-arm/arch-s3c2410/regs-lcd.h @@ -147,7 +147,16 @@ #define S3C2412_FRCPAT(x) S3C2410_LCDREG(0xB4 + ((x)*4)) -#endif /* ___ASM_ARCH_REGS_LCD_H */ +/* general registers */ + +/* base of the LCD registers, where INTPND, INTSRC and then INTMSK + * are available. */ +#define S3C2410_LCDINTBASE S3C2410_LCDREG(0x54) +#define S3C2412_LCDINTBASE S3C2410_LCDREG(0x24) +#define S3C24XX_LCDINTPND (0x00) +#define S3C24XX_LCDSRCPND (0x04) +#define S3C24XX_LCDINTMSK (0x08) +#endif /* ___ASM_ARCH_REGS_LCD_H */ diff --git a/include/asm-arm/arch-s3c2410/spi-gpio.h b/include/asm-arm/arch-s3c2410/spi-gpio.h index ba1dca88d480..73803731142a 100644 --- a/include/asm-arm/arch-s3c2410/spi-gpio.h +++ b/include/asm-arm/arch-s3c2410/spi-gpio.h @@ -13,9 +13,6 @@ #ifndef __ASM_ARCH_SPIGPIO_H #define __ASM_ARCH_SPIGPIO_H __FILE__ -struct s3c2410_spigpio_info; -struct spi_board_info; - struct s3c2410_spigpio_info { unsigned long pin_clk; unsigned long pin_mosi; @@ -23,9 +20,6 @@ struct s3c2410_spigpio_info { int bus_num; - unsigned long board_size; - struct spi_board_info *board_info; - void (*chip_select)(struct s3c2410_spigpio_info *spi, int cs); }; diff --git a/include/asm-arm/arch-s3c2410/spi.h b/include/asm-arm/arch-s3c2410/spi.h index 4029a1a1ab40..7ca0ed97a6d0 100644 --- a/include/asm-arm/arch-s3c2410/spi.h +++ b/include/asm-arm/arch-s3c2410/spi.h @@ -13,15 +13,9 @@ #ifndef __ASM_ARCH_SPI_H #define __ASM_ARCH_SPI_H __FILE__ -struct s3c2410_spi_info; -struct spi_board_info; - struct s3c2410_spi_info { unsigned long pin_cs; /* simple gpio cs */ - unsigned long board_size; - struct spi_board_info *board_info; - void (*set_cs)(struct s3c2410_spi_info *spi, int cs, int pol); }; diff --git a/include/asm-avr32/delay.h b/include/asm-avr32/delay.h index cc3b2e3343b3..a0ed9a9839a5 100644 --- a/include/asm-avr32/delay.h +++ b/include/asm-avr32/delay.h @@ -12,7 +12,7 @@ extern void __bad_ndelay(void); extern void __udelay(unsigned long usecs); extern void __ndelay(unsigned long nsecs); -extern void __const_udelay(unsigned long usecs); +extern void __const_udelay(unsigned long xloops); extern void __delay(unsigned long loops); #define udelay(n) (__builtin_constant_p(n) ? \ diff --git a/include/asm-avr32/timex.h b/include/asm-avr32/timex.h index 5e44ecb3ce0c..187dcf38b210 100644 --- a/include/asm-avr32/timex.h +++ b/include/asm-avr32/timex.h @@ -34,7 +34,6 @@ static inline cycles_t get_cycles (void) return 0; } -extern int read_current_timer(unsigned long *timer_value); -#define ARCH_HAS_READ_CURRENT_TIMER 1 +#define ARCH_HAS_READ_CURRENT_TIMER #endif /* __ASM_AVR32_TIMEX_H */ diff --git a/include/asm-avr32/unistd.h b/include/asm-avr32/unistd.h index de09009593f8..89861a27543e 100644 --- a/include/asm-avr32/unistd.h +++ b/include/asm-avr32/unistd.h @@ -297,7 +297,7 @@ #define __NR_utimensat 278 #define __NR_signalfd 279 -#define __NR_timerfd 280 +/* 280 was __NR_timerfd */ #define __NR_eventfd 281 #ifdef __KERNEL__ diff --git a/include/asm-blackfin/io.h b/include/asm-blackfin/io.h index 1601d62f39a5..574fe56989d1 100644 --- a/include/asm-blackfin/io.h +++ b/include/asm-blackfin/io.h @@ -188,8 +188,6 @@ extern void blkfin_inv_cache_all(void); #define page_to_phys(page) ((page - mem_map) << PAGE_SHIFT) #define page_to_bus(page) ((page - mem_map) << PAGE_SHIFT) -#define mm_ptov(vaddr) ((void *) (vaddr)) -#define mm_vtop(vaddr) ((unsigned long) (vaddr)) #define phys_to_virt(vaddr) ((void *) (vaddr)) #define virt_to_phys(vaddr) ((unsigned long) (vaddr)) diff --git a/include/asm-frv/unistd.h b/include/asm-frv/unistd.h index cd84f1771e34..e8c986667532 100644 --- a/include/asm-frv/unistd.h +++ b/include/asm-frv/unistd.h @@ -328,7 +328,7 @@ #define __NR_epoll_pwait 319 #define __NR_utimensat 320 #define __NR_signalfd 321 -#define __NR_timerfd 322 +/* #define __NR_timerfd 322 removed */ #define __NR_eventfd 323 #define __NR_fallocate 324 diff --git a/include/asm-generic/cputime.h b/include/asm-generic/cputime.h index 09204e40d663..1c1fa422d18a 100644 --- a/include/asm-generic/cputime.h +++ b/include/asm-generic/cputime.h @@ -18,6 +18,7 @@ typedef unsigned long cputime_t; #define cputime_lt(__a, __b) ((__a) < (__b)) #define cputime_le(__a, __b) ((__a) <= (__b)) #define cputime_to_jiffies(__ct) (__ct) +#define cputime_to_scaled(__ct) (__ct) #define jiffies_to_cputime(__hz) (__hz) typedef u64 cputime64_t; diff --git a/include/asm-generic/sections.h b/include/asm-generic/sections.h index 962cad7cfbbd..8feeae1f2369 100644 --- a/include/asm-generic/sections.h +++ b/include/asm-generic/sections.h @@ -8,8 +8,6 @@ extern char _data[], _sdata[], _edata[]; extern char __bss_start[], __bss_stop[]; extern char __init_begin[], __init_end[]; extern char _sinittext[], _einittext[]; -extern char _sextratext[] __attribute__((weak)); -extern char _eextratext[] __attribute__((weak)); extern char _end[]; extern char __per_cpu_start[], __per_cpu_end[]; extern char __kprobes_text_start[], __kprobes_text_end[]; diff --git a/include/asm-h8300/io.h b/include/asm-h8300/io.h index 7543a57b4ea1..26dc6ccd9441 100644 --- a/include/asm-h8300/io.h +++ b/include/asm-h8300/io.h @@ -302,8 +302,6 @@ static __inline__ void ctrl_outl(unsigned long b, unsigned long addr) /* * Macros used for converting between virtual and physical mappings. */ -#define mm_ptov(vaddr) ((void *) (vaddr)) -#define mm_vtop(vaddr) ((unsigned long) (vaddr)) #define phys_to_virt(vaddr) ((void *) (vaddr)) #define virt_to_phys(vaddr) ((unsigned long) (vaddr)) diff --git a/include/asm-h8300/virtconvert.h b/include/asm-h8300/virtconvert.h index ee7d5ea10065..19cfd62b11c3 100644 --- a/include/asm-h8300/virtconvert.h +++ b/include/asm-h8300/virtconvert.h @@ -10,8 +10,6 @@ #include <asm/setup.h> #include <asm/page.h> -#define mm_ptov(vaddr) ((void *) (vaddr)) -#define mm_vtop(vaddr) ((unsigned long) (vaddr)) #define phys_to_virt(vaddr) ((void *) (vaddr)) #define virt_to_phys(vaddr) ((unsigned long) (vaddr)) diff --git a/include/asm-m32r/delay.h b/include/asm-m32r/delay.h index 164448d23850..9dd9e999ea69 100644 --- a/include/asm-m32r/delay.h +++ b/include/asm-m32r/delay.h @@ -12,7 +12,7 @@ extern void __bad_ndelay(void); extern void __udelay(unsigned long usecs); extern void __ndelay(unsigned long nsecs); -extern void __const_udelay(unsigned long usecs); +extern void __const_udelay(unsigned long xloops); extern void __delay(unsigned long loops); #define udelay(n) (__builtin_constant_p(n) ? \ diff --git a/include/asm-m32r/unistd.h b/include/asm-m32r/unistd.h index f467eac9ba70..cf701c933249 100644 --- a/include/asm-m32r/unistd.h +++ b/include/asm-m32r/unistd.h @@ -327,7 +327,7 @@ #define __NR_epoll_pwait 319 #define __NR_utimensat 320 #define __NR_signalfd 321 -#define __NR_timerfd 322 +/* #define __NR_timerfd 322 removed */ #define __NR_eventfd 323 #define __NR_fallocate 324 diff --git a/include/asm-m68k/pgtable.h b/include/asm-m68k/pgtable.h index 778a4c538eb2..0b604f0f192d 100644 --- a/include/asm-m68k/pgtable.h +++ b/include/asm-m68k/pgtable.h @@ -107,8 +107,6 @@ extern void *empty_zero_page; /* 64-bit machines, beware! SRB. */ #define SIZEOF_PTR_LOG2 2 -#define mm_end_of_chunk(addr, len) 0 - extern void kernel_set_cachemode(void *addr, unsigned long size, int cmode); /* diff --git a/include/asm-m68knommu/io.h b/include/asm-m68knommu/io.h index 653d9b2d7ddf..6adef1ee2082 100644 --- a/include/asm-m68knommu/io.h +++ b/include/asm-m68knommu/io.h @@ -172,8 +172,6 @@ extern void iounmap(void *addr); /* * Macros used for converting between virtual and physical mappings. */ -#define mm_ptov(vaddr) ((void *) (vaddr)) -#define mm_vtop(vaddr) ((unsigned long) (vaddr)) #define phys_to_virt(vaddr) ((void *) (vaddr)) #define virt_to_phys(vaddr) ((unsigned long) (vaddr)) diff --git a/include/asm-powerpc/cputime.h b/include/asm-powerpc/cputime.h index 310804485208..f42e623030ee 100644 --- a/include/asm-powerpc/cputime.h +++ b/include/asm-powerpc/cputime.h @@ -52,12 +52,26 @@ typedef u64 cputime64_t; * Convert cputime <-> jiffies */ extern u64 __cputime_jiffies_factor; +DECLARE_PER_CPU(unsigned long, cputime_last_delta); +DECLARE_PER_CPU(unsigned long, cputime_scaled_last_delta); static inline unsigned long cputime_to_jiffies(const cputime_t ct) { return mulhdu(ct, __cputime_jiffies_factor); } +/* Estimate the scaled cputime by scaling the real cputime based on + * the last scaled to real ratio */ +static inline cputime_t cputime_to_scaled(const cputime_t ct) +{ + if (cpu_has_feature(CPU_FTR_SPURR) && + per_cpu(cputime_last_delta, smp_processor_id())) + return ct * + per_cpu(cputime_scaled_last_delta, smp_processor_id())/ + per_cpu(cputime_last_delta, smp_processor_id()); + return ct; +} + static inline cputime_t jiffies_to_cputime(const unsigned long jif) { cputime_t ct; diff --git a/include/asm-powerpc/dma.h b/include/asm-powerpc/dma.h index 7a4374bdbef4..a7e06e25c708 100644 --- a/include/asm-powerpc/dma.h +++ b/include/asm-powerpc/dma.h @@ -93,16 +93,6 @@ * */ -/* see prep_setup_arch() for detailed informations */ -#if defined(CONFIG_SOUND_CS4232) && defined(CONFIG_PPC_PREP) -extern long ppc_cs4232_dma, ppc_cs4232_dma2; -#define SND_DMA1 ppc_cs4232_dma -#define SND_DMA2 ppc_cs4232_dma2 -#else -#define SND_DMA1 -1 -#define SND_DMA2 -1 -#endif - /* 8237 DMA controllers */ #define IO_DMA1_BASE 0x00 /* 8 bit slave DMA, channels 0..3 */ #define IO_DMA2_BASE 0xC0 /* 16 bit master DMA, ch 4(=slave input)..7 */ @@ -269,24 +259,15 @@ static __inline__ void set_dma_page(unsigned int dmanr, int pagenr) dma_outb(pagenr >> 8, DMA_HI_PAGE_3); break; case 5: - if (SND_DMA1 == 5 || SND_DMA2 == 5) - dma_outb(pagenr, DMA_LO_PAGE_5); - else - dma_outb(pagenr & 0xfe, DMA_LO_PAGE_5); + dma_outb(pagenr & 0xfe, DMA_LO_PAGE_5); dma_outb(pagenr >> 8, DMA_HI_PAGE_5); break; case 6: - if (SND_DMA1 == 6 || SND_DMA2 == 6) - dma_outb(pagenr, DMA_LO_PAGE_6); - else - dma_outb(pagenr & 0xfe, DMA_LO_PAGE_6); + dma_outb(pagenr & 0xfe, DMA_LO_PAGE_6); dma_outb(pagenr >> 8, DMA_HI_PAGE_6); break; case 7: - if (SND_DMA1 == 7 || SND_DMA2 == 7) - dma_outb(pagenr, DMA_LO_PAGE_7); - else - dma_outb(pagenr & 0xfe, DMA_LO_PAGE_7); + dma_outb(pagenr & 0xfe, DMA_LO_PAGE_7); dma_outb(pagenr >> 8, DMA_HI_PAGE_7); break; } @@ -302,12 +283,6 @@ static __inline__ void set_dma_addr(unsigned int dmanr, unsigned int phys) ((dmanr & 3) << 1) + IO_DMA1_BASE); dma_outb((phys >> 8) & 0xff, ((dmanr & 3) << 1) + IO_DMA1_BASE); - } else if (dmanr == SND_DMA1 || dmanr == SND_DMA2) { - dma_outb(phys & 0xff, - ((dmanr & 3) << 2) + IO_DMA2_BASE); - dma_outb((phys >> 8) & 0xff, - ((dmanr & 3) << 2) + IO_DMA2_BASE); - dma_outb((dmanr & 3), DMA2_EXT_REG); } else { dma_outb((phys >> 1) & 0xff, ((dmanr & 3) << 2) + IO_DMA2_BASE); @@ -334,11 +309,6 @@ static __inline__ void set_dma_count(unsigned int dmanr, unsigned int count) ((dmanr & 3) << 1) + 1 + IO_DMA1_BASE); dma_outb((count >> 8) & 0xff, ((dmanr & 3) << 1) + 1 + IO_DMA1_BASE); - } else if (dmanr == SND_DMA1 || dmanr == SND_DMA2) { - dma_outb(count & 0xff, - ((dmanr & 3) << 2) + 2 + IO_DMA2_BASE); - dma_outb((count >> 8) & 0xff, - ((dmanr & 3) << 2) + 2 + IO_DMA2_BASE); } else { dma_outb((count >> 1) & 0xff, ((dmanr & 3) << 2) + 2 + IO_DMA2_BASE); @@ -368,8 +338,7 @@ static __inline__ int get_dma_residue(unsigned int dmanr) count = 1 + dma_inb(io_port); count += dma_inb(io_port) << 8; - return (dmanr <= 3 || dmanr == SND_DMA1 || dmanr == SND_DMA2) - ? count : (count << 1); + return (dmanr <= 3) ? count : (count << 1); } /* These are in kernel/dma.c: */ diff --git a/include/asm-powerpc/mediabay.h b/include/asm-powerpc/mediabay.h index 9daa3252d7b6..de83fe196309 100644 --- a/include/asm-powerpc/mediabay.h +++ b/include/asm-powerpc/mediabay.h @@ -18,14 +18,14 @@ #define MB_NO 7 /* media bay contains nothing */ int check_media_bay(struct device_node *which_bay, int what); -int check_media_bay_by_base(unsigned long base, int what); /* Number of bays in the machine or 0 */ extern int media_bay_count; -/* called by pmac-ide.c to register IDE controller for media bay */ -extern int media_bay_set_ide_infos(struct device_node* which_bay, - unsigned long base, int irq, int index); +int check_media_bay_by_base(unsigned long base, int what); +/* called by IDE PMAC host driver to register IDE controller for media bay */ +int media_bay_set_ide_infos(struct device_node *which_bay, unsigned long base, + int irq, int index); #endif /* __KERNEL__ */ #endif /* _PPC_MEDIABAY_H */ diff --git a/include/asm-powerpc/paca.h b/include/asm-powerpc/paca.h index f6dfce025adf..748b35ab37b5 100644 --- a/include/asm-powerpc/paca.h +++ b/include/asm-powerpc/paca.h @@ -115,8 +115,6 @@ struct paca_struct { u64 system_time; /* accumulated system TB ticks */ u64 startpurr; /* PURR/TB value snapshot */ u64 startspurr; /* SPURR value snapshot */ - u64 purrdelta; /* FIXME: document */ - u64 spurrdelta; /* FIXME: document */ }; extern struct paca_struct paca[]; diff --git a/include/asm-powerpc/ps3av.h b/include/asm-powerpc/ps3av.h index 967930b82ed3..fda98715cd35 100644 --- a/include/asm-powerpc/ps3av.h +++ b/include/asm-powerpc/ps3av.h @@ -310,19 +310,25 @@ #define PS3AV_MONITOR_TYPE_HDMI 1 /* HDMI */ #define PS3AV_MONITOR_TYPE_DVI 2 /* DVI */ -#define PS3AV_DEFAULT_HDMI_MODE_ID_REG_60 2 /* 480p */ -#define PS3AV_DEFAULT_AVMULTI_MODE_ID_REG_60 1 /* 480i */ -#define PS3AV_DEFAULT_HDMI_MODE_ID_REG_50 7 /* 576p */ -#define PS3AV_DEFAULT_AVMULTI_MODE_ID_REG_50 6 /* 576i */ - -#define PS3AV_REGION_60 0x01 -#define PS3AV_REGION_50 0x02 -#define PS3AV_REGION_RGB 0x10 - -#define get_status(buf) (((__u32 *)buf)[2]) -#define PS3AV_HDR_SIZE 4 /* version + size */ /* for video mode */ +enum ps3av_mode_num { + PS3AV_MODE_AUTO = 0, + PS3AV_MODE_480I = 1, + PS3AV_MODE_480P = 2, + PS3AV_MODE_720P60 = 3, + PS3AV_MODE_1080I60 = 4, + PS3AV_MODE_1080P60 = 5, + PS3AV_MODE_576I = 6, + PS3AV_MODE_576P = 7, + PS3AV_MODE_720P50 = 8, + PS3AV_MODE_1080I50 = 9, + PS3AV_MODE_1080P50 = 10, + PS3AV_MODE_WXGA = 11, + PS3AV_MODE_SXGA = 12, + PS3AV_MODE_WUXGA = 13, +}; + #define PS3AV_MODE_MASK 0x000F #define PS3AV_MODE_HDCP_OFF 0x1000 /* Retail PS3 product doesn't support this */ #define PS3AV_MODE_DITHER 0x0800 @@ -333,6 +339,19 @@ #define PS3AV_MODE_RGB 0x0020 +#define PS3AV_DEFAULT_HDMI_MODE_ID_REG_60 PS3AV_MODE_480P +#define PS3AV_DEFAULT_AVMULTI_MODE_ID_REG_60 PS3AV_MODE_480I +#define PS3AV_DEFAULT_HDMI_MODE_ID_REG_50 PS3AV_MODE_576P +#define PS3AV_DEFAULT_AVMULTI_MODE_ID_REG_50 PS3AV_MODE_576I + +#define PS3AV_REGION_60 0x01 +#define PS3AV_REGION_50 0x02 +#define PS3AV_REGION_RGB 0x10 + +#define get_status(buf) (((__u32 *)buf)[2]) +#define PS3AV_HDR_SIZE 4 /* version + size */ + + /** command packet structure **/ struct ps3av_send_hdr { u16 version; @@ -713,8 +732,6 @@ extern int ps3av_set_video_mode(u32); extern int ps3av_set_audio_mode(u32, u32, u32, u32, u32); extern int ps3av_get_auto_mode(void); extern int ps3av_get_mode(void); -extern int ps3av_get_scanmode(int); -extern int ps3av_get_refresh_rate(int); extern int ps3av_video_mode2res(u32, u32 *, u32 *); extern int ps3av_video_mute(int); extern int ps3av_audio_mute(int); diff --git a/include/asm-s390/cputime.h b/include/asm-s390/cputime.h index 4b3ef7cad115..133ce054fc89 100644 --- a/include/asm-s390/cputime.h +++ b/include/asm-s390/cputime.h @@ -54,6 +54,7 @@ __div(unsigned long long n, unsigned int base) #define cputime_lt(__a, __b) ((__a) < (__b)) #define cputime_le(__a, __b) ((__a) <= (__b)) #define cputime_to_jiffies(__ct) (__div((__ct), 1000000 / HZ)) +#define cputime_to_scaled(__ct) (__ct) #define jiffies_to_cputime(__hz) ((cputime_t)(__hz) * (1000000 / HZ)) #define cputime64_zero (0ULL) diff --git a/include/asm-sh/delay.h b/include/asm-sh/delay.h index 031db84f2aa1..d5d464041003 100644 --- a/include/asm-sh/delay.h +++ b/include/asm-sh/delay.h @@ -12,7 +12,7 @@ extern void __bad_ndelay(void); extern void __udelay(unsigned long usecs); extern void __ndelay(unsigned long nsecs); -extern void __const_udelay(unsigned long usecs); +extern void __const_udelay(unsigned long xloops); extern void __delay(unsigned long loops); #ifdef CONFIG_SUPERH32 diff --git a/include/asm-sh/unistd_32.h b/include/asm-sh/unistd_32.h index b182b1cb05fd..433fd1b48fa2 100644 --- a/include/asm-sh/unistd_32.h +++ b/include/asm-sh/unistd_32.h @@ -330,7 +330,7 @@ #define __NR_epoll_pwait 319 #define __NR_utimensat 320 #define __NR_signalfd 321 -#define __NR_timerfd 322 +/* #define __NR_timerfd 322 removed */ #define __NR_eventfd 323 #define __NR_fallocate 324 diff --git a/include/asm-sh/unistd_64.h b/include/asm-sh/unistd_64.h index 944511882cac..108d2ba897fe 100644 --- a/include/asm-sh/unistd_64.h +++ b/include/asm-sh/unistd_64.h @@ -370,7 +370,7 @@ #define __NR_epoll_pwait 347 #define __NR_utimensat 348 #define __NR_signalfd 349 -#define __NR_timerfd 350 +/* #define __NR_timerfd 350 removed */ #define __NR_eventfd 351 #define __NR_fallocate 352 diff --git a/include/asm-sparc/unistd.h b/include/asm-sparc/unistd.h index 0decdf763716..2338a0276377 100644 --- a/include/asm-sparc/unistd.h +++ b/include/asm-sparc/unistd.h @@ -327,11 +327,13 @@ #define __NR_epoll_pwait 309 #define __NR_utimensat 310 #define __NR_signalfd 311 -#define __NR_timerfd 312 +#define __NR_timerfd_create 312 #define __NR_eventfd 313 #define __NR_fallocate 314 +#define __NR_timerfd_settime 315 +#define __NR_timerfd_gettime 316 -#define NR_SYSCALLS 315 +#define NR_SYSCALLS 317 /* Sparc 32-bit only has the "setresuid32", "getresuid32" variants, * it never had the plain ones and there is no value to adding those diff --git a/include/asm-sparc64/io.h b/include/asm-sparc64/io.h index c299b853b5ba..b6ece223562d 100644 --- a/include/asm-sparc64/io.h +++ b/include/asm-sparc64/io.h @@ -16,7 +16,7 @@ /* BIO layer definitions. */ extern unsigned long kern_base, kern_size; #define page_to_phys(page) (page_to_pfn(page) << PAGE_SHIFT) -#define BIO_VMERGE_BOUNDARY 8192 +#define BIO_VMERGE_BOUNDARY 0 static inline u8 _inb(unsigned long addr) { diff --git a/include/asm-sparc64/timex.h b/include/asm-sparc64/timex.h index 2a5e4ebaad80..c622535c4560 100644 --- a/include/asm-sparc64/timex.h +++ b/include/asm-sparc64/timex.h @@ -14,10 +14,6 @@ typedef unsigned long cycles_t; #define get_cycles() tick_ops->get_tick() -#define ARCH_HAS_READ_CURRENT_TIMER 1 -#define read_current_timer(timer_val_p) \ -({ *timer_val_p = tick_ops->get_tick(); \ - 0; \ -}) +#define ARCH_HAS_READ_CURRENT_TIMER #endif diff --git a/include/asm-sparc64/unistd.h b/include/asm-sparc64/unistd.h index cb751b4d0f56..77559da0ea3f 100644 --- a/include/asm-sparc64/unistd.h +++ b/include/asm-sparc64/unistd.h @@ -329,11 +329,13 @@ #define __NR_epoll_pwait 309 #define __NR_utimensat 310 #define __NR_signalfd 311 -#define __NR_timerfd 312 +#define __NR_timerfd_create 312 #define __NR_eventfd 313 #define __NR_fallocate 314 +#define __NR_timerfd_settime 315 +#define __NR_timerfd_gettime 316 -#define NR_SYSCALLS 315 +#define NR_SYSCALLS 317 #ifdef __KERNEL__ /* sysconf options, for SunOS compatibility */ diff --git a/include/asm-v850/io.h b/include/asm-v850/io.h index cc364fcbec10..cdad251fba9f 100644 --- a/include/asm-v850/io.h +++ b/include/asm-v850/io.h @@ -122,8 +122,6 @@ outsl (unsigned long port, const void *src, unsigned long count) #endif /* Conversion between virtual and physical mappings. */ -#define mm_ptov(addr) ((void *)__phys_to_virt (addr)) -#define mm_vtop(addr) ((unsigned long)__virt_to_phys (addr)) #define phys_to_virt(addr) ((void *)__phys_to_virt (addr)) #define virt_to_phys(addr) ((unsigned long)__virt_to_phys (addr)) diff --git a/include/asm-x86/delay.h b/include/asm-x86/delay.h index d11d47fc1a0e..409a649204aa 100644 --- a/include/asm-x86/delay.h +++ b/include/asm-x86/delay.h @@ -13,7 +13,7 @@ extern void __bad_ndelay(void); extern void __udelay(unsigned long usecs); extern void __ndelay(unsigned long nsecs); -extern void __const_udelay(unsigned long usecs); +extern void __const_udelay(unsigned long xloops); extern void __delay(unsigned long loops); /* 0x10c7 is 2**32 / 1000000 (rounded up) */ diff --git a/include/asm-x86/timex.h b/include/asm-x86/timex.h index 27cfd6c599ba..43e5a78500c5 100644 --- a/include/asm-x86/timex.h +++ b/include/asm-x86/timex.h @@ -14,7 +14,6 @@ #endif #define CLOCK_TICK_RATE PIT_TICK_RATE -extern int read_current_timer(unsigned long *timer_value); -#define ARCH_HAS_READ_CURRENT_TIMER 1 +#define ARCH_HAS_READ_CURRENT_TIMER #endif diff --git a/include/linux/ac97_codec.h b/include/linux/ac97_codec.h index 22eb9367235a..0260c3e79fdd 100644 --- a/include/linux/ac97_codec.h +++ b/include/linux/ac97_codec.h @@ -326,11 +326,7 @@ struct ac97_ops #define AC97_DEFAULT_POWER_OFF 4 /* Needs warm reset to power up */ }; -extern int ac97_read_proc (char *page_out, char **start, off_t off, - int count, int *eof, void *data); extern int ac97_probe_codec(struct ac97_codec *); -extern unsigned int ac97_set_adc_rate(struct ac97_codec *codec, unsigned int rate); -extern unsigned int ac97_set_dac_rate(struct ac97_codec *codec, unsigned int rate); extern struct ac97_codec *ac97_alloc_codec(void); extern void ac97_release_codec(struct ac97_codec *codec); @@ -363,7 +359,4 @@ struct ac97_quirk { int type; /* quirk type above */ }; -struct pci_dev; -extern int ac97_tune_hardware(struct pci_dev *pdev, struct ac97_quirk *quirk, int override); - #endif /* _AC97_CODEC_H_ */ diff --git a/include/linux/acct.h b/include/linux/acct.h index 302eb727ecb8..e8cae54e8d88 100644 --- a/include/linux/acct.h +++ b/include/linux/acct.h @@ -173,7 +173,11 @@ typedef struct acct acct_t; static inline u32 jiffies_to_AHZ(unsigned long x) { #if (TICK_NSEC % (NSEC_PER_SEC / AHZ)) == 0 +# if HZ < AHZ + return x * (AHZ / HZ); +# else return x / (HZ / AHZ); +# endif #else u64 tmp = (u64)x * TICK_NSEC; do_div(tmp, (NSEC_PER_SEC / AHZ)); diff --git a/include/linux/compat.h b/include/linux/compat.h index ae0a483bef9b..a671dbff7a1f 100644 --- a/include/linux/compat.h +++ b/include/linux/compat.h @@ -257,16 +257,8 @@ asmlinkage long compat_sys_ptrace(compat_long_t request, compat_long_t pid, /* * epoll (fs/eventpoll.c) compat bits follow ... */ -#ifndef CONFIG_HAS_COMPAT_EPOLL_EVENT struct epoll_event; #define compat_epoll_event epoll_event -#else -asmlinkage long compat_sys_epoll_ctl(int epfd, int op, int fd, - struct compat_epoll_event __user *event); -asmlinkage long compat_sys_epoll_wait(int epfd, - struct compat_epoll_event __user *events, - int maxevents, int timeout); -#endif asmlinkage long compat_sys_epoll_pwait(int epfd, struct compat_epoll_event __user *events, int maxevents, int timeout, diff --git a/include/linux/fs.h b/include/linux/fs.h index 56bd421c1208..109734bf6377 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -21,7 +21,7 @@ /* Fixed constants first: */ #undef NR_OPEN -#define NR_OPEN (1024*1024) /* Absolute upper limit on fd num */ +extern int sysctl_nr_open; #define INR_OPEN 1024 /* Initial setting for nfile rlimits */ #define BLOCK_SIZE_BITS 10 @@ -977,7 +977,6 @@ extern int send_sigurg(struct fown_struct *fown); extern struct list_head super_blocks; extern spinlock_t sb_lock; -#define sb_entry(list) list_entry((list), struct super_block, s_list) #define S_BIAS (1<<30) struct super_block { struct list_head s_list; /* Keep this first */ @@ -1279,8 +1278,10 @@ struct super_operations { * * Two bits are used for locking and completion notification, I_LOCK and I_SYNC. * - * I_DIRTY_SYNC Inode itself is dirty. - * I_DIRTY_DATASYNC Data-related inode changes pending + * I_DIRTY_SYNC Inode is dirty, but doesn't have to be written on + * fdatasync(). i_atime is the usual cause. + * I_DIRTY_DATASYNC Inode is dirty and must be written on fdatasync(), f.e. + * because i_size changed. * I_DIRTY_PAGES Inode has dirty pages. Inode itself may be clean. * I_NEW get_new_inode() sets i_state to I_LOCK|I_NEW. Both * are cleared by unlock_new_inode(), called from iget(). @@ -1312,8 +1313,6 @@ struct super_operations { * purpose reduces latency and prevents some filesystem- * specific deadlocks. * - * Q: Why does I_DIRTY_DATASYNC exist? It appears as if it could be replaced - * by (I_DIRTY_SYNC|I_DIRTY_PAGES). * Q: What is the difference between I_WILL_FREE and I_FREEING? * Q: igrab() only checks on (I_FREEING|I_WILL_FREE). Should it also check on * I_CLEAR? If not, why? @@ -2113,6 +2112,7 @@ struct ctl_table; int proc_nr_files(struct ctl_table *table, int write, struct file *filp, void __user *buffer, size_t *lenp, loff_t *ppos); +int get_filesystem_list(char * buf); #endif /* __KERNEL__ */ #endif /* _LINUX_FS_H */ diff --git a/include/linux/fsnotify.h b/include/linux/fsnotify.h index 2bd31fa623b6..d4b7c4ac72e6 100644 --- a/include/linux/fsnotify.h +++ b/include/linux/fsnotify.h @@ -92,6 +92,14 @@ static inline void fsnotify_inoderemove(struct inode *inode) } /* + * fsnotify_link_count - inode's link count changed + */ +static inline void fsnotify_link_count(struct inode *inode) +{ + inotify_inode_queue_event(inode, IN_ATTRIB, 0, NULL, NULL); +} + +/* * fsnotify_create - 'name' was linked in */ static inline void fsnotify_create(struct inode *inode, struct dentry *dentry) @@ -103,6 +111,20 @@ static inline void fsnotify_create(struct inode *inode, struct dentry *dentry) } /* + * fsnotify_link - new hardlink in 'inode' directory + * Note: We have to pass also the linked inode ptr as some filesystems leave + * new_dentry->d_inode NULL and instantiate inode pointer later + */ +static inline void fsnotify_link(struct inode *dir, struct inode *inode, struct dentry *new_dentry) +{ + inode_dir_notify(dir, DN_CREATE); + inotify_inode_queue_event(dir, IN_CREATE, 0, new_dentry->d_name.name, + inode); + fsnotify_link_count(inode); + audit_inode_child(new_dentry->d_name.name, new_dentry, dir); +} + +/* * fsnotify_mkdir - directory 'name' was created */ static inline void fsnotify_mkdir(struct inode *inode, struct dentry *dentry) diff --git a/include/linux/hash.h b/include/linux/hash.h index acf17bb8e7f9..06d25c189cc5 100644 --- a/include/linux/hash.h +++ b/include/linux/hash.h @@ -1,6 +1,6 @@ #ifndef _LINUX_HASH_H #define _LINUX_HASH_H -/* Fast hashing routine for a long. +/* Fast hashing routine for ints, longs and pointers. (C) 2002 William Lee Irwin III, IBM */ /* @@ -13,23 +13,30 @@ * them can use shifts and additions instead of multiplications for * machines where multiplications are slow. */ -#if BITS_PER_LONG == 32 + +#include <asm/types.h> + /* 2^31 + 2^29 - 2^25 + 2^22 - 2^19 - 2^16 + 1 */ -#define GOLDEN_RATIO_PRIME 0x9e370001UL -#elif BITS_PER_LONG == 64 +#define GOLDEN_RATIO_PRIME_32 0x9e370001UL /* 2^63 + 2^61 - 2^57 + 2^54 - 2^51 - 2^18 + 1 */ -#define GOLDEN_RATIO_PRIME 0x9e37fffffffc0001UL +#define GOLDEN_RATIO_PRIME_64 0x9e37fffffffc0001UL + +#if BITS_PER_LONG == 32 +#define GOLDEN_RATIO_PRIME GOLDEN_RATIO_PRIME_32 +#define hash_long(val, bits) hash_32(val, bits) +#elif BITS_PER_LONG == 64 +#define hash_long(val, bits) hash_64(val, bits) +#define GOLDEN_RATIO_PRIME GOLDEN_RATIO_PRIME_64 #else -#error Define GOLDEN_RATIO_PRIME for your wordsize. +#error Wordsize not 32 or 64 #endif -static inline unsigned long hash_long(unsigned long val, unsigned int bits) +static inline u64 hash_64(u64 val, unsigned int bits) { - unsigned long hash = val; + u64 hash = val; -#if BITS_PER_LONG == 64 /* Sigh, gcc can't optimise this alone like it does for 32 bits. */ - unsigned long n = hash; + u64 n = hash; n <<= 18; hash -= n; n <<= 33; @@ -42,15 +49,20 @@ static inline unsigned long hash_long(unsigned long val, unsigned int bits) hash += n; n <<= 2; hash += n; -#else + + /* High bits are more random, so use them. */ + return hash >> (64 - bits); +} + +static inline u32 hash_32(u32 val, unsigned int bits) +{ /* On some cpus multiply is faster, on others gcc will do shifts */ - hash *= GOLDEN_RATIO_PRIME; -#endif + u32 hash = val * GOLDEN_RATIO_PRIME_32; /* High bits are more random, so use them. */ - return hash >> (BITS_PER_LONG - bits); + return hash >> (32 - bits); } - + static inline unsigned long hash_ptr(void *ptr, unsigned int bits) { return hash_long((unsigned long)ptr, bits); diff --git a/include/linux/i2c/pca9539.h b/include/linux/i2c/pca953x.h index 611d84ab7a30..3c7361217df8 100644 --- a/include/linux/i2c/pca9539.h +++ b/include/linux/i2c/pca953x.h @@ -1,6 +1,6 @@ /* platform data for the PCA9539 16-bit I/O expander driver */ -struct pca9539_platform_data { +struct pca953x_platform_data { /* number of the first GPIO */ unsigned gpio_base; diff --git a/include/linux/ide.h b/include/linux/ide.h index 367c17084a28..acec99da832d 100644 --- a/include/linux/ide.h +++ b/include/linux/ide.h @@ -115,10 +115,6 @@ typedef unsigned char byte; /* used everywhere */ #define SATA_ERROR_OFFSET (1) #define SATA_CONTROL_OFFSET (2) -#define SATA_MISC_OFFSET (0) -#define SATA_PHY_OFFSET (1) -#define SATA_IEN_OFFSET (2) - /* * Our Physical Region Descriptor (PRD) table should be large enough * to handle the biggest I/O request we are likely to see. Since requests @@ -173,7 +169,7 @@ enum { ide_unknown, ide_generic, ide_pci, ide_rz1000, ide_trm290, ide_cmd646, ide_cy82c693, ide_4drives, ide_pmac, ide_etrax100, ide_acorn, - ide_au1xxx, ide_forced + ide_au1xxx, ide_palm3710, ide_forced }; typedef u8 hwif_chipset_t; @@ -198,17 +194,6 @@ struct ide_drive_s; int ide_register_hw(hw_regs_t *, void (*)(struct ide_drive_s *), struct hwif_s **); -void ide_setup_ports( hw_regs_t *hw, - unsigned long base, - int *offsets, - unsigned long ctrl, - unsigned long intr, - ide_ack_intr_t *ack_intr, -#if 0 - ide_io_ops_t *iops, -#endif - int irq); - static inline void ide_std_init_ports(hw_regs_t *hw, unsigned long io_addr, unsigned long ctl_addr) @@ -473,7 +458,6 @@ typedef struct hwif_s { /* task file registers for pata and sata */ unsigned long io_ports[IDE_NR_PORTS]; unsigned long sata_scr[SATA_NR_PORTS]; - unsigned long sata_misc[SATA_NR_PORTS]; ide_drive_t drives[MAX_DRIVES]; /* drive info */ @@ -1014,7 +998,8 @@ extern int __ide_pci_register_driver(struct pci_driver *driver, struct module *o void ide_pci_setup_ports(struct pci_dev *, const struct ide_port_info *, int, u8 *); void ide_setup_pci_noise(struct pci_dev *, const struct ide_port_info *); -#ifdef CONFIG_BLK_DEV_IDEDMA_PCI +/* FIXME: palm_bk3710 uses BLK_DEV_IDEDMA_PCI without BLK_DEV_IDEPCI! */ +#if defined(CONFIG_BLK_DEV_IDEPCI) && defined(CONFIG_BLK_DEV_IDEDMA_PCI) void ide_hwif_setup_dma(ide_hwif_t *, const struct ide_port_info *); #else static inline void ide_hwif_setup_dma(ide_hwif_t *hwif, @@ -1324,4 +1309,25 @@ static inline void ide_set_irq(ide_drive_t *drive, int on) drive->hwif->OUTB(drive->ctl | (on ? 0 : 2), IDE_CONTROL_REG); } +static inline u8 ide_read_status(ide_drive_t *drive) +{ + ide_hwif_t *hwif = drive->hwif; + + return hwif->INB(hwif->io_ports[IDE_STATUS_OFFSET]); +} + +static inline u8 ide_read_altstatus(ide_drive_t *drive) +{ + ide_hwif_t *hwif = drive->hwif; + + return hwif->INB(hwif->io_ports[IDE_CONTROL_OFFSET]); +} + +static inline u8 ide_read_error(ide_drive_t *drive) +{ + ide_hwif_t *hwif = drive->hwif; + + return hwif->INB(hwif->io_ports[IDE_ERROR_OFFSET]); +} + #endif /* _IDE_H */ diff --git a/include/linux/interrupt.h b/include/linux/interrupt.h index c3db4a00f1fa..dea7598aeff4 100644 --- a/include/linux/interrupt.h +++ b/include/linux/interrupt.h @@ -444,4 +444,6 @@ static inline void init_irq_proc(void) } #endif +int show_interrupts(struct seq_file *p, void *v); + #endif diff --git a/include/linux/isdn.h b/include/linux/isdn.h index d0ecc8eebfbf..9cb2855bb170 100644 --- a/include/linux/isdn.h +++ b/include/linux/isdn.h @@ -507,7 +507,6 @@ typedef struct modem_info { struct ktermios normal_termios; /* For saving termios structs */ struct ktermios callout_termios; wait_queue_head_t open_wait, close_wait; - struct semaphore write_sem; spinlock_t readlock; } modem_info; diff --git a/include/linux/jbd.h b/include/linux/jbd.h index d9ecd13393b0..b18fd3b9b835 100644 --- a/include/linux/jbd.h +++ b/include/linux/jbd.h @@ -33,7 +33,6 @@ #include <linux/lockdep.h> #include <asm/semaphore.h> -#endif #define journal_oom_retry 1 @@ -84,7 +83,6 @@ static inline void jbd_free(void *ptr, size_t size) #define JFS_MIN_JOURNAL_BLOCKS 1024 -#ifdef __KERNEL__ /** * typedef handle_t - The handle_t type represents a single atomic update being performed by some process. @@ -924,7 +922,6 @@ extern int journal_recover (journal_t *journal); extern int journal_wipe (journal_t *, int); extern int journal_skip_recovery (journal_t *); extern void journal_update_superblock (journal_t *, int); -extern void __journal_abort_hard (journal_t *); extern void journal_abort (journal_t *, int); extern int journal_errno (journal_t *); extern void journal_ack_err (journal_t *); diff --git a/include/linux/kernel.h b/include/linux/kernel.h index ff356b2ee478..18222f267bc4 100644 --- a/include/linux/kernel.h +++ b/include/linux/kernel.h @@ -35,7 +35,7 @@ extern const char linux_proc_banner[]; #define ALIGN(x,a) __ALIGN_MASK(x,(typeof(x))(a)-1) #define __ALIGN_MASK(x,mask) (((x)+(mask))&~(mask)) #define PTR_ALIGN(p, a) ((typeof(p))ALIGN((unsigned long)(p), (a))) -#define IS_ALIGNED(x,a) (((x) % ((typeof(x))(a))) == 0) +#define IS_ALIGNED(x, a) (((x) & ((typeof(x))(a) - 1)) == 0) #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]) + __must_be_array(arr)) diff --git a/include/linux/kprobes.h b/include/linux/kprobes.h index 6168c0a44172..4a6ce82ba039 100644 --- a/include/linux/kprobes.h +++ b/include/linux/kprobes.h @@ -152,8 +152,10 @@ static inline int arch_trampoline_kprobe(struct kprobe *p) struct kretprobe { struct kprobe kp; kretprobe_handler_t handler; + kretprobe_handler_t entry_handler; int maxactive; int nmissed; + size_t data_size; struct hlist_head free_instances; struct hlist_head used_instances; }; @@ -164,6 +166,7 @@ struct kretprobe_instance { struct kretprobe *rp; kprobe_opcode_t *ret_addr; struct task_struct *task; + char data[0]; }; struct kretprobe_blackpoint { diff --git a/include/linux/log2.h b/include/linux/log2.h index c8cf5e8ef171..25b808631cd9 100644 --- a/include/linux/log2.h +++ b/include/linux/log2.h @@ -190,4 +190,20 @@ unsigned long __rounddown_pow_of_two(unsigned long n) __rounddown_pow_of_two(n) \ ) +/** + * order_base_2 - calculate the (rounded up) base 2 order of the argument + * @n: parameter + * + * The first few values calculated by this routine: + * ob2(0) = 0 + * ob2(1) = 0 + * ob2(2) = 1 + * ob2(3) = 2 + * ob2(4) = 2 + * ob2(5) = 3 + * ... and so on. + */ + +#define order_base_2(n) ilog2(roundup_pow_of_two(n)) + #endif /* _LINUX_LOG2_H */ diff --git a/include/linux/loop.h b/include/linux/loop.h index 26a0a103898f..46169a7b559b 100644 --- a/include/linux/loop.h +++ b/include/linux/loop.h @@ -76,6 +76,7 @@ struct loop_device { enum { LO_FLAGS_READ_ONLY = 1, LO_FLAGS_USE_AOPS = 2, + LO_FLAGS_AUTOCLEAR = 4, }; #include <asm/posix_types.h> /* for __kernel_old_dev_t */ diff --git a/include/linux/lp.h b/include/linux/lp.h index 7059b6b9878a..0df024bfd6f0 100644 --- a/include/linux/lp.h +++ b/include/linux/lp.h @@ -99,7 +99,7 @@ #ifdef __KERNEL__ #include <linux/wait.h> -#include <asm/semaphore.h> +#include <linux/mutex.h> /* Magic numbers for defining port-device mappings */ #define LP_PARPORT_UNSPEC -4 @@ -145,7 +145,7 @@ struct lp_struct { #endif wait_queue_head_t waitq; unsigned int last_error; - struct semaphore port_mutex; + struct mutex port_mutex; wait_queue_head_t dataq; long timeout; unsigned int best_mode; diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h index 39d32837265b..df6dd79a0d3b 100644 --- a/include/linux/pci_ids.h +++ b/include/linux/pci_ids.h @@ -1765,6 +1765,7 @@ #define PCI_DEVICE_ID_QUATECH_DSC100 0x0020 #define PCI_DEVICE_ID_QUATECH_ESC100D 0x0050 #define PCI_DEVICE_ID_QUATECH_ESC100M 0x0060 +#define PCI_DEVICE_ID_QUATECH_SPPXP_100 0x0278 #define PCI_VENDOR_ID_SEALEVEL 0x135e #define PCI_DEVICE_ID_SEALEVEL_U530 0x7101 diff --git a/include/linux/percpu.h b/include/linux/percpu.h index 50faa0ea28e4..1ac969724bb2 100644 --- a/include/linux/percpu.h +++ b/include/linux/percpu.h @@ -54,7 +54,7 @@ #ifdef CONFIG_SMP struct percpu_data { - void *ptrs[NR_CPUS]; + void *ptrs[1]; }; #define __percpu_disguise(pdata) (struct percpu_data *)~(unsigned long)(pdata) diff --git a/include/linux/pnp.h b/include/linux/pnp.h index b9339d8b95bc..cd6332b88829 100644 --- a/include/linux/pnp.h +++ b/include/linux/pnp.h @@ -258,6 +258,7 @@ extern struct pnp_protocol isapnp_protocol; #else #define pnp_device_is_isapnp(dev) 0 #endif +extern struct mutex pnp_res_mutex; #ifdef CONFIG_PNPBIOS extern struct pnp_protocol pnpbios_protocol; diff --git a/include/linux/ptrace.h b/include/linux/ptrace.h index 515bff053de8..6ab80714a916 100644 --- a/include/linux/ptrace.h +++ b/include/linux/ptrace.h @@ -204,6 +204,41 @@ static inline void user_enable_block_step(struct task_struct *task) } #endif /* arch_has_block_step */ +#ifndef arch_ptrace_stop_needed +/** + * arch_ptrace_stop_needed - Decide whether arch_ptrace_stop() should be called + * @code: current->exit_code value ptrace will stop with + * @info: siginfo_t pointer (or %NULL) for signal ptrace will stop with + * + * This is called with the siglock held, to decide whether or not it's + * necessary to release the siglock and call arch_ptrace_stop() with the + * same @code and @info arguments. It can be defined to a constant if + * arch_ptrace_stop() is never required, or always is. On machines where + * this makes sense, it should be defined to a quick test to optimize out + * calling arch_ptrace_stop() when it would be superfluous. For example, + * if the thread has not been back to user mode since the last stop, the + * thread state might indicate that nothing needs to be done. + */ +#define arch_ptrace_stop_needed(code, info) (0) +#endif + +#ifndef arch_ptrace_stop +/** + * arch_ptrace_stop - Do machine-specific work before stopping for ptrace + * @code: current->exit_code value ptrace will stop with + * @info: siginfo_t pointer (or %NULL) for signal ptrace will stop with + * + * This is called with no locks held when arch_ptrace_stop_needed() has + * just returned nonzero. It is allowed to block, e.g. for user memory + * access. The arch can have machine-specific work to be done before + * ptrace stops. On ia64, register backing store gets written back to user + * memory here. Since this can be costly (requires dropping the siglock), + * we only do it when the arch requires it for this particular stop, as + * indicated by arch_ptrace_stop_needed(). + */ +#define arch_ptrace_stop(code, info) do { } while (0) +#endif + #endif #endif diff --git a/include/linux/raid/bitmap.h b/include/linux/raid/bitmap.h index 306a1d1a5af0..e51b531cd0b2 100644 --- a/include/linux/raid/bitmap.h +++ b/include/linux/raid/bitmap.h @@ -244,6 +244,8 @@ struct bitmap { */ unsigned long daemon_lastrun; /* jiffies of last run */ unsigned long daemon_sleep; /* how many seconds between updates? */ + unsigned long last_end_sync; /* when we lasted called end_sync to + * update bitmap with resync progress */ atomic_t pending_writes; /* pending writes to the bitmap file */ wait_queue_head_t write_wait; @@ -275,6 +277,7 @@ void bitmap_endwrite(struct bitmap *bitmap, sector_t offset, int bitmap_start_sync(struct bitmap *bitmap, sector_t offset, int *blocks, int degraded); void bitmap_end_sync(struct bitmap *bitmap, sector_t offset, int *blocks, int aborted); void bitmap_close_sync(struct bitmap *bitmap); +void bitmap_cond_end_sync(struct bitmap *bitmap, sector_t sector); void bitmap_unplug(struct bitmap *bitmap); void bitmap_daemon_work(struct bitmap *bitmap); diff --git a/include/linux/raid/md_k.h b/include/linux/raid/md_k.h index dcb729244f47..85a068bab625 100644 --- a/include/linux/raid/md_k.h +++ b/include/linux/raid/md_k.h @@ -81,6 +81,8 @@ struct mdk_rdev_s #define In_sync 2 /* device is in_sync with rest of array */ #define WriteMostly 4 /* Avoid reading if at all possible */ #define BarriersNotsupp 5 /* BIO_RW_BARRIER is not supported */ +#define AllReserved 6 /* If whole device is reserved for + * one array */ int desc_nr; /* descriptor index in the superblock */ int raid_disk; /* role of device in array */ @@ -130,6 +132,9 @@ struct mddev_s minor_version, patch_version; int persistent; + int external; /* metadata is + * managed externally */ + char metadata_type[17]; /* externally set*/ int chunk_size; time_t ctime, utime; int level, layout; @@ -216,6 +221,8 @@ struct mddev_s atomic_t recovery_active; /* blocks scheduled, but not written */ wait_queue_head_t recovery_wait; sector_t recovery_cp; + sector_t resync_max; /* resync should pause + * when it gets here */ spinlock_t write_lock; wait_queue_head_t sb_wait; /* for waiting on superblock updates */ @@ -306,23 +313,17 @@ static inline char * mdname (mddev_t * mddev) * iterates through some rdev ringlist. It's safe to remove the * current 'rdev'. Dont touch 'tmp' though. */ -#define ITERATE_RDEV_GENERIC(head,rdev,tmp) \ +#define rdev_for_each_list(rdev, tmp, list) \ \ - for ((tmp) = (head).next; \ + for ((tmp) = (list).next; \ (rdev) = (list_entry((tmp), mdk_rdev_t, same_set)), \ - (tmp) = (tmp)->next, (tmp)->prev != &(head) \ + (tmp) = (tmp)->next, (tmp)->prev != &(list) \ ; ) /* * iterates through the 'same array disks' ringlist */ -#define ITERATE_RDEV(mddev,rdev,tmp) \ - ITERATE_RDEV_GENERIC((mddev)->disks,rdev,tmp) - -/* - * Iterates through 'pending RAID disks' - */ -#define ITERATE_RDEV_PENDING(rdev,tmp) \ - ITERATE_RDEV_GENERIC(pending_raid_disks,rdev,tmp) +#define rdev_for_each(rdev, tmp, mddev) \ + rdev_for_each_list(rdev, tmp, (mddev)->disks) typedef struct mdk_thread_s { void (*run) (mddev_t *mddev); diff --git a/include/linux/rcupdate.h b/include/linux/rcupdate.h index d32c14de270e..37a642c54871 100644 --- a/include/linux/rcupdate.h +++ b/include/linux/rcupdate.h @@ -174,10 +174,13 @@ struct rcu_head { * code. */ -#define rcu_assign_pointer(p, v) ({ \ - smp_wmb(); \ - (p) = (v); \ - }) +#define rcu_assign_pointer(p, v) \ + ({ \ + if (!__builtin_constant_p(v) || \ + ((v) != NULL)) \ + smp_wmb(); \ + (p) = (v); \ + }) /** * synchronize_sched - block until all CPUs have exited any non-preemptive diff --git a/include/linux/sched.h b/include/linux/sched.h index 9c13be3a21e8..7c8ca05c3cae 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -810,7 +810,7 @@ static inline int above_background_load(void) struct io_context; /* See blkdev.h */ #define NGROUPS_SMALL 32 -#define NGROUPS_PER_BLOCK ((int)(PAGE_SIZE / sizeof(gid_t))) +#define NGROUPS_PER_BLOCK ((unsigned int)(PAGE_SIZE / sizeof(gid_t))) struct group_info { int ngroups; atomic_t usage; diff --git a/include/linux/signal.h b/include/linux/signal.h index 0ae338866240..7e095147656c 100644 --- a/include/linux/signal.h +++ b/include/linux/signal.h @@ -371,6 +371,8 @@ int unhandled_signal(struct task_struct *tsk, int sig); (!siginmask(signr, SIG_KERNEL_IGNORE_MASK|SIG_KERNEL_STOP_MASK) && \ (t)->sighand->action[(signr)-1].sa.sa_handler == SIG_DFL) +void signals_init(void); + #endif /* __KERNEL__ */ #endif /* _LINUX_SIGNAL_H */ diff --git a/include/linux/sm501.h b/include/linux/sm501.h index 9e3aaad6fe4d..932a9efee8a5 100644 --- a/include/linux/sm501.h +++ b/include/linux/sm501.h @@ -70,6 +70,8 @@ extern unsigned long sm501_gpio_get(struct device *dev, #define SM501FB_FLAG_DISABLE_AT_EXIT (1<<1) #define SM501FB_FLAG_USE_HWCURSOR (1<<2) #define SM501FB_FLAG_USE_HWACCEL (1<<3) +#define SM501FB_FLAG_PANEL_USE_FPEN (1<<4) +#define SM501FB_FLAG_PANEL_USE_VBIASEN (1<<5) struct sm501_platdata_fbsub { struct fb_videomode *def_mode; diff --git a/include/linux/timex.h b/include/linux/timex.h index 24c6a2b59511..8ea3e71ba7fa 100644 --- a/include/linux/timex.h +++ b/include/linux/timex.h @@ -244,6 +244,8 @@ extern int do_adjtimex(struct timex *); /* Don't use! Compatibility define for existing users. */ #define tickadj (500/HZ ? : 1) +int read_current_timer(unsigned long *timer_val); + #endif /* KERNEL */ #endif /* LINUX_TIMEX_H */ diff --git a/include/linux/tty.h b/include/linux/tty.h index 402de892b3ed..5824a9777ad7 100644 --- a/include/linux/tty.h +++ b/include/linux/tty.h @@ -74,7 +74,6 @@ struct tty_buffer { struct tty_bufhead { struct delayed_work work; - struct semaphore pty_sem; spinlock_t lock; struct tty_buffer *head; /* Queue head */ struct tty_buffer *tail; /* Active buffer */ diff --git a/include/linux/vt_kern.h b/include/linux/vt_kern.h index feb5e99a1079..9448ffbdcbf6 100644 --- a/include/linux/vt_kern.h +++ b/include/linux/vt_kern.h @@ -77,6 +77,7 @@ void change_console(struct vc_data *new_vc); void reset_vc(struct vc_data *vc); extern int unbind_con_driver(const struct consw *csw, int first, int last, int deflt); +int vty_init(void); /* * vc_screen.c shares this temporary buffer with the console write code so that diff --git a/include/linux/w1-gpio.h b/include/linux/w1-gpio.h new file mode 100644 index 000000000000..9797fec7748a --- /dev/null +++ b/include/linux/w1-gpio.h @@ -0,0 +1,23 @@ +/* + * w1-gpio interface to platform code + * + * Copyright (C) 2007 Ville Syrjala <syrjala@sci.fi> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation. + */ +#ifndef _LINUX_W1_GPIO_H +#define _LINUX_W1_GPIO_H + +/** + * struct w1_gpio_platform_data - Platform-dependent data for w1-gpio + * @pin: GPIO pin to use + * @is_open_drain: GPIO pin is configured as open drain + */ +struct w1_gpio_platform_data { + unsigned int pin; + unsigned int is_open_drain:1; +}; + +#endif /* _LINUX_W1_GPIO_H */ diff --git a/include/video/atmel_lcdc.h b/include/video/atmel_lcdc.h index 4eea63761a3f..336c20db87f8 100644 --- a/include/video/atmel_lcdc.h +++ b/include/video/atmel_lcdc.h @@ -22,7 +22,7 @@ #ifndef __ATMEL_LCDC_H__ #define __ATMEL_LCDC_H__ - /* LCD Controller info data structure */ + /* LCD Controller info data structure, stored in device platform_data */ struct atmel_lcdfb_info { spinlock_t lock; struct fb_info *info; @@ -33,7 +33,14 @@ struct atmel_lcdfb_info { struct platform_device *pdev; struct clk *bus_clk; struct clk *lcdc_clk; - unsigned int default_bpp; + +#ifdef CONFIG_BACKLIGHT_ATMEL_LCDC + struct backlight_device *backlight; + u8 bl_power; +#endif + bool lcdcon_is_backlight; + + u8 default_bpp; unsigned int default_lcdcon2; unsigned int default_dmacon; void (*atmel_lcdfb_power_control)(int on); @@ -115,20 +122,20 @@ struct atmel_lcdfb_info { #define ATMEL_LCDC_MEMOR_LITTLE (1 << 31) #define ATMEL_LCDC_TIM1 0x0808 -#define ATMEL_LCDC_VFP (0xff << 0) +#define ATMEL_LCDC_VFP (0xffU << 0) #define ATMEL_LCDC_VBP_OFFSET 8 -#define ATMEL_LCDC_VBP (0xff << ATMEL_LCDC_VBP_OFFSET) +#define ATMEL_LCDC_VBP (0xffU << ATMEL_LCDC_VBP_OFFSET) #define ATMEL_LCDC_VPW_OFFSET 16 -#define ATMEL_LCDC_VPW (0x3f << ATMEL_LCDC_VPW_OFFSET) +#define ATMEL_LCDC_VPW (0x3fU << ATMEL_LCDC_VPW_OFFSET) #define ATMEL_LCDC_VHDLY_OFFSET 24 -#define ATMEL_LCDC_VHDLY (0xf << ATMEL_LCDC_VHDLY_OFFSET) +#define ATMEL_LCDC_VHDLY (0xfU << ATMEL_LCDC_VHDLY_OFFSET) #define ATMEL_LCDC_TIM2 0x080c -#define ATMEL_LCDC_HBP (0xff << 0) +#define ATMEL_LCDC_HBP (0xffU << 0) #define ATMEL_LCDC_HPW_OFFSET 8 -#define ATMEL_LCDC_HPW (0x3f << ATMEL_LCDC_HPW_OFFSET) +#define ATMEL_LCDC_HPW (0x3fU << ATMEL_LCDC_HPW_OFFSET) #define ATMEL_LCDC_HFP_OFFSET 21 -#define ATMEL_LCDC_HFP (0x7ff << ATMEL_LCDC_HFP_OFFSET) +#define ATMEL_LCDC_HFP (0x7ffU << ATMEL_LCDC_HFP_OFFSET) #define ATMEL_LCDC_LCDFRMCFG 0x0810 #define ATMEL_LCDC_LINEVAL (0x7ff << 0) diff --git a/init/calibrate.c b/init/calibrate.c index 2d3d73bd4ce1..ecb3822d4f70 100644 --- a/init/calibrate.c +++ b/init/calibrate.c @@ -7,8 +7,7 @@ #include <linux/jiffies.h> #include <linux/delay.h> #include <linux/init.h> - -#include <asm/timex.h> +#include <linux/timex.h> unsigned long preset_lpj; static int __init lpj_setup(char *str) @@ -29,7 +28,7 @@ __setup("lpj=", lpj_setup); #define DELAY_CALIBRATION_TICKS ((HZ < 100) ? 1 : (HZ/100)) #define MAX_DIRECT_CALIBRATION_RETRIES 5 -static unsigned long __devinit calibrate_delay_direct(void) +static unsigned long __cpuinit calibrate_delay_direct(void) { unsigned long pre_start, start, post_start; unsigned long pre_end, end, post_end; @@ -102,7 +101,7 @@ static unsigned long __devinit calibrate_delay_direct(void) return 0; } #else -static unsigned long __devinit calibrate_delay_direct(void) {return 0;} +static unsigned long __cpuinit calibrate_delay_direct(void) {return 0;} #endif /* @@ -112,7 +111,7 @@ static unsigned long __devinit calibrate_delay_direct(void) {return 0;} */ #define LPS_PREC 8 -void __devinit calibrate_delay(void) +void __cpuinit calibrate_delay(void) { unsigned long ticks, loopbit; int lps_precision = LPS_PREC; diff --git a/init/do_mounts.c b/init/do_mounts.c index 1161dfd7b0d3..f86573126f83 100644 --- a/init/do_mounts.c +++ b/init/do_mounts.c @@ -11,6 +11,7 @@ #include <linux/mount.h> #include <linux/device.h> #include <linux/init.h> +#include <linux/fs.h> #include <linux/nfs_fs.h> #include <linux/nfs_fs_sb.h> @@ -18,8 +19,6 @@ #include "do_mounts.h" -extern int get_filesystem_list(char * buf); - int __initdata rd_doload; /* 1 = load RAM disk, 0 = don't load */ int root_mountflags = MS_RDONLY | MS_SILENT; diff --git a/init/initramfs.c b/init/initramfs.c index 1db02a0025db..d53fee8d8604 100644 --- a/init/initramfs.c +++ b/init/initramfs.c @@ -503,7 +503,6 @@ static int __init retain_initrd_param(char *str) __setup("retain_initrd", retain_initrd_param); extern char __initramfs_start[], __initramfs_end[]; -#ifdef CONFIG_BLK_DEV_INITRD #include <linux/initrd.h> #include <linux/kexec.h> @@ -539,15 +538,12 @@ skip: initrd_end = 0; } -#endif - static int __init populate_rootfs(void) { char *err = unpack_to_rootfs(__initramfs_start, __initramfs_end - __initramfs_start, 0); if (err) panic(err); -#ifdef CONFIG_BLK_DEV_INITRD if (initrd_start) { #ifdef CONFIG_BLK_DEV_RAM int fd; @@ -579,7 +575,6 @@ static int __init populate_rootfs(void) free_initrd(); #endif } -#endif return 0; } rootfs_initcall(populate_rootfs); diff --git a/init/main.c b/init/main.c index cb81ed116f62..c691f5f7fc27 100644 --- a/init/main.c +++ b/init/main.c @@ -57,6 +57,7 @@ #include <linux/device.h> #include <linux/kthread.h> #include <linux/sched.h> +#include <linux/signal.h> #include <asm/io.h> #include <asm/bugs.h> @@ -83,7 +84,6 @@ extern void init_IRQ(void); extern void fork_init(unsigned long); extern void mca_init(void); extern void sbus_init(void); -extern void signals_init(void); extern void pidhash_init(void); extern void pidmap_init(void); extern void prio_tree_init(void); diff --git a/ipc/msg.c b/ipc/msg.c index fdf3db5731ce..ec0c724054b9 100644 --- a/ipc/msg.c +++ b/ipc/msg.c @@ -105,6 +105,7 @@ int msg_init_ns(struct ipc_namespace *ns) void msg_exit_ns(struct ipc_namespace *ns) { struct msg_queue *msq; + struct kern_ipc_perm *perm; int next_id; int total, in_use; @@ -113,10 +114,11 @@ void msg_exit_ns(struct ipc_namespace *ns) in_use = msg_ids(ns).in_use; for (total = 0, next_id = 0; total < in_use; next_id++) { - msq = idr_find(&msg_ids(ns).ipcs_idr, next_id); - if (msq == NULL) + perm = idr_find(&msg_ids(ns).ipcs_idr, next_id); + if (perm == NULL) continue; - ipc_lock_by_ptr(&msq->q_perm); + ipc_lock_by_ptr(perm); + msq = container_of(perm, struct msg_queue, q_perm); freeque(ns, msq); total++; } @@ -144,6 +146,9 @@ static inline struct msg_queue *msg_lock_check_down(struct ipc_namespace *ns, { struct kern_ipc_perm *ipcp = ipc_lock_check_down(&msg_ids(ns), id); + if (IS_ERR(ipcp)) + return (struct msg_queue *)ipcp; + return container_of(ipcp, struct msg_queue, q_perm); } @@ -155,6 +160,9 @@ static inline struct msg_queue *msg_lock(struct ipc_namespace *ns, int id) { struct kern_ipc_perm *ipcp = ipc_lock(&msg_ids(ns), id); + if (IS_ERR(ipcp)) + return (struct msg_queue *)ipcp; + return container_of(ipcp, struct msg_queue, q_perm); } @@ -163,6 +171,9 @@ static inline struct msg_queue *msg_lock_check(struct ipc_namespace *ns, { struct kern_ipc_perm *ipcp = ipc_lock_check(&msg_ids(ns), id); + if (IS_ERR(ipcp)) + return (struct msg_queue *)ipcp; + return container_of(ipcp, struct msg_queue, q_perm); } diff --git a/ipc/sem.c b/ipc/sem.c index 35952c0bae46..d65e285b7e30 100644 --- a/ipc/sem.c +++ b/ipc/sem.c @@ -143,6 +143,7 @@ int sem_init_ns(struct ipc_namespace *ns) void sem_exit_ns(struct ipc_namespace *ns) { struct sem_array *sma; + struct kern_ipc_perm *perm; int next_id; int total, in_use; @@ -151,10 +152,11 @@ void sem_exit_ns(struct ipc_namespace *ns) in_use = sem_ids(ns).in_use; for (total = 0, next_id = 0; total < in_use; next_id++) { - sma = idr_find(&sem_ids(ns).ipcs_idr, next_id); - if (sma == NULL) + perm = idr_find(&sem_ids(ns).ipcs_idr, next_id); + if (perm == NULL) continue; - ipc_lock_by_ptr(&sma->sem_perm); + ipc_lock_by_ptr(perm); + sma = container_of(perm, struct sem_array, sem_perm); freeary(ns, sma); total++; } @@ -181,6 +183,9 @@ static inline struct sem_array *sem_lock_check_down(struct ipc_namespace *ns, { struct kern_ipc_perm *ipcp = ipc_lock_check_down(&sem_ids(ns), id); + if (IS_ERR(ipcp)) + return (struct sem_array *)ipcp; + return container_of(ipcp, struct sem_array, sem_perm); } @@ -192,6 +197,9 @@ static inline struct sem_array *sem_lock(struct ipc_namespace *ns, int id) { struct kern_ipc_perm *ipcp = ipc_lock(&sem_ids(ns), id); + if (IS_ERR(ipcp)) + return (struct sem_array *)ipcp; + return container_of(ipcp, struct sem_array, sem_perm); } @@ -200,6 +208,9 @@ static inline struct sem_array *sem_lock_check(struct ipc_namespace *ns, { struct kern_ipc_perm *ipcp = ipc_lock_check(&sem_ids(ns), id); + if (IS_ERR(ipcp)) + return (struct sem_array *)ipcp; + return container_of(ipcp, struct sem_array, sem_perm); } diff --git a/ipc/shm.c b/ipc/shm.c index 3818fae625c5..65c3a294aba5 100644 --- a/ipc/shm.c +++ b/ipc/shm.c @@ -111,6 +111,7 @@ int shm_init_ns(struct ipc_namespace *ns) void shm_exit_ns(struct ipc_namespace *ns) { struct shmid_kernel *shp; + struct kern_ipc_perm *perm; int next_id; int total, in_use; @@ -119,10 +120,11 @@ void shm_exit_ns(struct ipc_namespace *ns) in_use = shm_ids(ns).in_use; for (total = 0, next_id = 0; total < in_use; next_id++) { - shp = idr_find(&shm_ids(ns).ipcs_idr, next_id); - if (shp == NULL) + perm = idr_find(&shm_ids(ns).ipcs_idr, next_id); + if (perm == NULL) continue; - ipc_lock_by_ptr(&shp->shm_perm); + ipc_lock_by_ptr(perm); + shp = container_of(perm, struct shmid_kernel, shm_perm); do_shm_rmid(ns, shp); total++; } @@ -149,6 +151,9 @@ static inline struct shmid_kernel *shm_lock_down(struct ipc_namespace *ns, { struct kern_ipc_perm *ipcp = ipc_lock_down(&shm_ids(ns), id); + if (IS_ERR(ipcp)) + return (struct shmid_kernel *)ipcp; + return container_of(ipcp, struct shmid_kernel, shm_perm); } @@ -158,6 +163,9 @@ static inline struct shmid_kernel *shm_lock_check_down( { struct kern_ipc_perm *ipcp = ipc_lock_check_down(&shm_ids(ns), id); + if (IS_ERR(ipcp)) + return (struct shmid_kernel *)ipcp; + return container_of(ipcp, struct shmid_kernel, shm_perm); } @@ -169,6 +177,9 @@ static inline struct shmid_kernel *shm_lock(struct ipc_namespace *ns, int id) { struct kern_ipc_perm *ipcp = ipc_lock(&shm_ids(ns), id); + if (IS_ERR(ipcp)) + return (struct shmid_kernel *)ipcp; + return container_of(ipcp, struct shmid_kernel, shm_perm); } @@ -177,6 +188,9 @@ static inline struct shmid_kernel *shm_lock_check(struct ipc_namespace *ns, { struct kern_ipc_perm *ipcp = ipc_lock_check(&shm_ids(ns), id); + if (IS_ERR(ipcp)) + return (struct shmid_kernel *)ipcp; + return container_of(ipcp, struct shmid_kernel, shm_perm); } diff --git a/ipc/util.c b/ipc/util.c index 1aa0ebf71bac..76c1f3461e22 100644 --- a/ipc/util.c +++ b/ipc/util.c @@ -802,8 +802,8 @@ struct ipc_proc_iter { /* * This routine locks the ipc structure found at least at position pos. */ -struct kern_ipc_perm *sysvipc_find_ipc(struct ipc_ids *ids, loff_t pos, - loff_t *new_pos) +static struct kern_ipc_perm *sysvipc_find_ipc(struct ipc_ids *ids, loff_t pos, + loff_t *new_pos) { struct kern_ipc_perm *ipc; int total, id; diff --git a/kernel/exit.c b/kernel/exit.c index 9d3d0f0b27d9..eb9934a82fc1 100644 --- a/kernel/exit.c +++ b/kernel/exit.c @@ -1590,8 +1590,6 @@ repeat: goto repeat; if (retval != 0) /* He released the lock. */ goto end; - } else if (p->exit_state == EXIT_DEAD) { - continue; } else if (p->exit_state == EXIT_ZOMBIE) { /* * Eligible but we cannot release it yet: @@ -1606,7 +1604,7 @@ repeat: /* He released the lock. */ if (retval != 0) goto end; - } else { + } else if (p->exit_state != EXIT_DEAD) { check_continued: /* * It's running now, so it might later diff --git a/kernel/fork.c b/kernel/fork.c index 2b55b74cd999..3995297567a9 100644 --- a/kernel/fork.c +++ b/kernel/fork.c @@ -1399,7 +1399,7 @@ fork_out: return ERR_PTR(retval); } -noinline struct pt_regs * __devinit __attribute__((weak)) idle_regs(struct pt_regs *regs) +noinline struct pt_regs * __cpuinit __attribute__((weak)) idle_regs(struct pt_regs *regs) { memset(regs, 0, sizeof(struct pt_regs)); return regs; @@ -1510,7 +1510,7 @@ long do_fork(unsigned long clone_flags, if (!(clone_flags & CLONE_STOPPED)) wake_up_new_task(p, clone_flags); else - p->state = TASK_STOPPED; + __set_task_state(p, TASK_STOPPED); if (unlikely (trace)) { current->ptrace_message = nr; diff --git a/kernel/kallsyms.c b/kernel/kallsyms.c index 7dadc71ce516..f091d13def00 100644 --- a/kernel/kallsyms.c +++ b/kernel/kallsyms.c @@ -53,14 +53,6 @@ static inline int is_kernel_inittext(unsigned long addr) return 0; } -static inline int is_kernel_extratext(unsigned long addr) -{ - if (addr >= (unsigned long)_sextratext - && addr <= (unsigned long)_eextratext) - return 1; - return 0; -} - static inline int is_kernel_text(unsigned long addr) { if (addr >= (unsigned long)_stext && addr <= (unsigned long)_etext) @@ -80,8 +72,7 @@ static int is_ksym_addr(unsigned long addr) if (all_var) return is_kernel(addr); - return is_kernel_text(addr) || is_kernel_inittext(addr) || - is_kernel_extratext(addr); + return is_kernel_text(addr) || is_kernel_inittext(addr); } /* expand a compressed symbol data into the resulting uncompressed string, diff --git a/kernel/kprobes.c b/kernel/kprobes.c index d0493eafea3e..7a86e6432338 100644 --- a/kernel/kprobes.c +++ b/kernel/kprobes.c @@ -699,6 +699,12 @@ static int __kprobes pre_handler_kretprobe(struct kprobe *p, struct kretprobe_instance, uflist); ri->rp = rp; ri->task = current; + + if (rp->entry_handler && rp->entry_handler(ri, regs)) { + spin_unlock_irqrestore(&kretprobe_lock, flags); + return 0; + } + arch_prepare_kretprobe(ri, regs); /* XXX(hch): why is there no hlist_move_head? */ @@ -745,7 +751,8 @@ int __kprobes register_kretprobe(struct kretprobe *rp) INIT_HLIST_HEAD(&rp->used_instances); INIT_HLIST_HEAD(&rp->free_instances); for (i = 0; i < rp->maxactive; i++) { - inst = kmalloc(sizeof(struct kretprobe_instance), GFP_KERNEL); + inst = kmalloc(sizeof(struct kretprobe_instance) + + rp->data_size, GFP_KERNEL); if (inst == NULL) { free_rp_inst(rp); return -ENOMEM; diff --git a/kernel/notifier.c b/kernel/notifier.c index 4253f472f060..643360d1bb14 100644 --- a/kernel/notifier.c +++ b/kernel/notifier.c @@ -4,6 +4,7 @@ #include <linux/notifier.h> #include <linux/rcupdate.h> #include <linux/vmalloc.h> +#include <linux/reboot.h> /* * Notifier list for kernel code which wants to be called diff --git a/kernel/params.c b/kernel/params.c index 42fe5e6126c0..e28c70628bb7 100644 --- a/kernel/params.c +++ b/kernel/params.c @@ -272,7 +272,7 @@ static int param_array(const char *name, unsigned int min, unsigned int max, void *elem, int elemsize, int (*set)(const char *, struct kernel_param *kp), - int *num) + unsigned int *num) { int ret; struct kernel_param kp; diff --git a/kernel/printk.c b/kernel/printk.c index 29ae1e99cde0..4a090621f379 100644 --- a/kernel/printk.c +++ b/kernel/printk.c @@ -93,16 +93,16 @@ static int console_locked, console_suspended; */ static DEFINE_SPINLOCK(logbuf_lock); -#define LOG_BUF_MASK (log_buf_len-1) +#define LOG_BUF_MASK (log_buf_len-1) #define LOG_BUF(idx) (log_buf[(idx) & LOG_BUF_MASK]) /* * The indices into log_buf are not constrained to log_buf_len - they * must be masked before subscripting */ -static unsigned long log_start; /* Index into log_buf: next char to be read by syslog() */ -static unsigned long con_start; /* Index into log_buf: next char to be sent to consoles */ -static unsigned long log_end; /* Index into log_buf: most-recently-written-char + 1 */ +static unsigned log_start; /* Index into log_buf: next char to be read by syslog() */ +static unsigned con_start; /* Index into log_buf: next char to be sent to consoles */ +static unsigned log_end; /* Index into log_buf: most-recently-written-char + 1 */ /* * Array of consoles built from command line options (console=) @@ -128,17 +128,17 @@ static int console_may_schedule; static char __log_buf[__LOG_BUF_LEN]; static char *log_buf = __log_buf; static int log_buf_len = __LOG_BUF_LEN; -static unsigned long logged_chars; /* Number of chars produced since last read+clear operation */ +static unsigned logged_chars; /* Number of chars produced since last read+clear operation */ static int __init log_buf_len_setup(char *str) { - unsigned long size = memparse(str, &str); + unsigned size = memparse(str, &str); unsigned long flags; if (size) size = roundup_pow_of_two(size); if (size > log_buf_len) { - unsigned long start, dest_idx, offset; + unsigned start, dest_idx, offset; char *new_log_buf; new_log_buf = alloc_bootmem(size); @@ -295,7 +295,7 @@ int log_buf_read(int idx) */ int do_syslog(int type, char __user *buf, int len) { - unsigned long i, j, limit, count; + unsigned i, j, limit, count; int do_clear = 0; char c; int error = 0; @@ -436,7 +436,7 @@ asmlinkage long sys_syslog(int type, char __user *buf, int len) /* * Call the console drivers on a range of log_buf */ -static void __call_console_drivers(unsigned long start, unsigned long end) +static void __call_console_drivers(unsigned start, unsigned end) { struct console *con; @@ -463,8 +463,8 @@ early_param("ignore_loglevel", ignore_loglevel_setup); /* * Write out chars from start to end - 1 inclusive */ -static void _call_console_drivers(unsigned long start, - unsigned long end, int msg_log_level) +static void _call_console_drivers(unsigned start, + unsigned end, int msg_log_level) { if ((msg_log_level < console_loglevel || ignore_loglevel) && console_drivers && start != end) { @@ -484,12 +484,12 @@ static void _call_console_drivers(unsigned long start, * log_buf[start] to log_buf[end - 1]. * The console_sem must be held. */ -static void call_console_drivers(unsigned long start, unsigned long end) +static void call_console_drivers(unsigned start, unsigned end) { - unsigned long cur_index, start_print; + unsigned cur_index, start_print; static int msg_level = -1; - BUG_ON(((long)(start - end)) > 0); + BUG_ON(((int)(start - end)) > 0); cur_index = start; start_print = start; @@ -790,7 +790,7 @@ asmlinkage long sys_syslog(int type, char __user *buf, int len) return -ENOSYS; } -static void call_console_drivers(unsigned long start, unsigned long end) +static void call_console_drivers(unsigned start, unsigned end) { } @@ -983,8 +983,8 @@ void wake_up_klogd(void) void release_console_sem(void) { unsigned long flags; - unsigned long _con_start, _log_end; - unsigned long wake_klogd = 0; + unsigned _con_start, _log_end; + unsigned wake_klogd = 0; if (console_suspended) { up(&secondary_console_sem); @@ -1275,7 +1275,7 @@ void tty_write_message(struct tty_struct *tty, char *msg) int __printk_ratelimit(int ratelimit_jiffies, int ratelimit_burst) { static DEFINE_SPINLOCK(ratelimit_lock); - static unsigned long toks = 10 * 5 * HZ; + static unsigned toks = 10 * 5 * HZ; static unsigned long last_msg; static int missed; unsigned long flags; diff --git a/kernel/ptrace.c b/kernel/ptrace.c index b0d4ab4dfd3d..628b03ab88a5 100644 --- a/kernel/ptrace.c +++ b/kernel/ptrace.c @@ -20,6 +20,7 @@ #include <linux/signal.h> #include <linux/audit.h> #include <linux/pid_namespace.h> +#include <linux/syscalls.h> #include <asm/pgtable.h> #include <asm/uaccess.h> @@ -53,7 +54,7 @@ void ptrace_untrace(struct task_struct *child) spin_lock(&child->sighand->siglock); if (task_is_traced(child)) { if (child->signal->flags & SIGNAL_STOP_STOPPED) { - child->state = TASK_STOPPED; + __set_task_state(child, TASK_STOPPED); } else { signal_wake_up(child, 1); } @@ -103,18 +104,16 @@ int ptrace_check_attach(struct task_struct *child, int kill) && child->signal != NULL) { ret = 0; spin_lock_irq(&child->sighand->siglock); - if (task_is_stopped(child)) { + if (task_is_stopped(child)) child->state = TASK_TRACED; - } else if (!task_is_traced(child) && !kill) { + else if (!task_is_traced(child) && !kill) ret = -ESRCH; - } spin_unlock_irq(&child->sighand->siglock); } read_unlock(&tasklist_lock); - if (!ret && !kill) { + if (!ret && !kill) wait_task_inactive(child); - } /* All systems go.. */ return ret; diff --git a/kernel/relay.c b/kernel/relay.c index 7c0373322f18..d080b9d161a7 100644 --- a/kernel/relay.c +++ b/kernel/relay.c @@ -37,37 +37,31 @@ static void relay_file_mmap_close(struct vm_area_struct *vma) } /* - * nopage() vm_op implementation for relay file mapping. + * fault() vm_op implementation for relay file mapping. */ -static struct page *relay_buf_nopage(struct vm_area_struct *vma, - unsigned long address, - int *type) +static int relay_buf_fault(struct vm_area_struct *vma, struct vm_fault *vmf) { struct page *page; struct rchan_buf *buf = vma->vm_private_data; - unsigned long offset = address - vma->vm_start; + pgoff_t pgoff = vmf->pgoff; - if (address > vma->vm_end) - return NOPAGE_SIGBUS; /* Disallow mremap */ if (!buf) - return NOPAGE_OOM; + return VM_FAULT_OOM; - page = vmalloc_to_page(buf->start + offset); + page = vmalloc_to_page(buf->start + (pgoff << PAGE_SHIFT)); if (!page) - return NOPAGE_OOM; + return VM_FAULT_SIGBUS; get_page(page); + vmf->page = page; - if (type) - *type = VM_FAULT_MINOR; - - return page; + return 0; } /* * vm_ops for relay file mappings. */ static struct vm_operations_struct relay_file_mmap_ops = { - .nopage = relay_buf_nopage, + .fault = relay_buf_fault, .close = relay_file_mmap_close, }; diff --git a/kernel/signal.c b/kernel/signal.c index 6a5f97cd337a..5d30ff561847 100644 --- a/kernel/signal.c +++ b/kernel/signal.c @@ -1578,6 +1578,17 @@ static inline int may_ptrace_stop(void) } /* + * Return nonzero if there is a SIGKILL that should be waking us up. + * Called with the siglock held. + */ +static int sigkill_pending(struct task_struct *tsk) +{ + return ((sigismember(&tsk->pending.signal, SIGKILL) || + sigismember(&tsk->signal->shared_pending.signal, SIGKILL)) && + !unlikely(sigismember(&tsk->blocked, SIGKILL))); +} + +/* * This must be called with current->sighand->siglock held. * * This should be the path for all ptrace stops. @@ -1590,6 +1601,26 @@ static inline int may_ptrace_stop(void) */ static void ptrace_stop(int exit_code, int nostop_code, siginfo_t *info) { + int killed = 0; + + if (arch_ptrace_stop_needed(exit_code, info)) { + /* + * The arch code has something special to do before a + * ptrace stop. This is allowed to block, e.g. for faults + * on user stack pages. We can't keep the siglock while + * calling arch_ptrace_stop, so we must release it now. + * To preserve proper semantics, we must do this before + * any signal bookkeeping like checking group_stop_count. + * Meanwhile, a SIGKILL could come in before we retake the + * siglock. That must prevent us from sleeping in TASK_TRACED. + * So after regaining the lock, we must check for SIGKILL. + */ + spin_unlock_irq(¤t->sighand->siglock); + arch_ptrace_stop(exit_code, info); + spin_lock_irq(¤t->sighand->siglock); + killed = sigkill_pending(current); + } + /* * If there is a group stop in progress, * we must participate in the bookkeeping. @@ -1601,11 +1632,11 @@ static void ptrace_stop(int exit_code, int nostop_code, siginfo_t *info) current->exit_code = exit_code; /* Let the debugger run. */ - set_current_state(TASK_TRACED); + __set_current_state(TASK_TRACED); spin_unlock_irq(¤t->sighand->siglock); try_to_freeze(); read_lock(&tasklist_lock); - if (may_ptrace_stop()) { + if (!unlikely(killed) && may_ptrace_stop()) { do_notify_parent_cldstop(current, CLD_TRAPPED); read_unlock(&tasklist_lock); schedule(); diff --git a/kernel/srcu.c b/kernel/srcu.c index 3507cabe963b..b0aeeaf22ce4 100644 --- a/kernel/srcu.c +++ b/kernel/srcu.c @@ -74,7 +74,7 @@ static int srcu_readers_active_idx(struct srcu_struct *sp, int idx) * severe errors when invoked on an active srcu_struct. That said, it * can be useful as an error check at cleanup time. */ -int srcu_readers_active(struct srcu_struct *sp) +static int srcu_readers_active(struct srcu_struct *sp) { return srcu_readers_active_idx(sp, 0) + srcu_readers_active_idx(sp, 1); } @@ -255,4 +255,3 @@ EXPORT_SYMBOL_GPL(srcu_read_lock); EXPORT_SYMBOL_GPL(srcu_read_unlock); EXPORT_SYMBOL_GPL(synchronize_srcu); EXPORT_SYMBOL_GPL(srcu_batches_completed); -EXPORT_SYMBOL_GPL(srcu_readers_active); diff --git a/kernel/stop_machine.c b/kernel/stop_machine.c index 51b5ee53571a..6f4e0e13f70c 100644 --- a/kernel/stop_machine.c +++ b/kernel/stop_machine.c @@ -29,7 +29,6 @@ enum stopmachine_state { static enum stopmachine_state stopmachine_state; static unsigned int stopmachine_num_threads; static atomic_t stopmachine_thread_ack; -static DECLARE_MUTEX(stopmachine_mutex); static int stopmachine(void *cpu) { @@ -170,6 +169,7 @@ static int do_stop(void *_smdata) struct task_struct *__stop_machine_run(int (*fn)(void *), void *data, unsigned int cpu) { + static DEFINE_MUTEX(stopmachine_mutex); struct stop_machine_data smdata; struct task_struct *p; @@ -177,7 +177,7 @@ struct task_struct *__stop_machine_run(int (*fn)(void *), void *data, smdata.data = data; init_completion(&smdata.done); - down(&stopmachine_mutex); + mutex_lock(&stopmachine_mutex); /* If they don't care which CPU fn runs on, bind to any online one. */ if (cpu == NR_CPUS) @@ -193,7 +193,7 @@ struct task_struct *__stop_machine_run(int (*fn)(void *), void *data, wake_up_process(p); wait_for_completion(&smdata.done); } - up(&stopmachine_mutex); + mutex_unlock(&stopmachine_mutex); return p; } diff --git a/kernel/sys.c b/kernel/sys.c index 53de35fc8245..e3c08d4324de 100644 --- a/kernel/sys.c +++ b/kernel/sys.c @@ -1145,16 +1145,16 @@ static int groups_to_user(gid_t __user *grouplist, struct group_info *group_info) { int i; - int count = group_info->ngroups; + unsigned int count = group_info->ngroups; for (i = 0; i < group_info->nblocks; i++) { - int cp_count = min(NGROUPS_PER_BLOCK, count); - int off = i * NGROUPS_PER_BLOCK; - int len = cp_count * sizeof(*grouplist); + unsigned int cp_count = min(NGROUPS_PER_BLOCK, count); + unsigned int len = cp_count * sizeof(*grouplist); - if (copy_to_user(grouplist+off, group_info->blocks[i], len)) + if (copy_to_user(grouplist, group_info->blocks[i], len)) return -EFAULT; + grouplist += NGROUPS_PER_BLOCK; count -= cp_count; } return 0; @@ -1165,16 +1165,16 @@ static int groups_from_user(struct group_info *group_info, gid_t __user *grouplist) { int i; - int count = group_info->ngroups; + unsigned int count = group_info->ngroups; for (i = 0; i < group_info->nblocks; i++) { - int cp_count = min(NGROUPS_PER_BLOCK, count); - int off = i * NGROUPS_PER_BLOCK; - int len = cp_count * sizeof(*grouplist); + unsigned int cp_count = min(NGROUPS_PER_BLOCK, count); + unsigned int len = cp_count * sizeof(*grouplist); - if (copy_from_user(group_info->blocks[i], grouplist+off, len)) + if (copy_from_user(group_info->blocks[i], grouplist, len)) return -EFAULT; + grouplist += NGROUPS_PER_BLOCK; count -= cp_count; } return 0; @@ -1472,7 +1472,7 @@ asmlinkage long sys_setrlimit(unsigned int resource, struct rlimit __user *rlim) if ((new_rlim.rlim_max > old_rlim->rlim_max) && !capable(CAP_SYS_RESOURCE)) return -EPERM; - if (resource == RLIMIT_NOFILE && new_rlim.rlim_max > NR_OPEN) + if (resource == RLIMIT_NOFILE && new_rlim.rlim_max > sysctl_nr_open) return -EPERM; retval = security_task_setrlimit(resource, &new_rlim); diff --git a/kernel/sysctl.c b/kernel/sysctl.c index 5e2ad5bf88e2..86daaa26d120 100644 --- a/kernel/sysctl.c +++ b/kernel/sysctl.c @@ -1203,6 +1203,14 @@ static struct ctl_table fs_table[] = { .proc_handler = &proc_dointvec, }, { + .ctl_name = CTL_UNNUMBERED, + .procname = "nr_open", + .data = &sysctl_nr_open, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = &proc_dointvec, + }, + { .ctl_name = FS_DENTRY, .procname = "dentry-state", .data = &dentry_stat, diff --git a/kernel/test_kprobes.c b/kernel/test_kprobes.c index 88cdb109e13c..06b6395b45b2 100644 --- a/kernel/test_kprobes.c +++ b/kernel/test_kprobes.c @@ -135,6 +135,12 @@ static int test_jprobe(void) #ifdef CONFIG_KRETPROBES static u32 krph_val; +static int entry_handler(struct kretprobe_instance *ri, struct pt_regs *regs) +{ + krph_val = (rand1 / div_factor); + return 0; +} + static int return_handler(struct kretprobe_instance *ri, struct pt_regs *regs) { unsigned long ret = regs_return_value(regs); @@ -144,13 +150,19 @@ static int return_handler(struct kretprobe_instance *ri, struct pt_regs *regs) printk(KERN_ERR "Kprobe smoke test failed: " "incorrect value in kretprobe handler\n"); } + if (krph_val == 0) { + handler_errors++; + printk(KERN_ERR "Kprobe smoke test failed: " + "call to kretprobe entry handler failed\n"); + } - krph_val = (rand1 / div_factor); + krph_val = rand1; return 0; } static struct kretprobe rp = { .handler = return_handler, + .entry_handler = entry_handler, .kp.symbol_name = "kprobe_target" }; @@ -167,7 +179,7 @@ static int test_kretprobe(void) ret = kprobe_target(rand1); unregister_kretprobe(&rp); - if (krph_val == 0) { + if (krph_val != rand1) { printk(KERN_ERR "Kprobe smoke test failed: " "kretprobe handler not called\n"); handler_errors++; diff --git a/kernel/time.c b/kernel/time.c index 4064c0566e77..33af3e55570d 100644 --- a/kernel/time.c +++ b/kernel/time.c @@ -566,7 +566,11 @@ EXPORT_SYMBOL(jiffies_to_timeval); clock_t jiffies_to_clock_t(long x) { #if (TICK_NSEC % (NSEC_PER_SEC / USER_HZ)) == 0 +# if HZ < USER_HZ + return x * (USER_HZ / HZ); +# else return x / (HZ / USER_HZ); +# endif #else u64 tmp = (u64)x * TICK_NSEC; do_div(tmp, (NSEC_PER_SEC / USER_HZ)); @@ -599,7 +603,14 @@ EXPORT_SYMBOL(clock_t_to_jiffies); u64 jiffies_64_to_clock_t(u64 x) { #if (TICK_NSEC % (NSEC_PER_SEC / USER_HZ)) == 0 +# if HZ < USER_HZ + x *= USER_HZ; + do_div(x, HZ); +# elif HZ > USER_HZ do_div(x, HZ / USER_HZ); +# else + /* Nothing to do */ +# endif #else /* * There are better ways that don't overflow early, @@ -611,7 +622,6 @@ u64 jiffies_64_to_clock_t(u64 x) #endif return x; } - EXPORT_SYMBOL(jiffies_64_to_clock_t); u64 nsec_to_clock_t(u64 x) @@ -646,7 +656,6 @@ u64 get_jiffies_64(void) } while (read_seqretry(&xtime_lock, seq)); return ret; } - EXPORT_SYMBOL(get_jiffies_64); #endif diff --git a/kernel/time/clocksource.c b/kernel/time/clocksource.c index 6e9259a5d501..81afb3927ecc 100644 --- a/kernel/time/clocksource.c +++ b/kernel/time/clocksource.c @@ -363,15 +363,13 @@ void clocksource_unregister(struct clocksource *cs) static ssize_t sysfs_show_current_clocksources(struct sys_device *dev, char *buf) { - char *curr = buf; + ssize_t count = 0; spin_lock_irq(&clocksource_lock); - curr += sprintf(curr, "%s ", curr_clocksource->name); + count = snprintf(buf, PAGE_SIZE, "%s\n", curr_clocksource->name); spin_unlock_irq(&clocksource_lock); - curr += sprintf(curr, "\n"); - - return curr - buf; + return count; } /** @@ -439,17 +437,20 @@ static ssize_t sysfs_show_available_clocksources(struct sys_device *dev, char *buf) { struct clocksource *src; - char *curr = buf; + ssize_t count = 0; spin_lock_irq(&clocksource_lock); list_for_each_entry(src, &clocksource_list, list) { - curr += sprintf(curr, "%s ", src->name); + count += snprintf(buf + count, + max((ssize_t)PAGE_SIZE - count, (ssize_t)0), + "%s ", src->name); } spin_unlock_irq(&clocksource_lock); - curr += sprintf(curr, "\n"); + count += snprintf(buf + count, + max((ssize_t)PAGE_SIZE - count, (ssize_t)0), "\n"); - return curr - buf; + return count; } /* diff --git a/kernel/timer.c b/kernel/timer.c index 9fbb472b8cf0..70b29b59343f 100644 --- a/kernel/timer.c +++ b/kernel/timer.c @@ -818,12 +818,14 @@ unsigned long next_timer_interrupt(void) #ifndef CONFIG_VIRT_CPU_ACCOUNTING void account_process_tick(struct task_struct *p, int user_tick) { + cputime_t one_jiffy = jiffies_to_cputime(1); + if (user_tick) { - account_user_time(p, jiffies_to_cputime(1)); - account_user_time_scaled(p, jiffies_to_cputime(1)); + account_user_time(p, one_jiffy); + account_user_time_scaled(p, cputime_to_scaled(one_jiffy)); } else { - account_system_time(p, HARDIRQ_OFFSET, jiffies_to_cputime(1)); - account_system_time_scaled(p, jiffies_to_cputime(1)); + account_system_time(p, HARDIRQ_OFFSET, one_jiffy); + account_system_time_scaled(p, cputime_to_scaled(one_jiffy)); } } #endif diff --git a/lib/extable.c b/lib/extable.c index 463f4560f16d..179c08745595 100644 --- a/lib/extable.c +++ b/lib/extable.c @@ -57,10 +57,10 @@ search_extable(const struct exception_table_entry *first, while (first <= last) { const struct exception_table_entry *mid; - mid = (last - first) / 2 + first; + mid = ((last - first) >> 1) + first; /* - * careful, the distance between entries can be - * larger than 2GB: + * careful, the distance between value and insn + * can be larger than MAX_LONG: */ if (mid->insn < value) first = mid + 1; diff --git a/lib/smp_processor_id.c b/lib/smp_processor_id.c index eddc9b3d3876..6c90fb90e19c 100644 --- a/lib/smp_processor_id.c +++ b/lib/smp_processor_id.c @@ -42,7 +42,9 @@ unsigned int debug_smp_processor_id(void) if (!printk_ratelimit()) goto out_enable; - printk(KERN_ERR "BUG: using smp_processor_id() in preemptible [%08x] code: %s/%d\n", preempt_count(), current->comm, current->pid); + printk(KERN_ERR "BUG: using smp_processor_id() in preemptible [%08x] " + "code: %s/%d\n", + preempt_count() - 1, current->comm, current->pid); print_symbol("caller is %s\n", (long)__builtin_return_address(0)); dump_stack(); diff --git a/mm/Makefile b/mm/Makefile index 44e2528af70c..4af5dff37277 100644 --- a/mm/Makefile +++ b/mm/Makefile @@ -16,6 +16,7 @@ obj-y := bootmem.o filemap.o mempool.o oom_kill.o fadvise.o \ obj-$(CONFIG_PROC_PAGE_MONITOR) += pagewalk.o obj-$(CONFIG_BOUNCE) += bounce.o obj-$(CONFIG_SWAP) += page_io.o swap_state.o swapfile.o thrash.o +obj-$(CONFIG_HAS_DMA) += dmapool.o obj-$(CONFIG_HUGETLBFS) += hugetlb.o obj-$(CONFIG_NUMA) += mempolicy.o obj-$(CONFIG_SPARSEMEM) += sparse.o diff --git a/mm/allocpercpu.c b/mm/allocpercpu.c index 00b02623f008..7e58322b7134 100644 --- a/mm/allocpercpu.c +++ b/mm/allocpercpu.c @@ -98,7 +98,7 @@ EXPORT_SYMBOL_GPL(__percpu_populate_mask); */ void *__percpu_alloc_mask(size_t size, gfp_t gfp, cpumask_t *mask) { - void *pdata = kzalloc(sizeof(struct percpu_data), gfp); + void *pdata = kzalloc(nr_cpu_ids * sizeof(void *), gfp); void *__pdata = __percpu_disguise(pdata); if (unlikely(!pdata)) diff --git a/mm/dmapool.c b/mm/dmapool.c new file mode 100644 index 000000000000..34aaac451a96 --- /dev/null +++ b/mm/dmapool.c @@ -0,0 +1,500 @@ +/* + * DMA Pool allocator + * + * Copyright 2001 David Brownell + * Copyright 2007 Intel Corporation + * Author: Matthew Wilcox <willy@linux.intel.com> + * + * This software may be redistributed and/or modified under the terms of + * the GNU General Public License ("GPL") version 2 as published by the + * Free Software Foundation. + * + * This allocator returns small blocks of a given size which are DMA-able by + * the given device. It uses the dma_alloc_coherent page allocator to get + * new pages, then splits them up into blocks of the required size. + * Many older drivers still have their own code to do this. + * + * The current design of this allocator is fairly simple. The pool is + * represented by the 'struct dma_pool' which keeps a doubly-linked list of + * allocated pages. Each page in the page_list is split into blocks of at + * least 'size' bytes. Free blocks are tracked in an unsorted singly-linked + * list of free blocks within the page. Used blocks aren't tracked, but we + * keep a count of how many are currently allocated from each page. + */ + +#include <linux/device.h> +#include <linux/dma-mapping.h> +#include <linux/dmapool.h> +#include <linux/kernel.h> +#include <linux/list.h> +#include <linux/module.h> +#include <linux/mutex.h> +#include <linux/poison.h> +#include <linux/sched.h> +#include <linux/slab.h> +#include <linux/spinlock.h> +#include <linux/string.h> +#include <linux/types.h> +#include <linux/wait.h> + +struct dma_pool { /* the pool */ + struct list_head page_list; + spinlock_t lock; + size_t size; + struct device *dev; + size_t allocation; + size_t boundary; + char name[32]; + wait_queue_head_t waitq; + struct list_head pools; +}; + +struct dma_page { /* cacheable header for 'allocation' bytes */ + struct list_head page_list; + void *vaddr; + dma_addr_t dma; + unsigned int in_use; + unsigned int offset; +}; + +#define POOL_TIMEOUT_JIFFIES ((100 /* msec */ * HZ) / 1000) + +static DEFINE_MUTEX(pools_lock); + +static ssize_t +show_pools(struct device *dev, struct device_attribute *attr, char *buf) +{ + unsigned temp; + unsigned size; + char *next; + struct dma_page *page; + struct dma_pool *pool; + + next = buf; + size = PAGE_SIZE; + + temp = scnprintf(next, size, "poolinfo - 0.1\n"); + size -= temp; + next += temp; + + mutex_lock(&pools_lock); + list_for_each_entry(pool, &dev->dma_pools, pools) { + unsigned pages = 0; + unsigned blocks = 0; + + list_for_each_entry(page, &pool->page_list, page_list) { + pages++; + blocks += page->in_use; + } + + /* per-pool info, no real statistics yet */ + temp = scnprintf(next, size, "%-16s %4u %4Zu %4Zu %2u\n", + pool->name, blocks, + pages * (pool->allocation / pool->size), + pool->size, pages); + size -= temp; + next += temp; + } + mutex_unlock(&pools_lock); + + return PAGE_SIZE - size; +} + +static DEVICE_ATTR(pools, S_IRUGO, show_pools, NULL); + +/** + * dma_pool_create - Creates a pool of consistent memory blocks, for dma. + * @name: name of pool, for diagnostics + * @dev: device that will be doing the DMA + * @size: size of the blocks in this pool. + * @align: alignment requirement for blocks; must be a power of two + * @boundary: returned blocks won't cross this power of two boundary + * Context: !in_interrupt() + * + * Returns a dma allocation pool with the requested characteristics, or + * null if one can't be created. Given one of these pools, dma_pool_alloc() + * may be used to allocate memory. Such memory will all have "consistent" + * DMA mappings, accessible by the device and its driver without using + * cache flushing primitives. The actual size of blocks allocated may be + * larger than requested because of alignment. + * + * If @boundary is nonzero, objects returned from dma_pool_alloc() won't + * cross that size boundary. This is useful for devices which have + * addressing restrictions on individual DMA transfers, such as not crossing + * boundaries of 4KBytes. + */ +struct dma_pool *dma_pool_create(const char *name, struct device *dev, + size_t size, size_t align, size_t boundary) +{ + struct dma_pool *retval; + size_t allocation; + + if (align == 0) { + align = 1; + } else if (align & (align - 1)) { + return NULL; + } + + if (size == 0) { + return NULL; + } else if (size < 4) { + size = 4; + } + + if ((size % align) != 0) + size = ALIGN(size, align); + + allocation = max_t(size_t, size, PAGE_SIZE); + + if (!boundary) { + boundary = allocation; + } else if ((boundary < size) || (boundary & (boundary - 1))) { + return NULL; + } + + retval = kmalloc_node(sizeof(*retval), GFP_KERNEL, dev_to_node(dev)); + if (!retval) + return retval; + + strlcpy(retval->name, name, sizeof(retval->name)); + + retval->dev = dev; + + INIT_LIST_HEAD(&retval->page_list); + spin_lock_init(&retval->lock); + retval->size = size; + retval->boundary = boundary; + retval->allocation = allocation; + init_waitqueue_head(&retval->waitq); + + if (dev) { + int ret; + + mutex_lock(&pools_lock); + if (list_empty(&dev->dma_pools)) + ret = device_create_file(dev, &dev_attr_pools); + else + ret = 0; + /* note: not currently insisting "name" be unique */ + if (!ret) + list_add(&retval->pools, &dev->dma_pools); + else { + kfree(retval); + retval = NULL; + } + mutex_unlock(&pools_lock); + } else + INIT_LIST_HEAD(&retval->pools); + + return retval; +} +EXPORT_SYMBOL(dma_pool_create); + +static void pool_initialise_page(struct dma_pool *pool, struct dma_page *page) +{ + unsigned int offset = 0; + unsigned int next_boundary = pool->boundary; + + do { + unsigned int next = offset + pool->size; + if (unlikely((next + pool->size) >= next_boundary)) { + next = next_boundary; + next_boundary += pool->boundary; + } + *(int *)(page->vaddr + offset) = next; + offset = next; + } while (offset < pool->allocation); +} + +static struct dma_page *pool_alloc_page(struct dma_pool *pool, gfp_t mem_flags) +{ + struct dma_page *page; + + page = kmalloc(sizeof(*page), mem_flags); + if (!page) + return NULL; + page->vaddr = dma_alloc_coherent(pool->dev, pool->allocation, + &page->dma, mem_flags); + if (page->vaddr) { +#ifdef CONFIG_DEBUG_SLAB + memset(page->vaddr, POOL_POISON_FREED, pool->allocation); +#endif + pool_initialise_page(pool, page); + list_add(&page->page_list, &pool->page_list); + page->in_use = 0; + page->offset = 0; + } else { + kfree(page); + page = NULL; + } + return page; +} + +static inline int is_page_busy(struct dma_page *page) +{ + return page->in_use != 0; +} + +static void pool_free_page(struct dma_pool *pool, struct dma_page *page) +{ + dma_addr_t dma = page->dma; + +#ifdef CONFIG_DEBUG_SLAB + memset(page->vaddr, POOL_POISON_FREED, pool->allocation); +#endif + dma_free_coherent(pool->dev, pool->allocation, page->vaddr, dma); + list_del(&page->page_list); + kfree(page); +} + +/** + * dma_pool_destroy - destroys a pool of dma memory blocks. + * @pool: dma pool that will be destroyed + * Context: !in_interrupt() + * + * Caller guarantees that no more memory from the pool is in use, + * and that nothing will try to use the pool after this call. + */ +void dma_pool_destroy(struct dma_pool *pool) +{ + mutex_lock(&pools_lock); + list_del(&pool->pools); + if (pool->dev && list_empty(&pool->dev->dma_pools)) + device_remove_file(pool->dev, &dev_attr_pools); + mutex_unlock(&pools_lock); + + while (!list_empty(&pool->page_list)) { + struct dma_page *page; + page = list_entry(pool->page_list.next, + struct dma_page, page_list); + if (is_page_busy(page)) { + if (pool->dev) + dev_err(pool->dev, + "dma_pool_destroy %s, %p busy\n", + pool->name, page->vaddr); + else + printk(KERN_ERR + "dma_pool_destroy %s, %p busy\n", + pool->name, page->vaddr); + /* leak the still-in-use consistent memory */ + list_del(&page->page_list); + kfree(page); + } else + pool_free_page(pool, page); + } + + kfree(pool); +} +EXPORT_SYMBOL(dma_pool_destroy); + +/** + * dma_pool_alloc - get a block of consistent memory + * @pool: dma pool that will produce the block + * @mem_flags: GFP_* bitmask + * @handle: pointer to dma address of block + * + * This returns the kernel virtual address of a currently unused block, + * and reports its dma address through the handle. + * If such a memory block can't be allocated, %NULL is returned. + */ +void *dma_pool_alloc(struct dma_pool *pool, gfp_t mem_flags, + dma_addr_t *handle) +{ + unsigned long flags; + struct dma_page *page; + size_t offset; + void *retval; + + spin_lock_irqsave(&pool->lock, flags); + restart: + list_for_each_entry(page, &pool->page_list, page_list) { + if (page->offset < pool->allocation) + goto ready; + } + page = pool_alloc_page(pool, GFP_ATOMIC); + if (!page) { + if (mem_flags & __GFP_WAIT) { + DECLARE_WAITQUEUE(wait, current); + + __set_current_state(TASK_INTERRUPTIBLE); + __add_wait_queue(&pool->waitq, &wait); + spin_unlock_irqrestore(&pool->lock, flags); + + schedule_timeout(POOL_TIMEOUT_JIFFIES); + + spin_lock_irqsave(&pool->lock, flags); + __remove_wait_queue(&pool->waitq, &wait); + goto restart; + } + retval = NULL; + goto done; + } + + ready: + page->in_use++; + offset = page->offset; + page->offset = *(int *)(page->vaddr + offset); + retval = offset + page->vaddr; + *handle = offset + page->dma; +#ifdef CONFIG_DEBUG_SLAB + memset(retval, POOL_POISON_ALLOCATED, pool->size); +#endif + done: + spin_unlock_irqrestore(&pool->lock, flags); + return retval; +} +EXPORT_SYMBOL(dma_pool_alloc); + +static struct dma_page *pool_find_page(struct dma_pool *pool, dma_addr_t dma) +{ + unsigned long flags; + struct dma_page *page; + + spin_lock_irqsave(&pool->lock, flags); + list_for_each_entry(page, &pool->page_list, page_list) { + if (dma < page->dma) + continue; + if (dma < (page->dma + pool->allocation)) + goto done; + } + page = NULL; + done: + spin_unlock_irqrestore(&pool->lock, flags); + return page; +} + +/** + * dma_pool_free - put block back into dma pool + * @pool: the dma pool holding the block + * @vaddr: virtual address of block + * @dma: dma address of block + * + * Caller promises neither device nor driver will again touch this block + * unless it is first re-allocated. + */ +void dma_pool_free(struct dma_pool *pool, void *vaddr, dma_addr_t dma) +{ + struct dma_page *page; + unsigned long flags; + unsigned int offset; + + page = pool_find_page(pool, dma); + if (!page) { + if (pool->dev) + dev_err(pool->dev, + "dma_pool_free %s, %p/%lx (bad dma)\n", + pool->name, vaddr, (unsigned long)dma); + else + printk(KERN_ERR "dma_pool_free %s, %p/%lx (bad dma)\n", + pool->name, vaddr, (unsigned long)dma); + return; + } + + offset = vaddr - page->vaddr; +#ifdef CONFIG_DEBUG_SLAB + if ((dma - page->dma) != offset) { + if (pool->dev) + dev_err(pool->dev, + "dma_pool_free %s, %p (bad vaddr)/%Lx\n", + pool->name, vaddr, (unsigned long long)dma); + else + printk(KERN_ERR + "dma_pool_free %s, %p (bad vaddr)/%Lx\n", + pool->name, vaddr, (unsigned long long)dma); + return; + } + { + unsigned int chain = page->offset; + while (chain < pool->allocation) { + if (chain != offset) { + chain = *(int *)(page->vaddr + chain); + continue; + } + if (pool->dev) + dev_err(pool->dev, "dma_pool_free %s, dma %Lx " + "already free\n", pool->name, + (unsigned long long)dma); + else + printk(KERN_ERR "dma_pool_free %s, dma %Lx " + "already free\n", pool->name, + (unsigned long long)dma); + return; + } + } + memset(vaddr, POOL_POISON_FREED, pool->size); +#endif + + spin_lock_irqsave(&pool->lock, flags); + page->in_use--; + *(int *)vaddr = page->offset; + page->offset = offset; + if (waitqueue_active(&pool->waitq)) + wake_up_locked(&pool->waitq); + /* + * Resist a temptation to do + * if (!is_page_busy(page)) pool_free_page(pool, page); + * Better have a few empty pages hang around. + */ + spin_unlock_irqrestore(&pool->lock, flags); +} +EXPORT_SYMBOL(dma_pool_free); + +/* + * Managed DMA pool + */ +static void dmam_pool_release(struct device *dev, void *res) +{ + struct dma_pool *pool = *(struct dma_pool **)res; + + dma_pool_destroy(pool); +} + +static int dmam_pool_match(struct device *dev, void *res, void *match_data) +{ + return *(struct dma_pool **)res == match_data; +} + +/** + * dmam_pool_create - Managed dma_pool_create() + * @name: name of pool, for diagnostics + * @dev: device that will be doing the DMA + * @size: size of the blocks in this pool. + * @align: alignment requirement for blocks; must be a power of two + * @allocation: returned blocks won't cross this boundary (or zero) + * + * Managed dma_pool_create(). DMA pool created with this function is + * automatically destroyed on driver detach. + */ +struct dma_pool *dmam_pool_create(const char *name, struct device *dev, + size_t size, size_t align, size_t allocation) +{ + struct dma_pool **ptr, *pool; + + ptr = devres_alloc(dmam_pool_release, sizeof(*ptr), GFP_KERNEL); + if (!ptr) + return NULL; + + pool = *ptr = dma_pool_create(name, dev, size, align, allocation); + if (pool) + devres_add(dev, ptr); + else + devres_free(ptr); + + return pool; +} +EXPORT_SYMBOL(dmam_pool_create); + +/** + * dmam_pool_destroy - Managed dma_pool_destroy() + * @pool: dma pool that will be destroyed + * + * Managed dma_pool_destroy(). + */ +void dmam_pool_destroy(struct dma_pool *pool) +{ + struct device *dev = pool->dev; + + dma_pool_destroy(pool); + WARN_ON(devres_destroy(dev, dmam_pool_release, dmam_pool_match, pool)); +} +EXPORT_SYMBOL(dmam_pool_destroy); diff --git a/scripts/checkstack.pl b/scripts/checkstack.pl index d716b76098bb..340ad6920511 100755 --- a/scripts/checkstack.pl +++ b/scripts/checkstack.pl @@ -2,7 +2,7 @@ # Check the stack usage of functions # -# Copyright Joern Engel <joern@wh.fh-wedel.de> +# Copyright Joern Engel <joern@lazybastard.org> # Inspired by Linus Torvalds # Original idea maybe from Keith Owens # s390 port and big speedup by Arnd Bergmann <arnd@bergmann-dalldorf.de> diff --git a/scripts/kallsyms.c b/scripts/kallsyms.c index 1f11d848532a..c912137f80e2 100644 --- a/scripts/kallsyms.c +++ b/scripts/kallsyms.c @@ -31,17 +31,16 @@ #define KSYM_NAME_LEN 128 - struct sym_entry { unsigned long long addr; unsigned int len; + unsigned int start_pos; unsigned char *sym; }; - static struct sym_entry *table; static unsigned int table_size, table_cnt; -static unsigned long long _text, _stext, _etext, _sinittext, _einittext, _sextratext, _eextratext; +static unsigned long long _text, _stext, _etext, _sinittext, _einittext; static int all_symbols = 0; static char symbol_prefix_char = '\0'; @@ -99,10 +98,6 @@ static int read_symbol(FILE *in, struct sym_entry *s) _sinittext = s->addr; else if (strcmp(sym, "_einittext") == 0) _einittext = s->addr; - else if (strcmp(sym, "_sextratext") == 0) - _sextratext = s->addr; - else if (strcmp(sym, "_eextratext") == 0) - _eextratext = s->addr; else if (toupper(stype) == 'A') { /* Keep these useful absolute symbols */ @@ -165,18 +160,18 @@ static int symbol_valid(struct sym_entry *s) * and inittext sections are discarded */ if (!all_symbols) { if ((s->addr < _stext || s->addr > _etext) - && (s->addr < _sinittext || s->addr > _einittext) - && (s->addr < _sextratext || s->addr > _eextratext)) + && (s->addr < _sinittext || s->addr > _einittext)) return 0; /* Corner case. Discard any symbols with the same value as - * _etext _einittext or _eextratext; they can move between pass - * 1 and 2 when the kallsyms data are added. If these symbols - * move then they may get dropped in pass 2, which breaks the - * kallsyms rules. + * _etext _einittext; they can move between pass 1 and 2 when + * the kallsyms data are added. If these symbols move then + * they may get dropped in pass 2, which breaks the kallsyms + * rules. */ - if ((s->addr == _etext && strcmp((char*)s->sym + offset, "_etext")) || - (s->addr == _einittext && strcmp((char*)s->sym + offset, "_einittext")) || - (s->addr == _eextratext && strcmp((char*)s->sym + offset, "_eextratext"))) + if ((s->addr == _etext && + strcmp((char *)s->sym + offset, "_etext")) || + (s->addr == _einittext && + strcmp((char *)s->sym + offset, "_einittext"))) return 0; } @@ -202,8 +197,10 @@ static void read_map(FILE *in) exit (1); } } - if (read_symbol(in, &table[table_cnt]) == 0) + if (read_symbol(in, &table[table_cnt]) == 0) { + table[table_cnt].start_pos = table_cnt; table_cnt++; + } } } @@ -506,6 +503,35 @@ static void optimize_token_table(void) optimize_result(); } +static int compare_symbols(const void *a, const void *b) +{ + const struct sym_entry *sa; + const struct sym_entry *sb; + int wa, wb; + + sa = a; + sb = b; + + /* sort by address first */ + if (sa->addr > sb->addr) + return 1; + if (sa->addr < sb->addr) + return -1; + + /* sort by "weakness" type */ + wa = (sa->sym[0] == 'w') || (sa->sym[0] == 'W'); + wb = (sb->sym[0] == 'w') || (sb->sym[0] == 'W'); + if (wa != wb) + return wa - wb; + + /* sort by initial order, so that other symbols are left undisturbed */ + return sa->start_pos - sb->start_pos; +} + +static void sort_symbols(void) +{ + qsort(table, table_cnt, sizeof(struct sym_entry), compare_symbols); +} int main(int argc, char **argv) { @@ -527,6 +553,7 @@ int main(int argc, char **argv) usage(); read_map(stdin); + sort_symbols(); optimize_token_table(); write_src(); diff --git a/sound/oss/Makefile b/sound/oss/Makefile index f883c4b676ab..1f86299fae40 100644 --- a/sound/oss/Makefile +++ b/sound/oss/Makefile @@ -6,7 +6,6 @@ # Each configuration option enables a list of files. obj-$(CONFIG_SOUND_OSS) += sound.o -obj-$(CONFIG_SOUND_CS4232) += cs4232.o ad1848.o # Please leave it as is, cause the link order is significant ! @@ -16,7 +15,6 @@ obj-$(CONFIG_SOUND_AEDSP16) += aedsp16.o obj-$(CONFIG_SOUND_PSS) += pss.o ad1848.o mpu401.o obj-$(CONFIG_SOUND_TRIX) += trix.o ad1848.o sb_lib.o uart401.o obj-$(CONFIG_SOUND_SSCAPE) += sscape.o ad1848.o mpu401.o -obj-$(CONFIG_SOUND_CS4232) += cs4232.o uart401.o obj-$(CONFIG_SOUND_MSS) += ad1848.o obj-$(CONFIG_SOUND_PAS) += pas2.o sb.o sb_lib.o uart401.o obj-$(CONFIG_SOUND_SB) += sb.o sb_lib.o uart401.o @@ -27,19 +25,12 @@ obj-$(CONFIG_SOUND_YM3812) += opl3.o obj-$(CONFIG_SOUND_VMIDI) += v_midi.o obj-$(CONFIG_SOUND_VIDC) += vidc_mod.o obj-$(CONFIG_SOUND_WAVEARTIST) += waveartist.o - -obj-$(CONFIG_SOUND_VIA82CXXX) += via82cxxx_audio.o ac97_codec.o -ifeq ($(CONFIG_MIDI_VIA82CXXX),y) - obj-$(CONFIG_SOUND_VIA82CXXX) += sound.o uart401.o -endif obj-$(CONFIG_SOUND_MSNDCLAS) += msnd.o msnd_classic.o obj-$(CONFIG_SOUND_MSNDPIN) += msnd.o msnd_pinnacle.o obj-$(CONFIG_SOUND_VWSND) += vwsnd.o -obj-$(CONFIG_SOUND_ICH) += i810_audio.o ac97_codec.o obj-$(CONFIG_SOUND_AU1550_AC97) += au1550_ac97.o ac97_codec.o obj-$(CONFIG_SOUND_TRIDENT) += trident.o ac97_codec.o obj-$(CONFIG_SOUND_BCM_CS4297A) += swarm_cs4297a.o -obj-$(CONFIG_SOUND_BT878) += btaudio.o obj-$(CONFIG_SOUND_WM97XX) += ac97_plugin_wm97xx.o diff --git a/sound/oss/ac97_codec.c b/sound/oss/ac97_codec.c index fef56cac06c8..87a672680761 100644 --- a/sound/oss/ac97_codec.c +++ b/sound/oss/ac97_codec.c @@ -189,42 +189,6 @@ static const struct { {0x57454301, "Winbond 83971D", &null_ops}, }; -static const char *ac97_stereo_enhancements[] = -{ - /* 0 */ "No 3D Stereo Enhancement", - /* 1 */ "Analog Devices Phat Stereo", - /* 2 */ "Creative Stereo Enhancement", - /* 3 */ "National Semi 3D Stereo Enhancement", - /* 4 */ "YAMAHA Ymersion", - /* 5 */ "BBE 3D Stereo Enhancement", - /* 6 */ "Crystal Semi 3D Stereo Enhancement", - /* 7 */ "Qsound QXpander", - /* 8 */ "Spatializer 3D Stereo Enhancement", - /* 9 */ "SRS 3D Stereo Enhancement", - /* 10 */ "Platform Tech 3D Stereo Enhancement", - /* 11 */ "AKM 3D Audio", - /* 12 */ "Aureal Stereo Enhancement", - /* 13 */ "Aztech 3D Enhancement", - /* 14 */ "Binaura 3D Audio Enhancement", - /* 15 */ "ESS Technology Stereo Enhancement", - /* 16 */ "Harman International VMAx", - /* 17 */ "Nvidea 3D Stereo Enhancement", - /* 18 */ "Philips Incredible Sound", - /* 19 */ "Texas Instruments 3D Stereo Enhancement", - /* 20 */ "VLSI Technology 3D Stereo Enhancement", - /* 21 */ "TriTech 3D Stereo Enhancement", - /* 22 */ "Realtek 3D Stereo Enhancement", - /* 23 */ "Samsung 3D Stereo Enhancement", - /* 24 */ "Wolfson Microelectronics 3D Enhancement", - /* 25 */ "Delta Integration 3D Enhancement", - /* 26 */ "SigmaTel 3D Enhancement", - /* 27 */ "Winbond 3D Stereo Enhancement", - /* 28 */ "Rockwell 3D Stereo Enhancement", - /* 29 */ "Reserved 29", - /* 30 */ "Reserved 30", - /* 31 */ "Reserved 31" -}; - /* this table has default mixer values for all OSS mixers. */ static struct mixer_defaults { int mixer; @@ -614,83 +578,6 @@ static int ac97_mixer_ioctl(struct ac97_codec *codec, unsigned int cmd, unsigned return -EINVAL; } -/* entry point for /proc/driver/controller_vendor/ac97/%d */ -int ac97_read_proc (char *page, char **start, off_t off, - int count, int *eof, void *data) -{ - int len = 0, cap, extid, val, id1, id2; - struct ac97_codec *codec; - int is_ac97_20 = 0; - - if ((codec = data) == NULL) - return -ENODEV; - - id1 = codec->codec_read(codec, AC97_VENDOR_ID1); - id2 = codec->codec_read(codec, AC97_VENDOR_ID2); - len += sprintf (page+len, "Vendor name : %s\n", codec->name); - len += sprintf (page+len, "Vendor id : %04X %04X\n", id1, id2); - - extid = codec->codec_read(codec, AC97_EXTENDED_ID); - extid &= ~((1<<2)|(1<<4)|(1<<5)|(1<<10)|(1<<11)|(1<<12)|(1<<13)); - len += sprintf (page+len, "AC97 Version : %s\n", - extid ? "2.0 or later" : "1.0"); - if (extid) is_ac97_20 = 1; - - cap = codec->codec_read(codec, AC97_RESET); - len += sprintf (page+len, "Capabilities :%s%s%s%s%s%s\n", - cap & 0x0001 ? " -dedicated MIC PCM IN channel-" : "", - cap & 0x0002 ? " -reserved1-" : "", - cap & 0x0004 ? " -bass & treble-" : "", - cap & 0x0008 ? " -simulated stereo-" : "", - cap & 0x0010 ? " -headphone out-" : "", - cap & 0x0020 ? " -loudness-" : ""); - val = cap & 0x00c0; - len += sprintf (page+len, "DAC resolutions :%s%s%s\n", - " -16-bit-", - val & 0x0040 ? " -18-bit-" : "", - val & 0x0080 ? " -20-bit-" : ""); - val = cap & 0x0300; - len += sprintf (page+len, "ADC resolutions :%s%s%s\n", - " -16-bit-", - val & 0x0100 ? " -18-bit-" : "", - val & 0x0200 ? " -20-bit-" : ""); - len += sprintf (page+len, "3D enhancement : %s\n", - ac97_stereo_enhancements[(cap >> 10) & 0x1f]); - - val = codec->codec_read(codec, AC97_GENERAL_PURPOSE); - len += sprintf (page+len, "POP path : %s 3D\n" - "Sim. stereo : %s\n" - "3D enhancement : %s\n" - "Loudness : %s\n" - "Mono output : %s\n" - "MIC select : %s\n" - "ADC/DAC loopback : %s\n", - val & 0x8000 ? "post" : "pre", - val & 0x4000 ? "on" : "off", - val & 0x2000 ? "on" : "off", - val & 0x1000 ? "on" : "off", - val & 0x0200 ? "MIC" : "MIX", - val & 0x0100 ? "MIC2" : "MIC1", - val & 0x0080 ? "on" : "off"); - - extid = codec->codec_read(codec, AC97_EXTENDED_ID); - cap = extid; - len += sprintf (page+len, "Ext Capabilities :%s%s%s%s%s%s%s\n", - cap & 0x0001 ? " -var rate PCM audio-" : "", - cap & 0x0002 ? " -2x PCM audio out-" : "", - cap & 0x0008 ? " -var rate MIC in-" : "", - cap & 0x0040 ? " -PCM center DAC-" : "", - cap & 0x0080 ? " -PCM surround DAC-" : "", - cap & 0x0100 ? " -PCM LFE DAC-" : "", - cap & 0x0200 ? " -slot/DAC mappings-" : ""); - if (is_ac97_20) { - len += sprintf (page+len, "Front DAC rate : %d\n", - codec->codec_read(codec, AC97_PCM_FRONT_DAC_RATE)); - } - - return len; -} - /** * codec_id - Turn id1/id2 into a PnP string * @id1: Vendor ID1 @@ -1313,176 +1200,5 @@ static int pt101_init(struct ac97_codec * codec) #endif -EXPORT_SYMBOL(ac97_read_proc); EXPORT_SYMBOL(ac97_probe_codec); -/* - * AC97 library support routines - */ - -/** - * ac97_set_dac_rate - set codec rate adaption - * @codec: ac97 code - * @rate: rate in hertz - * - * Set the DAC rate. Assumes the codec supports VRA. The caller is - * expected to have checked this little detail. - */ - -unsigned int ac97_set_dac_rate(struct ac97_codec *codec, unsigned int rate) -{ - unsigned int new_rate = rate; - u32 dacp; - u32 mast_vol, phone_vol, mono_vol, pcm_vol; - u32 mute_vol = 0x8000; /* The mute volume? */ - - if(rate != codec->codec_read(codec, AC97_PCM_FRONT_DAC_RATE)) - { - /* Mute several registers */ - mast_vol = codec->codec_read(codec, AC97_MASTER_VOL_STEREO); - mono_vol = codec->codec_read(codec, AC97_MASTER_VOL_MONO); - phone_vol = codec->codec_read(codec, AC97_HEADPHONE_VOL); - pcm_vol = codec->codec_read(codec, AC97_PCMOUT_VOL); - codec->codec_write(codec, AC97_MASTER_VOL_STEREO, mute_vol); - codec->codec_write(codec, AC97_MASTER_VOL_MONO, mute_vol); - codec->codec_write(codec, AC97_HEADPHONE_VOL, mute_vol); - codec->codec_write(codec, AC97_PCMOUT_VOL, mute_vol); - - /* Power down the DAC */ - dacp=codec->codec_read(codec, AC97_POWER_CONTROL); - codec->codec_write(codec, AC97_POWER_CONTROL, dacp|0x0200); - /* Load the rate and read the effective rate */ - codec->codec_write(codec, AC97_PCM_FRONT_DAC_RATE, rate); - new_rate=codec->codec_read(codec, AC97_PCM_FRONT_DAC_RATE); - /* Power it back up */ - codec->codec_write(codec, AC97_POWER_CONTROL, dacp); - - /* Restore volumes */ - codec->codec_write(codec, AC97_MASTER_VOL_STEREO, mast_vol); - codec->codec_write(codec, AC97_MASTER_VOL_MONO, mono_vol); - codec->codec_write(codec, AC97_HEADPHONE_VOL, phone_vol); - codec->codec_write(codec, AC97_PCMOUT_VOL, pcm_vol); - } - return new_rate; -} - -EXPORT_SYMBOL(ac97_set_dac_rate); - -/** - * ac97_set_adc_rate - set codec rate adaption - * @codec: ac97 code - * @rate: rate in hertz - * - * Set the ADC rate. Assumes the codec supports VRA. The caller is - * expected to have checked this little detail. - */ - -unsigned int ac97_set_adc_rate(struct ac97_codec *codec, unsigned int rate) -{ - unsigned int new_rate = rate; - u32 dacp; - - if(rate != codec->codec_read(codec, AC97_PCM_LR_ADC_RATE)) - { - /* Power down the ADC */ - dacp=codec->codec_read(codec, AC97_POWER_CONTROL); - codec->codec_write(codec, AC97_POWER_CONTROL, dacp|0x0100); - /* Load the rate and read the effective rate */ - codec->codec_write(codec, AC97_PCM_LR_ADC_RATE, rate); - new_rate=codec->codec_read(codec, AC97_PCM_LR_ADC_RATE); - /* Power it back up */ - codec->codec_write(codec, AC97_POWER_CONTROL, dacp); - } - return new_rate; -} - -EXPORT_SYMBOL(ac97_set_adc_rate); - -static int swap_headphone(int remove_master) -{ - struct list_head *l; - struct ac97_codec *c; - - if (remove_master) { - mutex_lock(&codec_mutex); - list_for_each(l, &codecs) - { - c = list_entry(l, struct ac97_codec, list); - if (supported_mixer(c, SOUND_MIXER_PHONEOUT)) - c->supported_mixers &= ~SOUND_MASK_PHONEOUT; - } - mutex_unlock(&codec_mutex); - } else - ac97_hw[SOUND_MIXER_PHONEOUT].offset = AC97_MASTER_VOL_STEREO; - - /* Scale values already match */ - ac97_hw[SOUND_MIXER_VOLUME].offset = AC97_MASTER_VOL_MONO; - return 0; -} - -static int apply_quirk(int quirk) -{ - switch (quirk) { - case AC97_TUNE_NONE: - return 0; - case AC97_TUNE_HP_ONLY: - return swap_headphone(1); - case AC97_TUNE_SWAP_HP: - return swap_headphone(0); - case AC97_TUNE_SWAP_SURROUND: - return -ENOSYS; /* not yet implemented */ - case AC97_TUNE_AD_SHARING: - return -ENOSYS; /* not yet implemented */ - case AC97_TUNE_ALC_JACK: - return -ENOSYS; /* not yet implemented */ - } - return -EINVAL; -} - -/** - * ac97_tune_hardware - tune up the hardware - * @pdev: pci_dev pointer - * @quirk: quirk list - * @override: explicit quirk value (overrides if not AC97_TUNE_DEFAULT) - * - * Do some workaround for each pci device, such as renaming of the - * headphone (true line-out) control as "Master". - * The quirk-list must be terminated with a zero-filled entry. - * - * Returns zero if successful, or a negative error code on failure. - */ - -int ac97_tune_hardware(struct pci_dev *pdev, struct ac97_quirk *quirk, int override) -{ - int result; - - if (!quirk) - return -EINVAL; - - if (override != AC97_TUNE_DEFAULT) { - result = apply_quirk(override); - if (result < 0) - printk(KERN_ERR "applying quirk type %d failed (%d)\n", override, result); - return result; - } - - for (; quirk->vendor; quirk++) { - if (quirk->vendor != pdev->subsystem_vendor) - continue; - if ((! quirk->mask && quirk->device == pdev->subsystem_device) || - quirk->device == (quirk->mask & pdev->subsystem_device)) { -#ifdef DEBUG - printk("ac97 quirk for %s (%04x:%04x)\n", quirk->name, ac97->subsystem_vendor, pdev->subsystem_device); -#endif - result = apply_quirk(quirk->type); - if (result < 0) - printk(KERN_ERR "applying quirk type %d for %s failed (%d)\n", quirk->type, quirk->name, result); - return result; - } - } - return 0; -} - -EXPORT_SYMBOL_GPL(ac97_tune_hardware); - -MODULE_LICENSE("GPL"); diff --git a/sound/oss/btaudio.c b/sound/oss/btaudio.c deleted file mode 100644 index 4d5cf05b8922..000000000000 --- a/sound/oss/btaudio.c +++ /dev/null @@ -1,1139 +0,0 @@ -/* - btaudio - bt878 audio dma driver for linux 2.4.x - - (c) 2000-2002 Gerd Knorr <kraxel@bytesex.org> - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - -*/ - -#include <linux/module.h> -#include <linux/errno.h> -#include <linux/pci.h> -#include <linux/sched.h> -#include <linux/signal.h> -#include <linux/types.h> -#include <linux/interrupt.h> -#include <linux/init.h> -#include <linux/poll.h> -#include <linux/sound.h> -#include <linux/soundcard.h> -#include <linux/slab.h> -#include <linux/kdev_t.h> -#include <linux/mutex.h> - -#include <asm/uaccess.h> -#include <asm/io.h> - - -/* mmio access */ -#define btwrite(dat,adr) writel((dat), (bta->mmio+(adr))) -#define btread(adr) readl(bta->mmio+(adr)) - -#define btand(dat,adr) btwrite((dat) & btread(adr), adr) -#define btor(dat,adr) btwrite((dat) | btread(adr), adr) -#define btaor(dat,mask,adr) btwrite((dat) | ((mask) & btread(adr)), adr) - -/* registers (shifted because bta->mmio is long) */ -#define REG_INT_STAT (0x100 >> 2) -#define REG_INT_MASK (0x104 >> 2) -#define REG_GPIO_DMA_CTL (0x10c >> 2) -#define REG_PACKET_LEN (0x110 >> 2) -#define REG_RISC_STRT_ADD (0x114 >> 2) -#define REG_RISC_COUNT (0x120 >> 2) - -/* IRQ bits - REG_INT_(STAT|MASK) */ -#define IRQ_SCERR (1 << 19) -#define IRQ_OCERR (1 << 18) -#define IRQ_PABORT (1 << 17) -#define IRQ_RIPERR (1 << 16) -#define IRQ_PPERR (1 << 15) -#define IRQ_FDSR (1 << 14) -#define IRQ_FTRGT (1 << 13) -#define IRQ_FBUS (1 << 12) -#define IRQ_RISCI (1 << 11) -#define IRQ_OFLOW (1 << 3) - -#define IRQ_BTAUDIO (IRQ_SCERR | IRQ_OCERR | IRQ_PABORT | IRQ_RIPERR |\ - IRQ_PPERR | IRQ_FDSR | IRQ_FTRGT | IRQ_FBUS |\ - IRQ_RISCI) - -/* REG_GPIO_DMA_CTL bits */ -#define DMA_CTL_A_PWRDN (1 << 26) -#define DMA_CTL_DA_SBR (1 << 14) -#define DMA_CTL_DA_ES2 (1 << 13) -#define DMA_CTL_ACAP_EN (1 << 4) -#define DMA_CTL_RISC_EN (1 << 1) -#define DMA_CTL_FIFO_EN (1 << 0) - -/* RISC instructions */ -#define RISC_WRITE (0x01 << 28) -#define RISC_JUMP (0x07 << 28) -#define RISC_SYNC (0x08 << 28) - -/* RISC bits */ -#define RISC_WR_SOL (1 << 27) -#define RISC_WR_EOL (1 << 26) -#define RISC_IRQ (1 << 24) -#define RISC_SYNC_RESYNC (1 << 15) -#define RISC_SYNC_FM1 0x06 -#define RISC_SYNC_VRO 0x0c - -#define HWBASE_AD (448000) - -/* -------------------------------------------------------------- */ - -struct btaudio { - /* linked list */ - struct btaudio *next; - - /* device info */ - int dsp_digital; - int dsp_analog; - int mixer_dev; - struct pci_dev *pci; - unsigned int irq; - unsigned long mem; - unsigned long __iomem *mmio; - - /* locking */ - int users; - struct mutex lock; - - /* risc instructions */ - unsigned int risc_size; - unsigned long *risc_cpu; - dma_addr_t risc_dma; - - /* audio data */ - unsigned int buf_size; - unsigned char *buf_cpu; - dma_addr_t buf_dma; - - /* buffer setup */ - int line_bytes; - int line_count; - int block_bytes; - int block_count; - - /* read fifo management */ - int recording; - int dma_block; - int read_offset; - int read_count; - wait_queue_head_t readq; - - /* settings */ - int gain[3]; - int source; - int bits; - int decimation; - int mixcount; - int sampleshift; - int channels; - int analog; - int rate; -}; - -struct cardinfo { - char *name; - int rate; -}; - -static struct btaudio *btaudios; -static unsigned int debug; -static unsigned int irq_debug; - -/* -------------------------------------------------------------- */ - -#define BUF_DEFAULT 128*1024 -#define BUF_MIN 8192 - -static int alloc_buffer(struct btaudio *bta) -{ - if (NULL == bta->buf_cpu) { - for (bta->buf_size = BUF_DEFAULT; bta->buf_size >= BUF_MIN; - bta->buf_size = bta->buf_size >> 1) { - bta->buf_cpu = pci_alloc_consistent - (bta->pci, bta->buf_size, &bta->buf_dma); - if (NULL != bta->buf_cpu) - break; - } - if (NULL == bta->buf_cpu) - return -ENOMEM; - memset(bta->buf_cpu,0,bta->buf_size); - } - if (NULL == bta->risc_cpu) { - bta->risc_size = PAGE_SIZE; - bta->risc_cpu = pci_alloc_consistent - (bta->pci, bta->risc_size, &bta->risc_dma); - if (NULL == bta->risc_cpu) { - pci_free_consistent(bta->pci, bta->buf_size, bta->buf_cpu, bta->buf_dma); - bta->buf_cpu = NULL; - return -ENOMEM; - } - } - return 0; -} - -static void free_buffer(struct btaudio *bta) -{ - if (NULL != bta->buf_cpu) { - pci_free_consistent(bta->pci, bta->buf_size, - bta->buf_cpu, bta->buf_dma); - bta->buf_cpu = NULL; - } - if (NULL != bta->risc_cpu) { - pci_free_consistent(bta->pci, bta->risc_size, - bta->risc_cpu, bta->risc_dma); - bta->risc_cpu = NULL; - } -} - -static int make_risc(struct btaudio *bta) -{ - int rp, bp, line, block; - unsigned long risc; - - bta->block_bytes = bta->buf_size >> 4; - bta->block_count = 1 << 4; - bta->line_bytes = bta->block_bytes; - bta->line_count = bta->block_count; - while (bta->line_bytes > 4095) { - bta->line_bytes >>= 1; - bta->line_count <<= 1; - } - if (bta->line_count > 255) - return -EINVAL; - if (debug) - printk(KERN_DEBUG - "btaudio: bufsize=%d - bs=%d bc=%d - ls=%d, lc=%d\n", - bta->buf_size,bta->block_bytes,bta->block_count, - bta->line_bytes,bta->line_count); - rp = 0; bp = 0; - block = 0; - bta->risc_cpu[rp++] = cpu_to_le32(RISC_SYNC|RISC_SYNC_FM1); - bta->risc_cpu[rp++] = cpu_to_le32(0); - for (line = 0; line < bta->line_count; line++) { - risc = RISC_WRITE | RISC_WR_SOL | RISC_WR_EOL; - risc |= bta->line_bytes; - if (0 == (bp & (bta->block_bytes-1))) { - risc |= RISC_IRQ; - risc |= (block & 0x0f) << 16; - risc |= (~block & 0x0f) << 20; - block++; - } - bta->risc_cpu[rp++] = cpu_to_le32(risc); - bta->risc_cpu[rp++] = cpu_to_le32(bta->buf_dma + bp); - bp += bta->line_bytes; - } - bta->risc_cpu[rp++] = cpu_to_le32(RISC_SYNC|RISC_SYNC_VRO); - bta->risc_cpu[rp++] = cpu_to_le32(0); - bta->risc_cpu[rp++] = cpu_to_le32(RISC_JUMP); - bta->risc_cpu[rp++] = cpu_to_le32(bta->risc_dma); - return 0; -} - -static int start_recording(struct btaudio *bta) -{ - int ret; - - if (0 != (ret = alloc_buffer(bta))) - return ret; - if (0 != (ret = make_risc(bta))) - return ret; - - btwrite(bta->risc_dma, REG_RISC_STRT_ADD); - btwrite((bta->line_count << 16) | bta->line_bytes, - REG_PACKET_LEN); - btwrite(IRQ_BTAUDIO, REG_INT_MASK); - if (bta->analog) { - btwrite(DMA_CTL_ACAP_EN | - DMA_CTL_RISC_EN | - DMA_CTL_FIFO_EN | - DMA_CTL_DA_ES2 | - ((bta->bits == 8) ? DMA_CTL_DA_SBR : 0) | - (bta->gain[bta->source] << 28) | - (bta->source << 24) | - (bta->decimation << 8), - REG_GPIO_DMA_CTL); - } else { - btwrite(DMA_CTL_ACAP_EN | - DMA_CTL_RISC_EN | - DMA_CTL_FIFO_EN | - DMA_CTL_DA_ES2 | - DMA_CTL_A_PWRDN | - (1 << 6) | - ((bta->bits == 8) ? DMA_CTL_DA_SBR : 0) | - (bta->gain[bta->source] << 28) | - (bta->source << 24) | - (bta->decimation << 8), - REG_GPIO_DMA_CTL); - } - bta->dma_block = 0; - bta->read_offset = 0; - bta->read_count = 0; - bta->recording = 1; - if (debug) - printk(KERN_DEBUG "btaudio: recording started\n"); - return 0; -} - -static void stop_recording(struct btaudio *bta) -{ - btand(~15, REG_GPIO_DMA_CTL); - bta->recording = 0; - if (debug) - printk(KERN_DEBUG "btaudio: recording stopped\n"); -} - - -/* -------------------------------------------------------------- */ - -static int btaudio_mixer_open(struct inode *inode, struct file *file) -{ - int minor = iminor(inode); - struct btaudio *bta; - - for (bta = btaudios; bta != NULL; bta = bta->next) - if (bta->mixer_dev == minor) - break; - if (NULL == bta) - return -ENODEV; - - if (debug) - printk("btaudio: open mixer [%d]\n",minor); - file->private_data = bta; - return 0; -} - -static int btaudio_mixer_release(struct inode *inode, struct file *file) -{ - return 0; -} - -static int btaudio_mixer_ioctl(struct inode *inode, struct file *file, - unsigned int cmd, unsigned long arg) -{ - struct btaudio *bta = file->private_data; - int ret,val=0,i=0; - void __user *argp = (void __user *)arg; - - if (cmd == SOUND_MIXER_INFO) { - mixer_info info; - memset(&info,0,sizeof(info)); - strlcpy(info.id,"bt878",sizeof(info.id)); - strlcpy(info.name,"Brooktree Bt878 audio",sizeof(info.name)); - info.modify_counter = bta->mixcount; - if (copy_to_user(argp, &info, sizeof(info))) - return -EFAULT; - return 0; - } - if (cmd == SOUND_OLD_MIXER_INFO) { - _old_mixer_info info; - memset(&info,0,sizeof(info)); - strlcpy(info.id, "bt878", sizeof(info.id)); - strlcpy(info.name,"Brooktree Bt878 audio",sizeof(info.name)); - if (copy_to_user(argp, &info, sizeof(info))) - return -EFAULT; - return 0; - } - if (cmd == OSS_GETVERSION) - return put_user(SOUND_VERSION, (int __user *)argp); - - /* read */ - if (_SIOC_DIR(cmd) & _SIOC_WRITE) - if (get_user(val, (int __user *)argp)) - return -EFAULT; - - switch (cmd) { - case MIXER_READ(SOUND_MIXER_CAPS): - ret = SOUND_CAP_EXCL_INPUT; - break; - case MIXER_READ(SOUND_MIXER_STEREODEVS): - ret = 0; - break; - case MIXER_READ(SOUND_MIXER_RECMASK): - case MIXER_READ(SOUND_MIXER_DEVMASK): - ret = SOUND_MASK_LINE1|SOUND_MASK_LINE2|SOUND_MASK_LINE3; - break; - - case MIXER_WRITE(SOUND_MIXER_RECSRC): - if (val & SOUND_MASK_LINE1 && bta->source != 0) - bta->source = 0; - else if (val & SOUND_MASK_LINE2 && bta->source != 1) - bta->source = 1; - else if (val & SOUND_MASK_LINE3 && bta->source != 2) - bta->source = 2; - btaor((bta->gain[bta->source] << 28) | - (bta->source << 24), - 0x0cffffff, REG_GPIO_DMA_CTL); - case MIXER_READ(SOUND_MIXER_RECSRC): - switch (bta->source) { - case 0: ret = SOUND_MASK_LINE1; break; - case 1: ret = SOUND_MASK_LINE2; break; - case 2: ret = SOUND_MASK_LINE3; break; - default: ret = 0; - } - break; - - case MIXER_WRITE(SOUND_MIXER_LINE1): - case MIXER_WRITE(SOUND_MIXER_LINE2): - case MIXER_WRITE(SOUND_MIXER_LINE3): - if (MIXER_WRITE(SOUND_MIXER_LINE1) == cmd) - i = 0; - if (MIXER_WRITE(SOUND_MIXER_LINE2) == cmd) - i = 1; - if (MIXER_WRITE(SOUND_MIXER_LINE3) == cmd) - i = 2; - bta->gain[i] = (val & 0xff) * 15 / 100; - if (bta->gain[i] > 15) bta->gain[i] = 15; - if (bta->gain[i] < 0) bta->gain[i] = 0; - if (i == bta->source) - btaor((bta->gain[bta->source]<<28), - 0x0fffffff, REG_GPIO_DMA_CTL); - ret = bta->gain[i] * 100 / 15; - ret |= ret << 8; - break; - - case MIXER_READ(SOUND_MIXER_LINE1): - case MIXER_READ(SOUND_MIXER_LINE2): - case MIXER_READ(SOUND_MIXER_LINE3): - if (MIXER_READ(SOUND_MIXER_LINE1) == cmd) - i = 0; - if (MIXER_READ(SOUND_MIXER_LINE2) == cmd) - i = 1; - if (MIXER_READ(SOUND_MIXER_LINE3) == cmd) - i = 2; - ret = bta->gain[i] * 100 / 15; - ret |= ret << 8; - break; - - default: - return -EINVAL; - } - if (put_user(ret, (int __user *)argp)) - return -EFAULT; - return 0; -} - -static const struct file_operations btaudio_mixer_fops = { - .owner = THIS_MODULE, - .llseek = no_llseek, - .open = btaudio_mixer_open, - .release = btaudio_mixer_release, - .ioctl = btaudio_mixer_ioctl, -}; - -/* -------------------------------------------------------------- */ - -static int btaudio_dsp_open(struct inode *inode, struct file *file, - struct btaudio *bta, int analog) -{ - mutex_lock(&bta->lock); - if (bta->users) - goto busy; - bta->users++; - file->private_data = bta; - - bta->analog = analog; - bta->dma_block = 0; - bta->read_offset = 0; - bta->read_count = 0; - bta->sampleshift = 0; - - mutex_unlock(&bta->lock); - return 0; - - busy: - mutex_unlock(&bta->lock); - return -EBUSY; -} - -static int btaudio_dsp_open_digital(struct inode *inode, struct file *file) -{ - int minor = iminor(inode); - struct btaudio *bta; - - for (bta = btaudios; bta != NULL; bta = bta->next) - if (bta->dsp_digital == minor) - break; - if (NULL == bta) - return -ENODEV; - - if (debug) - printk("btaudio: open digital dsp [%d]\n",minor); - return btaudio_dsp_open(inode,file,bta,0); -} - -static int btaudio_dsp_open_analog(struct inode *inode, struct file *file) -{ - int minor = iminor(inode); - struct btaudio *bta; - - for (bta = btaudios; bta != NULL; bta = bta->next) - if (bta->dsp_analog == minor) - break; - if (NULL == bta) - return -ENODEV; - - if (debug) - printk("btaudio: open analog dsp [%d]\n",minor); - return btaudio_dsp_open(inode,file,bta,1); -} - -static int btaudio_dsp_release(struct inode *inode, struct file *file) -{ - struct btaudio *bta = file->private_data; - - mutex_lock(&bta->lock); - if (bta->recording) - stop_recording(bta); - bta->users--; - mutex_unlock(&bta->lock); - return 0; -} - -static ssize_t btaudio_dsp_read(struct file *file, char __user *buffer, - size_t swcount, loff_t *ppos) -{ - struct btaudio *bta = file->private_data; - int hwcount = swcount << bta->sampleshift; - int nsrc, ndst, err, ret = 0; - DECLARE_WAITQUEUE(wait, current); - - add_wait_queue(&bta->readq, &wait); - mutex_lock(&bta->lock); - while (swcount > 0) { - if (0 == bta->read_count) { - if (!bta->recording) { - if (0 != (err = start_recording(bta))) { - if (0 == ret) - ret = err; - break; - } - } - if (file->f_flags & O_NONBLOCK) { - if (0 == ret) - ret = -EAGAIN; - break; - } - mutex_unlock(&bta->lock); - current->state = TASK_INTERRUPTIBLE; - schedule(); - mutex_lock(&bta->lock); - if(signal_pending(current)) { - if (0 == ret) - ret = -EINTR; - break; - } - } - nsrc = (bta->read_count < hwcount) ? bta->read_count : hwcount; - if (nsrc > bta->buf_size - bta->read_offset) - nsrc = bta->buf_size - bta->read_offset; - ndst = nsrc >> bta->sampleshift; - - if ((bta->analog && 0 == bta->sampleshift) || - (!bta->analog && 2 == bta->channels)) { - /* just copy */ - if (copy_to_user(buffer + ret, bta->buf_cpu + bta->read_offset, nsrc)) { - if (0 == ret) - ret = -EFAULT; - break; - } - - } else if (!bta->analog) { - /* stereo => mono (digital audio) */ - __s16 *src = (__s16*)(bta->buf_cpu + bta->read_offset); - __s16 __user *dst = (__s16 __user *)(buffer + ret); - __s16 avg; - int n = ndst>>1; - if (!access_ok(VERIFY_WRITE, dst, ndst)) { - if (0 == ret) - ret = -EFAULT; - break; - } - for (; n; n--, dst++) { - avg = (__s16)le16_to_cpu(*src) / 2; src++; - avg += (__s16)le16_to_cpu(*src) / 2; src++; - __put_user(cpu_to_le16(avg),dst); - } - - } else if (8 == bta->bits) { - /* copy + byte downsampling (audio A/D) */ - __u8 *src = bta->buf_cpu + bta->read_offset; - __u8 __user *dst = buffer + ret; - int n = ndst; - if (!access_ok(VERIFY_WRITE, dst, ndst)) { - if (0 == ret) - ret = -EFAULT; - break; - } - for (; n; n--, src += (1 << bta->sampleshift), dst++) - __put_user(*src, dst); - - } else { - /* copy + word downsampling (audio A/D) */ - __u16 *src = (__u16*)(bta->buf_cpu + bta->read_offset); - __u16 __user *dst = (__u16 __user *)(buffer + ret); - int n = ndst>>1; - if (!access_ok(VERIFY_WRITE,dst,ndst)) { - if (0 == ret) - ret = -EFAULT; - break; - } - for (; n; n--, src += (1 << bta->sampleshift), dst++) - __put_user(*src, dst); - } - - ret += ndst; - swcount -= ndst; - hwcount -= nsrc; - bta->read_count -= nsrc; - bta->read_offset += nsrc; - if (bta->read_offset == bta->buf_size) - bta->read_offset = 0; - } - mutex_unlock(&bta->lock); - remove_wait_queue(&bta->readq, &wait); - current->state = TASK_RUNNING; - return ret; -} - -static ssize_t btaudio_dsp_write(struct file *file, const char __user *buffer, - size_t count, loff_t *ppos) -{ - return -EINVAL; -} - -static int btaudio_dsp_ioctl(struct inode *inode, struct file *file, - unsigned int cmd, unsigned long arg) -{ - struct btaudio *bta = file->private_data; - int s, i, ret, val = 0; - void __user *argp = (void __user *)arg; - int __user *p = argp; - - switch (cmd) { - case OSS_GETVERSION: - return put_user(SOUND_VERSION, p); - case SNDCTL_DSP_GETCAPS: - return 0; - - case SNDCTL_DSP_SPEED: - if (get_user(val, p)) - return -EFAULT; - if (bta->analog) { - for (s = 0; s < 16; s++) - if (val << s >= HWBASE_AD*4/15) - break; - for (i = 15; i >= 5; i--) - if (val << s <= HWBASE_AD*4/i) - break; - bta->sampleshift = s; - bta->decimation = i; - if (debug) - printk(KERN_DEBUG "btaudio: rate: req=%d " - "dec=%d shift=%d hwrate=%d swrate=%d\n", - val,i,s,(HWBASE_AD*4/i),(HWBASE_AD*4/i)>>s); - } else { - bta->sampleshift = (bta->channels == 2) ? 0 : 1; - bta->decimation = 0; - } - if (bta->recording) { - mutex_lock(&bta->lock); - stop_recording(bta); - start_recording(bta); - mutex_unlock(&bta->lock); - } - /* fall through */ - case SOUND_PCM_READ_RATE: - if (bta->analog) { - return put_user(HWBASE_AD*4/bta->decimation>>bta->sampleshift, p); - } else { - return put_user(bta->rate, p); - } - - case SNDCTL_DSP_STEREO: - if (!bta->analog) { - if (get_user(val, p)) - return -EFAULT; - bta->channels = (val > 0) ? 2 : 1; - bta->sampleshift = (bta->channels == 2) ? 0 : 1; - if (debug) - printk(KERN_INFO - "btaudio: stereo=%d channels=%d\n", - val,bta->channels); - } else { - if (val == 1) - return -EFAULT; - else { - bta->channels = 1; - if (debug) - printk(KERN_INFO - "btaudio: stereo=0 channels=1\n"); - } - } - return put_user((bta->channels)-1, p); - - case SNDCTL_DSP_CHANNELS: - if (!bta->analog) { - if (get_user(val, p)) - return -EFAULT; - bta->channels = (val > 1) ? 2 : 1; - bta->sampleshift = (bta->channels == 2) ? 0 : 1; - if (debug) - printk(KERN_DEBUG - "btaudio: val=%d channels=%d\n", - val,bta->channels); - } - /* fall through */ - case SOUND_PCM_READ_CHANNELS: - return put_user(bta->channels, p); - - case SNDCTL_DSP_GETFMTS: /* Returns a mask */ - if (bta->analog) - return put_user(AFMT_S16_LE|AFMT_S8, p); - else - return put_user(AFMT_S16_LE, p); - - case SNDCTL_DSP_SETFMT: /* Selects ONE fmt*/ - if (get_user(val, p)) - return -EFAULT; - if (val != AFMT_QUERY) { - if (bta->analog) - bta->bits = (val == AFMT_S8) ? 8 : 16; - else - bta->bits = 16; - if (bta->recording) { - mutex_lock(&bta->lock); - stop_recording(bta); - start_recording(bta); - mutex_unlock(&bta->lock); - } - } - if (debug) - printk(KERN_DEBUG "btaudio: fmt: bits=%d\n",bta->bits); - return put_user((bta->bits==16) ? AFMT_S16_LE : AFMT_S8, - p); - break; - case SOUND_PCM_READ_BITS: - return put_user(bta->bits, p); - - case SNDCTL_DSP_NONBLOCK: - file->f_flags |= O_NONBLOCK; - return 0; - - case SNDCTL_DSP_RESET: - if (bta->recording) { - mutex_lock(&bta->lock); - stop_recording(bta); - mutex_unlock(&bta->lock); - } - return 0; - case SNDCTL_DSP_GETBLKSIZE: - if (!bta->recording) { - if (0 != (ret = alloc_buffer(bta))) - return ret; - if (0 != (ret = make_risc(bta))) - return ret; - } - return put_user(bta->block_bytes>>bta->sampleshift,p); - - case SNDCTL_DSP_SYNC: - /* NOP */ - return 0; - case SNDCTL_DSP_GETISPACE: - { - audio_buf_info info; - if (!bta->recording) - return -EINVAL; - info.fragsize = bta->block_bytes>>bta->sampleshift; - info.fragstotal = bta->block_count; - info.bytes = bta->read_count; - info.fragments = info.bytes / info.fragsize; - if (debug) - printk(KERN_DEBUG "btaudio: SNDCTL_DSP_GETISPACE " - "returns %d/%d/%d/%d\n", - info.fragsize, info.fragstotal, - info.bytes, info.fragments); - if (copy_to_user(argp, &info, sizeof(info))) - return -EFAULT; - return 0; - } -#if 0 /* TODO */ - case SNDCTL_DSP_GETTRIGGER: - case SNDCTL_DSP_SETTRIGGER: - case SNDCTL_DSP_SETFRAGMENT: -#endif - default: - return -EINVAL; - } -} - -static unsigned int btaudio_dsp_poll(struct file *file, struct poll_table_struct *wait) -{ - struct btaudio *bta = file->private_data; - unsigned int mask = 0; - - poll_wait(file, &bta->readq, wait); - - if (0 != bta->read_count) - mask |= (POLLIN | POLLRDNORM); - - return mask; -} - -static const struct file_operations btaudio_digital_dsp_fops = { - .owner = THIS_MODULE, - .llseek = no_llseek, - .open = btaudio_dsp_open_digital, - .release = btaudio_dsp_release, - .read = btaudio_dsp_read, - .write = btaudio_dsp_write, - .ioctl = btaudio_dsp_ioctl, - .poll = btaudio_dsp_poll, -}; - -static const struct file_operations btaudio_analog_dsp_fops = { - .owner = THIS_MODULE, - .llseek = no_llseek, - .open = btaudio_dsp_open_analog, - .release = btaudio_dsp_release, - .read = btaudio_dsp_read, - .write = btaudio_dsp_write, - .ioctl = btaudio_dsp_ioctl, - .poll = btaudio_dsp_poll, -}; - -/* -------------------------------------------------------------- */ - -static char *irq_name[] = { "", "", "", "OFLOW", "", "", "", "", "", "", "", - "RISCI", "FBUS", "FTRGT", "FDSR", "PPERR", - "RIPERR", "PABORT", "OCERR", "SCERR" }; - -static irqreturn_t btaudio_irq(int irq, void *dev_id) -{ - int count = 0; - u32 stat,astat; - struct btaudio *bta = dev_id; - int handled = 0; - - for (;;) { - count++; - stat = btread(REG_INT_STAT); - astat = stat & btread(REG_INT_MASK); - if (!astat) - return IRQ_RETVAL(handled); - handled = 1; - btwrite(astat,REG_INT_STAT); - - if (irq_debug) { - int i; - printk(KERN_DEBUG "btaudio: irq loop=%d risc=%x, bits:", - count, stat>>28); - for (i = 0; i < (sizeof(irq_name)/sizeof(char*)); i++) { - if (stat & (1 << i)) - printk(" %s",irq_name[i]); - if (astat & (1 << i)) - printk("*"); - } - printk("\n"); - } - if (stat & IRQ_RISCI) { - int blocks; - blocks = (stat >> 28) - bta->dma_block; - if (blocks < 0) - blocks += bta->block_count; - bta->dma_block = stat >> 28; - if (bta->read_count + 2*bta->block_bytes > bta->buf_size) { - stop_recording(bta); - printk(KERN_INFO "btaudio: buffer overrun\n"); - } - if (blocks > 0) { - bta->read_count += blocks * bta->block_bytes; - wake_up_interruptible(&bta->readq); - } - } - if (count > 10) { - printk(KERN_WARNING - "btaudio: Oops - irq mask cleared\n"); - btwrite(0, REG_INT_MASK); - } - } - return IRQ_NONE; -} - -/* -------------------------------------------------------------- */ - -static unsigned int dsp1 = -1; -static unsigned int dsp2 = -1; -static unsigned int mixer = -1; -static int latency = -1; -static int digital = 1; -static int analog = 1; -static int rate; - -#define BTA_OSPREY200 1 - -static struct cardinfo cards[] = { - [0] = { - .name = "default", - .rate = 32000, - }, - [BTA_OSPREY200] = { - .name = "Osprey 200", - .rate = 44100, - }, -}; - -static int __devinit btaudio_probe(struct pci_dev *pci_dev, - const struct pci_device_id *pci_id) -{ - struct btaudio *bta; - struct cardinfo *card = &cards[pci_id->driver_data]; - unsigned char revision,lat; - int rc = -EBUSY; - - if (pci_enable_device(pci_dev)) - return -EIO; - if (!request_mem_region(pci_resource_start(pci_dev,0), - pci_resource_len(pci_dev,0), - "btaudio")) { - return -EBUSY; - } - - bta = kzalloc(sizeof(*bta),GFP_ATOMIC); - if (!bta) { - rc = -ENOMEM; - goto fail0; - } - - bta->pci = pci_dev; - bta->irq = pci_dev->irq; - bta->mem = pci_resource_start(pci_dev,0); - bta->mmio = ioremap(pci_resource_start(pci_dev,0), - pci_resource_len(pci_dev,0)); - - bta->source = 1; - bta->bits = 8; - bta->channels = 1; - if (bta->analog) { - bta->decimation = 15; - } else { - bta->decimation = 0; - bta->sampleshift = 1; - } - - /* sample rate */ - bta->rate = card->rate; - if (rate) - bta->rate = rate; - - mutex_init(&bta->lock); - init_waitqueue_head(&bta->readq); - - if (-1 != latency) { - printk(KERN_INFO "btaudio: setting pci latency timer to %d\n", - latency); - pci_write_config_byte(pci_dev, PCI_LATENCY_TIMER, latency); - } - pci_read_config_byte(pci_dev, PCI_CLASS_REVISION, &revision); - pci_read_config_byte(pci_dev, PCI_LATENCY_TIMER, &lat); - printk(KERN_INFO "btaudio: Bt%x (rev %d) at %02x:%02x.%x, ", - pci_dev->device,revision,pci_dev->bus->number, - PCI_SLOT(pci_dev->devfn),PCI_FUNC(pci_dev->devfn)); - printk("irq: %d, latency: %d, mmio: 0x%lx\n", - bta->irq, lat, bta->mem); - printk("btaudio: using card config \"%s\"\n", card->name); - - /* init hw */ - btwrite(0, REG_GPIO_DMA_CTL); - btwrite(0, REG_INT_MASK); - btwrite(~0U, REG_INT_STAT); - pci_set_master(pci_dev); - - if ((rc = request_irq(bta->irq, btaudio_irq, IRQF_SHARED|IRQF_DISABLED, - "btaudio",(void *)bta)) < 0) { - printk(KERN_WARNING - "btaudio: can't request irq (rc=%d)\n",rc); - goto fail1; - } - - /* register devices */ - if (digital) { - rc = bta->dsp_digital = - register_sound_dsp(&btaudio_digital_dsp_fops,dsp1); - if (rc < 0) { - printk(KERN_WARNING - "btaudio: can't register digital dsp (rc=%d)\n",rc); - goto fail2; - } - printk(KERN_INFO "btaudio: registered device dsp%d [digital]\n", - bta->dsp_digital >> 4); - } - if (analog) { - rc = bta->dsp_analog = - register_sound_dsp(&btaudio_analog_dsp_fops,dsp2); - if (rc < 0) { - printk(KERN_WARNING - "btaudio: can't register analog dsp (rc=%d)\n",rc); - goto fail3; - } - printk(KERN_INFO "btaudio: registered device dsp%d [analog]\n", - bta->dsp_analog >> 4); - rc = bta->mixer_dev = register_sound_mixer(&btaudio_mixer_fops,mixer); - if (rc < 0) { - printk(KERN_WARNING - "btaudio: can't register mixer (rc=%d)\n",rc); - goto fail4; - } - printk(KERN_INFO "btaudio: registered device mixer%d\n", - bta->mixer_dev >> 4); - } - - /* hook into linked list */ - bta->next = btaudios; - btaudios = bta; - - pci_set_drvdata(pci_dev,bta); - return 0; - - fail4: - unregister_sound_dsp(bta->dsp_analog); - fail3: - if (digital) - unregister_sound_dsp(bta->dsp_digital); - fail2: - free_irq(bta->irq,bta); - fail1: - iounmap(bta->mmio); - kfree(bta); - fail0: - release_mem_region(pci_resource_start(pci_dev,0), - pci_resource_len(pci_dev,0)); - return rc; -} - -static void __devexit btaudio_remove(struct pci_dev *pci_dev) -{ - struct btaudio *bta = pci_get_drvdata(pci_dev); - struct btaudio *walk; - - /* turn off all DMA / IRQs */ - btand(~15, REG_GPIO_DMA_CTL); - btwrite(0, REG_INT_MASK); - btwrite(~0U, REG_INT_STAT); - - /* unregister devices */ - if (digital) { - unregister_sound_dsp(bta->dsp_digital); - } - if (analog) { - unregister_sound_dsp(bta->dsp_analog); - unregister_sound_mixer(bta->mixer_dev); - } - - /* free resources */ - free_buffer(bta); - free_irq(bta->irq,bta); - release_mem_region(pci_resource_start(pci_dev,0), - pci_resource_len(pci_dev,0)); - iounmap(bta->mmio); - - /* remove from linked list */ - if (bta == btaudios) { - btaudios = NULL; - } else { - for (walk = btaudios; walk->next != bta; walk = walk->next) - ; /* if (NULL == walk->next) BUG(); */ - walk->next = bta->next; - } - - pci_set_drvdata(pci_dev, NULL); - kfree(bta); - return; -} - -/* -------------------------------------------------------------- */ - -static struct pci_device_id btaudio_pci_tbl[] = { - { - .vendor = PCI_VENDOR_ID_BROOKTREE, - .device = 0x0878, - .subvendor = 0x0070, - .subdevice = 0xff01, - .driver_data = BTA_OSPREY200, - },{ - .vendor = PCI_VENDOR_ID_BROOKTREE, - .device = 0x0878, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - },{ - .vendor = PCI_VENDOR_ID_BROOKTREE, - .device = 0x0878, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - },{ - /* --- end of list --- */ - } -}; - -static struct pci_driver btaudio_pci_driver = { - .name = "btaudio", - .id_table = btaudio_pci_tbl, - .probe = btaudio_probe, - .remove = __devexit_p(btaudio_remove), -}; - -static int btaudio_init_module(void) -{ - printk(KERN_INFO "btaudio: driver version 0.7 loaded [%s%s%s]\n", - digital ? "digital" : "", - analog && digital ? "+" : "", - analog ? "analog" : ""); - return pci_register_driver(&btaudio_pci_driver); -} - -static void btaudio_cleanup_module(void) -{ - pci_unregister_driver(&btaudio_pci_driver); - return; -} - -module_init(btaudio_init_module); -module_exit(btaudio_cleanup_module); - -module_param(dsp1, int, S_IRUGO); -module_param(dsp2, int, S_IRUGO); -module_param(mixer, int, S_IRUGO); -module_param(debug, int, S_IRUGO | S_IWUSR); -module_param(irq_debug, int, S_IRUGO | S_IWUSR); -module_param(digital, int, S_IRUGO); -module_param(analog, int, S_IRUGO); -module_param(rate, int, S_IRUGO); -module_param(latency, int, S_IRUGO); -MODULE_PARM_DESC(latency,"pci latency timer"); - -MODULE_DEVICE_TABLE(pci, btaudio_pci_tbl); -MODULE_DESCRIPTION("bt878 audio dma driver"); -MODULE_AUTHOR("Gerd Knorr"); -MODULE_LICENSE("GPL"); - -/* - * Local variables: - * c-basic-offset: 8 - * End: - */ diff --git a/sound/oss/cs4232.c b/sound/oss/cs4232.c deleted file mode 100644 index de40e21bf279..000000000000 --- a/sound/oss/cs4232.c +++ /dev/null @@ -1,526 +0,0 @@ -/* - * Copyright (C) by Hannu Savolainen 1993-1997 - * - * cs4232.c - * - * The low level driver for Crystal CS4232 based cards. The CS4232 is - * a PnP compatible chip which contains a CS4231A codec, SB emulation, - * a MPU401 compatible MIDI port, joystick and synthesizer and IDE CD-ROM - * interfaces. This is just a temporary driver until full PnP support - * gets implemented. Just the WSS codec, FM synth and the MIDI ports are - * supported. Other interfaces are left uninitialized. - * - * ifdef ...WAVEFRONT... - * - * Support is provided for initializing the WaveFront synth - * interface as well, which is logical device #4. Note that if - * you have a Tropez+ card, you probably don't need to setup - * the CS4232-supported MIDI interface, since it corresponds to - * the internal 26-pin header that's hard to access. Using this - * requires an additional IRQ, a resource none too plentiful in - * this environment. Just don't set module parameters mpuio and - * mpuirq, and the MIDI port will be left uninitialized. You can - * still use the ICS2115 hosted MIDI interface which corresponds - * to the 9-pin D connector on the back of the card. - * - * endif ...WAVEFRONT... - * - * Supported chips are: - * CS4232 - * CS4236 - * CS4236B - * - * Note: You will need a PnP config setup to initialise some CS4232 boards - * anyway. - * - * Changes - * John Rood Added Bose Sound System Support. - * Toshio Spoor - * Alan Cox Modularisation, Basic cleanups. - * Paul Barton-Davis Separated MPU configuration, added - * Tropez+ (WaveFront) support - * Christoph Hellwig Adapted to module_init/module_exit, - * simple cleanups - * Arnaldo C. de Melo got rid of attach_uart401 - * Bartlomiej Zolnierkiewicz - * Added some __init/__initdata/__exit - * Marcus Meissner Added ISA PnP support. - */ - -#include <linux/pnp.h> -#include <linux/module.h> -#include <linux/init.h> - -#include "sound_config.h" - -#include "ad1848.h" -#include "mpu401.h" - -#define KEY_PORT 0x279 /* Same as LPT1 status port */ -#define CSN_NUM 0x99 /* Just a random number */ -#define INDEX_ADDRESS 0x00 /* (R0) Index Address Register */ -#define INDEX_DATA 0x01 /* (R1) Indexed Data Register */ -#define PIN_CONTROL 0x0a /* (I10) Pin Control */ -#define ENABLE_PINS 0xc0 /* XCTRL0/XCTRL1 enable */ - -static void CS_OUT(unsigned char a) -{ - outb(a, KEY_PORT); -} - -#define CS_OUT2(a, b) {CS_OUT(a);CS_OUT(b);} -#define CS_OUT3(a, b, c) {CS_OUT(a);CS_OUT(b);CS_OUT(c);} - -static int __initdata bss = 0; -static int mpu_base, mpu_irq; -static int synth_base, synth_irq; -static int mpu_detected; - -static int probe_cs4232_mpu(struct address_info *hw_config) -{ - /* - * Just write down the config values. - */ - - mpu_base = hw_config->io_base; - mpu_irq = hw_config->irq; - - return 1; -} - -static unsigned char crystal_key[] = /* A 32 byte magic key sequence */ -{ - 0x96, 0x35, 0x9a, 0xcd, 0xe6, 0xf3, 0x79, 0xbc, - 0x5e, 0xaf, 0x57, 0x2b, 0x15, 0x8a, 0xc5, 0xe2, - 0xf1, 0xf8, 0x7c, 0x3e, 0x9f, 0x4f, 0x27, 0x13, - 0x09, 0x84, 0x42, 0xa1, 0xd0, 0x68, 0x34, 0x1a -}; - -static void sleep(unsigned howlong) -{ - current->state = TASK_INTERRUPTIBLE; - schedule_timeout(howlong); -} - -static void enable_xctrl(int baseio) -{ - unsigned char regd; - - /* - * Some IBM Aptiva's have the Bose Sound System. By default - * the Bose Amplifier is disabled. The amplifier will be - * activated, by setting the XCTRL0 and XCTRL1 bits. - * Volume of the monitor bose speakers/woofer, can then - * be set by changing the PCM volume. - * - */ - - printk("cs4232: enabling Bose Sound System Amplifier.\n"); - - /* Switch to Pin Control Address */ - regd = inb(baseio + INDEX_ADDRESS) & 0xe0; - outb(((unsigned char) (PIN_CONTROL | regd)), baseio + INDEX_ADDRESS ); - - /* Activate the XCTRL0 and XCTRL1 Pins */ - regd = inb(baseio + INDEX_DATA); - outb(((unsigned char) (ENABLE_PINS | regd)), baseio + INDEX_DATA ); -} - -static int __init probe_cs4232(struct address_info *hw_config, int isapnp_configured) -{ - int i, n; - int base = hw_config->io_base, irq = hw_config->irq; - int dma1 = hw_config->dma, dma2 = hw_config->dma2; - struct resource *ports; - - if (base == -1 || irq == -1 || dma1 == -1) { - printk(KERN_ERR "cs4232: dma, irq and io must be set.\n"); - return 0; - } - - /* - * Verify that the I/O port range is free. - */ - - ports = request_region(base, 4, "ad1848"); - if (!ports) { - printk(KERN_ERR "cs4232.c: I/O port 0x%03x not free\n", base); - return 0; - } - if (ad1848_detect(ports, NULL, hw_config->osp)) { - goto got_it; /* The card is already active */ - } - if (isapnp_configured) { - printk(KERN_ERR "cs4232.c: ISA PnP configured, but not detected?\n"); - goto fail; - } - - /* - * This version of the driver doesn't use the PnP method when configuring - * the card but a simplified method defined by Crystal. This means that - * just one CS4232 compatible device can exist on the system. Also this - * method conflicts with possible PnP support in the OS. For this reason - * driver is just a temporary kludge. - * - * Also the Cirrus/Crystal method doesn't always work. Try ISA PnP first ;) - */ - - /* - * Repeat initialization few times since it doesn't always succeed in - * first time. - */ - - for (n = 0; n < 4; n++) - { - /* - * Wake up the card by sending a 32 byte Crystal key to the key port. - */ - - for (i = 0; i < 32; i++) - CS_OUT(crystal_key[i]); - - sleep(HZ / 10); - - /* - * Now set the CSN (Card Select Number). - */ - - CS_OUT2(0x06, CSN_NUM); - - /* - * Then set some config bytes. First logical device 0 - */ - - CS_OUT2(0x15, 0x00); /* Select logical device 0 (WSS/SB/FM) */ - CS_OUT3(0x47, (base >> 8) & 0xff, base & 0xff); /* WSS base */ - - if (!request_region(0x388, 4, "FM")) /* Not free */ - CS_OUT3(0x48, 0x00, 0x00) /* FM base off */ - else { - release_region(0x388, 4); - CS_OUT3(0x48, 0x03, 0x88); /* FM base 0x388 */ - } - - CS_OUT3(0x42, 0x00, 0x00); /* SB base off */ - CS_OUT2(0x22, irq); /* SB+WSS IRQ */ - CS_OUT2(0x2a, dma1); /* SB+WSS DMA */ - - if (dma2 != -1) - CS_OUT2(0x25, dma2) /* WSS DMA2 */ - else - CS_OUT2(0x25, 4); /* No WSS DMA2 */ - - CS_OUT2(0x33, 0x01); /* Activate logical dev 0 */ - - sleep(HZ / 10); - - /* - * Initialize logical device 3 (MPU) - */ - - if (mpu_base != 0 && mpu_irq != 0) - { - CS_OUT2(0x15, 0x03); /* Select logical device 3 (MPU) */ - CS_OUT3(0x47, (mpu_base >> 8) & 0xff, mpu_base & 0xff); /* MPU base */ - CS_OUT2(0x22, mpu_irq); /* MPU IRQ */ - CS_OUT2(0x33, 0x01); /* Activate logical dev 3 */ - } - - if(synth_base != 0) - { - CS_OUT2 (0x15, 0x04); /* logical device 4 (WaveFront) */ - CS_OUT3 (0x47, (synth_base >> 8) & 0xff, - synth_base & 0xff); /* base */ - CS_OUT2 (0x22, synth_irq); /* IRQ */ - CS_OUT2 (0x33, 0x01); /* Activate logical dev 4 */ - } - - /* - * Finally activate the chip - */ - - CS_OUT(0x79); - - sleep(HZ / 5); - - /* - * Then try to detect the codec part of the chip - */ - - if (ad1848_detect(ports, NULL, hw_config->osp)) - goto got_it; - - sleep(HZ); - } -fail: - release_region(base, 4); - return 0; - -got_it: - if (dma2 == -1) - dma2 = dma1; - - hw_config->slots[0] = ad1848_init("Crystal audio controller", ports, - irq, - dma1, /* Playback DMA */ - dma2, /* Capture DMA */ - 0, - hw_config->osp, - THIS_MODULE); - - if (hw_config->slots[0] != -1 && - audio_devs[hw_config->slots[0]]->mixer_dev!=-1) - { - /* Assume the mixer map is as suggested in the CS4232 databook */ - AD1848_REROUTE(SOUND_MIXER_LINE1, SOUND_MIXER_LINE); - AD1848_REROUTE(SOUND_MIXER_LINE2, SOUND_MIXER_CD); - AD1848_REROUTE(SOUND_MIXER_LINE3, SOUND_MIXER_SYNTH); /* FM synth */ - } - if (mpu_base != 0 && mpu_irq != 0) - { - static struct address_info hw_config2 = { - 0 - }; /* Ensure it's initialized */ - - hw_config2.io_base = mpu_base; - hw_config2.irq = mpu_irq; - hw_config2.dma = -1; - hw_config2.dma2 = -1; - hw_config2.always_detect = 0; - hw_config2.name = NULL; - hw_config2.driver_use_1 = 0; - hw_config2.driver_use_2 = 0; - hw_config2.card_subtype = 0; - - if (probe_uart401(&hw_config2, THIS_MODULE)) - { - mpu_detected = 1; - } - else - { - mpu_base = mpu_irq = 0; - } - hw_config->slots[1] = hw_config2.slots[1]; - } - - if (bss) - enable_xctrl(base); - - return 1; -} - -static void __devexit unload_cs4232(struct address_info *hw_config) -{ - int base = hw_config->io_base, irq = hw_config->irq; - int dma1 = hw_config->dma, dma2 = hw_config->dma2; - - if (dma2 == -1) - dma2 = dma1; - - ad1848_unload(base, - irq, - dma1, /* Playback DMA */ - dma2, /* Capture DMA */ - 0); - - sound_unload_audiodev(hw_config->slots[0]); - if (mpu_base != 0 && mpu_irq != 0 && mpu_detected) - { - static struct address_info hw_config2 = - { - 0 - }; /* Ensure it's initialized */ - - hw_config2.io_base = mpu_base; - hw_config2.irq = mpu_irq; - hw_config2.dma = -1; - hw_config2.dma2 = -1; - hw_config2.always_detect = 0; - hw_config2.name = NULL; - hw_config2.driver_use_1 = 0; - hw_config2.driver_use_2 = 0; - hw_config2.card_subtype = 0; - hw_config2.slots[1] = hw_config->slots[1]; - - unload_uart401(&hw_config2); - } -} - -static struct address_info cfg; -static struct address_info cfg_mpu; - -static int __initdata io = -1; -static int __initdata irq = -1; -static int __initdata dma = -1; -static int __initdata dma2 = -1; -static int __initdata mpuio = -1; -static int __initdata mpuirq = -1; -static int __initdata synthio = -1; -static int __initdata synthirq = -1; -static int __initdata isapnp = 1; - -static unsigned int cs4232_devices; - -MODULE_DESCRIPTION("CS4232 based soundcard driver"); -MODULE_AUTHOR("Hannu Savolainen, Paul Barton-Davis"); -MODULE_LICENSE("GPL"); - -module_param(io, int, 0); -MODULE_PARM_DESC(io,"base I/O port for AD1848"); -module_param(irq, int, 0); -MODULE_PARM_DESC(irq,"IRQ for AD1848 chip"); -module_param(dma, int, 0); -MODULE_PARM_DESC(dma,"8 bit DMA for AD1848 chip"); -module_param(dma2, int, 0); -MODULE_PARM_DESC(dma2,"16 bit DMA for AD1848 chip"); -module_param(mpuio, int, 0); -MODULE_PARM_DESC(mpuio,"MPU 401 base address"); -module_param(mpuirq, int, 0); -MODULE_PARM_DESC(mpuirq,"MPU 401 IRQ"); -module_param(synthio, int, 0); -MODULE_PARM_DESC(synthio,"Maui WaveTable base I/O port"); -module_param(synthirq, int, 0); -MODULE_PARM_DESC(synthirq,"Maui WaveTable IRQ"); -module_param(isapnp, bool, 0); -MODULE_PARM_DESC(isapnp,"Enable ISAPnP probing (default 1)"); -module_param(bss, bool, 0); -MODULE_PARM_DESC(bss,"Enable Bose Sound System Support (default 0)"); - -/* - * Install a CS4232 based card. Need to have ad1848 and mpu401 - * loaded ready. - */ - -/* All cs4232 based cards have the main ad1848 card either as CSC0000 or - * CSC0100. */ -static const struct pnp_device_id cs4232_pnp_table[] = { - { .id = "CSC0100", .driver_data = 0 }, - { .id = "CSC0000", .driver_data = 0 }, - /* Guillemot Turtlebeach something appears to be cs4232 compatible - * (untested) */ - { .id = "GIM0100", .driver_data = 0 }, - { .id = ""} -}; - -MODULE_DEVICE_TABLE(pnp, cs4232_pnp_table); - -static int __init cs4232_pnp_probe(struct pnp_dev *dev, const struct pnp_device_id *dev_id) -{ - struct address_info *isapnpcfg; - - isapnpcfg = kmalloc(sizeof(*isapnpcfg),GFP_KERNEL); - if (!isapnpcfg) - return -ENOMEM; - - isapnpcfg->irq = pnp_irq(dev, 0); - isapnpcfg->dma = pnp_dma(dev, 0); - isapnpcfg->dma2 = pnp_dma(dev, 1); - isapnpcfg->io_base = pnp_port_start(dev, 0); - if (probe_cs4232(isapnpcfg,TRUE) == 0) { - printk(KERN_ERR "cs4232: ISA PnP card found, but not detected?\n"); - kfree(isapnpcfg); - return -ENODEV; - } - pnp_set_drvdata(dev,isapnpcfg); - cs4232_devices++; - return 0; -} - -static void __devexit cs4232_pnp_remove(struct pnp_dev *dev) -{ - struct address_info *cfg = pnp_get_drvdata(dev); - if (cfg) { - unload_cs4232(cfg); - kfree(cfg); - } -} - -static struct pnp_driver cs4232_driver = { - .name = "cs4232", - .id_table = cs4232_pnp_table, - .probe = cs4232_pnp_probe, - .remove = __devexit_p(cs4232_pnp_remove), -}; - -static int __init init_cs4232(void) -{ -#ifdef CONFIG_SOUND_WAVEFRONT_MODULE - if(synthio == -1) - printk(KERN_INFO "cs4232: set synthio and synthirq to use the wavefront facilities.\n"); - else { - synth_base = synthio; - synth_irq = synthirq; - } -#else - if(synthio != -1) - printk(KERN_WARNING "cs4232: wavefront support not enabled in this driver.\n"); -#endif - cfg.irq = -1; - - if (isapnp) { - pnp_register_driver(&cs4232_driver); - if (cs4232_devices) - return 0; - } - - if(io==-1||irq==-1||dma==-1) - { - printk(KERN_ERR "cs4232: Must set io, irq and dma.\n"); - return -ENODEV; - } - - cfg.io_base = io; - cfg.irq = irq; - cfg.dma = dma; - cfg.dma2 = dma2; - - cfg_mpu.io_base = -1; - cfg_mpu.irq = -1; - - if (mpuio != -1 && mpuirq != -1) { - cfg_mpu.io_base = mpuio; - cfg_mpu.irq = mpuirq; - probe_cs4232_mpu(&cfg_mpu); /* Bug always returns 0 not OK -- AC */ - } - - if (probe_cs4232(&cfg,FALSE) == 0) - return -ENODEV; - - return 0; -} - -static void __exit cleanup_cs4232(void) -{ - pnp_unregister_driver(&cs4232_driver); - if (cfg.irq != -1) - unload_cs4232(&cfg); /* Unloads global MPU as well, if needed */ -} - -module_init(init_cs4232); -module_exit(cleanup_cs4232); - -#ifndef MODULE -static int __init setup_cs4232(char *str) -{ - /* io, irq, dma, dma2 mpuio, mpuirq*/ - int ints[7]; - - /* If we have isapnp cards, no need for options */ - pnp_register_driver(&cs4232_driver); - if (cs4232_devices) - return 1; - - str = get_options(str, ARRAY_SIZE(ints), ints); - - io = ints[1]; - irq = ints[2]; - dma = ints[3]; - dma2 = ints[4]; - mpuio = ints[5]; - mpuirq = ints[6]; - - return 1; -} - -__setup("cs4232=", setup_cs4232); -#endif diff --git a/sound/oss/dmasound/Kconfig b/sound/oss/dmasound/Kconfig index 71b313479f83..3eb782720e58 100644 --- a/sound/oss/dmasound/Kconfig +++ b/sound/oss/dmasound/Kconfig @@ -14,7 +14,7 @@ config DMASOUND_ATARI config DMASOUND_PAULA tristate "Amiga DMA sound support" - depends on (AMIGA || APUS) && SOUND + depends on AMIGA && SOUND select DMASOUND help If you want to use the internal audio of your Amiga in Linux, answer diff --git a/sound/oss/dmasound/dmasound_paula.c b/sound/oss/dmasound/dmasound_paula.c index 90fc058e1159..202e8103dc4d 100644 --- a/sound/oss/dmasound/dmasound_paula.c +++ b/sound/oss/dmasound/dmasound_paula.c @@ -91,10 +91,6 @@ static irqreturn_t AmiInterrupt(int irq, void *dummy); * power LED are controlled by the same line. */ -#ifdef CONFIG_APUS -#define mach_heartbeat ppc_md.heartbeat -#endif - static void (*saved_heartbeat)(int) = NULL; static inline void disable_heartbeat(void) diff --git a/sound/oss/i810_audio.c b/sound/oss/i810_audio.c deleted file mode 100644 index f5e31f11973d..000000000000 --- a/sound/oss/i810_audio.c +++ /dev/null @@ -1,3656 +0,0 @@ -/* - * Intel i810 and friends ICH driver for Linux - * Alan Cox <alan@redhat.com> - * - * Built from: - * Low level code: Zach Brown (original nonworking i810 OSS driver) - * Jaroslav Kysela <perex@suse.cz> (working ALSA driver) - * - * Framework: Thomas Sailer <sailer@ife.ee.ethz.ch> - * Extended by: Zach Brown <zab@redhat.com> - * and others.. - * - * Hardware Provided By: - * Analog Devices (A major AC97 codec maker) - * Intel Corp (you've probably heard of them already) - * - * AC97 clues and assistance provided by - * Analog Devices - * Zach 'Fufu' Brown - * Jeff Garzik - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - * - * Intel 810 theory of operation - * - * The chipset provides three DMA channels that talk to an AC97 - * CODEC (AC97 is a digital/analog mixer standard). At its simplest - * you get 48Khz audio with basic volume and mixer controls. At the - * best you get rate adaption in the codec. We set the card up so - * that we never take completion interrupts but instead keep the card - * chasing its tail around a ring buffer. This is needed for mmap - * mode audio and happens to work rather well for non-mmap modes too. - * - * The board has one output channel for PCM audio (supported) and - * a stereo line in and mono microphone input. Again these are normally - * locked to 48Khz only. Right now recording is not finished. - * - * There is no midi support, no synth support. Use timidity. To get - * esd working you need to use esd -r 48000 as it won't probe 48KHz - * by default. mpg123 can't handle 48Khz only audio so use xmms. - * - * Fix The Sound On Dell - * - * Not everyone uses 48KHz. We know of no way to detect this reliably - * and certainly not to get the right data. If your i810 audio sounds - * stupid you may need to investigate other speeds. According to Analog - * they tend to use a 14.318MHz clock which gives you a base rate of - * 41194Hz. - * - * This is available via the 'ftsodell=1' option. - * - * If you need to force a specific rate set the clocking= option - * - * This driver is cursed. (Ben LaHaise) - * - * ICH 3 caveats - * Intel errata #7 for ICH3 IO. We need to disable SMI stuff - * when codec probing. [Not Yet Done] - * - * ICH 4 caveats - * - * The ICH4 has the feature, that the codec ID doesn't have to be - * congruent with the IO connection. - * - * Therefore, from driver version 0.23 on, there is a "codec ID" <-> - * "IO register base offset" mapping (card->ac97_id_map) field. - * - * Juergen "George" Sawinski (jsaw) - */ - -#include <linux/module.h> -#include <linux/string.h> -#include <linux/ctype.h> -#include <linux/ioport.h> -#include <linux/sched.h> -#include <linux/delay.h> -#include <linux/sound.h> -#include <linux/slab.h> -#include <linux/soundcard.h> -#include <linux/pci.h> -#include <linux/interrupt.h> -#include <asm/io.h> -#include <asm/dma.h> -#include <linux/init.h> -#include <linux/poll.h> -#include <linux/spinlock.h> -#include <linux/smp_lock.h> -#include <linux/ac97_codec.h> -#include <linux/bitops.h> -#include <linux/mutex.h> -#include <linux/mm.h> - -#include <asm/uaccess.h> - -#define DRIVER_VERSION "1.01" - -#define MODULOP2(a, b) ((a) & ((b) - 1)) -#define MASKP2(a, b) ((a) & ~((b) - 1)) - -static int ftsodell; -static int strict_clocking; -static unsigned int clocking; -static int spdif_locked; -static int ac97_quirk = AC97_TUNE_DEFAULT; - -//#define DEBUG -//#define DEBUG2 -//#define DEBUG_INTERRUPTS -//#define DEBUG_MMAP -//#define DEBUG_MMIO - -#define ADC_RUNNING 1 -#define DAC_RUNNING 2 - -#define I810_FMT_16BIT 1 -#define I810_FMT_STEREO 2 -#define I810_FMT_MASK 3 - -#define SPDIF_ON 0x0004 -#define SURR_ON 0x0010 -#define CENTER_LFE_ON 0x0020 -#define VOL_MUTED 0x8000 - -/* the 810's array of pointers to data buffers */ - -struct sg_item { -#define BUSADDR_MASK 0xFFFFFFFE - u32 busaddr; -#define CON_IOC 0x80000000 /* interrupt on completion */ -#define CON_BUFPAD 0x40000000 /* pad underrun with last sample, else 0 */ -#define CON_BUFLEN_MASK 0x0000ffff /* buffer length in samples */ - u32 control; -}; - -/* an instance of the i810 channel */ -#define SG_LEN 32 -struct i810_channel -{ - /* these sg guys should probably be allocated - separately as nocache. Must be 8 byte aligned */ - struct sg_item sg[SG_LEN]; /* 32*8 */ - u32 offset; /* 4 */ - u32 port; /* 4 */ - u32 used; - u32 num; -}; - -/* - * we have 3 separate dma engines. pcm in, pcm out, and mic. - * each dma engine has controlling registers. These goofy - * names are from the datasheet, but make it easy to write - * code while leafing through it. - * - * ICH4 has 6 dma engines, pcm in, pcm out, mic, pcm in 2, - * mic in 2, s/pdif. Of special interest is the fact that - * the upper 3 DMA engines on the ICH4 *must* be accessed - * via mmio access instead of pio access. - */ - -#define ENUM_ENGINE(PRE,DIG) \ -enum { \ - PRE##_BASE = 0x##DIG##0, /* Base Address */ \ - PRE##_BDBAR = 0x##DIG##0, /* Buffer Descriptor list Base Address */ \ - PRE##_CIV = 0x##DIG##4, /* Current Index Value */ \ - PRE##_LVI = 0x##DIG##5, /* Last Valid Index */ \ - PRE##_SR = 0x##DIG##6, /* Status Register */ \ - PRE##_PICB = 0x##DIG##8, /* Position In Current Buffer */ \ - PRE##_PIV = 0x##DIG##a, /* Prefetched Index Value */ \ - PRE##_CR = 0x##DIG##b /* Control Register */ \ -} - -ENUM_ENGINE(OFF,0); /* Offsets */ -ENUM_ENGINE(PI,0); /* PCM In */ -ENUM_ENGINE(PO,1); /* PCM Out */ -ENUM_ENGINE(MC,2); /* Mic In */ - -enum { - GLOB_CNT = 0x2c, /* Global Control */ - GLOB_STA = 0x30, /* Global Status */ - CAS = 0x34 /* Codec Write Semaphore Register */ -}; - -ENUM_ENGINE(MC2,4); /* Mic In 2 */ -ENUM_ENGINE(PI2,5); /* PCM In 2 */ -ENUM_ENGINE(SP,6); /* S/PDIF */ - -enum { - SDM = 0x80 /* SDATA_IN Map Register */ -}; - -/* interrupts for a dma engine */ -#define DMA_INT_FIFO (1<<4) /* fifo under/over flow */ -#define DMA_INT_COMPLETE (1<<3) /* buffer read/write complete and ioc set */ -#define DMA_INT_LVI (1<<2) /* last valid done */ -#define DMA_INT_CELV (1<<1) /* last valid is current */ -#define DMA_INT_DCH (1) /* DMA Controller Halted (happens on LVI interrupts) */ -#define DMA_INT_MASK (DMA_INT_FIFO|DMA_INT_COMPLETE|DMA_INT_LVI) - -/* interrupts for the whole chip */ -#define INT_SEC (1<<11) -#define INT_PRI (1<<10) -#define INT_MC (1<<7) -#define INT_PO (1<<6) -#define INT_PI (1<<5) -#define INT_MO (1<<2) -#define INT_NI (1<<1) -#define INT_GPI (1<<0) -#define INT_MASK (INT_SEC|INT_PRI|INT_MC|INT_PO|INT_PI|INT_MO|INT_NI|INT_GPI) - -/* magic numbers to protect our data structures */ -#define I810_CARD_MAGIC 0x5072696E /* "Prin" */ -#define I810_STATE_MAGIC 0x63657373 /* "cess" */ -#define I810_DMA_MASK 0xffffffff /* DMA buffer mask for pci_alloc_consist */ -#define NR_HW_CH 3 - -/* maxinum number of AC97 codecs connected, AC97 2.0 defined 4 */ -#define NR_AC97 4 - -/* Please note that an 8bit mono stream is not valid on this card, you must have a 16bit */ -/* stream at a minimum for this card to be happy */ -static const unsigned sample_size[] = { 1, 2, 2, 4 }; -/* Samples are 16bit values, so we are shifting to a word, not to a byte, hence shift */ -/* values are one less than might be expected */ -static const unsigned sample_shift[] = { -1, 0, 0, 1 }; - -enum { - ICH82801AA = 0, - ICH82901AB, - INTEL440MX, - INTELICH2, - INTELICH3, - INTELICH4, - INTELICH5, - SI7012, - NVIDIA_NFORCE, - AMD768, - AMD8111 -}; - -static char * card_names[] = { - "Intel ICH 82801AA", - "Intel ICH 82901AB", - "Intel 440MX", - "Intel ICH2", - "Intel ICH3", - "Intel ICH4", - "Intel ICH5", - "SiS 7012", - "NVIDIA nForce Audio", - "AMD 768", - "AMD-8111 IOHub" -}; - -/* These are capabilities (and bugs) the chipsets _can_ have */ -static struct { - int16_t nr_ac97; -#define CAP_MMIO 0x0001 -#define CAP_20BIT_AUDIO_SUPPORT 0x0002 - u_int16_t flags; -} card_cap[] = { - { 1, 0x0000 }, /* ICH82801AA */ - { 1, 0x0000 }, /* ICH82901AB */ - { 1, 0x0000 }, /* INTEL440MX */ - { 1, 0x0000 }, /* INTELICH2 */ - { 2, 0x0000 }, /* INTELICH3 */ - { 3, 0x0003 }, /* INTELICH4 */ - { 3, 0x0003 }, /* INTELICH5 */ - /*@FIXME to be verified*/ { 2, 0x0000 }, /* SI7012 */ - /*@FIXME to be verified*/ { 2, 0x0000 }, /* NVIDIA_NFORCE */ - /*@FIXME to be verified*/ { 2, 0x0000 }, /* AMD768 */ - /*@FIXME to be verified*/ { 3, 0x0001 }, /* AMD8111 */ -}; - -static struct pci_device_id i810_pci_tbl [] = { - {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801AA_5, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, ICH82801AA}, - {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801AB_5, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, ICH82901AB}, - {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_440MX, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, INTEL440MX}, - {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_4, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, INTELICH2}, - {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_5, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, INTELICH3}, - {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_5, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, INTELICH4}, - {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801EB_5, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, INTELICH5}, - {PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_7012, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, SI7012}, - {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_MCP1_AUDIO, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, NVIDIA_NFORCE}, - {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_MCP2_AUDIO, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, NVIDIA_NFORCE}, - {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_MCP3_AUDIO, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, NVIDIA_NFORCE}, - {PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_OPUS_7445, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, AMD768}, - {PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_8111_AUDIO, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, AMD8111}, - {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ESB_5, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, INTELICH4}, - {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH6_18, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, INTELICH4}, - {PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_CK804_AUDIO, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, NVIDIA_NFORCE}, - {0,} -}; - -MODULE_DEVICE_TABLE (pci, i810_pci_tbl); - -#ifdef CONFIG_PM -#define PM_SUSPENDED(card) (card->pm_suspended) -#else -#define PM_SUSPENDED(card) (0) -#endif - -/* "software" or virtual channel, an instance of opened /dev/dsp */ -struct i810_state { - unsigned int magic; - struct i810_card *card; /* Card info */ - - /* single open lock mechanism, only used for recording */ - struct mutex open_mutex; - wait_queue_head_t open_wait; - - /* file mode */ - mode_t open_mode; - - /* virtual channel number */ - int virt; - -#ifdef CONFIG_PM - unsigned int pm_saved_dac_rate,pm_saved_adc_rate; -#endif - struct dmabuf { - /* wave sample stuff */ - unsigned int rate; - unsigned char fmt, enable, trigger; - - /* hardware channel */ - struct i810_channel *read_channel; - struct i810_channel *write_channel; - - /* OSS buffer management stuff */ - void *rawbuf; - dma_addr_t dma_handle; - unsigned buforder; - unsigned numfrag; - unsigned fragshift; - - /* our buffer acts like a circular ring */ - unsigned hwptr; /* where dma last started, updated by update_ptr */ - unsigned swptr; /* where driver last clear/filled, updated by read/write */ - int count; /* bytes to be consumed or been generated by dma machine */ - unsigned total_bytes; /* total bytes dmaed by hardware */ - - unsigned error; /* number of over/underruns */ - wait_queue_head_t wait; /* put process on wait queue when no more space in buffer */ - - /* redundant, but makes calculations easier */ - /* what the hardware uses */ - unsigned dmasize; - unsigned fragsize; - unsigned fragsamples; - - /* what we tell the user to expect */ - unsigned userfrags; - unsigned userfragsize; - - /* OSS stuff */ - unsigned mapped:1; - unsigned ready:1; - unsigned update_flag; - unsigned ossfragsize; - unsigned ossmaxfrags; - unsigned subdivision; - } dmabuf; -}; - - -struct i810_card { - unsigned int magic; - - /* We keep i810 cards in a linked list */ - struct i810_card *next; - - /* The i810 has a certain amount of cross channel interaction - so we use a single per card lock */ - spinlock_t lock; - - /* Control AC97 access serialization */ - spinlock_t ac97_lock; - - /* PCI device stuff */ - struct pci_dev * pci_dev; - u16 pci_id; - u16 pci_id_internal; /* used to access card_cap[] */ -#ifdef CONFIG_PM - u16 pm_suspended; - int pm_saved_mixer_settings[SOUND_MIXER_NRDEVICES][NR_AC97]; -#endif - /* soundcore stuff */ - int dev_audio; - - /* structures for abstraction of hardware facilities, codecs, banks and channels*/ - u16 ac97_id_map[NR_AC97]; - struct ac97_codec *ac97_codec[NR_AC97]; - struct i810_state *states[NR_HW_CH]; - struct i810_channel *channel; /* 1:1 to states[] but diff. lifetime */ - dma_addr_t chandma; - - u16 ac97_features; - u16 ac97_status; - u16 channels; - - /* hardware resources */ - unsigned long ac97base; - unsigned long iobase; - u32 irq; - - unsigned long ac97base_mmio_phys; - unsigned long iobase_mmio_phys; - u_int8_t __iomem *ac97base_mmio; - u_int8_t __iomem *iobase_mmio; - - int use_mmio; - - /* Function support */ - struct i810_channel *(*alloc_pcm_channel)(struct i810_card *); - struct i810_channel *(*alloc_rec_pcm_channel)(struct i810_card *); - struct i810_channel *(*alloc_rec_mic_channel)(struct i810_card *); - void (*free_pcm_channel)(struct i810_card *, int chan); - - /* We have a *very* long init time possibly, so use this to block */ - /* attempts to open our devices before we are ready (stops oops'es) */ - int initializing; -}; - -/* extract register offset from codec struct */ -#define IO_REG_OFF(codec) (((struct i810_card *) codec->private_data)->ac97_id_map[codec->id]) - -#define I810_IOREAD(size, type, card, off) \ -({ \ - type val; \ - if (card->use_mmio) \ - val=read##size(card->iobase_mmio+off); \ - else \ - val=in##size(card->iobase+off); \ - val; \ -}) - -#define I810_IOREADL(card, off) I810_IOREAD(l, u32, card, off) -#define I810_IOREADW(card, off) I810_IOREAD(w, u16, card, off) -#define I810_IOREADB(card, off) I810_IOREAD(b, u8, card, off) - -#define I810_IOWRITE(size, val, card, off) \ -({ \ - if (card->use_mmio) \ - write##size(val, card->iobase_mmio+off); \ - else \ - out##size(val, card->iobase+off); \ -}) - -#define I810_IOWRITEL(val, card, off) I810_IOWRITE(l, val, card, off) -#define I810_IOWRITEW(val, card, off) I810_IOWRITE(w, val, card, off) -#define I810_IOWRITEB(val, card, off) I810_IOWRITE(b, val, card, off) - -#define GET_CIV(card, port) MODULOP2(I810_IOREADB((card), (port) + OFF_CIV), SG_LEN) -#define GET_LVI(card, port) MODULOP2(I810_IOREADB((card), (port) + OFF_LVI), SG_LEN) - -/* set LVI from CIV */ -#define CIV_TO_LVI(card, port, off) \ - I810_IOWRITEB(MODULOP2(GET_CIV((card), (port)) + (off), SG_LEN), (card), (port) + OFF_LVI) - -static struct ac97_quirk ac97_quirks[] __devinitdata = { - { - .vendor = 0x0e11, - .device = 0x00b8, - .name = "Compaq Evo D510C", - .type = AC97_TUNE_HP_ONLY - }, - { - .vendor = 0x1028, - .device = 0x00d8, - .name = "Dell Precision 530", /* AD1885 */ - .type = AC97_TUNE_HP_ONLY - }, - { - .vendor = 0x1028, - .device = 0x0126, - .name = "Dell Optiplex GX260", /* AD1981A */ - .type = AC97_TUNE_HP_ONLY - }, - { - .vendor = 0x1028, - .device = 0x012d, - .name = "Dell Precision 450", /* AD1981B*/ - .type = AC97_TUNE_HP_ONLY - }, - { /* FIXME: which codec? */ - .vendor = 0x103c, - .device = 0x00c3, - .name = "Hewlett-Packard onboard", - .type = AC97_TUNE_HP_ONLY - }, - { - .vendor = 0x103c, - .device = 0x12f1, - .name = "HP xw8200", /* AD1981B*/ - .type = AC97_TUNE_HP_ONLY - }, - { - .vendor = 0x103c, - .device = 0x3008, - .name = "HP xw4200", /* AD1981B*/ - .type = AC97_TUNE_HP_ONLY - }, - { - .vendor = 0x10f1, - .device = 0x2665, - .name = "Fujitsu-Siemens Celsius", /* AD1981? */ - .type = AC97_TUNE_HP_ONLY - }, - { - .vendor = 0x10f1, - .device = 0x2885, - .name = "AMD64 Mobo", /* ALC650 */ - .type = AC97_TUNE_HP_ONLY - }, - { - .vendor = 0x110a, - .device = 0x0056, - .name = "Fujitsu-Siemens Scenic", /* AD1981? */ - .type = AC97_TUNE_HP_ONLY - }, - { - .vendor = 0x11d4, - .device = 0x5375, - .name = "ADI AD1985 (discrete)", - .type = AC97_TUNE_HP_ONLY - }, - { - .vendor = 0x1462, - .device = 0x5470, - .name = "MSI P4 ATX 645 Ultra", - .type = AC97_TUNE_HP_ONLY - }, - { - .vendor = 0x1734, - .device = 0x0088, - .name = "Fujitsu-Siemens D1522", /* AD1981 */ - .type = AC97_TUNE_HP_ONLY - }, - { - .vendor = 0x8086, - .device = 0x4856, - .name = "Intel D845WN (82801BA)", - .type = AC97_TUNE_SWAP_HP - }, - { - .vendor = 0x8086, - .device = 0x4d44, - .name = "Intel D850EMV2", /* AD1885 */ - .type = AC97_TUNE_HP_ONLY - }, - { - .vendor = 0x8086, - .device = 0x4d56, - .name = "Intel ICH/AD1885", - .type = AC97_TUNE_HP_ONLY - }, - { - .vendor = 0x1028, - .device = 0x012d, - .name = "Dell Precision 450", /* AD1981B*/ - .type = AC97_TUNE_HP_ONLY - }, - { - .vendor = 0x103c, - .device = 0x3008, - .name = "HP xw4200", /* AD1981B*/ - .type = AC97_TUNE_HP_ONLY - }, - { - .vendor = 0x103c, - .device = 0x12f1, - .name = "HP xw8200", /* AD1981B*/ - .type = AC97_TUNE_HP_ONLY - }, - { } /* terminator */ -}; - -static struct i810_card *devs = NULL; - -static int i810_open_mixdev(struct inode *inode, struct file *file); -static int i810_ioctl_mixdev(struct inode *inode, struct file *file, - unsigned int cmd, unsigned long arg); -static u16 i810_ac97_get(struct ac97_codec *dev, u8 reg); -static void i810_ac97_set(struct ac97_codec *dev, u8 reg, u16 data); -static u16 i810_ac97_get_mmio(struct ac97_codec *dev, u8 reg); -static void i810_ac97_set_mmio(struct ac97_codec *dev, u8 reg, u16 data); -static u16 i810_ac97_get_io(struct ac97_codec *dev, u8 reg); -static void i810_ac97_set_io(struct ac97_codec *dev, u8 reg, u16 data); - -static struct i810_channel *i810_alloc_pcm_channel(struct i810_card *card) -{ - if(card->channel[1].used==1) - return NULL; - card->channel[1].used=1; - return &card->channel[1]; -} - -static struct i810_channel *i810_alloc_rec_pcm_channel(struct i810_card *card) -{ - if(card->channel[0].used==1) - return NULL; - card->channel[0].used=1; - return &card->channel[0]; -} - -static struct i810_channel *i810_alloc_rec_mic_channel(struct i810_card *card) -{ - if(card->channel[2].used==1) - return NULL; - card->channel[2].used=1; - return &card->channel[2]; -} - -static void i810_free_pcm_channel(struct i810_card *card, int channel) -{ - card->channel[channel].used=0; -} - -static int i810_valid_spdif_rate ( struct ac97_codec *codec, int rate ) -{ - unsigned long id = 0L; - - id = (i810_ac97_get(codec, AC97_VENDOR_ID1) << 16); - id |= i810_ac97_get(codec, AC97_VENDOR_ID2) & 0xffff; -#ifdef DEBUG - printk ( "i810_audio: codec = %s, codec_id = 0x%08lx\n", codec->name, id); -#endif - switch ( id ) { - case 0x41445361: /* AD1886 */ - if (rate == 48000) { - return 1; - } - break; - default: /* all other codecs, until we know otherwiae */ - if (rate == 48000 || rate == 44100 || rate == 32000) { - return 1; - } - break; - } - return (0); -} - -/* i810_set_spdif_output - * - * Configure the S/PDIF output transmitter. When we turn on - * S/PDIF, we turn off the analog output. This may not be - * the right thing to do. - * - * Assumptions: - * The DSP sample rate must already be set to a supported - * S/PDIF rate (32kHz, 44.1kHz, or 48kHz) or we abort. - */ -static int i810_set_spdif_output(struct i810_state *state, int slots, int rate) -{ - int vol; - int aud_reg; - int r = 0; - struct ac97_codec *codec = state->card->ac97_codec[0]; - - if(!codec->codec_ops->digital) { - state->card->ac97_status &= ~SPDIF_ON; - } else { - if ( slots == -1 ) { /* Turn off S/PDIF */ - codec->codec_ops->digital(codec, 0, 0, 0); - /* If the volume wasn't muted before we turned on S/PDIF, unmute it */ - if ( !(state->card->ac97_status & VOL_MUTED) ) { - aud_reg = i810_ac97_get(codec, AC97_MASTER_VOL_STEREO); - i810_ac97_set(codec, AC97_MASTER_VOL_STEREO, (aud_reg & ~VOL_MUTED)); - } - state->card->ac97_status &= ~(VOL_MUTED | SPDIF_ON); - return 0; - } - - vol = i810_ac97_get(codec, AC97_MASTER_VOL_STEREO); - state->card->ac97_status = vol & VOL_MUTED; - - r = codec->codec_ops->digital(codec, slots, rate, 0); - - if(r) - state->card->ac97_status |= SPDIF_ON; - else - state->card->ac97_status &= ~SPDIF_ON; - - /* Mute the analog output */ - /* Should this only mute the PCM volume??? */ - i810_ac97_set(codec, AC97_MASTER_VOL_STEREO, (vol | VOL_MUTED)); - } - return r; -} - -/* i810_set_dac_channels - * - * Configure the codec's multi-channel DACs - * - * The logic is backwards. Setting the bit to 1 turns off the DAC. - * - * What about the ICH? We currently configure it using the - * SNDCTL_DSP_CHANNELS ioctl. If we're turnning on the DAC, - * does that imply that we want the ICH set to support - * these channels? - * - * TODO: - * vailidate that the codec really supports these DACs - * before turning them on. - */ -static void i810_set_dac_channels(struct i810_state *state, int channel) -{ - int aud_reg; - struct ac97_codec *codec = state->card->ac97_codec[0]; - - /* No codec, no setup */ - - if(codec == NULL) - return; - - aud_reg = i810_ac97_get(codec, AC97_EXTENDED_STATUS); - aud_reg |= AC97_EA_PRI | AC97_EA_PRJ | AC97_EA_PRK; - state->card->ac97_status &= ~(SURR_ON | CENTER_LFE_ON); - - switch ( channel ) { - case 2: /* always enabled */ - break; - case 4: - aud_reg &= ~AC97_EA_PRJ; - state->card->ac97_status |= SURR_ON; - break; - case 6: - aud_reg &= ~(AC97_EA_PRJ | AC97_EA_PRI | AC97_EA_PRK); - state->card->ac97_status |= SURR_ON | CENTER_LFE_ON; - break; - default: - break; - } - i810_ac97_set(codec, AC97_EXTENDED_STATUS, aud_reg); - -} - - -/* set playback sample rate */ -static unsigned int i810_set_dac_rate(struct i810_state * state, unsigned int rate) -{ - struct dmabuf *dmabuf = &state->dmabuf; - u32 new_rate; - struct ac97_codec *codec=state->card->ac97_codec[0]; - - if(!(state->card->ac97_features&0x0001)) - { - dmabuf->rate = clocking; -#ifdef DEBUG - printk("Asked for %d Hz, but ac97_features says we only do %dHz. Sorry!\n", - rate,clocking); -#endif - return clocking; - } - - if (rate > 48000) - rate = 48000; - if (rate < 8000) - rate = 8000; - dmabuf->rate = rate; - - /* - * Adjust for misclocked crap - */ - rate = ( rate * clocking)/48000; - if(strict_clocking && rate < 8000) { - rate = 8000; - dmabuf->rate = (rate * 48000)/clocking; - } - - new_rate=ac97_set_dac_rate(codec, rate); - if(new_rate != rate) { - dmabuf->rate = (new_rate * 48000)/clocking; - } -#ifdef DEBUG - printk("i810_audio: called i810_set_dac_rate : asked for %d, got %d\n", rate, dmabuf->rate); -#endif - rate = new_rate; - return dmabuf->rate; -} - -/* set recording sample rate */ -static unsigned int i810_set_adc_rate(struct i810_state * state, unsigned int rate) -{ - struct dmabuf *dmabuf = &state->dmabuf; - u32 new_rate; - struct ac97_codec *codec=state->card->ac97_codec[0]; - - if(!(state->card->ac97_features&0x0001)) - { - dmabuf->rate = clocking; - return clocking; - } - - if (rate > 48000) - rate = 48000; - if (rate < 8000) - rate = 8000; - dmabuf->rate = rate; - - /* - * Adjust for misclocked crap - */ - - rate = ( rate * clocking)/48000; - if(strict_clocking && rate < 8000) { - rate = 8000; - dmabuf->rate = (rate * 48000)/clocking; - } - - new_rate = ac97_set_adc_rate(codec, rate); - - if(new_rate != rate) { - dmabuf->rate = (new_rate * 48000)/clocking; - rate = new_rate; - } -#ifdef DEBUG - printk("i810_audio: called i810_set_adc_rate : rate = %d/%d\n", dmabuf->rate, rate); -#endif - return dmabuf->rate; -} - -/* get current playback/recording dma buffer pointer (byte offset from LBA), - called with spinlock held! */ - -static inline unsigned i810_get_dma_addr(struct i810_state *state, int rec) -{ - struct dmabuf *dmabuf = &state->dmabuf; - unsigned int civ, offset, port, port_picb, bytes = 2; - - if (!dmabuf->enable) - return 0; - - if (rec) - port = dmabuf->read_channel->port; - else - port = dmabuf->write_channel->port; - - if(state->card->pci_id == PCI_DEVICE_ID_SI_7012) { - port_picb = port + OFF_SR; - bytes = 1; - } else - port_picb = port + OFF_PICB; - - do { - civ = GET_CIV(state->card, port); - offset = I810_IOREADW(state->card, port_picb); - /* Must have a delay here! */ - if(offset == 0) - udelay(1); - /* Reread both registers and make sure that that total - * offset from the first reading to the second is 0. - * There is an issue with SiS hardware where it will count - * picb down to 0, then update civ to the next value, - * then set the new picb to fragsize bytes. We can catch - * it between the civ update and the picb update, making - * it look as though we are 1 fragsize ahead of where we - * are. The next to we get the address though, it will - * be back in the right place, and we will suddenly think - * we just went forward dmasize - fragsize bytes, causing - * totally stupid *huge* dma overrun messages. We are - * assuming that the 1us delay is more than long enough - * that we won't have to worry about the chip still being - * out of sync with reality ;-) - */ - } while (civ != GET_CIV(state->card, port) || offset != I810_IOREADW(state->card, port_picb)); - - return (((civ + 1) * dmabuf->fragsize - (bytes * offset)) - % dmabuf->dmasize); -} - -/* Stop recording (lock held) */ -static inline void __stop_adc(struct i810_state *state) -{ - struct dmabuf *dmabuf = &state->dmabuf; - struct i810_card *card = state->card; - - dmabuf->enable &= ~ADC_RUNNING; - I810_IOWRITEB(0, card, PI_CR); - // wait for the card to acknowledge shutdown - while( I810_IOREADB(card, PI_CR) != 0 ) ; - // now clear any latent interrupt bits (like the halt bit) - if(card->pci_id == PCI_DEVICE_ID_SI_7012) - I810_IOWRITEB( I810_IOREADB(card, PI_PICB), card, PI_PICB ); - else - I810_IOWRITEB( I810_IOREADB(card, PI_SR), card, PI_SR ); - I810_IOWRITEL( I810_IOREADL(card, GLOB_STA) & INT_PI, card, GLOB_STA); -} - -static void stop_adc(struct i810_state *state) -{ - struct i810_card *card = state->card; - unsigned long flags; - - spin_lock_irqsave(&card->lock, flags); - __stop_adc(state); - spin_unlock_irqrestore(&card->lock, flags); -} - -static inline void __start_adc(struct i810_state *state) -{ - struct dmabuf *dmabuf = &state->dmabuf; - - if (dmabuf->count < dmabuf->dmasize && dmabuf->ready && !dmabuf->enable && - (dmabuf->trigger & PCM_ENABLE_INPUT)) { - dmabuf->enable |= ADC_RUNNING; - // Interrupt enable, LVI enable, DMA enable - I810_IOWRITEB(0x10 | 0x04 | 0x01, state->card, PI_CR); - } -} - -static void start_adc(struct i810_state *state) -{ - struct i810_card *card = state->card; - unsigned long flags; - - spin_lock_irqsave(&card->lock, flags); - __start_adc(state); - spin_unlock_irqrestore(&card->lock, flags); -} - -/* stop playback (lock held) */ -static inline void __stop_dac(struct i810_state *state) -{ - struct dmabuf *dmabuf = &state->dmabuf; - struct i810_card *card = state->card; - - dmabuf->enable &= ~DAC_RUNNING; - I810_IOWRITEB(0, card, PO_CR); - // wait for the card to acknowledge shutdown - while( I810_IOREADB(card, PO_CR) != 0 ) ; - // now clear any latent interrupt bits (like the halt bit) - if(card->pci_id == PCI_DEVICE_ID_SI_7012) - I810_IOWRITEB( I810_IOREADB(card, PO_PICB), card, PO_PICB ); - else - I810_IOWRITEB( I810_IOREADB(card, PO_SR), card, PO_SR ); - I810_IOWRITEL( I810_IOREADL(card, GLOB_STA) & INT_PO, card, GLOB_STA); -} - -static void stop_dac(struct i810_state *state) -{ - struct i810_card *card = state->card; - unsigned long flags; - - spin_lock_irqsave(&card->lock, flags); - __stop_dac(state); - spin_unlock_irqrestore(&card->lock, flags); -} - -static inline void __start_dac(struct i810_state *state) -{ - struct dmabuf *dmabuf = &state->dmabuf; - - if (dmabuf->count > 0 && dmabuf->ready && !dmabuf->enable && - (dmabuf->trigger & PCM_ENABLE_OUTPUT)) { - dmabuf->enable |= DAC_RUNNING; - // Interrupt enable, LVI enable, DMA enable - I810_IOWRITEB(0x10 | 0x04 | 0x01, state->card, PO_CR); - } -} -static void start_dac(struct i810_state *state) -{ - struct i810_card *card = state->card; - unsigned long flags; - - spin_lock_irqsave(&card->lock, flags); - __start_dac(state); - spin_unlock_irqrestore(&card->lock, flags); -} - -#define DMABUF_DEFAULTORDER (16-PAGE_SHIFT) -#define DMABUF_MINORDER 1 - -/* allocate DMA buffer, playback and recording buffer should be allocated separately */ -static int alloc_dmabuf(struct i810_state *state) -{ - struct dmabuf *dmabuf = &state->dmabuf; - void *rawbuf= NULL; - int order, size; - struct page *page, *pend; - - /* If we don't have any oss frag params, then use our default ones */ - if(dmabuf->ossmaxfrags == 0) - dmabuf->ossmaxfrags = 4; - if(dmabuf->ossfragsize == 0) - dmabuf->ossfragsize = (PAGE_SIZE<<DMABUF_DEFAULTORDER)/dmabuf->ossmaxfrags; - size = dmabuf->ossfragsize * dmabuf->ossmaxfrags; - - if(dmabuf->rawbuf && (PAGE_SIZE << dmabuf->buforder) == size) - return 0; - /* alloc enough to satisfy the oss params */ - for (order = DMABUF_DEFAULTORDER; order >= DMABUF_MINORDER; order--) { - if ( (PAGE_SIZE<<order) > size ) - continue; - if ((rawbuf = pci_alloc_consistent(state->card->pci_dev, - PAGE_SIZE << order, - &dmabuf->dma_handle))) - break; - } - if (!rawbuf) - return -ENOMEM; - - -#ifdef DEBUG - printk("i810_audio: allocated %ld (order = %d) bytes at %p\n", - PAGE_SIZE << order, order, rawbuf); -#endif - - dmabuf->ready = dmabuf->mapped = 0; - dmabuf->rawbuf = rawbuf; - dmabuf->buforder = order; - - /* now mark the pages as reserved; otherwise remap_pfn_range doesn't do what we want */ - pend = virt_to_page(rawbuf + (PAGE_SIZE << order) - 1); - for (page = virt_to_page(rawbuf); page <= pend; page++) - SetPageReserved(page); - - return 0; -} - -/* free DMA buffer */ -static void dealloc_dmabuf(struct i810_state *state) -{ - struct dmabuf *dmabuf = &state->dmabuf; - struct page *page, *pend; - - if (dmabuf->rawbuf) { - /* undo marking the pages as reserved */ - pend = virt_to_page(dmabuf->rawbuf + (PAGE_SIZE << dmabuf->buforder) - 1); - for (page = virt_to_page(dmabuf->rawbuf); page <= pend; page++) - ClearPageReserved(page); - pci_free_consistent(state->card->pci_dev, PAGE_SIZE << dmabuf->buforder, - dmabuf->rawbuf, dmabuf->dma_handle); - } - dmabuf->rawbuf = NULL; - dmabuf->mapped = dmabuf->ready = 0; -} - -static int prog_dmabuf(struct i810_state *state, unsigned rec) -{ - struct dmabuf *dmabuf = &state->dmabuf; - struct i810_channel *c; - struct sg_item *sg; - unsigned long flags; - int ret; - unsigned fragint; - int i; - - spin_lock_irqsave(&state->card->lock, flags); - if(dmabuf->enable & DAC_RUNNING) - __stop_dac(state); - if(dmabuf->enable & ADC_RUNNING) - __stop_adc(state); - dmabuf->total_bytes = 0; - dmabuf->count = dmabuf->error = 0; - dmabuf->swptr = dmabuf->hwptr = 0; - spin_unlock_irqrestore(&state->card->lock, flags); - - /* allocate DMA buffer, let alloc_dmabuf determine if we are already - * allocated well enough or if we should replace the current buffer - * (assuming one is already allocated, if it isn't, then allocate it). - */ - if ((ret = alloc_dmabuf(state))) - return ret; - - /* FIXME: figure out all this OSS fragment stuff */ - /* I did, it now does what it should according to the OSS API. DL */ - /* We may not have realloced our dmabuf, but the fragment size to - * fragment number ratio may have changed, so go ahead and reprogram - * things - */ - dmabuf->dmasize = PAGE_SIZE << dmabuf->buforder; - dmabuf->numfrag = SG_LEN; - dmabuf->fragsize = dmabuf->dmasize/dmabuf->numfrag; - dmabuf->fragsamples = dmabuf->fragsize >> 1; - dmabuf->fragshift = ffs(dmabuf->fragsize) - 1; - dmabuf->userfragsize = dmabuf->ossfragsize; - dmabuf->userfrags = dmabuf->dmasize/dmabuf->ossfragsize; - - memset(dmabuf->rawbuf, 0, dmabuf->dmasize); - - if(dmabuf->ossmaxfrags == 4) { - fragint = 8; - } else if (dmabuf->ossmaxfrags == 8) { - fragint = 4; - } else if (dmabuf->ossmaxfrags == 16) { - fragint = 2; - } else { - fragint = 1; - } - /* - * Now set up the ring - */ - if(dmabuf->read_channel) - c = dmabuf->read_channel; - else - c = dmabuf->write_channel; - while(c != NULL) { - sg=&c->sg[0]; - /* - * Load up 32 sg entries and take an interrupt at half - * way (we might want more interrupts later..) - */ - - for(i=0;i<dmabuf->numfrag;i++) - { - sg->busaddr=(u32)dmabuf->dma_handle+dmabuf->fragsize*i; - // the card will always be doing 16bit stereo - sg->control=dmabuf->fragsamples; - if(state->card->pci_id == PCI_DEVICE_ID_SI_7012) - sg->control <<= 1; - sg->control|=CON_BUFPAD; - // set us up to get IOC interrupts as often as needed to - // satisfy numfrag requirements, no more - if( ((i+1) % fragint) == 0) { - sg->control|=CON_IOC; - } - sg++; - } - spin_lock_irqsave(&state->card->lock, flags); - I810_IOWRITEB(2, state->card, c->port+OFF_CR); /* reset DMA machine */ - while( I810_IOREADB(state->card, c->port+OFF_CR) & 0x02 ) ; - I810_IOWRITEL((u32)state->card->chandma + - c->num*sizeof(struct i810_channel), - state->card, c->port+OFF_BDBAR); - CIV_TO_LVI(state->card, c->port, 0); - - spin_unlock_irqrestore(&state->card->lock, flags); - - if(c != dmabuf->write_channel) - c = dmabuf->write_channel; - else - c = NULL; - } - - /* set the ready flag for the dma buffer */ - dmabuf->ready = 1; - -#ifdef DEBUG - printk("i810_audio: prog_dmabuf, sample rate = %d, format = %d,\n\tnumfrag = %d, " - "fragsize = %d dmasize = %d\n", - dmabuf->rate, dmabuf->fmt, dmabuf->numfrag, - dmabuf->fragsize, dmabuf->dmasize); -#endif - - return 0; -} - -static void __i810_update_lvi(struct i810_state *state, int rec) -{ - struct dmabuf *dmabuf = &state->dmabuf; - int x, port; - int trigger; - int count, fragsize; - void (*start)(struct i810_state *); - - count = dmabuf->count; - if (rec) { - port = dmabuf->read_channel->port; - trigger = PCM_ENABLE_INPUT; - start = __start_adc; - count = dmabuf->dmasize - count; - } else { - port = dmabuf->write_channel->port; - trigger = PCM_ENABLE_OUTPUT; - start = __start_dac; - } - - /* Do not process partial fragments. */ - fragsize = dmabuf->fragsize; - if (count < fragsize) - return; - - /* if we are currently stopped, then our CIV is actually set to our - * *last* sg segment and we are ready to wrap to the next. However, - * if we set our LVI to the last sg segment, then it won't wrap to - * the next sg segment, it won't even get a start. So, instead, when - * we are stopped, we set both the LVI value and also we increment - * the CIV value to the next sg segment to be played so that when - * we call start, things will operate properly. Since the CIV can't - * be written to directly for this purpose, we set the LVI to CIV + 1 - * temporarily. Once the engine has started we set the LVI to its - * final value. - */ - if (!dmabuf->enable && dmabuf->ready) { - if (!(dmabuf->trigger & trigger)) - return; - - CIV_TO_LVI(state->card, port, 1); - - start(state); - while (!(I810_IOREADB(state->card, port + OFF_CR) & ((1<<4) | (1<<2)))) - ; - } - - /* MASKP2(swptr, fragsize) - 1 is the tail of our transfer */ - x = MODULOP2(MASKP2(dmabuf->swptr, fragsize) - 1, dmabuf->dmasize); - x >>= dmabuf->fragshift; - I810_IOWRITEB(x, state->card, port + OFF_LVI); -} - -static void i810_update_lvi(struct i810_state *state, int rec) -{ - struct dmabuf *dmabuf = &state->dmabuf; - unsigned long flags; - - if(!dmabuf->ready) - return; - spin_lock_irqsave(&state->card->lock, flags); - __i810_update_lvi(state, rec); - spin_unlock_irqrestore(&state->card->lock, flags); -} - -/* update buffer manangement pointers, especially, dmabuf->count and dmabuf->hwptr */ -static void i810_update_ptr(struct i810_state *state) -{ - struct dmabuf *dmabuf = &state->dmabuf; - unsigned hwptr; - unsigned fragmask, dmamask; - int diff; - - fragmask = MASKP2(~0, dmabuf->fragsize); - dmamask = MODULOP2(~0, dmabuf->dmasize); - - /* error handling and process wake up for ADC */ - if (dmabuf->enable == ADC_RUNNING) { - /* update hardware pointer */ - hwptr = i810_get_dma_addr(state, 1) & fragmask; - diff = (hwptr - dmabuf->hwptr) & dmamask; -#if defined(DEBUG_INTERRUPTS) || defined(DEBUG_MMAP) - printk("ADC HWP %d,%d,%d\n", hwptr, dmabuf->hwptr, diff); -#endif - dmabuf->hwptr = hwptr; - dmabuf->total_bytes += diff; - dmabuf->count += diff; - if (dmabuf->count > dmabuf->dmasize) { - /* buffer underrun or buffer overrun */ - /* this is normal for the end of a read */ - /* only give an error if we went past the */ - /* last valid sg entry */ - if (GET_CIV(state->card, PI_BASE) != - GET_LVI(state->card, PI_BASE)) { - printk(KERN_WARNING "i810_audio: DMA overrun on read\n"); - dmabuf->error++; - } - } - if (diff) - wake_up(&dmabuf->wait); - } - /* error handling and process wake up for DAC */ - if (dmabuf->enable == DAC_RUNNING) { - /* update hardware pointer */ - hwptr = i810_get_dma_addr(state, 0) & fragmask; - diff = (hwptr - dmabuf->hwptr) & dmamask; -#if defined(DEBUG_INTERRUPTS) || defined(DEBUG_MMAP) - printk("DAC HWP %d,%d,%d\n", hwptr, dmabuf->hwptr, diff); -#endif - dmabuf->hwptr = hwptr; - dmabuf->total_bytes += diff; - dmabuf->count -= diff; - if (dmabuf->count < 0) { - /* buffer underrun or buffer overrun */ - /* this is normal for the end of a write */ - /* only give an error if we went past the */ - /* last valid sg entry */ - if (GET_CIV(state->card, PO_BASE) != - GET_LVI(state->card, PO_BASE)) { - printk(KERN_WARNING "i810_audio: DMA overrun on write\n"); - printk("i810_audio: CIV %d, LVI %d, hwptr %x, " - "count %d\n", - GET_CIV(state->card, PO_BASE), - GET_LVI(state->card, PO_BASE), - dmabuf->hwptr, dmabuf->count); - dmabuf->error++; - } - } - if (diff) - wake_up(&dmabuf->wait); - } -} - -static inline int i810_get_free_write_space(struct i810_state *state) -{ - struct dmabuf *dmabuf = &state->dmabuf; - int free; - - i810_update_ptr(state); - // catch underruns during playback - if (dmabuf->count < 0) { - dmabuf->count = 0; - dmabuf->swptr = dmabuf->hwptr; - } - free = dmabuf->dmasize - dmabuf->count; - if(free < 0) - return(0); - return(free); -} - -static inline int i810_get_available_read_data(struct i810_state *state) -{ - struct dmabuf *dmabuf = &state->dmabuf; - int avail; - - i810_update_ptr(state); - // catch overruns during record - if (dmabuf->count > dmabuf->dmasize) { - dmabuf->count = dmabuf->dmasize; - dmabuf->swptr = dmabuf->hwptr; - } - avail = dmabuf->count; - if(avail < 0) - return(0); - return(avail); -} - -static inline void fill_partial_frag(struct dmabuf *dmabuf) -{ - unsigned fragsize; - unsigned swptr, len; - - fragsize = dmabuf->fragsize; - swptr = dmabuf->swptr; - len = fragsize - MODULOP2(dmabuf->swptr, fragsize); - if (len == fragsize) - return; - - memset(dmabuf->rawbuf + swptr, '\0', len); - dmabuf->swptr = MODULOP2(swptr + len, dmabuf->dmasize); - dmabuf->count += len; -} - -static int drain_dac(struct i810_state *state, int signals_allowed) -{ - DECLARE_WAITQUEUE(wait, current); - struct dmabuf *dmabuf = &state->dmabuf; - unsigned long flags; - unsigned long tmo; - int count; - - if (!dmabuf->ready) - return 0; - if(dmabuf->mapped) { - stop_dac(state); - return 0; - } - - spin_lock_irqsave(&state->card->lock, flags); - - fill_partial_frag(dmabuf); - - /* - * This will make sure that our LVI is correct, that our - * pointer is updated, and that the DAC is running. We - * have to force the setting of dmabuf->trigger to avoid - * any possible deadlocks. - */ - dmabuf->trigger = PCM_ENABLE_OUTPUT; - __i810_update_lvi(state, 0); - - spin_unlock_irqrestore(&state->card->lock, flags); - - add_wait_queue(&dmabuf->wait, &wait); - for (;;) { - - spin_lock_irqsave(&state->card->lock, flags); - i810_update_ptr(state); - count = dmabuf->count; - - /* It seems that we have to set the current state to - * TASK_INTERRUPTIBLE every time to make the process - * really go to sleep. This also has to be *after* the - * update_ptr() call because update_ptr is likely to - * do a wake_up() which will unset this before we ever - * try to sleep, resuling in a tight loop in this code - * instead of actually sleeping and waiting for an - * interrupt to wake us up! - */ - __set_current_state(signals_allowed ? - TASK_INTERRUPTIBLE : TASK_UNINTERRUPTIBLE); - spin_unlock_irqrestore(&state->card->lock, flags); - - if (count <= 0) - break; - - if (signal_pending(current) && signals_allowed) { - break; - } - - /* - * set the timeout to significantly longer than it *should* - * take for the DAC to drain the DMA buffer - */ - tmo = (count * HZ) / (dmabuf->rate); - if (!schedule_timeout(tmo >= 2 ? tmo : 2)){ - printk(KERN_ERR "i810_audio: drain_dac, dma timeout?\n"); - count = 0; - break; - } - } - set_current_state(TASK_RUNNING); - remove_wait_queue(&dmabuf->wait, &wait); - if(count > 0 && signal_pending(current) && signals_allowed) - return -ERESTARTSYS; - stop_dac(state); - return 0; -} - -static void i810_channel_interrupt(struct i810_card *card) -{ - int i, count; - -#ifdef DEBUG_INTERRUPTS - printk("CHANNEL "); -#endif - for(i=0;i<NR_HW_CH;i++) - { - struct i810_state *state = card->states[i]; - struct i810_channel *c; - struct dmabuf *dmabuf; - unsigned long port; - u16 status; - - if(!state) - continue; - if(!state->dmabuf.ready) - continue; - dmabuf = &state->dmabuf; - if(dmabuf->enable & DAC_RUNNING) { - c=dmabuf->write_channel; - } else if(dmabuf->enable & ADC_RUNNING) { - c=dmabuf->read_channel; - } else /* This can occur going from R/W to close */ - continue; - - port = c->port; - - if(card->pci_id == PCI_DEVICE_ID_SI_7012) - status = I810_IOREADW(card, port + OFF_PICB); - else - status = I810_IOREADW(card, port + OFF_SR); - -#ifdef DEBUG_INTERRUPTS - printk("NUM %d PORT %X IRQ ( ST%d ", c->num, c->port, status); -#endif - if(status & DMA_INT_COMPLETE) - { - /* only wake_up() waiters if this interrupt signals - * us being beyond a userfragsize of data open or - * available, and i810_update_ptr() does that for - * us - */ - i810_update_ptr(state); -#ifdef DEBUG_INTERRUPTS - printk("COMP %d ", dmabuf->hwptr / - dmabuf->fragsize); -#endif - } - if(status & (DMA_INT_LVI | DMA_INT_DCH)) - { - /* wake_up() unconditionally on LVI and DCH */ - i810_update_ptr(state); - wake_up(&dmabuf->wait); -#ifdef DEBUG_INTERRUPTS - if(status & DMA_INT_LVI) - printk("LVI "); - if(status & DMA_INT_DCH) - printk("DCH -"); -#endif - count = dmabuf->count; - if(dmabuf->enable & ADC_RUNNING) - count = dmabuf->dmasize - count; - if (count >= (int)dmabuf->fragsize) { - I810_IOWRITEB(I810_IOREADB(card, port+OFF_CR) | 1, card, port+OFF_CR); -#ifdef DEBUG_INTERRUPTS - printk(" CONTINUE "); -#endif - } else { - if (dmabuf->enable & DAC_RUNNING) - __stop_dac(state); - if (dmabuf->enable & ADC_RUNNING) - __stop_adc(state); - dmabuf->enable = 0; -#ifdef DEBUG_INTERRUPTS - printk(" STOP "); -#endif - } - } - if(card->pci_id == PCI_DEVICE_ID_SI_7012) - I810_IOWRITEW(status & DMA_INT_MASK, card, port + OFF_PICB); - else - I810_IOWRITEW(status & DMA_INT_MASK, card, port + OFF_SR); - } -#ifdef DEBUG_INTERRUPTS - printk(")\n"); -#endif -} - -static irqreturn_t i810_interrupt(int irq, void *dev_id) -{ - struct i810_card *card = dev_id; - u32 status; - - spin_lock(&card->lock); - - status = I810_IOREADL(card, GLOB_STA); - - if(!(status & INT_MASK)) - { - spin_unlock(&card->lock); - return IRQ_NONE; /* not for us */ - } - - if(status & (INT_PO|INT_PI|INT_MC)) - i810_channel_interrupt(card); - - /* clear 'em */ - I810_IOWRITEL(status & INT_MASK, card, GLOB_STA); - spin_unlock(&card->lock); - return IRQ_HANDLED; -} - -/* in this loop, dmabuf.count signifies the amount of data that is - waiting to be copied to the user's buffer. It is filled by the dma - machine and drained by this loop. */ - -static ssize_t i810_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos) -{ - struct i810_state *state = (struct i810_state *)file->private_data; - struct i810_card *card=state ? state->card : NULL; - struct dmabuf *dmabuf = &state->dmabuf; - ssize_t ret; - unsigned long flags; - unsigned int swptr; - int cnt; - int pending; - DECLARE_WAITQUEUE(waita, current); - -#ifdef DEBUG2 - printk("i810_audio: i810_read called, count = %d\n", count); -#endif - - if (dmabuf->mapped) - return -ENXIO; - if (dmabuf->enable & DAC_RUNNING) - return -ENODEV; - if (!dmabuf->read_channel) { - dmabuf->ready = 0; - dmabuf->read_channel = card->alloc_rec_pcm_channel(card); - if (!dmabuf->read_channel) { - return -EBUSY; - } - } - if (!dmabuf->ready && (ret = prog_dmabuf(state, 1))) - return ret; - if (!access_ok(VERIFY_WRITE, buffer, count)) - return -EFAULT; - ret = 0; - - pending = 0; - - add_wait_queue(&dmabuf->wait, &waita); - while (count > 0) { - set_current_state(TASK_INTERRUPTIBLE); - spin_lock_irqsave(&card->lock, flags); - if (PM_SUSPENDED(card)) { - spin_unlock_irqrestore(&card->lock, flags); - schedule(); - if (signal_pending(current)) { - if (!ret) ret = -EAGAIN; - break; - } - continue; - } - cnt = i810_get_available_read_data(state); - swptr = dmabuf->swptr; - // this is to make the copy_to_user simpler below - if(cnt > (dmabuf->dmasize - swptr)) - cnt = dmabuf->dmasize - swptr; - spin_unlock_irqrestore(&card->lock, flags); - - if (cnt > count) - cnt = count; - if (cnt <= 0) { - unsigned long tmo; - /* - * Don't let us deadlock. The ADC won't start if - * dmabuf->trigger isn't set. A call to SETTRIGGER - * could have turned it off after we set it to on - * previously. - */ - dmabuf->trigger = PCM_ENABLE_INPUT; - /* - * This does three things. Updates LVI to be correct, - * makes sure the ADC is running, and updates the - * hwptr. - */ - i810_update_lvi(state,1); - if (file->f_flags & O_NONBLOCK) { - if (!ret) ret = -EAGAIN; - goto done; - } - /* Set the timeout to how long it would take to fill - * two of our buffers. If we haven't been woke up - * by then, then we know something is wrong. - */ - tmo = (dmabuf->dmasize * HZ * 2) / (dmabuf->rate * 4); - /* There are two situations when sleep_on_timeout returns, one is when - the interrupt is serviced correctly and the process is waked up by - ISR ON TIME. Another is when timeout is expired, which means that - either interrupt is NOT serviced correctly (pending interrupt) or it - is TOO LATE for the process to be scheduled to run (scheduler latency) - which results in a (potential) buffer overrun. And worse, there is - NOTHING we can do to prevent it. */ - if (!schedule_timeout(tmo >= 2 ? tmo : 2)) { -#ifdef DEBUG - printk(KERN_ERR "i810_audio: recording schedule timeout, " - "dmasz %u fragsz %u count %i hwptr %u swptr %u\n", - dmabuf->dmasize, dmabuf->fragsize, dmabuf->count, - dmabuf->hwptr, dmabuf->swptr); -#endif - /* a buffer overrun, we delay the recovery until next time the - while loop begin and we REALLY have space to record */ - } - if (signal_pending(current)) { - ret = ret ? ret : -ERESTARTSYS; - goto done; - } - continue; - } - - if (copy_to_user(buffer, dmabuf->rawbuf + swptr, cnt)) { - if (!ret) ret = -EFAULT; - goto done; - } - - swptr = MODULOP2(swptr + cnt, dmabuf->dmasize); - - spin_lock_irqsave(&card->lock, flags); - - if (PM_SUSPENDED(card)) { - spin_unlock_irqrestore(&card->lock, flags); - continue; - } - dmabuf->swptr = swptr; - pending = dmabuf->count -= cnt; - spin_unlock_irqrestore(&card->lock, flags); - - count -= cnt; - buffer += cnt; - ret += cnt; - } - done: - pending = dmabuf->dmasize - pending; - if (dmabuf->enable || pending >= dmabuf->userfragsize) - i810_update_lvi(state, 1); - set_current_state(TASK_RUNNING); - remove_wait_queue(&dmabuf->wait, &waita); - - return ret; -} - -/* in this loop, dmabuf.count signifies the amount of data that is waiting to be dma to - the soundcard. it is drained by the dma machine and filled by this loop. */ -static ssize_t i810_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos) -{ - struct i810_state *state = (struct i810_state *)file->private_data; - struct i810_card *card=state ? state->card : NULL; - struct dmabuf *dmabuf = &state->dmabuf; - ssize_t ret; - unsigned long flags; - unsigned int swptr = 0; - int pending; - int cnt; - DECLARE_WAITQUEUE(waita, current); - -#ifdef DEBUG2 - printk("i810_audio: i810_write called, count = %d\n", count); -#endif - - if (dmabuf->mapped) - return -ENXIO; - if (dmabuf->enable & ADC_RUNNING) - return -ENODEV; - if (!dmabuf->write_channel) { - dmabuf->ready = 0; - dmabuf->write_channel = card->alloc_pcm_channel(card); - if(!dmabuf->write_channel) - return -EBUSY; - } - if (!dmabuf->ready && (ret = prog_dmabuf(state, 0))) - return ret; - if (!access_ok(VERIFY_READ, buffer, count)) - return -EFAULT; - ret = 0; - - pending = 0; - - add_wait_queue(&dmabuf->wait, &waita); - while (count > 0) { - set_current_state(TASK_INTERRUPTIBLE); - spin_lock_irqsave(&state->card->lock, flags); - if (PM_SUSPENDED(card)) { - spin_unlock_irqrestore(&card->lock, flags); - schedule(); - if (signal_pending(current)) { - if (!ret) ret = -EAGAIN; - break; - } - continue; - } - - cnt = i810_get_free_write_space(state); - swptr = dmabuf->swptr; - /* Bound the maximum size to how much we can copy to the - * dma buffer before we hit the end. If we have more to - * copy then it will get done in a second pass of this - * loop starting from the beginning of the buffer. - */ - if(cnt > (dmabuf->dmasize - swptr)) - cnt = dmabuf->dmasize - swptr; - spin_unlock_irqrestore(&state->card->lock, flags); - -#ifdef DEBUG2 - printk(KERN_INFO "i810_audio: i810_write: %d bytes available space\n", cnt); -#endif - if (cnt > count) - cnt = count; - if (cnt <= 0) { - unsigned long tmo; - // There is data waiting to be played - /* - * Force the trigger setting since we would - * deadlock with it set any other way - */ - dmabuf->trigger = PCM_ENABLE_OUTPUT; - i810_update_lvi(state,0); - if (file->f_flags & O_NONBLOCK) { - if (!ret) ret = -EAGAIN; - goto ret; - } - /* Not strictly correct but works */ - tmo = (dmabuf->dmasize * HZ * 2) / (dmabuf->rate * 4); - /* There are two situations when sleep_on_timeout returns, one is when - the interrupt is serviced correctly and the process is waked up by - ISR ON TIME. Another is when timeout is expired, which means that - either interrupt is NOT serviced correctly (pending interrupt) or it - is TOO LATE for the process to be scheduled to run (scheduler latency) - which results in a (potential) buffer underrun. And worse, there is - NOTHING we can do to prevent it. */ - if (!schedule_timeout(tmo >= 2 ? tmo : 2)) { -#ifdef DEBUG - printk(KERN_ERR "i810_audio: playback schedule timeout, " - "dmasz %u fragsz %u count %i hwptr %u swptr %u\n", - dmabuf->dmasize, dmabuf->fragsize, dmabuf->count, - dmabuf->hwptr, dmabuf->swptr); -#endif - /* a buffer underrun, we delay the recovery until next time the - while loop begin and we REALLY have data to play */ - //return ret; - } - if (signal_pending(current)) { - if (!ret) ret = -ERESTARTSYS; - goto ret; - } - continue; - } - if (copy_from_user(dmabuf->rawbuf+swptr,buffer,cnt)) { - if (!ret) ret = -EFAULT; - goto ret; - } - - swptr = MODULOP2(swptr + cnt, dmabuf->dmasize); - - spin_lock_irqsave(&state->card->lock, flags); - if (PM_SUSPENDED(card)) { - spin_unlock_irqrestore(&card->lock, flags); - continue; - } - - dmabuf->swptr = swptr; - pending = dmabuf->count += cnt; - - count -= cnt; - buffer += cnt; - ret += cnt; - spin_unlock_irqrestore(&state->card->lock, flags); - } -ret: - if (dmabuf->enable || pending >= dmabuf->userfragsize) - i810_update_lvi(state, 0); - set_current_state(TASK_RUNNING); - remove_wait_queue(&dmabuf->wait, &waita); - - return ret; -} - -/* No kernel lock - we have our own spinlock */ -static unsigned int i810_poll(struct file *file, struct poll_table_struct *wait) -{ - struct i810_state *state = (struct i810_state *)file->private_data; - struct dmabuf *dmabuf = &state->dmabuf; - unsigned long flags; - unsigned int mask = 0; - - if(!dmabuf->ready) - return 0; - poll_wait(file, &dmabuf->wait, wait); - spin_lock_irqsave(&state->card->lock, flags); - if (dmabuf->enable & ADC_RUNNING || - dmabuf->trigger & PCM_ENABLE_INPUT) { - if (i810_get_available_read_data(state) >= - (signed)dmabuf->userfragsize) - mask |= POLLIN | POLLRDNORM; - } - if (dmabuf->enable & DAC_RUNNING || - dmabuf->trigger & PCM_ENABLE_OUTPUT) { - if (i810_get_free_write_space(state) >= - (signed)dmabuf->userfragsize) - mask |= POLLOUT | POLLWRNORM; - } - spin_unlock_irqrestore(&state->card->lock, flags); - return mask; -} - -static int i810_mmap(struct file *file, struct vm_area_struct *vma) -{ - struct i810_state *state = (struct i810_state *)file->private_data; - struct dmabuf *dmabuf = &state->dmabuf; - int ret = -EINVAL; - unsigned long size; - - lock_kernel(); - if (vma->vm_flags & VM_WRITE) { - if (!dmabuf->write_channel && - (dmabuf->write_channel = - state->card->alloc_pcm_channel(state->card)) == NULL) { - ret = -EBUSY; - goto out; - } - } - if (vma->vm_flags & VM_READ) { - if (!dmabuf->read_channel && - (dmabuf->read_channel = - state->card->alloc_rec_pcm_channel(state->card)) == NULL) { - ret = -EBUSY; - goto out; - } - } - if ((ret = prog_dmabuf(state, 0)) != 0) - goto out; - - ret = -EINVAL; - if (vma->vm_pgoff != 0) - goto out; - size = vma->vm_end - vma->vm_start; - if (size > (PAGE_SIZE << dmabuf->buforder)) - goto out; - ret = -EAGAIN; - if (remap_pfn_range(vma, vma->vm_start, - virt_to_phys(dmabuf->rawbuf) >> PAGE_SHIFT, - size, vma->vm_page_prot)) - goto out; - dmabuf->mapped = 1; - dmabuf->trigger = 0; - ret = 0; -#ifdef DEBUG_MMAP - printk("i810_audio: mmap'ed %ld bytes of data space\n", size); -#endif -out: - unlock_kernel(); - return ret; -} - -static int i810_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) -{ - struct i810_state *state = (struct i810_state *)file->private_data; - struct i810_channel *c = NULL; - struct dmabuf *dmabuf = &state->dmabuf; - unsigned long flags; - audio_buf_info abinfo; - count_info cinfo; - unsigned int i_glob_cnt; - int val = 0, ret; - struct ac97_codec *codec = state->card->ac97_codec[0]; - void __user *argp = (void __user *)arg; - int __user *p = argp; - -#ifdef DEBUG - printk("i810_audio: i810_ioctl, arg=0x%x, cmd=", arg ? *p : 0); -#endif - - switch (cmd) - { - case OSS_GETVERSION: -#ifdef DEBUG - printk("OSS_GETVERSION\n"); -#endif - return put_user(SOUND_VERSION, p); - - case SNDCTL_DSP_RESET: -#ifdef DEBUG - printk("SNDCTL_DSP_RESET\n"); -#endif - spin_lock_irqsave(&state->card->lock, flags); - if (dmabuf->enable == DAC_RUNNING) { - c = dmabuf->write_channel; - __stop_dac(state); - } - if (dmabuf->enable == ADC_RUNNING) { - c = dmabuf->read_channel; - __stop_adc(state); - } - if (c != NULL) { - I810_IOWRITEB(2, state->card, c->port+OFF_CR); /* reset DMA machine */ - while ( I810_IOREADB(state->card, c->port+OFF_CR) & 2 ) - cpu_relax(); - I810_IOWRITEL((u32)state->card->chandma + - c->num*sizeof(struct i810_channel), - state->card, c->port+OFF_BDBAR); - CIV_TO_LVI(state->card, c->port, 0); - } - - spin_unlock_irqrestore(&state->card->lock, flags); - synchronize_irq(state->card->pci_dev->irq); - dmabuf->ready = 0; - dmabuf->swptr = dmabuf->hwptr = 0; - dmabuf->count = dmabuf->total_bytes = 0; - return 0; - - case SNDCTL_DSP_SYNC: -#ifdef DEBUG - printk("SNDCTL_DSP_SYNC\n"); -#endif - if (dmabuf->enable != DAC_RUNNING || file->f_flags & O_NONBLOCK) - return 0; - if((val = drain_dac(state, 1))) - return val; - dmabuf->total_bytes = 0; - return 0; - - case SNDCTL_DSP_SPEED: /* set smaple rate */ -#ifdef DEBUG - printk("SNDCTL_DSP_SPEED\n"); -#endif - if (get_user(val, p)) - return -EFAULT; - if (val >= 0) { - if (file->f_mode & FMODE_WRITE) { - if ( (state->card->ac97_status & SPDIF_ON) ) { /* S/PDIF Enabled */ - /* AD1886 only supports 48000, need to check that */ - if ( i810_valid_spdif_rate ( codec, val ) ) { - /* Set DAC rate */ - i810_set_spdif_output ( state, -1, 0 ); - stop_dac(state); - dmabuf->ready = 0; - spin_lock_irqsave(&state->card->lock, flags); - i810_set_dac_rate(state, val); - spin_unlock_irqrestore(&state->card->lock, flags); - /* Set S/PDIF transmitter rate. */ - i810_set_spdif_output ( state, AC97_EA_SPSA_3_4, val ); - if ( ! (state->card->ac97_status & SPDIF_ON) ) { - val = dmabuf->rate; - } - } else { /* Not a valid rate for S/PDIF, ignore it */ - val = dmabuf->rate; - } - } else { - stop_dac(state); - dmabuf->ready = 0; - spin_lock_irqsave(&state->card->lock, flags); - i810_set_dac_rate(state, val); - spin_unlock_irqrestore(&state->card->lock, flags); - } - } - if (file->f_mode & FMODE_READ) { - stop_adc(state); - dmabuf->ready = 0; - spin_lock_irqsave(&state->card->lock, flags); - i810_set_adc_rate(state, val); - spin_unlock_irqrestore(&state->card->lock, flags); - } - } - return put_user(dmabuf->rate, p); - - case SNDCTL_DSP_STEREO: /* set stereo or mono channel */ -#ifdef DEBUG - printk("SNDCTL_DSP_STEREO\n"); -#endif - if (dmabuf->enable & DAC_RUNNING) { - stop_dac(state); - } - if (dmabuf->enable & ADC_RUNNING) { - stop_adc(state); - } - return put_user(1, p); - - case SNDCTL_DSP_GETBLKSIZE: - if (file->f_mode & FMODE_WRITE) { - if (!dmabuf->ready && (val = prog_dmabuf(state, 0))) - return val; - } - if (file->f_mode & FMODE_READ) { - if (!dmabuf->ready && (val = prog_dmabuf(state, 1))) - return val; - } -#ifdef DEBUG - printk("SNDCTL_DSP_GETBLKSIZE %d\n", dmabuf->userfragsize); -#endif - return put_user(dmabuf->userfragsize, p); - - case SNDCTL_DSP_GETFMTS: /* Returns a mask of supported sample format*/ -#ifdef DEBUG - printk("SNDCTL_DSP_GETFMTS\n"); -#endif - return put_user(AFMT_S16_LE, p); - - case SNDCTL_DSP_SETFMT: /* Select sample format */ -#ifdef DEBUG - printk("SNDCTL_DSP_SETFMT\n"); -#endif - return put_user(AFMT_S16_LE, p); - - case SNDCTL_DSP_CHANNELS: -#ifdef DEBUG - printk("SNDCTL_DSP_CHANNELS\n"); -#endif - if (get_user(val, p)) - return -EFAULT; - - if (val > 0) { - if (dmabuf->enable & DAC_RUNNING) { - stop_dac(state); - } - if (dmabuf->enable & ADC_RUNNING) { - stop_adc(state); - } - } else { - return put_user(state->card->channels, p); - } - - /* ICH and ICH0 only support 2 channels */ - if ( state->card->pci_id == PCI_DEVICE_ID_INTEL_82801AA_5 - || state->card->pci_id == PCI_DEVICE_ID_INTEL_82801AB_5) - return put_user(2, p); - - /* Multi-channel support was added with ICH2. Bits in */ - /* Global Status and Global Control register are now */ - /* used to indicate this. */ - - i_glob_cnt = I810_IOREADL(state->card, GLOB_CNT); - - /* Current # of channels enabled */ - if ( i_glob_cnt & 0x0100000 ) - ret = 4; - else if ( i_glob_cnt & 0x0200000 ) - ret = 6; - else - ret = 2; - - switch ( val ) { - case 2: /* 2 channels is always supported */ - I810_IOWRITEL(i_glob_cnt & 0xffcfffff, - state->card, GLOB_CNT); - /* Do we need to change mixer settings???? */ - break; - case 4: /* Supported on some chipsets, better check first */ - if ( state->card->channels >= 4 ) { - I810_IOWRITEL((i_glob_cnt & 0xffcfffff) | 0x100000, - state->card, GLOB_CNT); - /* Do we need to change mixer settings??? */ - } else { - val = ret; - } - break; - case 6: /* Supported on some chipsets, better check first */ - if ( state->card->channels >= 6 ) { - I810_IOWRITEL((i_glob_cnt & 0xffcfffff) | 0x200000, - state->card, GLOB_CNT); - /* Do we need to change mixer settings??? */ - } else { - val = ret; - } - break; - default: /* nothing else is ever supported by the chipset */ - val = ret; - break; - } - - return put_user(val, p); - - case SNDCTL_DSP_POST: /* the user has sent all data and is notifying us */ - /* we update the swptr to the end of the last sg segment then return */ -#ifdef DEBUG - printk("SNDCTL_DSP_POST\n"); -#endif - if(!dmabuf->ready || (dmabuf->enable != DAC_RUNNING)) - return 0; - if((dmabuf->swptr % dmabuf->fragsize) != 0) { - val = dmabuf->fragsize - (dmabuf->swptr % dmabuf->fragsize); - dmabuf->swptr += val; - dmabuf->count += val; - } - return 0; - - case SNDCTL_DSP_SUBDIVIDE: - if (dmabuf->subdivision) - return -EINVAL; - if (get_user(val, p)) - return -EFAULT; - if (val != 1 && val != 2 && val != 4) - return -EINVAL; -#ifdef DEBUG - printk("SNDCTL_DSP_SUBDIVIDE %d\n", val); -#endif - dmabuf->subdivision = val; - dmabuf->ready = 0; - return 0; - - case SNDCTL_DSP_SETFRAGMENT: - if (get_user(val, p)) - return -EFAULT; - - dmabuf->ossfragsize = 1<<(val & 0xffff); - dmabuf->ossmaxfrags = (val >> 16) & 0xffff; - if (!dmabuf->ossfragsize || !dmabuf->ossmaxfrags) - return -EINVAL; - /* - * Bound the frag size into our allowed range of 256 - 4096 - */ - if (dmabuf->ossfragsize < 256) - dmabuf->ossfragsize = 256; - else if (dmabuf->ossfragsize > 4096) - dmabuf->ossfragsize = 4096; - /* - * The numfrags could be something reasonable, or it could - * be 0xffff meaning "Give me as much as possible". So, - * we check the numfrags * fragsize doesn't exceed our - * 64k buffer limit, nor is it less than our 8k minimum. - * If it fails either one of these checks, then adjust the - * number of fragments, not the size of them. It's OK if - * our number of fragments doesn't equal 32 or anything - * like our hardware based number now since we are using - * a different frag count for the hardware. Before we get - * into this though, bound the maxfrags to avoid overflow - * issues. A reasonable bound would be 64k / 256 since our - * maximum buffer size is 64k and our minimum frag size is - * 256. On the other end, our minimum buffer size is 8k and - * our maximum frag size is 4k, so the lower bound should - * be 2. - */ - - if(dmabuf->ossmaxfrags > 256) - dmabuf->ossmaxfrags = 256; - else if (dmabuf->ossmaxfrags < 2) - dmabuf->ossmaxfrags = 2; - - val = dmabuf->ossfragsize * dmabuf->ossmaxfrags; - while (val < 8192) { - val <<= 1; - dmabuf->ossmaxfrags <<= 1; - } - while (val > 65536) { - val >>= 1; - dmabuf->ossmaxfrags >>= 1; - } - dmabuf->ready = 0; -#ifdef DEBUG - printk("SNDCTL_DSP_SETFRAGMENT 0x%x, %d, %d\n", val, - dmabuf->ossfragsize, dmabuf->ossmaxfrags); -#endif - - return 0; - - case SNDCTL_DSP_GETOSPACE: - if (!(file->f_mode & FMODE_WRITE)) - return -EINVAL; - if (!dmabuf->ready && (val = prog_dmabuf(state, 0)) != 0) - return val; - spin_lock_irqsave(&state->card->lock, flags); - i810_update_ptr(state); - abinfo.fragsize = dmabuf->userfragsize; - abinfo.fragstotal = dmabuf->userfrags; - if (dmabuf->mapped) - abinfo.bytes = dmabuf->dmasize; - else - abinfo.bytes = i810_get_free_write_space(state); - abinfo.fragments = abinfo.bytes / dmabuf->userfragsize; - spin_unlock_irqrestore(&state->card->lock, flags); -#if defined(DEBUG) || defined(DEBUG_MMAP) - printk("SNDCTL_DSP_GETOSPACE %d, %d, %d, %d\n", abinfo.bytes, - abinfo.fragsize, abinfo.fragments, abinfo.fragstotal); -#endif - return copy_to_user(argp, &abinfo, sizeof(abinfo)) ? -EFAULT : 0; - - case SNDCTL_DSP_GETOPTR: - if (!(file->f_mode & FMODE_WRITE)) - return -EINVAL; - if (!dmabuf->ready && (val = prog_dmabuf(state, 0)) != 0) - return val; - spin_lock_irqsave(&state->card->lock, flags); - val = i810_get_free_write_space(state); - cinfo.bytes = dmabuf->total_bytes; - cinfo.ptr = dmabuf->hwptr; - cinfo.blocks = val/dmabuf->userfragsize; - if (dmabuf->mapped && (dmabuf->trigger & PCM_ENABLE_OUTPUT)) { - dmabuf->count += val; - dmabuf->swptr = (dmabuf->swptr + val) % dmabuf->dmasize; - __i810_update_lvi(state, 0); - } - spin_unlock_irqrestore(&state->card->lock, flags); -#if defined(DEBUG) || defined(DEBUG_MMAP) - printk("SNDCTL_DSP_GETOPTR %d, %d, %d, %d\n", cinfo.bytes, - cinfo.blocks, cinfo.ptr, dmabuf->count); -#endif - return copy_to_user(argp, &cinfo, sizeof(cinfo)) ? -EFAULT : 0; - - case SNDCTL_DSP_GETISPACE: - if (!(file->f_mode & FMODE_READ)) - return -EINVAL; - if (!dmabuf->ready && (val = prog_dmabuf(state, 1)) != 0) - return val; - spin_lock_irqsave(&state->card->lock, flags); - abinfo.bytes = i810_get_available_read_data(state); - abinfo.fragsize = dmabuf->userfragsize; - abinfo.fragstotal = dmabuf->userfrags; - abinfo.fragments = abinfo.bytes / dmabuf->userfragsize; - spin_unlock_irqrestore(&state->card->lock, flags); -#if defined(DEBUG) || defined(DEBUG_MMAP) - printk("SNDCTL_DSP_GETISPACE %d, %d, %d, %d\n", abinfo.bytes, - abinfo.fragsize, abinfo.fragments, abinfo.fragstotal); -#endif - return copy_to_user(argp, &abinfo, sizeof(abinfo)) ? -EFAULT : 0; - - case SNDCTL_DSP_GETIPTR: - if (!(file->f_mode & FMODE_READ)) - return -EINVAL; - if (!dmabuf->ready && (val = prog_dmabuf(state, 0)) != 0) - return val; - spin_lock_irqsave(&state->card->lock, flags); - val = i810_get_available_read_data(state); - cinfo.bytes = dmabuf->total_bytes; - cinfo.blocks = val/dmabuf->userfragsize; - cinfo.ptr = dmabuf->hwptr; - if (dmabuf->mapped && (dmabuf->trigger & PCM_ENABLE_INPUT)) { - dmabuf->count -= val; - dmabuf->swptr = (dmabuf->swptr + val) % dmabuf->dmasize; - __i810_update_lvi(state, 1); - } - spin_unlock_irqrestore(&state->card->lock, flags); -#if defined(DEBUG) || defined(DEBUG_MMAP) - printk("SNDCTL_DSP_GETIPTR %d, %d, %d, %d\n", cinfo.bytes, - cinfo.blocks, cinfo.ptr, dmabuf->count); -#endif - return copy_to_user(argp, &cinfo, sizeof(cinfo)) ? -EFAULT : 0; - - case SNDCTL_DSP_NONBLOCK: -#ifdef DEBUG - printk("SNDCTL_DSP_NONBLOCK\n"); -#endif - file->f_flags |= O_NONBLOCK; - return 0; - - case SNDCTL_DSP_GETCAPS: -#ifdef DEBUG - printk("SNDCTL_DSP_GETCAPS\n"); -#endif - return put_user(DSP_CAP_REALTIME|DSP_CAP_TRIGGER|DSP_CAP_MMAP|DSP_CAP_BIND, - p); - - case SNDCTL_DSP_GETTRIGGER: - val = 0; -#ifdef DEBUG - printk("SNDCTL_DSP_GETTRIGGER 0x%x\n", dmabuf->trigger); -#endif - return put_user(dmabuf->trigger, p); - - case SNDCTL_DSP_SETTRIGGER: - if (get_user(val, p)) - return -EFAULT; -#if defined(DEBUG) || defined(DEBUG_MMAP) - printk("SNDCTL_DSP_SETTRIGGER 0x%x\n", val); -#endif - /* silently ignore invalid PCM_ENABLE_xxx bits, - * like the other drivers do - */ - if (!(file->f_mode & FMODE_READ )) - val &= ~PCM_ENABLE_INPUT; - if (!(file->f_mode & FMODE_WRITE )) - val &= ~PCM_ENABLE_OUTPUT; - if((file->f_mode & FMODE_READ) && !(val & PCM_ENABLE_INPUT) && dmabuf->enable == ADC_RUNNING) { - stop_adc(state); - } - if((file->f_mode & FMODE_WRITE) && !(val & PCM_ENABLE_OUTPUT) && dmabuf->enable == DAC_RUNNING) { - stop_dac(state); - } - dmabuf->trigger = val; - if((val & PCM_ENABLE_OUTPUT) && !(dmabuf->enable & DAC_RUNNING)) { - if (!dmabuf->write_channel) { - dmabuf->ready = 0; - dmabuf->write_channel = state->card->alloc_pcm_channel(state->card); - if (!dmabuf->write_channel) - return -EBUSY; - } - if (!dmabuf->ready && (ret = prog_dmabuf(state, 0))) - return ret; - if (dmabuf->mapped) { - spin_lock_irqsave(&state->card->lock, flags); - i810_update_ptr(state); - dmabuf->count = 0; - dmabuf->swptr = dmabuf->hwptr; - dmabuf->count = i810_get_free_write_space(state); - dmabuf->swptr = (dmabuf->swptr + dmabuf->count) % dmabuf->dmasize; - spin_unlock_irqrestore(&state->card->lock, flags); - } - i810_update_lvi(state, 0); - start_dac(state); - } - if((val & PCM_ENABLE_INPUT) && !(dmabuf->enable & ADC_RUNNING)) { - if (!dmabuf->read_channel) { - dmabuf->ready = 0; - dmabuf->read_channel = state->card->alloc_rec_pcm_channel(state->card); - if (!dmabuf->read_channel) - return -EBUSY; - } - if (!dmabuf->ready && (ret = prog_dmabuf(state, 1))) - return ret; - if (dmabuf->mapped) { - spin_lock_irqsave(&state->card->lock, flags); - i810_update_ptr(state); - dmabuf->swptr = dmabuf->hwptr; - dmabuf->count = 0; - spin_unlock_irqrestore(&state->card->lock, flags); - } - i810_update_lvi(state, 1); - start_adc(state); - } - return 0; - - case SNDCTL_DSP_SETDUPLEX: -#ifdef DEBUG - printk("SNDCTL_DSP_SETDUPLEX\n"); -#endif - return -EINVAL; - - case SNDCTL_DSP_GETODELAY: - if (!(file->f_mode & FMODE_WRITE)) - return -EINVAL; - spin_lock_irqsave(&state->card->lock, flags); - i810_update_ptr(state); - val = dmabuf->count; - spin_unlock_irqrestore(&state->card->lock, flags); -#ifdef DEBUG - printk("SNDCTL_DSP_GETODELAY %d\n", dmabuf->count); -#endif - return put_user(val, p); - - case SOUND_PCM_READ_RATE: -#ifdef DEBUG - printk("SOUND_PCM_READ_RATE %d\n", dmabuf->rate); -#endif - return put_user(dmabuf->rate, p); - - case SOUND_PCM_READ_CHANNELS: -#ifdef DEBUG - printk("SOUND_PCM_READ_CHANNELS\n"); -#endif - return put_user(2, p); - - case SOUND_PCM_READ_BITS: -#ifdef DEBUG - printk("SOUND_PCM_READ_BITS\n"); -#endif - return put_user(AFMT_S16_LE, p); - - case SNDCTL_DSP_SETSPDIF: /* Set S/PDIF Control register */ -#ifdef DEBUG - printk("SNDCTL_DSP_SETSPDIF\n"); -#endif - if (get_user(val, p)) - return -EFAULT; - - /* Check to make sure the codec supports S/PDIF transmitter */ - - if((state->card->ac97_features & 4)) { - /* mask out the transmitter speed bits so the user can't set them */ - val &= ~0x3000; - - /* Add the current transmitter speed bits to the passed value */ - ret = i810_ac97_get(codec, AC97_SPDIF_CONTROL); - val |= (ret & 0x3000); - - i810_ac97_set(codec, AC97_SPDIF_CONTROL, val); - if(i810_ac97_get(codec, AC97_SPDIF_CONTROL) != val ) { - printk(KERN_ERR "i810_audio: Unable to set S/PDIF configuration to 0x%04x.\n", val); - return -EFAULT; - } - } -#ifdef DEBUG - else - printk(KERN_WARNING "i810_audio: S/PDIF transmitter not avalible.\n"); -#endif - return put_user(val, p); - - case SNDCTL_DSP_GETSPDIF: /* Get S/PDIF Control register */ -#ifdef DEBUG - printk("SNDCTL_DSP_GETSPDIF\n"); -#endif - if (get_user(val, p)) - return -EFAULT; - - /* Check to make sure the codec supports S/PDIF transmitter */ - - if(!(state->card->ac97_features & 4)) { -#ifdef DEBUG - printk(KERN_WARNING "i810_audio: S/PDIF transmitter not avalible.\n"); -#endif - val = 0; - } else { - val = i810_ac97_get(codec, AC97_SPDIF_CONTROL); - } - //return put_user((val & 0xcfff), p); - return put_user(val, p); - - case SNDCTL_DSP_GETCHANNELMASK: -#ifdef DEBUG - printk("SNDCTL_DSP_GETCHANNELMASK\n"); -#endif - if (get_user(val, p)) - return -EFAULT; - - /* Based on AC'97 DAC support, not ICH hardware */ - val = DSP_BIND_FRONT; - if ( state->card->ac97_features & 0x0004 ) - val |= DSP_BIND_SPDIF; - - if ( state->card->ac97_features & 0x0080 ) - val |= DSP_BIND_SURR; - if ( state->card->ac97_features & 0x0140 ) - val |= DSP_BIND_CENTER_LFE; - - return put_user(val, p); - - case SNDCTL_DSP_BIND_CHANNEL: -#ifdef DEBUG - printk("SNDCTL_DSP_BIND_CHANNEL\n"); -#endif - if (get_user(val, p)) - return -EFAULT; - if ( val == DSP_BIND_QUERY ) { - val = DSP_BIND_FRONT; /* Always report this as being enabled */ - if ( state->card->ac97_status & SPDIF_ON ) - val |= DSP_BIND_SPDIF; - else { - if ( state->card->ac97_status & SURR_ON ) - val |= DSP_BIND_SURR; - if ( state->card->ac97_status & CENTER_LFE_ON ) - val |= DSP_BIND_CENTER_LFE; - } - } else { /* Not a query, set it */ - if (!(file->f_mode & FMODE_WRITE)) - return -EINVAL; - if ( dmabuf->enable == DAC_RUNNING ) { - stop_dac(state); - } - if ( val & DSP_BIND_SPDIF ) { /* Turn on SPDIF */ - /* Ok, this should probably define what slots - * to use. For now, we'll only set it to the - * defaults: - * - * non multichannel codec maps to slots 3&4 - * 2 channel codec maps to slots 7&8 - * 4 channel codec maps to slots 6&9 - * 6 channel codec maps to slots 10&11 - * - * there should be some way for the app to - * select the slot assignment. - */ - - i810_set_spdif_output ( state, AC97_EA_SPSA_3_4, dmabuf->rate ); - if ( !(state->card->ac97_status & SPDIF_ON) ) - val &= ~DSP_BIND_SPDIF; - } else { - int mask; - int channels; - - /* Turn off S/PDIF if it was on */ - if ( state->card->ac97_status & SPDIF_ON ) - i810_set_spdif_output ( state, -1, 0 ); - - mask = val & (DSP_BIND_FRONT | DSP_BIND_SURR | DSP_BIND_CENTER_LFE); - switch (mask) { - case DSP_BIND_FRONT: - channels = 2; - break; - case DSP_BIND_FRONT|DSP_BIND_SURR: - channels = 4; - break; - case DSP_BIND_FRONT|DSP_BIND_SURR|DSP_BIND_CENTER_LFE: - channels = 6; - break; - default: - val = DSP_BIND_FRONT; - channels = 2; - break; - } - i810_set_dac_channels ( state, channels ); - - /* check that they really got turned on */ - if (!(state->card->ac97_status & SURR_ON)) - val &= ~DSP_BIND_SURR; - if (!(state->card->ac97_status & CENTER_LFE_ON)) - val &= ~DSP_BIND_CENTER_LFE; - } - } - return put_user(val, p); - - case SNDCTL_DSP_MAPINBUF: - case SNDCTL_DSP_MAPOUTBUF: - case SNDCTL_DSP_SETSYNCRO: - case SOUND_PCM_WRITE_FILTER: - case SOUND_PCM_READ_FILTER: -#ifdef DEBUG - printk("SNDCTL_* -EINVAL\n"); -#endif - return -EINVAL; - } - return -EINVAL; -} - -static int i810_open(struct inode *inode, struct file *file) -{ - int i = 0; - struct i810_card *card = devs; - struct i810_state *state = NULL; - struct dmabuf *dmabuf = NULL; - - /* find an avaiable virtual channel (instance of /dev/dsp) */ - while (card != NULL) { - /* - * If we are initializing and then fail, card could go - * away unuexpectedly while we are in the for() loop. - * So, check for card on each iteration before we check - * for card->initializing to avoid a possible oops. - * This usually only matters for times when the driver is - * autoloaded by kmod. - */ - for (i = 0; i < 50 && card && card->initializing; i++) { - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(HZ/20); - } - for (i = 0; i < NR_HW_CH && card && !card->initializing; i++) { - if (card->states[i] == NULL) { - state = card->states[i] = (struct i810_state *) - kzalloc(sizeof(struct i810_state), GFP_KERNEL); - if (state == NULL) - return -ENOMEM; - dmabuf = &state->dmabuf; - goto found_virt; - } - } - card = card->next; - } - /* no more virtual channel avaiable */ - if (!state) - return -ENODEV; - -found_virt: - /* initialize the virtual channel */ - state->virt = i; - state->card = card; - state->magic = I810_STATE_MAGIC; - init_waitqueue_head(&dmabuf->wait); - mutex_init(&state->open_mutex); - file->private_data = state; - dmabuf->trigger = 0; - - /* allocate hardware channels */ - if(file->f_mode & FMODE_READ) { - if((dmabuf->read_channel = card->alloc_rec_pcm_channel(card)) == NULL) { - kfree (card->states[i]); - card->states[i] = NULL; - return -EBUSY; - } - dmabuf->trigger |= PCM_ENABLE_INPUT; - i810_set_adc_rate(state, 8000); - } - if(file->f_mode & FMODE_WRITE) { - if((dmabuf->write_channel = card->alloc_pcm_channel(card)) == NULL) { - /* make sure we free the record channel allocated above */ - if(file->f_mode & FMODE_READ) - card->free_pcm_channel(card,dmabuf->read_channel->num); - kfree (card->states[i]); - card->states[i] = NULL; - return -EBUSY; - } - /* Initialize to 8kHz? What if we don't support 8kHz? */ - /* Let's change this to check for S/PDIF stuff */ - - dmabuf->trigger |= PCM_ENABLE_OUTPUT; - if ( spdif_locked ) { - i810_set_dac_rate(state, spdif_locked); - i810_set_spdif_output(state, AC97_EA_SPSA_3_4, spdif_locked); - } else { - i810_set_dac_rate(state, 8000); - /* Put the ACLink in 2 channel mode by default */ - i = I810_IOREADL(card, GLOB_CNT); - I810_IOWRITEL(i & 0xffcfffff, card, GLOB_CNT); - } - } - - /* set default sample format. According to OSS Programmer's Guide /dev/dsp - should be default to unsigned 8-bits, mono, with sample rate 8kHz and - /dev/dspW will accept 16-bits sample, but we don't support those so we - set it immediately to stereo and 16bit, which is all we do support */ - dmabuf->fmt |= I810_FMT_16BIT | I810_FMT_STEREO; - dmabuf->ossfragsize = 0; - dmabuf->ossmaxfrags = 0; - dmabuf->subdivision = 0; - - state->open_mode |= file->f_mode & (FMODE_READ | FMODE_WRITE); - - return nonseekable_open(inode, file); -} - -static int i810_release(struct inode *inode, struct file *file) -{ - struct i810_state *state = (struct i810_state *)file->private_data; - struct i810_card *card = state->card; - struct dmabuf *dmabuf = &state->dmabuf; - unsigned long flags; - - lock_kernel(); - - /* stop DMA state machine and free DMA buffers/channels */ - if(dmabuf->trigger & PCM_ENABLE_OUTPUT) { - drain_dac(state, 0); - } - if(dmabuf->trigger & PCM_ENABLE_INPUT) { - stop_adc(state); - } - spin_lock_irqsave(&card->lock, flags); - dealloc_dmabuf(state); - if (file->f_mode & FMODE_WRITE) { - state->card->free_pcm_channel(state->card, dmabuf->write_channel->num); - } - if (file->f_mode & FMODE_READ) { - state->card->free_pcm_channel(state->card, dmabuf->read_channel->num); - } - - state->card->states[state->virt] = NULL; - kfree(state); - spin_unlock_irqrestore(&card->lock, flags); - unlock_kernel(); - - return 0; -} - -static /*const*/ struct file_operations i810_audio_fops = { - .owner = THIS_MODULE, - .llseek = no_llseek, - .read = i810_read, - .write = i810_write, - .poll = i810_poll, - .ioctl = i810_ioctl, - .mmap = i810_mmap, - .open = i810_open, - .release = i810_release, -}; - -/* Write AC97 codec registers */ - -static u16 i810_ac97_get_mmio(struct ac97_codec *dev, u8 reg) -{ - struct i810_card *card = dev->private_data; - int count = 100; - u16 reg_set = IO_REG_OFF(dev) | (reg&0x7f); - - while(count-- && (readb(card->iobase_mmio + CAS) & 1)) - udelay(1); - -#ifdef DEBUG_MMIO - { - u16 ans = readw(card->ac97base_mmio + reg_set); - printk(KERN_DEBUG "i810_audio: ac97_get_mmio(%d) -> 0x%04X\n", ((int) reg_set) & 0xffff, (u32) ans); - return ans; - } -#else - return readw(card->ac97base_mmio + reg_set); -#endif -} - -static u16 i810_ac97_get_io(struct ac97_codec *dev, u8 reg) -{ - struct i810_card *card = dev->private_data; - int count = 100; - u16 reg_set = IO_REG_OFF(dev) | (reg&0x7f); - - while(count-- && (I810_IOREADB(card, CAS) & 1)) - udelay(1); - - return inw(card->ac97base + reg_set); -} - -static void i810_ac97_set_mmio(struct ac97_codec *dev, u8 reg, u16 data) -{ - struct i810_card *card = dev->private_data; - int count = 100; - u16 reg_set = IO_REG_OFF(dev) | (reg&0x7f); - - while(count-- && (readb(card->iobase_mmio + CAS) & 1)) - udelay(1); - - writew(data, card->ac97base_mmio + reg_set); - -#ifdef DEBUG_MMIO - printk(KERN_DEBUG "i810_audio: ac97_set_mmio(0x%04X, %d)\n", (u32) data, ((int) reg_set) & 0xffff); -#endif -} - -static void i810_ac97_set_io(struct ac97_codec *dev, u8 reg, u16 data) -{ - struct i810_card *card = dev->private_data; - int count = 100; - u16 reg_set = IO_REG_OFF(dev) | (reg&0x7f); - - while(count-- && (I810_IOREADB(card, CAS) & 1)) - udelay(1); - - outw(data, card->ac97base + reg_set); -} - -static u16 i810_ac97_get(struct ac97_codec *dev, u8 reg) -{ - struct i810_card *card = dev->private_data; - u16 ret; - - spin_lock(&card->ac97_lock); - if (card->use_mmio) { - ret = i810_ac97_get_mmio(dev, reg); - } - else { - ret = i810_ac97_get_io(dev, reg); - } - spin_unlock(&card->ac97_lock); - - return ret; -} - -static void i810_ac97_set(struct ac97_codec *dev, u8 reg, u16 data) -{ - struct i810_card *card = dev->private_data; - - spin_lock(&card->ac97_lock); - if (card->use_mmio) { - i810_ac97_set_mmio(dev, reg, data); - } - else { - i810_ac97_set_io(dev, reg, data); - } - spin_unlock(&card->ac97_lock); -} - - -/* OSS /dev/mixer file operation methods */ - -static int i810_open_mixdev(struct inode *inode, struct file *file) -{ - int i; - int minor = iminor(inode); - struct i810_card *card = devs; - - for (card = devs; card != NULL; card = card->next) { - /* - * If we are initializing and then fail, card could go - * away unuexpectedly while we are in the for() loop. - * So, check for card on each iteration before we check - * for card->initializing to avoid a possible oops. - * This usually only matters for times when the driver is - * autoloaded by kmod. - */ - for (i = 0; i < 50 && card && card->initializing; i++) { - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(HZ/20); - } - for (i = 0; i < NR_AC97 && card && !card->initializing; i++) - if (card->ac97_codec[i] != NULL && - card->ac97_codec[i]->dev_mixer == minor) { - file->private_data = card->ac97_codec[i]; - return nonseekable_open(inode, file); - } - } - return -ENODEV; -} - -static int i810_ioctl_mixdev(struct inode *inode, struct file *file, unsigned int cmd, - unsigned long arg) -{ - struct ac97_codec *codec = (struct ac97_codec *)file->private_data; - - return codec->mixer_ioctl(codec, cmd, arg); -} - -static /*const*/ struct file_operations i810_mixer_fops = { - .owner = THIS_MODULE, - .llseek = no_llseek, - .ioctl = i810_ioctl_mixdev, - .open = i810_open_mixdev, -}; - -/* AC97 codec initialisation. These small functions exist so we don't - duplicate code between module init and apm resume */ - -static inline int i810_ac97_exists(struct i810_card *card, int ac97_number) -{ - u32 reg = I810_IOREADL(card, GLOB_STA); - switch (ac97_number) { - case 0: - return reg & (1<<8); - case 1: - return reg & (1<<9); - case 2: - return reg & (1<<28); - } - return 0; -} - -static inline int i810_ac97_enable_variable_rate(struct ac97_codec *codec) -{ - i810_ac97_set(codec, AC97_EXTENDED_STATUS, 9); - i810_ac97_set(codec,AC97_EXTENDED_STATUS, - i810_ac97_get(codec, AC97_EXTENDED_STATUS)|0xE800); - - return (i810_ac97_get(codec, AC97_EXTENDED_STATUS)&1); -} - - -static int i810_ac97_probe_and_powerup(struct i810_card *card,struct ac97_codec *codec) -{ - /* Returns 0 on failure */ - int i; - - if (ac97_probe_codec(codec) == 0) return 0; - - /* power it all up */ - i810_ac97_set(codec, AC97_POWER_CONTROL, - i810_ac97_get(codec, AC97_POWER_CONTROL) & ~0x7f00); - - /* wait for analog ready */ - for (i=100; i && ((i810_ac97_get(codec, AC97_POWER_CONTROL) & 0xf) != 0xf); i--) - { - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(HZ/20); - } - return i; -} - -static int is_new_ich(u16 pci_id) -{ - switch (pci_id) { - case PCI_DEVICE_ID_INTEL_82801DB_5: - case PCI_DEVICE_ID_INTEL_82801EB_5: - case PCI_DEVICE_ID_INTEL_ESB_5: - case PCI_DEVICE_ID_INTEL_ICH6_18: - return 1; - default: - break; - } - - return 0; -} - -static inline int ich_use_mmio(struct i810_card *card) -{ - return is_new_ich(card->pci_id) && card->use_mmio; -} - -/** - * i810_ac97_power_up_bus - bring up AC97 link - * @card : ICH audio device to power up - * - * Bring up the ACLink AC97 codec bus - */ - -static int i810_ac97_power_up_bus(struct i810_card *card) -{ - u32 reg = I810_IOREADL(card, GLOB_CNT); - int i; - int primary_codec_id = 0; - - if((reg&2)==0) /* Cold required */ - reg|=2; - else - reg|=4; /* Warm */ - - reg&=~8; /* ACLink on */ - - /* At this point we deassert AC_RESET # */ - I810_IOWRITEL(reg , card, GLOB_CNT); - - /* We must now allow time for the Codec initialisation. - 600mS is the specified time */ - - for(i=0;i<10;i++) - { - if((I810_IOREADL(card, GLOB_CNT)&4)==0) - break; - - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(HZ/20); - } - if(i==10) - { - printk(KERN_ERR "i810_audio: AC'97 reset failed.\n"); - return 0; - } - - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(HZ/2); - - /* - * See if the primary codec comes ready. This must happen - * before we start doing DMA stuff - */ - /* see i810_ac97_init for the next 10 lines (jsaw) */ - if (card->use_mmio) - readw(card->ac97base_mmio); - else - inw(card->ac97base); - if (ich_use_mmio(card)) { - primary_codec_id = (int) readl(card->iobase_mmio + SDM) & 0x3; - printk(KERN_INFO "i810_audio: Primary codec has ID %d\n", - primary_codec_id); - } - - if(! i810_ac97_exists(card, primary_codec_id)) - { - printk(KERN_INFO "i810_audio: Codec not ready.. wait.. "); - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(HZ); /* actually 600mS by the spec */ - - if(i810_ac97_exists(card, primary_codec_id)) - printk("OK\n"); - else - printk("no response.\n"); - } - if (card->use_mmio) - readw(card->ac97base_mmio); - else - inw(card->ac97base); - return 1; -} - -static int __devinit i810_ac97_init(struct i810_card *card) -{ - int num_ac97 = 0; - int ac97_id; - int total_channels = 0; - int nr_ac97_max = card_cap[card->pci_id_internal].nr_ac97; - struct ac97_codec *codec; - u16 eid; - u32 reg; - - if(!i810_ac97_power_up_bus(card)) return 0; - - /* Number of channels supported */ - /* What about the codec? Just because the ICH supports */ - /* multiple channels doesn't mean the codec does. */ - /* we'll have to modify this in the codec section below */ - /* to reflect what the codec has. */ - /* ICH and ICH0 only support 2 channels so don't bother */ - /* to check.... */ - - card->channels = 2; - reg = I810_IOREADL(card, GLOB_STA); - if ( reg & 0x0200000 ) - card->channels = 6; - else if ( reg & 0x0100000 ) - card->channels = 4; - printk(KERN_INFO "i810_audio: Audio Controller supports %d channels.\n", card->channels); - printk(KERN_INFO "i810_audio: Defaulting to base 2 channel mode.\n"); - reg = I810_IOREADL(card, GLOB_CNT); - I810_IOWRITEL(reg & 0xffcfffff, card, GLOB_CNT); - - for (num_ac97 = 0; num_ac97 < NR_AC97; num_ac97++) - card->ac97_codec[num_ac97] = NULL; - - /*@FIXME I don't know, if I'm playing to safe here... (jsaw) */ - if ((nr_ac97_max > 2) && !card->use_mmio) nr_ac97_max = 2; - - for (num_ac97 = 0; num_ac97 < nr_ac97_max; num_ac97++) { - /* codec reset */ - printk(KERN_INFO "i810_audio: Resetting connection %d\n", num_ac97); - if (card->use_mmio) - readw(card->ac97base_mmio + 0x80*num_ac97); - else - inw(card->ac97base + 0x80*num_ac97); - - /* If we have the SDATA_IN Map Register, as on ICH4, we - do not loop thru all possible codec IDs but thru all - possible IO channels. Bit 0:1 of SDM then holds the - last codec ID spoken to. - */ - if (ich_use_mmio(card)) { - ac97_id = (int) readl(card->iobase_mmio + SDM) & 0x3; - printk(KERN_INFO "i810_audio: Connection %d with codec id %d\n", - num_ac97, ac97_id); - } - else { - ac97_id = num_ac97; - } - - /* The ICH programmer's reference says you should */ - /* check the ready status before probing. So we chk */ - /* What do we do if it's not ready? Wait and try */ - /* again, or abort? */ - if (!i810_ac97_exists(card, ac97_id)) { - if(num_ac97 == 0) - printk(KERN_ERR "i810_audio: Primary codec not ready.\n"); - } - - if ((codec = ac97_alloc_codec()) == NULL) - return -ENOMEM; - - /* initialize some basic codec information, other fields will be filled - in ac97_probe_codec */ - codec->private_data = card; - codec->id = ac97_id; - card->ac97_id_map[ac97_id] = num_ac97 * 0x80; - - if (card->use_mmio) { - codec->codec_read = i810_ac97_get_mmio; - codec->codec_write = i810_ac97_set_mmio; - } - else { - codec->codec_read = i810_ac97_get_io; - codec->codec_write = i810_ac97_set_io; - } - - if(!i810_ac97_probe_and_powerup(card,codec)) { - printk(KERN_ERR "i810_audio: timed out waiting for codec %d analog ready.\n", ac97_id); - ac97_release_codec(codec); - break; /* it didn't work */ - } - /* Store state information about S/PDIF transmitter */ - card->ac97_status = 0; - - /* Don't attempt to get eid until powerup is complete */ - eid = i810_ac97_get(codec, AC97_EXTENDED_ID); - - if(eid==0xFFFF) - { - printk(KERN_WARNING "i810_audio: no codec attached ?\n"); - ac97_release_codec(codec); - break; - } - - /* Check for an AC97 1.0 soft modem (ID1) */ - - if(codec->modem) - { - printk(KERN_WARNING "i810_audio: codec %d is a softmodem - skipping.\n", ac97_id); - ac97_release_codec(codec); - continue; - } - - card->ac97_features = eid; - - /* Now check the codec for useful features to make up for - the dumbness of the 810 hardware engine */ - - if(!(eid&0x0001)) - printk(KERN_WARNING "i810_audio: only 48Khz playback available.\n"); - else - { - if(!i810_ac97_enable_variable_rate(codec)) { - printk(KERN_WARNING "i810_audio: Codec refused to allow VRA, using 48Khz only.\n"); - card->ac97_features&=~1; - } - } - - /* Turn on the amplifier */ - - codec->codec_write(codec, AC97_POWER_CONTROL, - codec->codec_read(codec, AC97_POWER_CONTROL) & ~0x8000); - - /* Determine how many channels the codec(s) support */ - /* - The primary codec always supports 2 */ - /* - If the codec supports AMAP, surround DACs will */ - /* automaticlly get assigned to slots. */ - /* * Check for surround DACs and increment if */ - /* found. */ - /* - Else check if the codec is revision 2.2 */ - /* * If surround DACs exist, assign them to slots */ - /* and increment channel count. */ - - /* All of this only applies to ICH2 and above. ICH */ - /* and ICH0 only support 2 channels. ICH2 will only */ - /* support multiple codecs in a "split audio" config. */ - /* as described above. */ - - /* TODO: Remove all the debugging messages! */ - - if((eid & 0xc000) == 0) /* primary codec */ - total_channels += 2; - - if(eid & 0x200) { /* GOOD, AMAP support */ - if (eid & 0x0080) /* L/R Surround channels */ - total_channels += 2; - if (eid & 0x0140) /* LFE and Center channels */ - total_channels += 2; - printk("i810_audio: AC'97 codec %d supports AMAP, total channels = %d\n", ac97_id, total_channels); - } else if (eid & 0x0400) { /* this only works on 2.2 compliant codecs */ - eid &= 0xffcf; - if((eid & 0xc000) != 0) { - switch ( total_channels ) { - case 2: - /* Set dsa1, dsa0 to 01 */ - eid |= 0x0010; - break; - case 4: - /* Set dsa1, dsa0 to 10 */ - eid |= 0x0020; - break; - case 6: - /* Set dsa1, dsa0 to 11 */ - eid |= 0x0030; - break; - } - total_channels += 2; - } - i810_ac97_set(codec, AC97_EXTENDED_ID, eid); - eid = i810_ac97_get(codec, AC97_EXTENDED_ID); - printk("i810_audio: AC'97 codec %d, new EID value = 0x%04x\n", ac97_id, eid); - if (eid & 0x0080) /* L/R Surround channels */ - total_channels += 2; - if (eid & 0x0140) /* LFE and Center channels */ - total_channels += 2; - printk("i810_audio: AC'97 codec %d, DAC map configured, total channels = %d\n", ac97_id, total_channels); - } else { - printk("i810_audio: AC'97 codec %d Unable to map surround DAC's (or DAC's not present), total channels = %d\n", ac97_id, total_channels); - } - - if ((codec->dev_mixer = register_sound_mixer(&i810_mixer_fops, -1)) < 0) { - printk(KERN_ERR "i810_audio: couldn't register mixer!\n"); - ac97_release_codec(codec); - break; - } - - card->ac97_codec[num_ac97] = codec; - } - - /* tune up the primary codec */ - ac97_tune_hardware(card->pci_dev, ac97_quirks, ac97_quirk); - - /* pick the minimum of channels supported by ICHx or codec(s) */ - card->channels = (card->channels > total_channels)?total_channels:card->channels; - - return num_ac97; -} - -static void __devinit i810_configure_clocking (void) -{ - struct i810_card *card; - struct i810_state *state; - struct dmabuf *dmabuf; - unsigned int i, offset, new_offset; - unsigned long flags; - - card = devs; - /* We could try to set the clocking for multiple cards, but can you even have - * more than one i810 in a machine? Besides, clocking is global, so unless - * someone actually thinks more than one i810 in a machine is possible and - * decides to rewrite that little bit, setting the rate for more than one card - * is a waste of time. - */ - if(card != NULL) { - state = card->states[0] = (struct i810_state *) - kzalloc(sizeof(struct i810_state), GFP_KERNEL); - if (state == NULL) - return; - dmabuf = &state->dmabuf; - - dmabuf->write_channel = card->alloc_pcm_channel(card); - state->virt = 0; - state->card = card; - state->magic = I810_STATE_MAGIC; - init_waitqueue_head(&dmabuf->wait); - mutex_init(&state->open_mutex); - dmabuf->fmt = I810_FMT_STEREO | I810_FMT_16BIT; - dmabuf->trigger = PCM_ENABLE_OUTPUT; - i810_set_spdif_output(state, -1, 0); - i810_set_dac_channels(state, 2); - i810_set_dac_rate(state, 48000); - if(prog_dmabuf(state, 0) != 0) { - goto config_out_nodmabuf; - } - if(dmabuf->dmasize < 16384) { - goto config_out; - } - dmabuf->count = dmabuf->dmasize; - CIV_TO_LVI(card, dmabuf->write_channel->port, -1); - local_irq_save(flags); - start_dac(state); - offset = i810_get_dma_addr(state, 0); - mdelay(50); - new_offset = i810_get_dma_addr(state, 0); - stop_dac(state); - local_irq_restore(flags); - i = new_offset - offset; -#ifdef DEBUG_INTERRUPTS - printk("i810_audio: %d bytes in 50 milliseconds\n", i); -#endif - if(i == 0) - goto config_out; - i = i / 4 * 20; - if (i > 48500 || i < 47500) { - clocking = clocking * clocking / i; - printk("i810_audio: setting clocking to %d\n", clocking); - } -config_out: - dealloc_dmabuf(state); -config_out_nodmabuf: - state->card->free_pcm_channel(state->card,state->dmabuf.write_channel->num); - kfree(state); - card->states[0] = NULL; - } -} - -/* install the driver, we do not allocate hardware channel nor DMA buffer now, they are defered - until "ACCESS" time (in prog_dmabuf called by open/read/write/ioctl/mmap) */ - -static int __devinit i810_probe(struct pci_dev *pci_dev, const struct pci_device_id *pci_id) -{ - struct i810_card *card; - - if (pci_enable_device(pci_dev)) - return -EIO; - - if (pci_set_dma_mask(pci_dev, I810_DMA_MASK)) { - printk(KERN_ERR "i810_audio: architecture does not support" - " 32bit PCI busmaster DMA\n"); - return -ENODEV; - } - - if ((card = kzalloc(sizeof(struct i810_card), GFP_KERNEL)) == NULL) { - printk(KERN_ERR "i810_audio: out of memory\n"); - return -ENOMEM; - } - - card->initializing = 1; - card->pci_dev = pci_dev; - card->pci_id = pci_id->device; - card->ac97base = pci_resource_start (pci_dev, 0); - card->iobase = pci_resource_start (pci_dev, 1); - - if (!(card->ac97base) || !(card->iobase)) { - card->ac97base = 0; - card->iobase = 0; - } - - /* if chipset could have mmio capability, check it */ - if (card_cap[pci_id->driver_data].flags & CAP_MMIO) { - card->ac97base_mmio_phys = pci_resource_start (pci_dev, 2); - card->iobase_mmio_phys = pci_resource_start (pci_dev, 3); - - if ((card->ac97base_mmio_phys) && (card->iobase_mmio_phys)) { - card->use_mmio = 1; - } - else { - card->ac97base_mmio_phys = 0; - card->iobase_mmio_phys = 0; - } - } - - if (!(card->use_mmio) && (!(card->iobase) || !(card->ac97base))) { - printk(KERN_ERR "i810_audio: No I/O resources available.\n"); - goto out_mem; - } - - card->irq = pci_dev->irq; - card->next = devs; - card->magic = I810_CARD_MAGIC; -#ifdef CONFIG_PM - card->pm_suspended=0; -#endif - spin_lock_init(&card->lock); - spin_lock_init(&card->ac97_lock); - devs = card; - - pci_set_master(pci_dev); - - printk(KERN_INFO "i810: %s found at IO 0x%04lx and 0x%04lx, " - "MEM 0x%04lx and 0x%04lx, IRQ %d\n", - card_names[pci_id->driver_data], - card->iobase, card->ac97base, - card->ac97base_mmio_phys, card->iobase_mmio_phys, - card->irq); - - card->alloc_pcm_channel = i810_alloc_pcm_channel; - card->alloc_rec_pcm_channel = i810_alloc_rec_pcm_channel; - card->alloc_rec_mic_channel = i810_alloc_rec_mic_channel; - card->free_pcm_channel = i810_free_pcm_channel; - - if ((card->channel = pci_alloc_consistent(pci_dev, - sizeof(struct i810_channel)*NR_HW_CH, &card->chandma)) == NULL) { - printk(KERN_ERR "i810: cannot allocate channel DMA memory\n"); - goto out_mem; - } - - { /* We may dispose of this altogether some time soon, so... */ - struct i810_channel *cp = card->channel; - - cp[0].offset = 0; - cp[0].port = 0x00; - cp[0].num = 0; - cp[1].offset = 0; - cp[1].port = 0x10; - cp[1].num = 1; - cp[2].offset = 0; - cp[2].port = 0x20; - cp[2].num = 2; - } - - /* claim our iospace and irq */ - if (!request_region(card->iobase, 64, card_names[pci_id->driver_data])) { - printk(KERN_ERR "i810_audio: unable to allocate region %lx\n", card->iobase); - goto out_region1; - } - if (!request_region(card->ac97base, 256, card_names[pci_id->driver_data])) { - printk(KERN_ERR "i810_audio: unable to allocate region %lx\n", card->ac97base); - goto out_region2; - } - - if (card->use_mmio) { - if (request_mem_region(card->ac97base_mmio_phys, 512, "ich_audio MMBAR")) { - if ((card->ac97base_mmio = ioremap(card->ac97base_mmio_phys, 512))) { /*@FIXME can ioremap fail? don't know (jsaw) */ - if (request_mem_region(card->iobase_mmio_phys, 256, "ich_audio MBBAR")) { - if ((card->iobase_mmio = ioremap(card->iobase_mmio_phys, 256))) { - printk(KERN_INFO "i810: %s mmio at 0x%04lx and 0x%04lx\n", - card_names[pci_id->driver_data], - (unsigned long) card->ac97base_mmio, - (unsigned long) card->iobase_mmio); - } - else { - iounmap(card->ac97base_mmio); - release_mem_region(card->ac97base_mmio_phys, 512); - release_mem_region(card->iobase_mmio_phys, 512); - card->use_mmio = 0; - } - } - else { - iounmap(card->ac97base_mmio); - release_mem_region(card->ac97base_mmio_phys, 512); - card->use_mmio = 0; - } - } - } - else { - card->use_mmio = 0; - } - } - - /* initialize AC97 codec and register /dev/mixer */ - if (i810_ac97_init(card) <= 0) - goto out_iospace; - pci_set_drvdata(pci_dev, card); - - if(clocking == 0) { - clocking = 48000; - i810_configure_clocking(); - } - - /* register /dev/dsp */ - if ((card->dev_audio = register_sound_dsp(&i810_audio_fops, -1)) < 0) { - int i; - printk(KERN_ERR "i810_audio: couldn't register DSP device!\n"); - for (i = 0; i < NR_AC97; i++) - if (card->ac97_codec[i] != NULL) { - unregister_sound_mixer(card->ac97_codec[i]->dev_mixer); - ac97_release_codec(card->ac97_codec[i]); - } - goto out_iospace; - } - - if (request_irq(card->irq, &i810_interrupt, IRQF_SHARED, - card_names[pci_id->driver_data], card)) { - printk(KERN_ERR "i810_audio: unable to allocate irq %d\n", card->irq); - goto out_iospace; - } - - - card->initializing = 0; - return 0; - -out_iospace: - if (card->use_mmio) { - iounmap(card->ac97base_mmio); - iounmap(card->iobase_mmio); - release_mem_region(card->ac97base_mmio_phys, 512); - release_mem_region(card->iobase_mmio_phys, 256); - } - release_region(card->ac97base, 256); -out_region2: - release_region(card->iobase, 64); -out_region1: - pci_free_consistent(pci_dev, sizeof(struct i810_channel)*NR_HW_CH, - card->channel, card->chandma); -out_mem: - kfree(card); - return -ENODEV; -} - -static void __devexit i810_remove(struct pci_dev *pci_dev) -{ - int i; - struct i810_card *card = pci_get_drvdata(pci_dev); - /* free hardware resources */ - free_irq(card->irq, devs); - release_region(card->iobase, 64); - release_region(card->ac97base, 256); - pci_free_consistent(pci_dev, sizeof(struct i810_channel)*NR_HW_CH, - card->channel, card->chandma); - if (card->use_mmio) { - iounmap(card->ac97base_mmio); - iounmap(card->iobase_mmio); - release_mem_region(card->ac97base_mmio_phys, 512); - release_mem_region(card->iobase_mmio_phys, 256); - } - - /* unregister audio devices */ - for (i = 0; i < NR_AC97; i++) - if (card->ac97_codec[i] != NULL) { - unregister_sound_mixer(card->ac97_codec[i]->dev_mixer); - ac97_release_codec(card->ac97_codec[i]); - card->ac97_codec[i] = NULL; - } - unregister_sound_dsp(card->dev_audio); - kfree(card); -} - -#ifdef CONFIG_PM -static int i810_pm_suspend(struct pci_dev *dev, pm_message_t pm_state) -{ - struct i810_card *card = pci_get_drvdata(dev); - struct i810_state *state; - unsigned long flags; - struct dmabuf *dmabuf; - int i,num_ac97; -#ifdef DEBUG - printk("i810_audio: i810_pm_suspend called\n"); -#endif - if(!card) return 0; - spin_lock_irqsave(&card->lock, flags); - card->pm_suspended=1; - for(i=0;i<NR_HW_CH;i++) { - state = card->states[i]; - if(!state) continue; - /* this happens only if there are open files */ - dmabuf = &state->dmabuf; - if(dmabuf->enable & DAC_RUNNING || - (dmabuf->count && (dmabuf->trigger & PCM_ENABLE_OUTPUT))) { - state->pm_saved_dac_rate=dmabuf->rate; - stop_dac(state); - } else { - state->pm_saved_dac_rate=0; - } - if(dmabuf->enable & ADC_RUNNING) { - state->pm_saved_adc_rate=dmabuf->rate; - stop_adc(state); - } else { - state->pm_saved_adc_rate=0; - } - dmabuf->ready = 0; - dmabuf->swptr = dmabuf->hwptr = 0; - dmabuf->count = dmabuf->total_bytes = 0; - } - - spin_unlock_irqrestore(&card->lock, flags); - - /* save mixer settings */ - for (num_ac97 = 0; num_ac97 < NR_AC97; num_ac97++) { - struct ac97_codec *codec = card->ac97_codec[num_ac97]; - if(!codec) continue; - for(i=0;i< SOUND_MIXER_NRDEVICES ;i++) { - if((supported_mixer(codec,i)) && - (codec->read_mixer)) { - card->pm_saved_mixer_settings[i][num_ac97]= - codec->read_mixer(codec,i); - } - } - } - pci_save_state(dev); /* XXX do we need this? */ - pci_disable_device(dev); /* disable busmastering */ - pci_set_power_state(dev,3); /* Zzz. */ - - return 0; -} - - -static int i810_pm_resume(struct pci_dev *dev) -{ - int num_ac97,i=0; - struct i810_card *card=pci_get_drvdata(dev); - pci_enable_device(dev); - pci_restore_state (dev); - - /* observation of a toshiba portege 3440ct suggests that the - hardware has to be more or less completely reinitialized from - scratch after an apm suspend. Works For Me. -dan */ - - i810_ac97_power_up_bus(card); - - for (num_ac97 = 0; num_ac97 < NR_AC97; num_ac97++) { - struct ac97_codec *codec = card->ac97_codec[num_ac97]; - /* check they haven't stolen the hardware while we were - away */ - if(!codec || !i810_ac97_exists(card,num_ac97)) { - if(num_ac97) continue; - else BUG(); - } - if(!i810_ac97_probe_and_powerup(card,codec)) BUG(); - - if((card->ac97_features&0x0001)) { - /* at probe time we found we could do variable - rates, but APM suspend has made it forget - its magical powers */ - if(!i810_ac97_enable_variable_rate(codec)) BUG(); - } - /* we lost our mixer settings, so restore them */ - for(i=0;i< SOUND_MIXER_NRDEVICES ;i++) { - if(supported_mixer(codec,i)){ - int val=card-> - pm_saved_mixer_settings[i][num_ac97]; - codec->mixer_state[i]=val; - codec->write_mixer(codec,i, - (val & 0xff) , - ((val >> 8) & 0xff) ); - } - } - } - - /* we need to restore the sample rate from whatever it was */ - for(i=0;i<NR_HW_CH;i++) { - struct i810_state * state=card->states[i]; - if(state) { - if(state->pm_saved_adc_rate) - i810_set_adc_rate(state,state->pm_saved_adc_rate); - if(state->pm_saved_dac_rate) - i810_set_dac_rate(state,state->pm_saved_dac_rate); - } - } - - - card->pm_suspended = 0; - - /* any processes that were reading/writing during the suspend - probably ended up here */ - for(i=0;i<NR_HW_CH;i++) { - struct i810_state *state = card->states[i]; - if(state) wake_up(&state->dmabuf.wait); - } - - return 0; -} -#endif /* CONFIG_PM */ - -MODULE_AUTHOR("The Linux kernel team"); -MODULE_DESCRIPTION("Intel 810 audio support"); -MODULE_LICENSE("GPL"); -module_param(ftsodell, int, 0444); -module_param(clocking, uint, 0444); -module_param(strict_clocking, int, 0444); -module_param(spdif_locked, int, 0444); - -#define I810_MODULE_NAME "i810_audio" - -static struct pci_driver i810_pci_driver = { - .name = I810_MODULE_NAME, - .id_table = i810_pci_tbl, - .probe = i810_probe, - .remove = __devexit_p(i810_remove), -#ifdef CONFIG_PM - .suspend = i810_pm_suspend, - .resume = i810_pm_resume, -#endif /* CONFIG_PM */ -}; - - -static int __init i810_init_module (void) -{ - int retval; - - printk(KERN_INFO "Intel 810 + AC97 Audio, version " - DRIVER_VERSION ", " __TIME__ " " __DATE__ "\n"); - - retval = pci_register_driver(&i810_pci_driver); - if (retval) - return retval; - - if(ftsodell != 0) { - printk("i810_audio: ftsodell is now a deprecated option.\n"); - } - if(spdif_locked > 0 ) { - if(spdif_locked == 32000 || spdif_locked == 44100 || spdif_locked == 48000) { - printk("i810_audio: Enabling S/PDIF at sample rate %dHz.\n", spdif_locked); - } else { - printk("i810_audio: S/PDIF can only be locked to 32000, 44100, or 48000Hz.\n"); - spdif_locked = 0; - } - } - - return 0; -} - -static void __exit i810_cleanup_module (void) -{ - pci_unregister_driver(&i810_pci_driver); -} - -module_init(i810_init_module); -module_exit(i810_cleanup_module); - -/* -Local Variables: -c-basic-offset: 8 -End: -*/ diff --git a/sound/oss/pss.c b/sound/oss/pss.c index ece428b2ba9f..16ed06950dc1 100644 --- a/sound/oss/pss.c +++ b/sound/oss/pss.c @@ -232,14 +232,12 @@ static int set_irq(pss_confdata * devc, int dev, int irq) return 1; } -static int set_io_base(pss_confdata * devc, int dev, int base) +static void set_io_base(pss_confdata * devc, int dev, int base) { unsigned short tmp = inw(REG(dev)) & 0x003f; unsigned short bits = (base & 0x0ffc) << 4; outw(bits | tmp, REG(dev)); - - return 1; } static int set_dma(pss_confdata * devc, int dev, int dma) @@ -673,20 +671,12 @@ static void configure_nonsound_components(void) /* Configure CDROM port */ - if(pss_cdrom_port == -1) /* If cdrom port enablation wasn't requested */ - { + if (pss_cdrom_port == -1) { /* If cdrom port enablation wasn't requested */ printk(KERN_INFO "PSS: CDROM port not enabled.\n"); - } - else if(check_region(pss_cdrom_port, 2)) - { + } else if (check_region(pss_cdrom_port, 2)) { printk(KERN_ERR "PSS: CDROM I/O port conflict.\n"); - } - else if(!set_io_base(devc, CONF_CDROM, pss_cdrom_port)) - { - printk(KERN_ERR "PSS: CDROM I/O port could not be set.\n"); - } - else /* CDROM port successfully configured */ - { + } else { + set_io_base(devc, CONF_CDROM, pss_cdrom_port); printk(KERN_INFO "PSS: CDROM I/O port set to 0x%x.\n", pss_cdrom_port); } } @@ -758,10 +748,7 @@ static int __init probe_pss_mpu(struct address_info *hw_config) printk(KERN_ERR "PSS: MPU I/O port conflict\n"); return 0; } - if (!set_io_base(devc, CONF_MIDI, hw_config->io_base)) { - printk(KERN_ERR "PSS: MIDI base could not be set.\n"); - goto fail; - } + set_io_base(devc, CONF_MIDI, hw_config->io_base); if (!set_irq(devc, CONF_MIDI, hw_config->irq)) { printk(KERN_ERR "PSS: MIDI IRQ allocation error.\n"); goto fail; @@ -1057,10 +1044,7 @@ static int __init probe_pss_mss(struct address_info *hw_config) release_region(hw_config->io_base, 4); return 0; } - if (!set_io_base(devc, CONF_WSS, hw_config->io_base)) { - printk("PSS: WSS base not settable.\n"); - goto fail; - } + set_io_base(devc, CONF_WSS, hw_config->io_base); if (!set_irq(devc, CONF_WSS, hw_config->irq)) { printk("PSS: WSS IRQ allocation error.\n"); goto fail; diff --git a/sound/oss/sb_common.c b/sound/oss/sb_common.c index 07cbacf63824..77d0e5efda76 100644 --- a/sound/oss/sb_common.c +++ b/sound/oss/sb_common.c @@ -1228,7 +1228,8 @@ int probe_sbmpu(struct address_info *hw_config, struct module *owner) } attach_mpu401(hw_config, owner); if (last_sb->irq == -hw_config->irq) - last_sb->midi_irq_cookie=(void *)hw_config->slots[1]; + last_sb->midi_irq_cookie = + (void *)(long) hw_config->slots[1]; return 1; } #endif diff --git a/sound/oss/trident.c b/sound/oss/trident.c index 96adc47917aa..6959ee1bd17f 100644 --- a/sound/oss/trident.c +++ b/sound/oss/trident.c @@ -2935,7 +2935,7 @@ trident_ac97_set(struct ac97_codec *codec, u8 reg, u16 val) do { if ((inw(TRID_REG(card, address)) & busy) == 0) break; - } while (count--); + } while (--count); data |= (mask | (reg & AC97_REG_ADDR)); @@ -2996,7 +2996,7 @@ trident_ac97_get(struct ac97_codec *codec, u8 reg) data = inl(TRID_REG(card, address)); if ((data & busy) == 0) break; - } while (count--); + } while (--count); spin_unlock_irqrestore(&card->lock, flags); if (count == 0) { diff --git a/sound/oss/via82cxxx_audio.c b/sound/oss/via82cxxx_audio.c deleted file mode 100644 index f95aa0946758..000000000000 --- a/sound/oss/via82cxxx_audio.c +++ /dev/null @@ -1,3616 +0,0 @@ -/* - * Support for VIA 82Cxxx Audio Codecs - * Copyright 1999,2000 Jeff Garzik - * - * Updated to support the VIA 8233/8235 audio subsystem - * Alan Cox <alan@redhat.com> (C) Copyright 2002, 2003 Red Hat Inc - * - * Distributed under the GNU GENERAL PUBLIC LICENSE (GPL) Version 2. - * See the "COPYING" file distributed with this software for more info. - * NO WARRANTY - * - * For a list of known bugs (errata) and documentation, - * see via-audio.pdf in Documentation/DocBook. - * If this documentation does not exist, run "make pdfdocs". - */ - - -#define VIA_VERSION "1.9.1-ac4-2.5" - - -#include <linux/module.h> -#include <linux/kernel.h> -#include <linux/fs.h> -#include <linux/mm.h> -#include <linux/pci.h> -#include <linux/poison.h> -#include <linux/init.h> -#include <linux/interrupt.h> -#include <linux/proc_fs.h> -#include <linux/spinlock.h> -#include <linux/sound.h> -#include <linux/poll.h> -#include <linux/soundcard.h> -#include <linux/ac97_codec.h> -#include <linux/ioport.h> -#include <linux/delay.h> -#include <linux/dma-mapping.h> -#include <asm/io.h> -#include <asm/uaccess.h> -#include <linux/mutex.h> - -#include "sound_config.h" -#include "dev_table.h" -#include "mpu401.h" - - -#undef VIA_DEBUG /* define to enable debugging output and checks */ -#ifdef VIA_DEBUG -/* note: prints function name for you */ -#define DPRINTK(fmt, args...) printk(KERN_DEBUG "%s: " fmt, __FUNCTION__ , ## args) -#else -#define DPRINTK(fmt, args...) -#endif - -#undef VIA_NDEBUG /* define to disable lightweight runtime checks */ -#ifdef VIA_NDEBUG -#define assert(expr) -#else -#define assert(expr) \ - if(!(expr)) { \ - printk( "Assertion failed! %s,%s,%s,line=%d\n", \ - #expr,__FILE__,__FUNCTION__,__LINE__); \ - } -#endif - -#define VIA_SUPPORT_MMAP 1 /* buggy, for now... */ - -#define MAX_CARDS 1 - -#define VIA_CARD_NAME "VIA 82Cxxx Audio driver " VIA_VERSION -#define VIA_MODULE_NAME "via82cxxx" -#define PFX VIA_MODULE_NAME ": " - -#define VIA_COUNTER_LIMIT 100000 - -/* size of DMA buffers */ -#define VIA_MAX_BUFFER_DMA_PAGES 32 - -/* buffering default values in ms */ -#define VIA_DEFAULT_FRAG_TIME 20 -#define VIA_DEFAULT_BUFFER_TIME 500 - -/* the hardware has a 256 fragment limit */ -#define VIA_MIN_FRAG_NUMBER 2 -#define VIA_MAX_FRAG_NUMBER 128 - -#define VIA_MAX_FRAG_SIZE PAGE_SIZE -#define VIA_MIN_FRAG_SIZE (VIA_MAX_BUFFER_DMA_PAGES * PAGE_SIZE / VIA_MAX_FRAG_NUMBER) - - -/* 82C686 function 5 (audio codec) PCI configuration registers */ -#define VIA_ACLINK_STATUS 0x40 -#define VIA_ACLINK_CTRL 0x41 -#define VIA_FUNC_ENABLE 0x42 -#define VIA_PNP_CONTROL 0x43 -#define VIA_FM_NMI_CTRL 0x48 - -/* - * controller base 0 (scatter-gather) registers - * - * NOTE: Via datasheet lists first channel as "read" - * channel and second channel as "write" channel. - * I changed the naming of the constants to be more - * clear than I felt the datasheet to be. - */ - -#define VIA_BASE0_PCM_OUT_CHAN 0x00 /* output PCM to user */ -#define VIA_BASE0_PCM_OUT_CHAN_STATUS 0x00 -#define VIA_BASE0_PCM_OUT_CHAN_CTRL 0x01 -#define VIA_BASE0_PCM_OUT_CHAN_TYPE 0x02 - -#define VIA_BASE0_PCM_IN_CHAN 0x10 /* input PCM from user */ -#define VIA_BASE0_PCM_IN_CHAN_STATUS 0x10 -#define VIA_BASE0_PCM_IN_CHAN_CTRL 0x11 -#define VIA_BASE0_PCM_IN_CHAN_TYPE 0x12 - -/* offsets from base */ -#define VIA_PCM_STATUS 0x00 -#define VIA_PCM_CONTROL 0x01 -#define VIA_PCM_TYPE 0x02 -#define VIA_PCM_LEFTVOL 0x02 -#define VIA_PCM_RIGHTVOL 0x03 -#define VIA_PCM_TABLE_ADDR 0x04 -#define VIA_PCM_STOPRATE 0x08 /* 8233+ */ -#define VIA_PCM_BLOCK_COUNT 0x0C - -/* XXX unused DMA channel for FM PCM data */ -#define VIA_BASE0_FM_OUT_CHAN 0x20 -#define VIA_BASE0_FM_OUT_CHAN_STATUS 0x20 -#define VIA_BASE0_FM_OUT_CHAN_CTRL 0x21 -#define VIA_BASE0_FM_OUT_CHAN_TYPE 0x22 - -/* Six channel audio output on 8233 */ -#define VIA_BASE0_MULTI_OUT_CHAN 0x40 -#define VIA_BASE0_MULTI_OUT_CHAN_STATUS 0x40 -#define VIA_BASE0_MULTI_OUT_CHAN_CTRL 0x41 -#define VIA_BASE0_MULTI_OUT_CHAN_TYPE 0x42 - -#define VIA_BASE0_AC97_CTRL 0x80 -#define VIA_BASE0_SGD_STATUS_SHADOW 0x84 -#define VIA_BASE0_GPI_INT_ENABLE 0x8C -#define VIA_INTR_OUT ((1<<0) | (1<<4) | (1<<8)) -#define VIA_INTR_IN ((1<<1) | (1<<5) | (1<<9)) -#define VIA_INTR_FM ((1<<2) | (1<<6) | (1<<10)) -#define VIA_INTR_MASK (VIA_INTR_OUT | VIA_INTR_IN | VIA_INTR_FM) - -/* Newer VIA we need to monitor the low 3 bits of each channel. This - mask covers the channels we don't yet use as well - */ - -#define VIA_NEW_INTR_MASK 0x77077777UL - -/* VIA_BASE0_AUDIO_xxx_CHAN_TYPE bits */ -#define VIA_IRQ_ON_FLAG (1<<0) /* int on each flagged scatter block */ -#define VIA_IRQ_ON_EOL (1<<1) /* int at end of scatter list */ -#define VIA_INT_SEL_PCI_LAST_LINE_READ (0) /* int at PCI read of last line */ -#define VIA_INT_SEL_LAST_SAMPLE_SENT (1<<2) /* int at last sample sent */ -#define VIA_INT_SEL_ONE_LINE_LEFT (1<<3) /* int at less than one line to send */ -#define VIA_PCM_FMT_STEREO (1<<4) /* PCM stereo format (bit clear == mono) */ -#define VIA_PCM_FMT_16BIT (1<<5) /* PCM 16-bit format (bit clear == 8-bit) */ -#define VIA_PCM_REC_FIFO (1<<6) /* PCM Recording FIFO */ -#define VIA_RESTART_SGD_ON_EOL (1<<7) /* restart scatter-gather at EOL */ -#define VIA_PCM_FMT_MASK (VIA_PCM_FMT_STEREO|VIA_PCM_FMT_16BIT) -#define VIA_CHAN_TYPE_MASK (VIA_RESTART_SGD_ON_EOL | \ - VIA_IRQ_ON_FLAG | \ - VIA_IRQ_ON_EOL) -#define VIA_CHAN_TYPE_INT_SELECT (VIA_INT_SEL_LAST_SAMPLE_SENT) - -/* PCI configuration register bits and masks */ -#define VIA_CR40_AC97_READY 0x01 -#define VIA_CR40_AC97_LOW_POWER 0x02 -#define VIA_CR40_SECONDARY_READY 0x04 - -#define VIA_CR41_AC97_ENABLE 0x80 /* enable AC97 codec */ -#define VIA_CR41_AC97_RESET 0x40 /* clear bit to reset AC97 */ -#define VIA_CR41_AC97_WAKEUP 0x20 /* wake up from power-down mode */ -#define VIA_CR41_AC97_SDO 0x10 /* force Serial Data Out (SDO) high */ -#define VIA_CR41_VRA 0x08 /* enable variable sample rate */ -#define VIA_CR41_PCM_ENABLE 0x04 /* AC Link SGD Read Channel PCM Data Output */ -#define VIA_CR41_FM_PCM_ENABLE 0x02 /* AC Link FM Channel PCM Data Out */ -#define VIA_CR41_SB_PCM_ENABLE 0x01 /* AC Link SB PCM Data Output */ -#define VIA_CR41_BOOT_MASK (VIA_CR41_AC97_ENABLE | \ - VIA_CR41_AC97_WAKEUP | \ - VIA_CR41_AC97_SDO) -#define VIA_CR41_RUN_MASK (VIA_CR41_AC97_ENABLE | \ - VIA_CR41_AC97_RESET | \ - VIA_CR41_VRA | \ - VIA_CR41_PCM_ENABLE) - -#define VIA_CR42_SB_ENABLE 0x01 -#define VIA_CR42_MIDI_ENABLE 0x02 -#define VIA_CR42_FM_ENABLE 0x04 -#define VIA_CR42_GAME_ENABLE 0x08 -#define VIA_CR42_MIDI_IRQMASK 0x40 -#define VIA_CR42_MIDI_PNP 0x80 - -#define VIA_CR44_SECOND_CODEC_SUPPORT (1 << 6) -#define VIA_CR44_AC_LINK_ACCESS (1 << 7) - -#define VIA_CR48_FM_TRAP_TO_NMI (1 << 2) - -/* controller base 0 register bitmasks */ -#define VIA_INT_DISABLE_MASK (~(0x01|0x02)) -#define VIA_SGD_STOPPED (1 << 2) -#define VIA_SGD_PAUSED (1 << 6) -#define VIA_SGD_ACTIVE (1 << 7) -#define VIA_SGD_TERMINATE (1 << 6) -#define VIA_SGD_FLAG (1 << 0) -#define VIA_SGD_EOL (1 << 1) -#define VIA_SGD_START (1 << 7) - -#define VIA_CR80_FIRST_CODEC 0 -#define VIA_CR80_SECOND_CODEC (1 << 30) -#define VIA_CR80_FIRST_CODEC_VALID (1 << 25) -#define VIA_CR80_VALID (1 << 25) -#define VIA_CR80_SECOND_CODEC_VALID (1 << 27) -#define VIA_CR80_BUSY (1 << 24) -#define VIA_CR83_BUSY (1) -#define VIA_CR83_FIRST_CODEC_VALID (1 << 1) -#define VIA_CR80_READ (1 << 23) -#define VIA_CR80_WRITE_MODE 0 -#define VIA_CR80_REG_IDX(idx) ((((idx) & 0xFF) >> 1) << 16) - -/* capabilities we announce */ -#ifdef VIA_SUPPORT_MMAP -#define VIA_DSP_CAP (DSP_CAP_REVISION | DSP_CAP_DUPLEX | DSP_CAP_MMAP | \ - DSP_CAP_TRIGGER | DSP_CAP_REALTIME) -#else -#define VIA_DSP_CAP (DSP_CAP_REVISION | DSP_CAP_DUPLEX | \ - DSP_CAP_TRIGGER | DSP_CAP_REALTIME) -#endif - -/* scatter-gather DMA table entry, exactly as passed to hardware */ -struct via_sgd_table { - u32 addr; - u32 count; /* includes additional VIA_xxx bits also */ -}; - -#define VIA_EOL (1 << 31) -#define VIA_FLAG (1 << 30) -#define VIA_STOP (1 << 29) - - -enum via_channel_states { - sgd_stopped = 0, - sgd_in_progress = 1, -}; - - -struct via_buffer_pgtbl { - dma_addr_t handle; - void *cpuaddr; -}; - - -struct via_channel { - atomic_t n_frags; - atomic_t hw_ptr; - wait_queue_head_t wait; - - unsigned int sw_ptr; - unsigned int slop_len; - unsigned int n_irqs; - int bytes; - - unsigned is_active : 1; - unsigned is_record : 1; - unsigned is_mapped : 1; - unsigned is_enabled : 1; - unsigned is_multi: 1; /* 8233 6 channel */ - u8 pcm_fmt; /* VIA_PCM_FMT_xxx */ - u8 channels; /* Channel count */ - - unsigned rate; /* sample rate */ - unsigned int frag_size; - unsigned int frag_number; - - unsigned char intmask; - - volatile struct via_sgd_table *sgtable; - dma_addr_t sgt_handle; - - unsigned int page_number; - struct via_buffer_pgtbl pgtbl[VIA_MAX_BUFFER_DMA_PAGES]; - - long iobase; - - const char *name; -}; - - -/* data stored for each chip */ -struct via_info { - struct pci_dev *pdev; - long baseaddr; - - struct ac97_codec *ac97; - spinlock_t ac97_lock; - spinlock_t lock; - int card_num; /* unique card number, from 0 */ - - int dev_dsp; /* /dev/dsp index from register_sound_dsp() */ - - unsigned rev_h : 1; - unsigned legacy: 1; /* Has legacy ports */ - unsigned intmask: 1; /* Needs int bits */ - unsigned sixchannel: 1; /* 8233/35 with 6 channel support */ - unsigned volume: 1; - - unsigned locked_rate : 1; - - int mixer_vol; /* 8233/35 volume - not yet implemented */ - - struct mutex syscall_mutex; - struct mutex open_mutex; - - /* The 8233/8235 have 4 DX audio channels, two record and - one six channel out. We bind ch_in to DX 1, ch_out to multichannel - and ch_fm to DX 2. DX 3 and REC0/REC1 are unused at the - moment */ - - struct via_channel ch_in; - struct via_channel ch_out; - struct via_channel ch_fm; - -#ifdef CONFIG_MIDI_VIA82CXXX - void *midi_devc; - struct address_info midi_info; -#endif -}; - - -/* number of cards, used for assigning unique numbers to cards */ -static unsigned via_num_cards; - - - -/**************************************************************** - * - * prototypes - * - * - */ - -static int via_init_one (struct pci_dev *dev, const struct pci_device_id *id); -static void __devexit via_remove_one (struct pci_dev *pdev); - -static ssize_t via_dsp_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos); -static ssize_t via_dsp_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos); -static unsigned int via_dsp_poll(struct file *file, struct poll_table_struct *wait); -static int via_dsp_ioctl (struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg); -static int via_dsp_open (struct inode *inode, struct file *file); -static int via_dsp_release(struct inode *inode, struct file *file); -static int via_dsp_mmap(struct file *file, struct vm_area_struct *vma); - -static u16 via_ac97_read_reg (struct ac97_codec *codec, u8 reg); -static void via_ac97_write_reg (struct ac97_codec *codec, u8 reg, u16 value); -static u8 via_ac97_wait_idle (struct via_info *card); - -static void via_chan_free (struct via_info *card, struct via_channel *chan); -static void via_chan_clear (struct via_info *card, struct via_channel *chan); -static void via_chan_pcm_fmt (struct via_channel *chan, int reset); -static void via_chan_buffer_free (struct via_info *card, struct via_channel *chan); - - -/**************************************************************** - * - * Various data the driver needs - * - * - */ - - -static struct pci_device_id via_pci_tbl[] = { - { PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C686_5, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - { PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8233_5, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1}, - { 0, } -}; -MODULE_DEVICE_TABLE(pci,via_pci_tbl); - - -static struct pci_driver via_driver = { - .name = VIA_MODULE_NAME, - .id_table = via_pci_tbl, - .probe = via_init_one, - .remove = __devexit_p(via_remove_one), -}; - - -/**************************************************************** - * - * Low-level base 0 register read/write helpers - * - * - */ - -/** - * via_chan_stop - Terminate DMA on specified PCM channel - * @iobase: PCI base address for SGD channel registers - * - * Terminate scatter-gather DMA operation for given - * channel (derived from @iobase), if DMA is active. - * - * Note that @iobase is not the PCI base address, - * but the PCI base address plus an offset to - * one of three PCM channels supported by the chip. - * - */ - -static inline void via_chan_stop (long iobase) -{ - if (inb (iobase + VIA_PCM_STATUS) & VIA_SGD_ACTIVE) - outb (VIA_SGD_TERMINATE, iobase + VIA_PCM_CONTROL); -} - - -/** - * via_chan_status_clear - Clear status flags on specified DMA channel - * @iobase: PCI base address for SGD channel registers - * - * Clear any pending status flags for the given - * DMA channel (derived from @iobase), if any - * flags are asserted. - * - * Note that @iobase is not the PCI base address, - * but the PCI base address plus an offset to - * one of three PCM channels supported by the chip. - * - */ - -static inline void via_chan_status_clear (long iobase) -{ - u8 tmp = inb (iobase + VIA_PCM_STATUS); - - if (tmp != 0) - outb (tmp, iobase + VIA_PCM_STATUS); -} - - -/** - * sg_begin - Begin recording or playback on a PCM channel - * @chan: Channel for which DMA operation shall begin - * - * Start scatter-gather DMA for the given channel. - * - */ - -static inline void sg_begin (struct via_channel *chan) -{ - DPRINTK("Start with intmask %d\n", chan->intmask); - DPRINTK("About to start from %d to %d\n", - inl(chan->iobase + VIA_PCM_BLOCK_COUNT), - inb(chan->iobase + VIA_PCM_STOPRATE + 3)); - outb (VIA_SGD_START|chan->intmask, chan->iobase + VIA_PCM_CONTROL); - DPRINTK("Status is now %02X\n", inb(chan->iobase + VIA_PCM_STATUS)); - DPRINTK("Control is now %02X\n", inb(chan->iobase + VIA_PCM_CONTROL)); -} - - -static int sg_active (long iobase) -{ - u8 tmp = inb (iobase + VIA_PCM_STATUS); - if ((tmp & VIA_SGD_STOPPED) || (tmp & VIA_SGD_PAUSED)) { - printk(KERN_WARNING "via82cxxx warning: SG stopped or paused\n"); - return 0; - } - if (tmp & VIA_SGD_ACTIVE) - return 1; - return 0; -} - -static int via_sg_offset(struct via_channel *chan) -{ - return inl (chan->iobase + VIA_PCM_BLOCK_COUNT) & 0x00FFFFFF; -} - -/**************************************************************** - * - * Miscellaneous debris - * - * - */ - - -/** - * via_syscall_down - down the card-specific syscell semaphore - * @card: Private info for specified board - * @nonblock: boolean, non-zero if O_NONBLOCK is set - * - * Encapsulates standard method of acquiring the syscall sem. - * - * Returns negative errno on error, or zero for success. - */ - -static inline int via_syscall_down (struct via_info *card, int nonblock) -{ - /* Thomas Sailer: - * EAGAIN is supposed to be used if IO is pending, - * not if there is contention on some internal - * synchronization primitive which should be - * held only for a short time anyway - */ - nonblock = 0; - - if (nonblock) { - if (!mutex_trylock(&card->syscall_mutex)) - return -EAGAIN; - } else { - if (mutex_lock_interruptible(&card->syscall_mutex)) - return -ERESTARTSYS; - } - - return 0; -} - - -/** - * via_stop_everything - Stop all audio operations - * @card: Private info for specified board - * - * Stops all DMA operations and interrupts, and clear - * any pending status bits resulting from those operations. - */ - -static void via_stop_everything (struct via_info *card) -{ - u8 tmp, new_tmp; - - DPRINTK ("ENTER\n"); - - assert (card != NULL); - - /* - * terminate any existing operations on audio read/write channels - */ - via_chan_stop (card->baseaddr + VIA_BASE0_PCM_OUT_CHAN); - via_chan_stop (card->baseaddr + VIA_BASE0_PCM_IN_CHAN); - via_chan_stop (card->baseaddr + VIA_BASE0_FM_OUT_CHAN); - if(card->sixchannel) - via_chan_stop (card->baseaddr + VIA_BASE0_MULTI_OUT_CHAN); - - /* - * clear any existing stops / flags (sanity check mainly) - */ - via_chan_status_clear (card->baseaddr + VIA_BASE0_PCM_OUT_CHAN); - via_chan_status_clear (card->baseaddr + VIA_BASE0_PCM_IN_CHAN); - via_chan_status_clear (card->baseaddr + VIA_BASE0_FM_OUT_CHAN); - if(card->sixchannel) - via_chan_status_clear (card->baseaddr + VIA_BASE0_MULTI_OUT_CHAN); - - /* - * clear any enabled interrupt bits - */ - tmp = inb (card->baseaddr + VIA_BASE0_PCM_OUT_CHAN_TYPE); - new_tmp = tmp & ~(VIA_IRQ_ON_FLAG|VIA_IRQ_ON_EOL|VIA_RESTART_SGD_ON_EOL); - if (tmp != new_tmp) - outb (0, card->baseaddr + VIA_BASE0_PCM_OUT_CHAN_TYPE); - - tmp = inb (card->baseaddr + VIA_BASE0_PCM_IN_CHAN_TYPE); - new_tmp = tmp & ~(VIA_IRQ_ON_FLAG|VIA_IRQ_ON_EOL|VIA_RESTART_SGD_ON_EOL); - if (tmp != new_tmp) - outb (0, card->baseaddr + VIA_BASE0_PCM_IN_CHAN_TYPE); - - tmp = inb (card->baseaddr + VIA_BASE0_FM_OUT_CHAN_TYPE); - new_tmp = tmp & ~(VIA_IRQ_ON_FLAG|VIA_IRQ_ON_EOL|VIA_RESTART_SGD_ON_EOL); - if (tmp != new_tmp) - outb (0, card->baseaddr + VIA_BASE0_FM_OUT_CHAN_TYPE); - - if(card->sixchannel) - { - tmp = inb (card->baseaddr + VIA_BASE0_MULTI_OUT_CHAN_TYPE); - new_tmp = tmp & ~(VIA_IRQ_ON_FLAG|VIA_IRQ_ON_EOL|VIA_RESTART_SGD_ON_EOL); - if (tmp != new_tmp) - outb (0, card->baseaddr + VIA_BASE0_MULTI_OUT_CHAN_TYPE); - } - - udelay(10); - - /* - * clear any existing flags - */ - via_chan_status_clear (card->baseaddr + VIA_BASE0_PCM_OUT_CHAN); - via_chan_status_clear (card->baseaddr + VIA_BASE0_PCM_IN_CHAN); - via_chan_status_clear (card->baseaddr + VIA_BASE0_FM_OUT_CHAN); - - DPRINTK ("EXIT\n"); -} - - -/** - * via_set_rate - Set PCM rate for given channel - * @ac97: Pointer to generic codec info struct - * @chan: Private info for specified channel - * @rate: Desired PCM sample rate, in Khz - * - * Sets the PCM sample rate for a channel. - * - * Values for @rate are clamped to a range of 4000 Khz through 48000 Khz, - * due to hardware constraints. - */ - -static int via_set_rate (struct ac97_codec *ac97, - struct via_channel *chan, unsigned rate) -{ - struct via_info *card = ac97->private_data; - int rate_reg; - u32 dacp; - u32 mast_vol, phone_vol, mono_vol, pcm_vol; - u32 mute_vol = 0x8000; /* The mute volume? -- Seems to work! */ - - DPRINTK ("ENTER, rate = %d\n", rate); - - if (chan->rate == rate) - goto out; - if (card->locked_rate) { - chan->rate = 48000; - goto out; - } - - if (rate > 48000) rate = 48000; - if (rate < 4000) rate = 4000; - - rate_reg = chan->is_record ? AC97_PCM_LR_ADC_RATE : - AC97_PCM_FRONT_DAC_RATE; - - /* Save current state */ - dacp=via_ac97_read_reg(ac97, AC97_POWER_CONTROL); - mast_vol = via_ac97_read_reg(ac97, AC97_MASTER_VOL_STEREO); - mono_vol = via_ac97_read_reg(ac97, AC97_MASTER_VOL_MONO); - phone_vol = via_ac97_read_reg(ac97, AC97_HEADPHONE_VOL); - pcm_vol = via_ac97_read_reg(ac97, AC97_PCMOUT_VOL); - /* Mute - largely reduces popping */ - via_ac97_write_reg(ac97, AC97_MASTER_VOL_STEREO, mute_vol); - via_ac97_write_reg(ac97, AC97_MASTER_VOL_MONO, mute_vol); - via_ac97_write_reg(ac97, AC97_HEADPHONE_VOL, mute_vol); - via_ac97_write_reg(ac97, AC97_PCMOUT_VOL, mute_vol); - /* Power down the DAC */ - via_ac97_write_reg(ac97, AC97_POWER_CONTROL, dacp|0x0200); - - /* Set new rate */ - via_ac97_write_reg (ac97, rate_reg, rate); - - /* Power DAC back up */ - via_ac97_write_reg(ac97, AC97_POWER_CONTROL, dacp); - udelay (200); /* reduces popping */ - - /* Restore volumes */ - via_ac97_write_reg(ac97, AC97_MASTER_VOL_STEREO, mast_vol); - via_ac97_write_reg(ac97, AC97_MASTER_VOL_MONO, mono_vol); - via_ac97_write_reg(ac97, AC97_HEADPHONE_VOL, phone_vol); - via_ac97_write_reg(ac97, AC97_PCMOUT_VOL, pcm_vol); - - /* the hardware might return a value different than what we - * passed to it, so read the rate value back from hardware - * to see what we came up with - */ - chan->rate = via_ac97_read_reg (ac97, rate_reg); - - if (chan->rate == 0) { - card->locked_rate = 1; - chan->rate = 48000; - printk (KERN_WARNING PFX "Codec rate locked at 48Khz\n"); - } - -out: - DPRINTK ("EXIT, returning rate %d Hz\n", chan->rate); - return chan->rate; -} - - -/**************************************************************** - * - * Channel-specific operations - * - * - */ - - -/** - * via_chan_init_defaults - Initialize a struct via_channel - * @card: Private audio chip info - * @chan: Channel to be initialized - * - * Zero @chan, and then set all static defaults for the structure. - */ - -static void via_chan_init_defaults (struct via_info *card, struct via_channel *chan) -{ - memset (chan, 0, sizeof (*chan)); - - if(card->intmask) - chan->intmask = 0x23; /* Turn on the IRQ bits */ - - if (chan == &card->ch_out) { - chan->name = "PCM-OUT"; - if(card->sixchannel) - { - chan->iobase = card->baseaddr + VIA_BASE0_MULTI_OUT_CHAN; - chan->is_multi = 1; - DPRINTK("Using multichannel for pcm out\n"); - } - else - chan->iobase = card->baseaddr + VIA_BASE0_PCM_OUT_CHAN; - } else if (chan == &card->ch_in) { - chan->name = "PCM-IN"; - chan->iobase = card->baseaddr + VIA_BASE0_PCM_IN_CHAN; - chan->is_record = 1; - } else if (chan == &card->ch_fm) { - chan->name = "PCM-OUT-FM"; - chan->iobase = card->baseaddr + VIA_BASE0_FM_OUT_CHAN; - } else { - BUG(); - } - - init_waitqueue_head (&chan->wait); - - chan->pcm_fmt = VIA_PCM_FMT_MASK; - chan->is_enabled = 1; - - chan->frag_number = 0; - chan->frag_size = 0; - atomic_set(&chan->n_frags, 0); - atomic_set (&chan->hw_ptr, 0); -} - -/** - * via_chan_init - Initialize PCM channel - * @card: Private audio chip info - * @chan: Channel to be initialized - * - * Performs some of the preparations necessary to begin - * using a PCM channel. - * - * Currently the preparations consist of - * setting the PCM channel to a known state. - */ - - -static void via_chan_init (struct via_info *card, struct via_channel *chan) -{ - - DPRINTK ("ENTER\n"); - - /* bzero channel structure, and init members to defaults */ - via_chan_init_defaults (card, chan); - - /* stop any existing channel output */ - via_chan_clear (card, chan); - via_chan_status_clear (chan->iobase); - via_chan_pcm_fmt (chan, 1); - - DPRINTK ("EXIT\n"); -} - -/** - * via_chan_buffer_init - Initialize PCM channel buffer - * @card: Private audio chip info - * @chan: Channel to be initialized - * - * Performs some of the preparations necessary to begin - * using a PCM channel. - * - * Currently the preparations include allocating the - * scatter-gather DMA table and buffers, - * and passing the - * address of the DMA table to the hardware. - * - * Note that special care is taken when passing the - * DMA table address to hardware, because it was found - * during driver development that the hardware did not - * always "take" the address. - */ - -static int via_chan_buffer_init (struct via_info *card, struct via_channel *chan) -{ - int page, offset; - int i; - - DPRINTK ("ENTER\n"); - - - chan->intmask = 0; - if(card->intmask) - chan->intmask = 0x23; /* Turn on the IRQ bits */ - - if (chan->sgtable != NULL) { - DPRINTK ("EXIT\n"); - return 0; - } - - /* alloc DMA-able memory for scatter-gather table */ - chan->sgtable = pci_alloc_consistent (card->pdev, - (sizeof (struct via_sgd_table) * chan->frag_number), - &chan->sgt_handle); - if (!chan->sgtable) { - printk (KERN_ERR PFX "DMA table alloc fail, aborting\n"); - DPRINTK ("EXIT\n"); - return -ENOMEM; - } - - memset ((void*)chan->sgtable, 0, - (sizeof (struct via_sgd_table) * chan->frag_number)); - - /* alloc DMA-able memory for scatter-gather buffers */ - - chan->page_number = (chan->frag_number * chan->frag_size) / PAGE_SIZE + - (((chan->frag_number * chan->frag_size) % PAGE_SIZE) ? 1 : 0); - - for (i = 0; i < chan->page_number; i++) { - chan->pgtbl[i].cpuaddr = pci_alloc_consistent (card->pdev, PAGE_SIZE, - &chan->pgtbl[i].handle); - - if (!chan->pgtbl[i].cpuaddr) { - chan->page_number = i; - goto err_out_nomem; - } - -#ifndef VIA_NDEBUG - memset (chan->pgtbl[i].cpuaddr, 0xBC, chan->frag_size); -#endif - -#if 1 - DPRINTK ("dmabuf_pg #%d (h=%lx, v2p=%lx, a=%p)\n", - i, (long)chan->pgtbl[i].handle, - virt_to_phys(chan->pgtbl[i].cpuaddr), - chan->pgtbl[i].cpuaddr); -#endif - } - - for (i = 0; i < chan->frag_number; i++) { - - page = i / (PAGE_SIZE / chan->frag_size); - offset = (i % (PAGE_SIZE / chan->frag_size)) * chan->frag_size; - - chan->sgtable[i].count = cpu_to_le32 (chan->frag_size | VIA_FLAG); - chan->sgtable[i].addr = cpu_to_le32 (chan->pgtbl[page].handle + offset); - -#if 1 - DPRINTK ("dmabuf #%d (32(h)=%lx)\n", - i, - (long)chan->sgtable[i].addr); -#endif - } - - /* overwrite the last buffer information */ - chan->sgtable[chan->frag_number - 1].count = cpu_to_le32 (chan->frag_size | VIA_EOL); - - /* set location of DMA-able scatter-gather info table */ - DPRINTK ("outl (0x%X, 0x%04lX)\n", - chan->sgt_handle, chan->iobase + VIA_PCM_TABLE_ADDR); - - via_ac97_wait_idle (card); - outl (chan->sgt_handle, chan->iobase + VIA_PCM_TABLE_ADDR); - udelay (20); - via_ac97_wait_idle (card); - /* load no rate adaption, stereo 16bit, set up ring slots */ - if(card->sixchannel) - { - if(!chan->is_multi) - { - outl (0xFFFFF | (0x3 << 20) | (chan->frag_number << 24), chan->iobase + VIA_PCM_STOPRATE); - udelay (20); - via_ac97_wait_idle (card); - } - } - - DPRINTK ("inl (0x%lX) = %x\n", - chan->iobase + VIA_PCM_TABLE_ADDR, - inl(chan->iobase + VIA_PCM_TABLE_ADDR)); - - DPRINTK ("EXIT\n"); - return 0; - -err_out_nomem: - printk (KERN_ERR PFX "DMA buffer alloc fail, aborting\n"); - via_chan_buffer_free (card, chan); - DPRINTK ("EXIT\n"); - return -ENOMEM; -} - - -/** - * via_chan_free - Release a PCM channel - * @card: Private audio chip info - * @chan: Channel to be released - * - * Performs all the functions necessary to clean up - * an initialized channel. - * - * Currently these functions include disabled any - * active DMA operations, setting the PCM channel - * back to a known state, and releasing any allocated - * sound buffers. - */ - -static void via_chan_free (struct via_info *card, struct via_channel *chan) -{ - DPRINTK ("ENTER\n"); - - spin_lock_irq (&card->lock); - - /* stop any existing channel output */ - via_chan_status_clear (chan->iobase); - via_chan_stop (chan->iobase); - via_chan_status_clear (chan->iobase); - - spin_unlock_irq (&card->lock); - - synchronize_irq(card->pdev->irq); - - DPRINTK ("EXIT\n"); -} - -static void via_chan_buffer_free (struct via_info *card, struct via_channel *chan) -{ - int i; - - DPRINTK ("ENTER\n"); - - /* zero location of DMA-able scatter-gather info table */ - via_ac97_wait_idle(card); - outl (0, chan->iobase + VIA_PCM_TABLE_ADDR); - - for (i = 0; i < chan->page_number; i++) - if (chan->pgtbl[i].cpuaddr) { - pci_free_consistent (card->pdev, PAGE_SIZE, - chan->pgtbl[i].cpuaddr, - chan->pgtbl[i].handle); - chan->pgtbl[i].cpuaddr = NULL; - chan->pgtbl[i].handle = 0; - } - - chan->page_number = 0; - - if (chan->sgtable) { - pci_free_consistent (card->pdev, - (sizeof (struct via_sgd_table) * chan->frag_number), - (void*)chan->sgtable, chan->sgt_handle); - chan->sgtable = NULL; - } - - DPRINTK ("EXIT\n"); -} - - -/** - * via_chan_pcm_fmt - Update PCM channel settings - * @chan: Channel to be updated - * @reset: Boolean. If non-zero, channel will be reset - * to 8-bit mono mode. - * - * Stores the settings of the current PCM format, - * 8-bit or 16-bit, and mono/stereo, into the - * hardware settings for the specified channel. - * If @reset is non-zero, the channel is reset - * to 8-bit mono mode. Otherwise, the channel - * is set to the values stored in the channel - * information struct @chan. - */ - -static void via_chan_pcm_fmt (struct via_channel *chan, int reset) -{ - DPRINTK ("ENTER, pcm_fmt=0x%02X, reset=%s\n", - chan->pcm_fmt, reset ? "yes" : "no"); - - assert (chan != NULL); - - if (reset) - { - /* reset to 8-bit mono mode */ - chan->pcm_fmt = 0; - chan->channels = 1; - } - - /* enable interrupts on FLAG and EOL */ - chan->pcm_fmt |= VIA_CHAN_TYPE_MASK; - - /* if we are recording, enable recording fifo bit */ - if (chan->is_record) - chan->pcm_fmt |= VIA_PCM_REC_FIFO; - /* set interrupt select bits where applicable (PCM in & out channels) */ - if (!chan->is_record) - chan->pcm_fmt |= VIA_CHAN_TYPE_INT_SELECT; - - DPRINTK("SET FMT - %02x %02x\n", chan->intmask , chan->is_multi); - - if(chan->intmask) - { - u32 m; - - /* - * Channel 0x4 is up to 6 x 16bit and has to be - * programmed differently - */ - - if(chan->is_multi) - { - u8 c = 0; - - /* - * Load the type bit for num channels - * and 8/16bit - */ - - if(chan->pcm_fmt & VIA_PCM_FMT_16BIT) - c = 1 << 7; - if(chan->pcm_fmt & VIA_PCM_FMT_STEREO) - c |= (2<<4); - else - c |= (1<<4); - - outb(c, chan->iobase + VIA_PCM_TYPE); - - /* - * Set the channel steering - * Mono - * Channel 0 to slot 3 - * Channel 0 to slot 4 - * Stereo - * Channel 0 to slot 3 - * Channel 1 to slot 4 - */ - - switch(chan->channels) - { - case 1: - outl(0xFF000000 | (1<<0) | (1<<4) , chan->iobase + VIA_PCM_STOPRATE); - break; - case 2: - outl(0xFF000000 | (1<<0) | (2<<4) , chan->iobase + VIA_PCM_STOPRATE); - break; - case 4: - outl(0xFF000000 | (1<<0) | (2<<4) | (3<<8) | (4<<12), chan->iobase + VIA_PCM_STOPRATE); - break; - case 6: - outl(0xFF000000 | (1<<0) | (2<<4) | (5<<8) | (6<<12) | (3<<16) | (4<<20), chan->iobase + VIA_PCM_STOPRATE); - break; - } - } - else - { - /* - * New style, turn off channel volume - * control, set bits in the right register - */ - outb(0x0, chan->iobase + VIA_PCM_LEFTVOL); - outb(0x0, chan->iobase + VIA_PCM_RIGHTVOL); - - m = inl(chan->iobase + VIA_PCM_STOPRATE); - m &= ~(3<<20); - if(chan->pcm_fmt & VIA_PCM_FMT_STEREO) - m |= (1 << 20); - if(chan->pcm_fmt & VIA_PCM_FMT_16BIT) - m |= (1 << 21); - outl(m, chan->iobase + VIA_PCM_STOPRATE); - } - } - else - outb (chan->pcm_fmt, chan->iobase + VIA_PCM_TYPE); - - - DPRINTK ("EXIT, pcm_fmt = 0x%02X, reg = 0x%02X\n", - chan->pcm_fmt, - inb (chan->iobase + VIA_PCM_TYPE)); -} - - -/** - * via_chan_clear - Stop DMA channel operation, and reset pointers - * @card: the chip to accessed - * @chan: Channel to be cleared - * - * Call via_chan_stop to halt DMA operations, and then resets - * all software pointers which track DMA operation. - */ - -static void via_chan_clear (struct via_info *card, struct via_channel *chan) -{ - DPRINTK ("ENTER\n"); - via_chan_stop (chan->iobase); - via_chan_buffer_free(card, chan); - chan->is_active = 0; - chan->is_mapped = 0; - chan->is_enabled = 1; - chan->slop_len = 0; - chan->sw_ptr = 0; - chan->n_irqs = 0; - atomic_set (&chan->hw_ptr, 0); - DPRINTK ("EXIT\n"); -} - - -/** - * via_chan_set_speed - Set PCM sample rate for given channel - * @card: Private info for specified board - * @chan: Channel whose sample rate will be adjusted - * @val: New sample rate, in Khz - * - * Helper function for the %SNDCTL_DSP_SPEED ioctl. OSS semantics - * demand that all audio operations halt (if they are not already - * halted) when the %SNDCTL_DSP_SPEED is given. - * - * This function halts all audio operations for the given channel - * @chan, and then calls via_set_rate to set the audio hardware - * to the new rate. - */ - -static int via_chan_set_speed (struct via_info *card, - struct via_channel *chan, int val) -{ - DPRINTK ("ENTER, requested rate = %d\n", val); - - via_chan_clear (card, chan); - - val = via_set_rate (card->ac97, chan, val); - - DPRINTK ("EXIT, returning %d\n", val); - return val; -} - - -/** - * via_chan_set_fmt - Set PCM sample size for given channel - * @card: Private info for specified board - * @chan: Channel whose sample size will be adjusted - * @val: New sample size, use the %AFMT_xxx constants - * - * Helper function for the %SNDCTL_DSP_SETFMT ioctl. OSS semantics - * demand that all audio operations halt (if they are not already - * halted) when the %SNDCTL_DSP_SETFMT is given. - * - * This function halts all audio operations for the given channel - * @chan, and then calls via_chan_pcm_fmt to set the audio hardware - * to the new sample size, either 8-bit or 16-bit. - */ - -static int via_chan_set_fmt (struct via_info *card, - struct via_channel *chan, int val) -{ - DPRINTK ("ENTER, val=%s\n", - val == AFMT_U8 ? "AFMT_U8" : - val == AFMT_S16_LE ? "AFMT_S16_LE" : - "unknown"); - - via_chan_clear (card, chan); - - assert (val != AFMT_QUERY); /* this case is handled elsewhere */ - - switch (val) { - case AFMT_S16_LE: - if ((chan->pcm_fmt & VIA_PCM_FMT_16BIT) == 0) { - chan->pcm_fmt |= VIA_PCM_FMT_16BIT; - via_chan_pcm_fmt (chan, 0); - } - break; - - case AFMT_U8: - if (chan->pcm_fmt & VIA_PCM_FMT_16BIT) { - chan->pcm_fmt &= ~VIA_PCM_FMT_16BIT; - via_chan_pcm_fmt (chan, 0); - } - break; - - default: - DPRINTK ("unknown AFMT: 0x%X\n", val); - val = AFMT_S16_LE; - } - - DPRINTK ("EXIT\n"); - return val; -} - - -/** - * via_chan_set_stereo - Enable or disable stereo for a DMA channel - * @card: Private info for specified board - * @chan: Channel whose stereo setting will be adjusted - * @val: New sample size, use the %AFMT_xxx constants - * - * Helper function for the %SNDCTL_DSP_CHANNELS and %SNDCTL_DSP_STEREO ioctls. OSS semantics - * demand that all audio operations halt (if they are not already - * halted) when %SNDCTL_DSP_CHANNELS or SNDCTL_DSP_STEREO is given. - * - * This function halts all audio operations for the given channel - * @chan, and then calls via_chan_pcm_fmt to set the audio hardware - * to enable or disable stereo. - */ - -static int via_chan_set_stereo (struct via_info *card, - struct via_channel *chan, int val) -{ - DPRINTK ("ENTER, channels = %d\n", val); - - via_chan_clear (card, chan); - - switch (val) { - - /* mono */ - case 1: - chan->pcm_fmt &= ~VIA_PCM_FMT_STEREO; - chan->channels = 1; - via_chan_pcm_fmt (chan, 0); - break; - - /* stereo */ - case 2: - chan->pcm_fmt |= VIA_PCM_FMT_STEREO; - chan->channels = 2; - via_chan_pcm_fmt (chan, 0); - break; - - case 4: - case 6: - if(chan->is_multi) - { - chan->pcm_fmt |= VIA_PCM_FMT_STEREO; - chan->channels = val; - break; - } - /* unknown */ - default: - val = -EINVAL; - break; - } - - DPRINTK ("EXIT, returning %d\n", val); - return val; -} - -static int via_chan_set_buffering (struct via_info *card, - struct via_channel *chan, int val) -{ - int shift; - - DPRINTK ("ENTER\n"); - - /* in both cases the buffer cannot be changed */ - if (chan->is_active || chan->is_mapped) { - DPRINTK ("EXIT\n"); - return -EINVAL; - } - - /* called outside SETFRAGMENT */ - /* set defaults or do nothing */ - if (val < 0) { - - if (chan->frag_size && chan->frag_number) - goto out; - - DPRINTK ("\n"); - - chan->frag_size = (VIA_DEFAULT_FRAG_TIME * chan->rate * chan->channels - * ((chan->pcm_fmt & VIA_PCM_FMT_16BIT) ? 2 : 1)) / 1000 - 1; - - shift = 0; - while (chan->frag_size) { - chan->frag_size >>= 1; - shift++; - } - chan->frag_size = 1 << shift; - - chan->frag_number = (VIA_DEFAULT_BUFFER_TIME / VIA_DEFAULT_FRAG_TIME); - - DPRINTK ("setting default values %d %d\n", chan->frag_size, chan->frag_number); - } else { - chan->frag_size = 1 << (val & 0xFFFF); - chan->frag_number = (val >> 16) & 0xFFFF; - - DPRINTK ("using user values %d %d\n", chan->frag_size, chan->frag_number); - } - - /* quake3 wants frag_number to be a power of two */ - shift = 0; - while (chan->frag_number) { - chan->frag_number >>= 1; - shift++; - } - chan->frag_number = 1 << shift; - - if (chan->frag_size > VIA_MAX_FRAG_SIZE) - chan->frag_size = VIA_MAX_FRAG_SIZE; - else if (chan->frag_size < VIA_MIN_FRAG_SIZE) - chan->frag_size = VIA_MIN_FRAG_SIZE; - - if (chan->frag_number < VIA_MIN_FRAG_NUMBER) - chan->frag_number = VIA_MIN_FRAG_NUMBER; - if (chan->frag_number > VIA_MAX_FRAG_NUMBER) - chan->frag_number = VIA_MAX_FRAG_NUMBER; - - if ((chan->frag_number * chan->frag_size) / PAGE_SIZE > VIA_MAX_BUFFER_DMA_PAGES) - chan->frag_number = (VIA_MAX_BUFFER_DMA_PAGES * PAGE_SIZE) / chan->frag_size; - -out: - if (chan->is_record) - atomic_set (&chan->n_frags, 0); - else - atomic_set (&chan->n_frags, chan->frag_number); - - DPRINTK ("EXIT\n"); - - return 0; -} - -#ifdef VIA_CHAN_DUMP_BUFS -/** - * via_chan_dump_bufs - Display DMA table contents - * @chan: Channel whose DMA table will be displayed - * - * Debugging function which displays the contents of the - * scatter-gather DMA table for the given channel @chan. - */ - -static void via_chan_dump_bufs (struct via_channel *chan) -{ - int i; - - for (i = 0; i < chan->frag_number; i++) { - DPRINTK ("#%02d: addr=%x, count=%u, flag=%d, eol=%d\n", - i, chan->sgtable[i].addr, - chan->sgtable[i].count & 0x00FFFFFF, - chan->sgtable[i].count & VIA_FLAG ? 1 : 0, - chan->sgtable[i].count & VIA_EOL ? 1 : 0); - } - DPRINTK ("buf_in_use = %d, nextbuf = %d\n", - atomic_read (&chan->buf_in_use), - atomic_read (&chan->sw_ptr)); -} -#endif /* VIA_CHAN_DUMP_BUFS */ - - -/** - * via_chan_flush_frag - Flush partially-full playback buffer to hardware - * @chan: Channel whose DMA table will be flushed - * - * Flushes partially-full playback buffer to hardware. - */ - -static void via_chan_flush_frag (struct via_channel *chan) -{ - DPRINTK ("ENTER\n"); - - assert (chan->slop_len > 0); - - if (chan->sw_ptr == (chan->frag_number - 1)) - chan->sw_ptr = 0; - else - chan->sw_ptr++; - - chan->slop_len = 0; - - assert (atomic_read (&chan->n_frags) > 0); - atomic_dec (&chan->n_frags); - - DPRINTK ("EXIT\n"); -} - - - -/** - * via_chan_maybe_start - Initiate audio hardware DMA operation - * @chan: Channel whose DMA is to be started - * - * Initiate DMA operation, if the DMA engine for the given - * channel @chan is not already active. - */ - -static inline void via_chan_maybe_start (struct via_channel *chan) -{ - assert (chan->is_active == sg_active(chan->iobase)); - - DPRINTK ("MAYBE START %s\n", chan->name); - if (!chan->is_active && chan->is_enabled) { - chan->is_active = 1; - sg_begin (chan); - DPRINTK ("starting channel %s\n", chan->name); - } -} - - -/**************************************************************** - * - * Interface to ac97-codec module - * - * - */ - -/** - * via_ac97_wait_idle - Wait until AC97 codec is not busy - * @card: Private info for specified board - * - * Sleep until the AC97 codec is no longer busy. - * Returns the final value read from the SGD - * register being polled. - */ - -static u8 via_ac97_wait_idle (struct via_info *card) -{ - u8 tmp8; - int counter = VIA_COUNTER_LIMIT; - - DPRINTK ("ENTER/EXIT\n"); - - assert (card != NULL); - assert (card->pdev != NULL); - - do { - udelay (15); - - tmp8 = inb (card->baseaddr + 0x83); - } while ((tmp8 & VIA_CR83_BUSY) && (counter-- > 0)); - - if (tmp8 & VIA_CR83_BUSY) - printk (KERN_WARNING PFX "timeout waiting on AC97 codec\n"); - return tmp8; -} - - -/** - * via_ac97_read_reg - Read AC97 standard register - * @codec: Pointer to generic AC97 codec info - * @reg: Index of AC97 register to be read - * - * Read the value of a single AC97 codec register, - * as defined by the Intel AC97 specification. - * - * Defines the standard AC97 read-register operation - * required by the kernel's ac97_codec interface. - * - * Returns the 16-bit value stored in the specified - * register. - */ - -static u16 via_ac97_read_reg (struct ac97_codec *codec, u8 reg) -{ - unsigned long data; - struct via_info *card; - int counter; - - DPRINTK ("ENTER\n"); - - assert (codec != NULL); - assert (codec->private_data != NULL); - - card = codec->private_data; - - spin_lock(&card->ac97_lock); - - /* Every time we write to register 80 we cause a transaction. - The only safe way to clear the valid bit is to write it at - the same time as the command */ - data = (reg << 16) | VIA_CR80_READ | VIA_CR80_VALID; - - outl (data, card->baseaddr + VIA_BASE0_AC97_CTRL); - udelay (20); - - for (counter = VIA_COUNTER_LIMIT; counter > 0; counter--) { - udelay (1); - if ((((data = inl(card->baseaddr + VIA_BASE0_AC97_CTRL)) & - (VIA_CR80_VALID|VIA_CR80_BUSY)) == VIA_CR80_VALID)) - goto out; - } - - printk (KERN_WARNING PFX "timeout while reading AC97 codec (0x%lX)\n", data); - goto err_out; - -out: - /* Once the valid bit has become set, we must wait a complete AC97 - frame before the data has settled. */ - udelay(25); - data = (unsigned long) inl (card->baseaddr + VIA_BASE0_AC97_CTRL); - - outb (0x02, card->baseaddr + 0x83); - - if (((data & 0x007F0000) >> 16) == reg) { - DPRINTK ("EXIT, success, data=0x%lx, retval=0x%lx\n", - data, data & 0x0000FFFF); - spin_unlock(&card->ac97_lock); - return data & 0x0000FFFF; - } - - printk (KERN_WARNING "via82cxxx_audio: not our index: reg=0x%x, newreg=0x%lx\n", - reg, ((data & 0x007F0000) >> 16)); - -err_out: - spin_unlock(&card->ac97_lock); - DPRINTK ("EXIT, returning 0\n"); - return 0; -} - - -/** - * via_ac97_write_reg - Write AC97 standard register - * @codec: Pointer to generic AC97 codec info - * @reg: Index of AC97 register to be written - * @value: Value to be written to AC97 register - * - * Write the value of a single AC97 codec register, - * as defined by the Intel AC97 specification. - * - * Defines the standard AC97 write-register operation - * required by the kernel's ac97_codec interface. - */ - -static void via_ac97_write_reg (struct ac97_codec *codec, u8 reg, u16 value) -{ - u32 data; - struct via_info *card; - int counter; - - DPRINTK ("ENTER\n"); - - assert (codec != NULL); - assert (codec->private_data != NULL); - - card = codec->private_data; - - spin_lock(&card->ac97_lock); - - data = (reg << 16) + value; - outl (data, card->baseaddr + VIA_BASE0_AC97_CTRL); - udelay (10); - - for (counter = VIA_COUNTER_LIMIT; counter > 0; counter--) { - if ((inb (card->baseaddr + 0x83) & VIA_CR83_BUSY) == 0) - goto out; - - udelay (15); - } - - printk (KERN_WARNING PFX "timeout after AC97 codec write (0x%X, 0x%X)\n", reg, value); - -out: - spin_unlock(&card->ac97_lock); - DPRINTK ("EXIT\n"); -} - - -static int via_mixer_open (struct inode *inode, struct file *file) -{ - int minor = iminor(inode); - struct via_info *card; - struct pci_dev *pdev = NULL; - struct pci_driver *drvr; - - DPRINTK ("ENTER\n"); - - while ((pdev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, pdev)) != NULL) { - drvr = pci_dev_driver (pdev); - if (drvr == &via_driver) { - assert (pci_get_drvdata (pdev) != NULL); - - card = pci_get_drvdata (pdev); - if (card->ac97->dev_mixer == minor) - goto match; - } - } - - DPRINTK ("EXIT, returning -ENODEV\n"); - return -ENODEV; - -match: - pci_dev_put(pdev); - file->private_data = card->ac97; - - DPRINTK ("EXIT, returning 0\n"); - return nonseekable_open(inode, file); -} - -static int via_mixer_ioctl (struct inode *inode, struct file *file, unsigned int cmd, - unsigned long arg) -{ - struct ac97_codec *codec = file->private_data; - struct via_info *card; - int nonblock = (file->f_flags & O_NONBLOCK); - int rc; - - DPRINTK ("ENTER\n"); - - assert (codec != NULL); - card = codec->private_data; - assert (card != NULL); - - rc = via_syscall_down (card, nonblock); - if (rc) goto out; - -#if 0 - /* - * Intercept volume control on 8233 and 8235 - */ - if(card->volume) - { - switch(cmd) - { - case SOUND_MIXER_READ_VOLUME: - return card->mixer_vol; - case SOUND_MIXER_WRITE_VOLUME: - { - int v; - if(get_user(v, (int *)arg)) - { - rc = -EFAULT; - goto out; - } - card->mixer_vol = v; - } - } - } -#endif - rc = codec->mixer_ioctl(codec, cmd, arg); - - mutex_unlock(&card->syscall_mutex); - -out: - DPRINTK ("EXIT, returning %d\n", rc); - return rc; -} - - -static const struct file_operations via_mixer_fops = { - .owner = THIS_MODULE, - .open = via_mixer_open, - .llseek = no_llseek, - .ioctl = via_mixer_ioctl, -}; - - -static int __devinit via_ac97_reset (struct via_info *card) -{ - struct pci_dev *pdev = card->pdev; - u8 tmp8; - u16 tmp16; - - DPRINTK ("ENTER\n"); - - assert (pdev != NULL); - -#ifndef NDEBUG - { - u8 r40,r41,r42,r43,r44,r48; - pci_read_config_byte (card->pdev, 0x40, &r40); - pci_read_config_byte (card->pdev, 0x41, &r41); - pci_read_config_byte (card->pdev, 0x42, &r42); - pci_read_config_byte (card->pdev, 0x43, &r43); - pci_read_config_byte (card->pdev, 0x44, &r44); - pci_read_config_byte (card->pdev, 0x48, &r48); - DPRINTK ("PCI config: %02X %02X %02X %02X %02X %02X\n", - r40,r41,r42,r43,r44,r48); - - spin_lock_irq (&card->lock); - DPRINTK ("regs==%02X %02X %02X %08X %08X %08X %08X\n", - inb (card->baseaddr + 0x00), - inb (card->baseaddr + 0x01), - inb (card->baseaddr + 0x02), - inl (card->baseaddr + 0x04), - inl (card->baseaddr + 0x0C), - inl (card->baseaddr + 0x80), - inl (card->baseaddr + 0x84)); - spin_unlock_irq (&card->lock); - - } -#endif - - /* - * Reset AC97 controller: enable, disable, enable, - * pausing after each command for good luck. Only - * do this if the codec is not ready, because it causes - * loud pops and such due to such a hard codec reset. - */ - pci_read_config_byte (pdev, VIA_ACLINK_STATUS, &tmp8); - if ((tmp8 & VIA_CR40_AC97_READY) == 0) { - pci_write_config_byte (pdev, VIA_ACLINK_CTRL, - VIA_CR41_AC97_ENABLE | - VIA_CR41_AC97_RESET | - VIA_CR41_AC97_WAKEUP); - udelay (100); - - pci_write_config_byte (pdev, VIA_ACLINK_CTRL, 0); - udelay (100); - - pci_write_config_byte (pdev, VIA_ACLINK_CTRL, - VIA_CR41_AC97_ENABLE | - VIA_CR41_PCM_ENABLE | - VIA_CR41_VRA | VIA_CR41_AC97_RESET); - udelay (100); - } - - /* Make sure VRA is enabled, in case we didn't do a - * complete codec reset, above - */ - pci_read_config_byte (pdev, VIA_ACLINK_CTRL, &tmp8); - if (((tmp8 & VIA_CR41_VRA) == 0) || - ((tmp8 & VIA_CR41_AC97_ENABLE) == 0) || - ((tmp8 & VIA_CR41_PCM_ENABLE) == 0) || - ((tmp8 & VIA_CR41_AC97_RESET) == 0)) { - pci_write_config_byte (pdev, VIA_ACLINK_CTRL, - VIA_CR41_AC97_ENABLE | - VIA_CR41_PCM_ENABLE | - VIA_CR41_VRA | VIA_CR41_AC97_RESET); - udelay (100); - } - - if(card->legacy) - { -#if 0 /* this breaks on K7M */ - /* disable legacy stuff */ - pci_write_config_byte (pdev, 0x42, 0x00); - udelay(10); -#endif - - /* route FM trap to IRQ, disable FM trap */ - pci_write_config_byte (pdev, 0x48, 0x05); - udelay(10); - } - - /* disable all codec GPI interrupts */ - outl (0, pci_resource_start (pdev, 0) + 0x8C); - - /* WARNING: this line is magic. Remove this - * and things break. */ - /* enable variable rate */ - tmp16 = via_ac97_read_reg (card->ac97, AC97_EXTENDED_STATUS); - if ((tmp16 & 1) == 0) - via_ac97_write_reg (card->ac97, AC97_EXTENDED_STATUS, tmp16 | 1); - - DPRINTK ("EXIT, returning 0\n"); - return 0; -} - - -static void via_ac97_codec_wait (struct ac97_codec *codec) -{ - assert (codec->private_data != NULL); - via_ac97_wait_idle (codec->private_data); -} - - -static int __devinit via_ac97_init (struct via_info *card) -{ - int rc; - u16 tmp16; - - DPRINTK ("ENTER\n"); - - assert (card != NULL); - - card->ac97 = ac97_alloc_codec(); - if(card->ac97 == NULL) - return -ENOMEM; - - card->ac97->private_data = card; - card->ac97->codec_read = via_ac97_read_reg; - card->ac97->codec_write = via_ac97_write_reg; - card->ac97->codec_wait = via_ac97_codec_wait; - - card->ac97->dev_mixer = register_sound_mixer (&via_mixer_fops, -1); - if (card->ac97->dev_mixer < 0) { - printk (KERN_ERR PFX "unable to register AC97 mixer, aborting\n"); - DPRINTK ("EXIT, returning -EIO\n"); - ac97_release_codec(card->ac97); - return -EIO; - } - - rc = via_ac97_reset (card); - if (rc) { - printk (KERN_ERR PFX "unable to reset AC97 codec, aborting\n"); - goto err_out; - } - - mdelay(10); - - if (ac97_probe_codec (card->ac97) == 0) { - printk (KERN_ERR PFX "unable to probe AC97 codec, aborting\n"); - rc = -EIO; - goto err_out; - } - - /* enable variable rate */ - tmp16 = via_ac97_read_reg (card->ac97, AC97_EXTENDED_STATUS); - via_ac97_write_reg (card->ac97, AC97_EXTENDED_STATUS, tmp16 | 1); - - /* - * If we cannot enable VRA, we have a locked-rate codec. - * We try again to enable VRA before assuming so, however. - */ - tmp16 = via_ac97_read_reg (card->ac97, AC97_EXTENDED_STATUS); - if ((tmp16 & 1) == 0) { - via_ac97_write_reg (card->ac97, AC97_EXTENDED_STATUS, tmp16 | 1); - tmp16 = via_ac97_read_reg (card->ac97, AC97_EXTENDED_STATUS); - if ((tmp16 & 1) == 0) { - card->locked_rate = 1; - printk (KERN_WARNING PFX "Codec rate locked at 48Khz\n"); - } - } - - DPRINTK ("EXIT, returning 0\n"); - return 0; - -err_out: - unregister_sound_mixer (card->ac97->dev_mixer); - DPRINTK ("EXIT, returning %d\n", rc); - ac97_release_codec(card->ac97); - return rc; -} - - -static void via_ac97_cleanup (struct via_info *card) -{ - DPRINTK ("ENTER\n"); - - assert (card != NULL); - assert (card->ac97->dev_mixer >= 0); - - unregister_sound_mixer (card->ac97->dev_mixer); - ac97_release_codec(card->ac97); - - DPRINTK ("EXIT\n"); -} - - - -/**************************************************************** - * - * Interrupt-related code - * - */ - -/** - * via_intr_channel - handle an interrupt for a single channel - * @card: unused - * @chan: handle interrupt for this channel - * - * This is the "meat" of the interrupt handler, - * containing the actions taken each time an interrupt - * occurs. All communication and coordination with - * userspace takes place here. - * - * Locking: inside card->lock - */ - -static void via_intr_channel (struct via_info *card, struct via_channel *chan) -{ - u8 status; - int n; - - /* check pertinent bits of status register for action bits */ - status = inb (chan->iobase) & (VIA_SGD_FLAG | VIA_SGD_EOL | VIA_SGD_STOPPED); - if (!status) - return; - - /* acknowledge any flagged bits ASAP */ - outb (status, chan->iobase); - - if (!chan->sgtable) /* XXX: temporary solution */ - return; - - /* grab current h/w ptr value */ - n = atomic_read (&chan->hw_ptr); - - /* sanity check: make sure our h/w ptr doesn't have a weird value */ - assert (n >= 0); - assert (n < chan->frag_number); - - - /* reset SGD data structure in memory to reflect a full buffer, - * and advance the h/w ptr, wrapping around to zero if needed - */ - if (n == (chan->frag_number - 1)) { - chan->sgtable[n].count = cpu_to_le32(chan->frag_size | VIA_EOL); - atomic_set (&chan->hw_ptr, 0); - } else { - chan->sgtable[n].count = cpu_to_le32(chan->frag_size | VIA_FLAG); - atomic_inc (&chan->hw_ptr); - } - - /* accounting crap for SNDCTL_DSP_GETxPTR */ - chan->n_irqs++; - chan->bytes += chan->frag_size; - /* FIXME - signed overflow is undefined */ - if (chan->bytes < 0) /* handle overflow of 31-bit value */ - chan->bytes = chan->frag_size; - /* all following checks only occur when not in mmap(2) mode */ - if (!chan->is_mapped) - { - /* If we are recording, then n_frags represents the number - * of fragments waiting to be handled by userspace. - * If we are playback, then n_frags represents the number - * of fragments remaining to be filled by userspace. - * We increment here. If we reach max number of fragments, - * this indicates an underrun/overrun. For this case under OSS, - * we stop the record/playback process. - */ - if (atomic_read (&chan->n_frags) < chan->frag_number) - atomic_inc (&chan->n_frags); - assert (atomic_read (&chan->n_frags) <= chan->frag_number); - if (atomic_read (&chan->n_frags) == chan->frag_number) { - chan->is_active = 0; - via_chan_stop (chan->iobase); - } - } - /* wake up anyone listening to see when interrupts occur */ - wake_up_all (&chan->wait); - - DPRINTK ("%s intr, status=0x%02X, hwptr=0x%lX, chan->hw_ptr=%d\n", - chan->name, status, (long) inl (chan->iobase + 0x04), - atomic_read (&chan->hw_ptr)); - - DPRINTK ("%s intr, channel n_frags == %d, missed %d\n", chan->name, - atomic_read (&chan->n_frags), missed); -} - - -static irqreturn_t via_interrupt(int irq, void *dev_id) -{ - struct via_info *card = dev_id; - u32 status32; - - /* to minimize interrupt sharing costs, we use the SGD status - * shadow register to check the status of all inputs and - * outputs with a single 32-bit bus read. If no interrupt - * conditions are flagged, we exit immediately - */ - status32 = inl (card->baseaddr + VIA_BASE0_SGD_STATUS_SHADOW); - if (!(status32 & VIA_INTR_MASK)) - { -#ifdef CONFIG_MIDI_VIA82CXXX - if (card->midi_devc) - uart401intr(irq, card->midi_devc); -#endif - return IRQ_HANDLED; - } - DPRINTK ("intr, status32 == 0x%08X\n", status32); - - /* synchronize interrupt handling under SMP. this spinlock - * goes away completely on UP - */ - spin_lock (&card->lock); - - if (status32 & VIA_INTR_OUT) - via_intr_channel (card, &card->ch_out); - if (status32 & VIA_INTR_IN) - via_intr_channel (card, &card->ch_in); - if (status32 & VIA_INTR_FM) - via_intr_channel (card, &card->ch_fm); - - spin_unlock (&card->lock); - - return IRQ_HANDLED; -} - -static irqreturn_t via_new_interrupt(int irq, void *dev_id) -{ - struct via_info *card = dev_id; - u32 status32; - - /* to minimize interrupt sharing costs, we use the SGD status - * shadow register to check the status of all inputs and - * outputs with a single 32-bit bus read. If no interrupt - * conditions are flagged, we exit immediately - */ - status32 = inl (card->baseaddr + VIA_BASE0_SGD_STATUS_SHADOW); - if (!(status32 & VIA_NEW_INTR_MASK)) - return IRQ_NONE; - /* - * goes away completely on UP - */ - spin_lock (&card->lock); - - via_intr_channel (card, &card->ch_out); - via_intr_channel (card, &card->ch_in); - via_intr_channel (card, &card->ch_fm); - - spin_unlock (&card->lock); - return IRQ_HANDLED; -} - - -/** - * via_interrupt_init - Initialize interrupt handling - * @card: Private info for specified board - * - * Obtain and reserve IRQ for using in handling audio events. - * Also, disable any IRQ-generating resources, to make sure - * we don't get interrupts before we want them. - */ - -static int via_interrupt_init (struct via_info *card) -{ - u8 tmp8; - - DPRINTK ("ENTER\n"); - - assert (card != NULL); - assert (card->pdev != NULL); - - /* check for sane IRQ number. can this ever happen? */ - if (card->pdev->irq < 2) { - printk (KERN_ERR PFX "insane IRQ %d, aborting\n", - card->pdev->irq); - DPRINTK ("EXIT, returning -EIO\n"); - return -EIO; - } - - /* VIA requires this is done */ - pci_write_config_byte(card->pdev, PCI_INTERRUPT_LINE, card->pdev->irq); - - if(card->legacy) - { - /* make sure FM irq is not routed to us */ - pci_read_config_byte (card->pdev, VIA_FM_NMI_CTRL, &tmp8); - if ((tmp8 & VIA_CR48_FM_TRAP_TO_NMI) == 0) { - tmp8 |= VIA_CR48_FM_TRAP_TO_NMI; - pci_write_config_byte (card->pdev, VIA_FM_NMI_CTRL, tmp8); - } - if (request_irq (card->pdev->irq, via_interrupt, IRQF_SHARED, VIA_MODULE_NAME, card)) { - printk (KERN_ERR PFX "unable to obtain IRQ %d, aborting\n", - card->pdev->irq); - DPRINTK ("EXIT, returning -EBUSY\n"); - return -EBUSY; - } - } - else - { - if (request_irq (card->pdev->irq, via_new_interrupt, IRQF_SHARED, VIA_MODULE_NAME, card)) { - printk (KERN_ERR PFX "unable to obtain IRQ %d, aborting\n", - card->pdev->irq); - DPRINTK ("EXIT, returning -EBUSY\n"); - return -EBUSY; - } - } - - DPRINTK ("EXIT, returning 0\n"); - return 0; -} - - -/**************************************************************** - * - * OSS DSP device - * - */ - -static const struct file_operations via_dsp_fops = { - .owner = THIS_MODULE, - .open = via_dsp_open, - .release = via_dsp_release, - .read = via_dsp_read, - .write = via_dsp_write, - .poll = via_dsp_poll, - .llseek = no_llseek, - .ioctl = via_dsp_ioctl, - .mmap = via_dsp_mmap, -}; - - -static int __devinit via_dsp_init (struct via_info *card) -{ - u8 tmp8; - - DPRINTK ("ENTER\n"); - - assert (card != NULL); - - if(card->legacy) - { - /* turn off legacy features, if not already */ - pci_read_config_byte (card->pdev, VIA_FUNC_ENABLE, &tmp8); - if (tmp8 & (VIA_CR42_SB_ENABLE | VIA_CR42_FM_ENABLE)) { - tmp8 &= ~(VIA_CR42_SB_ENABLE | VIA_CR42_FM_ENABLE); - pci_write_config_byte (card->pdev, VIA_FUNC_ENABLE, tmp8); - } - } - - via_stop_everything (card); - - card->dev_dsp = register_sound_dsp (&via_dsp_fops, -1); - if (card->dev_dsp < 0) { - DPRINTK ("EXIT, returning -ENODEV\n"); - return -ENODEV; - } - DPRINTK ("EXIT, returning 0\n"); - return 0; -} - - -static void via_dsp_cleanup (struct via_info *card) -{ - DPRINTK ("ENTER\n"); - - assert (card != NULL); - assert (card->dev_dsp >= 0); - - via_stop_everything (card); - - unregister_sound_dsp (card->dev_dsp); - - DPRINTK ("EXIT\n"); -} - - -static struct page * via_mm_nopage (struct vm_area_struct * vma, - unsigned long address, int *type) -{ - struct via_info *card = vma->vm_private_data; - struct via_channel *chan = &card->ch_out; - unsigned long max_bufs; - struct page *dmapage; - unsigned long pgoff; - int rd, wr; - - DPRINTK ("ENTER, start %lXh, ofs %lXh, pgoff %ld, addr %lXh\n", - vma->vm_start, - address - vma->vm_start, - (address - vma->vm_start) >> PAGE_SHIFT, - address); - - if (address > vma->vm_end) { - DPRINTK ("EXIT, returning NOPAGE_SIGBUS\n"); - return NOPAGE_SIGBUS; /* Disallow mremap */ - } - if (!card) { - DPRINTK ("EXIT, returning NOPAGE_SIGBUS\n"); - return NOPAGE_SIGBUS; /* Nothing allocated */ - } - - pgoff = vma->vm_pgoff + ((address - vma->vm_start) >> PAGE_SHIFT); - rd = card->ch_in.is_mapped; - wr = card->ch_out.is_mapped; - - max_bufs = chan->frag_number; - if (rd && wr) - max_bufs *= 2; - if (pgoff >= max_bufs) - return NOPAGE_SIGBUS; - - /* if full-duplex (read+write) and we have two sets of bufs, - * then the playback buffers come first, sez soundcard.c */ - if (pgoff >= chan->page_number) { - pgoff -= chan->page_number; - chan = &card->ch_in; - } else if (!wr) - chan = &card->ch_in; - - assert ((((unsigned long)chan->pgtbl[pgoff].cpuaddr) % PAGE_SIZE) == 0); - - dmapage = virt_to_page (chan->pgtbl[pgoff].cpuaddr); - DPRINTK ("EXIT, returning page %p for cpuaddr %lXh\n", - dmapage, (unsigned long) chan->pgtbl[pgoff].cpuaddr); - get_page (dmapage); - if (type) - *type = VM_FAULT_MINOR; - return dmapage; -} - - -#ifndef VM_RESERVED -static int via_mm_swapout (struct page *page, struct file *filp) -{ - return 0; -} -#endif /* VM_RESERVED */ - - -static struct vm_operations_struct via_mm_ops = { - .nopage = via_mm_nopage, - -#ifndef VM_RESERVED - .swapout = via_mm_swapout, -#endif -}; - - -static int via_dsp_mmap(struct file *file, struct vm_area_struct *vma) -{ - struct via_info *card; - int nonblock = (file->f_flags & O_NONBLOCK); - int rc = -EINVAL, rd=0, wr=0; - unsigned long max_size, size, start, offset; - - assert (file != NULL); - assert (vma != NULL); - card = file->private_data; - assert (card != NULL); - - DPRINTK ("ENTER, start %lXh, size %ld, pgoff %ld\n", - vma->vm_start, - vma->vm_end - vma->vm_start, - vma->vm_pgoff); - - max_size = 0; - if (vma->vm_flags & VM_READ) { - rd = 1; - via_chan_set_buffering(card, &card->ch_in, -1); - via_chan_buffer_init (card, &card->ch_in); - max_size += card->ch_in.page_number << PAGE_SHIFT; - } - if (vma->vm_flags & VM_WRITE) { - wr = 1; - via_chan_set_buffering(card, &card->ch_out, -1); - via_chan_buffer_init (card, &card->ch_out); - max_size += card->ch_out.page_number << PAGE_SHIFT; - } - - start = vma->vm_start; - offset = (vma->vm_pgoff << PAGE_SHIFT); - size = vma->vm_end - vma->vm_start; - - /* some basic size/offset sanity checks */ - if (size > max_size) - goto out; - if (offset > max_size - size) - goto out; - - rc = via_syscall_down (card, nonblock); - if (rc) goto out; - - vma->vm_ops = &via_mm_ops; - vma->vm_private_data = card; - -#ifdef VM_RESERVED - vma->vm_flags |= VM_RESERVED; -#endif - - if (rd) - card->ch_in.is_mapped = 1; - if (wr) - card->ch_out.is_mapped = 1; - - mutex_unlock(&card->syscall_mutex); - rc = 0; - -out: - DPRINTK ("EXIT, returning %d\n", rc); - return rc; -} - - -static ssize_t via_dsp_do_read (struct via_info *card, - char __user *userbuf, size_t count, - int nonblock) -{ - DECLARE_WAITQUEUE(wait, current); - const char __user *orig_userbuf = userbuf; - struct via_channel *chan = &card->ch_in; - size_t size; - int n, tmp; - ssize_t ret = 0; - - /* if SGD has not yet been started, start it */ - via_chan_maybe_start (chan); - -handle_one_block: - /* just to be a nice neighbor */ - /* Thomas Sailer: - * But also to ourselves, release semaphore if we do so */ - if (need_resched()) { - mutex_unlock(&card->syscall_mutex); - schedule (); - ret = via_syscall_down (card, nonblock); - if (ret) - goto out; - } - - /* grab current channel software pointer. In the case of - * recording, this is pointing to the next buffer that - * will receive data from the audio hardware. - */ - n = chan->sw_ptr; - - /* n_frags represents the number of fragments waiting - * to be copied to userland. sleep until at least - * one buffer has been read from the audio hardware. - */ - add_wait_queue(&chan->wait, &wait); - for (;;) { - __set_current_state(TASK_INTERRUPTIBLE); - tmp = atomic_read (&chan->n_frags); - assert (tmp >= 0); - assert (tmp <= chan->frag_number); - if (tmp) - break; - if (nonblock || !chan->is_active) { - ret = -EAGAIN; - break; - } - - mutex_unlock(&card->syscall_mutex); - - DPRINTK ("Sleeping on block %d\n", n); - schedule(); - - ret = via_syscall_down (card, nonblock); - if (ret) - break; - - if (signal_pending (current)) { - ret = -ERESTARTSYS; - break; - } - } - set_current_state(TASK_RUNNING); - remove_wait_queue(&chan->wait, &wait); - if (ret) - goto out; - - /* Now that we have a buffer we can read from, send - * as much as sample data possible to userspace. - */ - while ((count > 0) && (chan->slop_len < chan->frag_size)) { - size_t slop_left = chan->frag_size - chan->slop_len; - void *base = chan->pgtbl[n / (PAGE_SIZE / chan->frag_size)].cpuaddr; - unsigned ofs = (n % (PAGE_SIZE / chan->frag_size)) * chan->frag_size; - - size = (count < slop_left) ? count : slop_left; - if (copy_to_user (userbuf, - base + ofs + chan->slop_len, - size)) { - ret = -EFAULT; - goto out; - } - - count -= size; - chan->slop_len += size; - userbuf += size; - } - - /* If we didn't copy the buffer completely to userspace, - * stop now. - */ - if (chan->slop_len < chan->frag_size) - goto out; - - /* - * If we get to this point, we copied one buffer completely - * to userspace, give the buffer back to the hardware. - */ - - /* advance channel software pointer to point to - * the next buffer from which we will copy - */ - if (chan->sw_ptr == (chan->frag_number - 1)) - chan->sw_ptr = 0; - else - chan->sw_ptr++; - - /* mark one less buffer waiting to be processed */ - assert (atomic_read (&chan->n_frags) > 0); - atomic_dec (&chan->n_frags); - - /* we are at a block boundary, there is no fragment data */ - chan->slop_len = 0; - - DPRINTK ("Flushed block %u, sw_ptr now %u, n_frags now %d\n", - n, chan->sw_ptr, atomic_read (&chan->n_frags)); - - DPRINTK ("regs==%02X %02X %02X %08X %08X %08X %08X\n", - inb (card->baseaddr + 0x00), - inb (card->baseaddr + 0x01), - inb (card->baseaddr + 0x02), - inl (card->baseaddr + 0x04), - inl (card->baseaddr + 0x0C), - inl (card->baseaddr + 0x80), - inl (card->baseaddr + 0x84)); - - if (count > 0) - goto handle_one_block; - -out: - return (userbuf != orig_userbuf) ? (userbuf - orig_userbuf) : ret; -} - - -static ssize_t via_dsp_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos) -{ - struct via_info *card; - int nonblock = (file->f_flags & O_NONBLOCK); - int rc; - - DPRINTK ("ENTER, file=%p, buffer=%p, count=%u, ppos=%lu\n", - file, buffer, count, ppos ? ((unsigned long)*ppos) : 0); - - assert (file != NULL); - card = file->private_data; - assert (card != NULL); - - rc = via_syscall_down (card, nonblock); - if (rc) goto out; - - if (card->ch_in.is_mapped) { - rc = -ENXIO; - goto out_up; - } - - via_chan_set_buffering(card, &card->ch_in, -1); - rc = via_chan_buffer_init (card, &card->ch_in); - - if (rc) - goto out_up; - - rc = via_dsp_do_read (card, buffer, count, nonblock); - -out_up: - mutex_unlock(&card->syscall_mutex); -out: - DPRINTK ("EXIT, returning %ld\n",(long) rc); - return rc; -} - - -static ssize_t via_dsp_do_write (struct via_info *card, - const char __user *userbuf, size_t count, - int nonblock) -{ - DECLARE_WAITQUEUE(wait, current); - const char __user *orig_userbuf = userbuf; - struct via_channel *chan = &card->ch_out; - volatile struct via_sgd_table *sgtable = chan->sgtable; - size_t size; - int n, tmp; - ssize_t ret = 0; - -handle_one_block: - /* just to be a nice neighbor */ - /* Thomas Sailer: - * But also to ourselves, release semaphore if we do so */ - if (need_resched()) { - mutex_unlock(&card->syscall_mutex); - schedule (); - ret = via_syscall_down (card, nonblock); - if (ret) - goto out; - } - - /* grab current channel fragment pointer. In the case of - * playback, this is pointing to the next fragment that - * should receive data from userland. - */ - n = chan->sw_ptr; - - /* n_frags represents the number of fragments remaining - * to be filled by userspace. Sleep until - * at least one fragment is available for our use. - */ - add_wait_queue(&chan->wait, &wait); - for (;;) { - __set_current_state(TASK_INTERRUPTIBLE); - tmp = atomic_read (&chan->n_frags); - assert (tmp >= 0); - assert (tmp <= chan->frag_number); - if (tmp) - break; - if (nonblock || !chan->is_active) { - ret = -EAGAIN; - break; - } - - mutex_unlock(&card->syscall_mutex); - - DPRINTK ("Sleeping on page %d, tmp==%d, ir==%d\n", n, tmp, chan->is_record); - schedule(); - - ret = via_syscall_down (card, nonblock); - if (ret) - break; - - if (signal_pending (current)) { - ret = -ERESTARTSYS; - break; - } - } - set_current_state(TASK_RUNNING); - remove_wait_queue(&chan->wait, &wait); - if (ret) - goto out; - - /* Now that we have at least one fragment we can write to, fill the buffer - * as much as possible with data from userspace. - */ - while ((count > 0) && (chan->slop_len < chan->frag_size)) { - size_t slop_left = chan->frag_size - chan->slop_len; - - size = (count < slop_left) ? count : slop_left; - if (copy_from_user (chan->pgtbl[n / (PAGE_SIZE / chan->frag_size)].cpuaddr + (n % (PAGE_SIZE / chan->frag_size)) * chan->frag_size + chan->slop_len, - userbuf, size)) { - ret = -EFAULT; - goto out; - } - - count -= size; - chan->slop_len += size; - userbuf += size; - } - - /* If we didn't fill up the buffer with data, stop now. - * Put a 'stop' marker in the DMA table too, to tell the - * audio hardware to stop if it gets here. - */ - if (chan->slop_len < chan->frag_size) { - sgtable[n].count = cpu_to_le32 (chan->slop_len | VIA_EOL | VIA_STOP); - goto out; - } - - /* - * If we get to this point, we have filled a buffer with - * audio data, flush the buffer to audio hardware. - */ - - /* Record the true size for the audio hardware to notice */ - if (n == (chan->frag_number - 1)) - sgtable[n].count = cpu_to_le32 (chan->frag_size | VIA_EOL); - else - sgtable[n].count = cpu_to_le32 (chan->frag_size | VIA_FLAG); - - /* advance channel software pointer to point to - * the next buffer we will fill with data - */ - if (chan->sw_ptr == (chan->frag_number - 1)) - chan->sw_ptr = 0; - else - chan->sw_ptr++; - - /* mark one less buffer as being available for userspace consumption */ - assert (atomic_read (&chan->n_frags) > 0); - atomic_dec (&chan->n_frags); - - /* we are at a block boundary, there is no fragment data */ - chan->slop_len = 0; - - /* if SGD has not yet been started, start it */ - via_chan_maybe_start (chan); - - DPRINTK ("Flushed block %u, sw_ptr now %u, n_frags now %d\n", - n, chan->sw_ptr, atomic_read (&chan->n_frags)); - - DPRINTK ("regs==S=%02X C=%02X TP=%02X BP=%08X RT=%08X SG=%08X CC=%08X SS=%08X\n", - inb (card->baseaddr + 0x00), - inb (card->baseaddr + 0x01), - inb (card->baseaddr + 0x02), - inl (card->baseaddr + 0x04), - inl (card->baseaddr + 0x08), - inl (card->baseaddr + 0x0C), - inl (card->baseaddr + 0x80), - inl (card->baseaddr + 0x84)); - - if (count > 0) - goto handle_one_block; - -out: - if (userbuf - orig_userbuf) - return userbuf - orig_userbuf; - else - return ret; -} - - -static ssize_t via_dsp_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos) -{ - struct via_info *card; - ssize_t rc; - int nonblock = (file->f_flags & O_NONBLOCK); - - DPRINTK ("ENTER, file=%p, buffer=%p, count=%u, ppos=%lu\n", - file, buffer, count, ppos ? ((unsigned long)*ppos) : 0); - - assert (file != NULL); - card = file->private_data; - assert (card != NULL); - - rc = via_syscall_down (card, nonblock); - if (rc) goto out; - - if (card->ch_out.is_mapped) { - rc = -ENXIO; - goto out_up; - } - - via_chan_set_buffering(card, &card->ch_out, -1); - rc = via_chan_buffer_init (card, &card->ch_out); - - if (rc) - goto out_up; - - rc = via_dsp_do_write (card, buffer, count, nonblock); - -out_up: - mutex_unlock(&card->syscall_mutex); -out: - DPRINTK ("EXIT, returning %ld\n",(long) rc); - return rc; -} - - -static unsigned int via_dsp_poll(struct file *file, struct poll_table_struct *wait) -{ - struct via_info *card; - struct via_channel *chan; - unsigned int mask = 0; - - DPRINTK ("ENTER\n"); - - assert (file != NULL); - card = file->private_data; - assert (card != NULL); - - if (file->f_mode & FMODE_READ) { - chan = &card->ch_in; - if (sg_active (chan->iobase)) - poll_wait(file, &chan->wait, wait); - if (atomic_read (&chan->n_frags) > 0) - mask |= POLLIN | POLLRDNORM; - } - - if (file->f_mode & FMODE_WRITE) { - chan = &card->ch_out; - if (sg_active (chan->iobase)) - poll_wait(file, &chan->wait, wait); - if (atomic_read (&chan->n_frags) > 0) - mask |= POLLOUT | POLLWRNORM; - } - - DPRINTK ("EXIT, returning %u\n", mask); - return mask; -} - - -/** - * via_dsp_drain_playback - sleep until all playback samples are flushed - * @card: Private info for specified board - * @chan: Channel to drain - * @nonblock: boolean, non-zero if O_NONBLOCK is set - * - * Sleeps until all playback has been flushed to the audio - * hardware. - * - * Locking: inside card->syscall_mutex - */ - -static int via_dsp_drain_playback (struct via_info *card, - struct via_channel *chan, int nonblock) -{ - DECLARE_WAITQUEUE(wait, current); - int ret = 0; - - DPRINTK ("ENTER, nonblock = %d\n", nonblock); - - if (chan->slop_len > 0) - via_chan_flush_frag (chan); - - if (atomic_read (&chan->n_frags) == chan->frag_number) - goto out; - - via_chan_maybe_start (chan); - - add_wait_queue(&chan->wait, &wait); - for (;;) { - DPRINTK ("FRAGS %d FRAGNUM %d\n", atomic_read(&chan->n_frags), chan->frag_number); - __set_current_state(TASK_INTERRUPTIBLE); - if (atomic_read (&chan->n_frags) >= chan->frag_number) - break; - - if (nonblock) { - DPRINTK ("EXIT, returning -EAGAIN\n"); - ret = -EAGAIN; - break; - } - -#ifdef VIA_DEBUG - { - u8 r40,r41,r42,r43,r44,r48; - pci_read_config_byte (card->pdev, 0x40, &r40); - pci_read_config_byte (card->pdev, 0x41, &r41); - pci_read_config_byte (card->pdev, 0x42, &r42); - pci_read_config_byte (card->pdev, 0x43, &r43); - pci_read_config_byte (card->pdev, 0x44, &r44); - pci_read_config_byte (card->pdev, 0x48, &r48); - DPRINTK ("PCI config: %02X %02X %02X %02X %02X %02X\n", - r40,r41,r42,r43,r44,r48); - - DPRINTK ("regs==%02X %02X %02X %08X %08X %08X %08X\n", - inb (card->baseaddr + 0x00), - inb (card->baseaddr + 0x01), - inb (card->baseaddr + 0x02), - inl (card->baseaddr + 0x04), - inl (card->baseaddr + 0x0C), - inl (card->baseaddr + 0x80), - inl (card->baseaddr + 0x84)); - } - - if (!chan->is_active) - printk (KERN_ERR "sleeping but not active\n"); -#endif - - mutex_unlock(&card->syscall_mutex); - - DPRINTK ("sleeping, nbufs=%d\n", atomic_read (&chan->n_frags)); - schedule(); - - if ((ret = via_syscall_down (card, nonblock))) - break; - - if (signal_pending (current)) { - DPRINTK ("EXIT, returning -ERESTARTSYS\n"); - ret = -ERESTARTSYS; - break; - } - } - set_current_state(TASK_RUNNING); - remove_wait_queue(&chan->wait, &wait); - -#ifdef VIA_DEBUG - { - u8 r40,r41,r42,r43,r44,r48; - pci_read_config_byte (card->pdev, 0x40, &r40); - pci_read_config_byte (card->pdev, 0x41, &r41); - pci_read_config_byte (card->pdev, 0x42, &r42); - pci_read_config_byte (card->pdev, 0x43, &r43); - pci_read_config_byte (card->pdev, 0x44, &r44); - pci_read_config_byte (card->pdev, 0x48, &r48); - DPRINTK ("PCI config: %02X %02X %02X %02X %02X %02X\n", - r40,r41,r42,r43,r44,r48); - - DPRINTK ("regs==%02X %02X %02X %08X %08X %08X %08X\n", - inb (card->baseaddr + 0x00), - inb (card->baseaddr + 0x01), - inb (card->baseaddr + 0x02), - inl (card->baseaddr + 0x04), - inl (card->baseaddr + 0x0C), - inl (card->baseaddr + 0x80), - inl (card->baseaddr + 0x84)); - - DPRINTK ("final nbufs=%d\n", atomic_read (&chan->n_frags)); - } -#endif - -out: - DPRINTK ("EXIT, returning %d\n", ret); - return ret; -} - - -/** - * via_dsp_ioctl_space - get information about channel buffering - * @card: Private info for specified board - * @chan: pointer to channel-specific info - * @arg: user buffer for returned information - * - * Handles SNDCTL_DSP_GETISPACE and SNDCTL_DSP_GETOSPACE. - * - * Locking: inside card->syscall_mutex - */ - -static int via_dsp_ioctl_space (struct via_info *card, - struct via_channel *chan, - void __user *arg) -{ - audio_buf_info info; - - via_chan_set_buffering(card, chan, -1); - - info.fragstotal = chan->frag_number; - info.fragsize = chan->frag_size; - - /* number of full fragments we can read/write without blocking */ - info.fragments = atomic_read (&chan->n_frags); - - if ((chan->slop_len % chan->frag_size > 0) && (info.fragments > 0)) - info.fragments--; - - /* number of bytes that can be read or written immediately - * without blocking. - */ - info.bytes = (info.fragments * chan->frag_size); - if (chan->slop_len % chan->frag_size > 0) - info.bytes += chan->frag_size - (chan->slop_len % chan->frag_size); - - DPRINTK ("EXIT, returning fragstotal=%d, fragsize=%d, fragments=%d, bytes=%d\n", - info.fragstotal, - info.fragsize, - info.fragments, - info.bytes); - - return copy_to_user (arg, &info, sizeof (info))?-EFAULT:0; -} - - -/** - * via_dsp_ioctl_ptr - get information about hardware buffer ptr - * @card: Private info for specified board - * @chan: pointer to channel-specific info - * @arg: user buffer for returned information - * - * Handles SNDCTL_DSP_GETIPTR and SNDCTL_DSP_GETOPTR. - * - * Locking: inside card->syscall_mutex - */ - -static int via_dsp_ioctl_ptr (struct via_info *card, - struct via_channel *chan, - void __user *arg) -{ - count_info info; - - spin_lock_irq (&card->lock); - - info.bytes = chan->bytes; - info.blocks = chan->n_irqs; - chan->n_irqs = 0; - - spin_unlock_irq (&card->lock); - - if (chan->is_active) { - unsigned long extra; - info.ptr = atomic_read (&chan->hw_ptr) * chan->frag_size; - extra = chan->frag_size - via_sg_offset(chan); - info.ptr += extra; - info.bytes += extra; - } else { - info.ptr = 0; - } - - DPRINTK ("EXIT, returning bytes=%d, blocks=%d, ptr=%d\n", - info.bytes, - info.blocks, - info.ptr); - - return copy_to_user (arg, &info, sizeof (info))?-EFAULT:0; -} - - -static int via_dsp_ioctl_trigger (struct via_channel *chan, int val) -{ - int enable, do_something; - - if (chan->is_record) - enable = (val & PCM_ENABLE_INPUT); - else - enable = (val & PCM_ENABLE_OUTPUT); - - if (!chan->is_enabled && enable) { - do_something = 1; - } else if (chan->is_enabled && !enable) { - do_something = -1; - } else { - do_something = 0; - } - - DPRINTK ("enable=%d, do_something=%d\n", - enable, do_something); - - if (chan->is_active && do_something) - return -EINVAL; - - if (do_something == 1) { - chan->is_enabled = 1; - via_chan_maybe_start (chan); - DPRINTK ("Triggering input\n"); - } - - else if (do_something == -1) { - chan->is_enabled = 0; - DPRINTK ("Setup input trigger\n"); - } - - return 0; -} - - -static int via_dsp_ioctl (struct inode *inode, struct file *file, - unsigned int cmd, unsigned long arg) -{ - int rc, rd=0, wr=0, val=0; - struct via_info *card; - struct via_channel *chan; - int nonblock = (file->f_flags & O_NONBLOCK); - int __user *ip = (int __user *)arg; - void __user *p = (void __user *)arg; - - assert (file != NULL); - card = file->private_data; - assert (card != NULL); - - if (file->f_mode & FMODE_WRITE) - wr = 1; - if (file->f_mode & FMODE_READ) - rd = 1; - - rc = via_syscall_down (card, nonblock); - if (rc) - return rc; - rc = -EINVAL; - - switch (cmd) { - - /* OSS API version. XXX unverified */ - case OSS_GETVERSION: - DPRINTK ("ioctl OSS_GETVERSION, EXIT, returning SOUND_VERSION\n"); - rc = put_user (SOUND_VERSION, ip); - break; - - /* list of supported PCM data formats */ - case SNDCTL_DSP_GETFMTS: - DPRINTK ("DSP_GETFMTS, EXIT, returning AFMT U8|S16_LE\n"); - rc = put_user (AFMT_U8 | AFMT_S16_LE, ip); - break; - - /* query or set current channel's PCM data format */ - case SNDCTL_DSP_SETFMT: - if (get_user(val, ip)) { - rc = -EFAULT; - break; - } - DPRINTK ("DSP_SETFMT, val==%d\n", val); - if (val != AFMT_QUERY) { - rc = 0; - - if (rd) - rc = via_chan_set_fmt (card, &card->ch_in, val); - - if (rc >= 0 && wr) - rc = via_chan_set_fmt (card, &card->ch_out, val); - - if (rc < 0) - break; - - val = rc; - } else { - if ((rd && (card->ch_in.pcm_fmt & VIA_PCM_FMT_16BIT)) || - (wr && (card->ch_out.pcm_fmt & VIA_PCM_FMT_16BIT))) - val = AFMT_S16_LE; - else - val = AFMT_U8; - } - DPRINTK ("SETFMT EXIT, returning %d\n", val); - rc = put_user (val, ip); - break; - - /* query or set number of channels (1=mono, 2=stereo, 4/6 for multichannel) */ - case SNDCTL_DSP_CHANNELS: - if (get_user(val, ip)) { - rc = -EFAULT; - break; - } - DPRINTK ("DSP_CHANNELS, val==%d\n", val); - if (val != 0) { - rc = 0; - - if (rd) - rc = via_chan_set_stereo (card, &card->ch_in, val); - - if (rc >= 0 && wr) - rc = via_chan_set_stereo (card, &card->ch_out, val); - - if (rc < 0) - break; - - val = rc; - } else { - if (rd) - val = card->ch_in.channels; - else - val = card->ch_out.channels; - } - DPRINTK ("CHANNELS EXIT, returning %d\n", val); - rc = put_user (val, ip); - break; - - /* enable (val is not zero) or disable (val == 0) stereo */ - case SNDCTL_DSP_STEREO: - if (get_user(val, ip)) { - rc = -EFAULT; - break; - } - DPRINTK ("DSP_STEREO, val==%d\n", val); - rc = 0; - - if (rd) - rc = via_chan_set_stereo (card, &card->ch_in, val ? 2 : 1); - if (rc >= 0 && wr) - rc = via_chan_set_stereo (card, &card->ch_out, val ? 2 : 1); - - if (rc < 0) - break; - - val = rc - 1; - - DPRINTK ("STEREO EXIT, returning %d\n", val); - rc = put_user(val, ip); - break; - - /* query or set sampling rate */ - case SNDCTL_DSP_SPEED: - if (get_user(val, ip)) { - rc = -EFAULT; - break; - } - DPRINTK ("DSP_SPEED, val==%d\n", val); - if (val < 0) { - rc = -EINVAL; - break; - } - if (val > 0) { - rc = 0; - - if (rd) - rc = via_chan_set_speed (card, &card->ch_in, val); - if (rc >= 0 && wr) - rc = via_chan_set_speed (card, &card->ch_out, val); - - if (rc < 0) - break; - - val = rc; - } else { - if (rd) - val = card->ch_in.rate; - else if (wr) - val = card->ch_out.rate; - else - val = 0; - } - DPRINTK ("SPEED EXIT, returning %d\n", val); - rc = put_user (val, ip); - break; - - /* wait until all buffers have been played, and then stop device */ - case SNDCTL_DSP_SYNC: - DPRINTK ("DSP_SYNC\n"); - rc = 0; - if (wr) { - DPRINTK ("SYNC EXIT (after calling via_dsp_drain_playback)\n"); - rc = via_dsp_drain_playback (card, &card->ch_out, nonblock); - } - break; - - /* stop recording/playback immediately */ - case SNDCTL_DSP_RESET: - DPRINTK ("DSP_RESET\n"); - if (rd) { - via_chan_clear (card, &card->ch_in); - card->ch_in.frag_number = 0; - card->ch_in.frag_size = 0; - atomic_set(&card->ch_in.n_frags, 0); - } - - if (wr) { - via_chan_clear (card, &card->ch_out); - card->ch_out.frag_number = 0; - card->ch_out.frag_size = 0; - atomic_set(&card->ch_out.n_frags, 0); - } - - rc = 0; - break; - - case SNDCTL_DSP_NONBLOCK: - file->f_flags |= O_NONBLOCK; - rc = 0; - break; - - /* obtain bitmask of device capabilities, such as mmap, full duplex, etc. */ - case SNDCTL_DSP_GETCAPS: - DPRINTK ("DSP_GETCAPS\n"); - rc = put_user(VIA_DSP_CAP, ip); - break; - - /* obtain buffer fragment size */ - case SNDCTL_DSP_GETBLKSIZE: - DPRINTK ("DSP_GETBLKSIZE\n"); - - if (rd) { - via_chan_set_buffering(card, &card->ch_in, -1); - rc = put_user(card->ch_in.frag_size, ip); - } else if (wr) { - via_chan_set_buffering(card, &card->ch_out, -1); - rc = put_user(card->ch_out.frag_size, ip); - } - break; - - /* obtain information about input buffering */ - case SNDCTL_DSP_GETISPACE: - DPRINTK ("DSP_GETISPACE\n"); - if (rd) - rc = via_dsp_ioctl_space (card, &card->ch_in, p); - break; - - /* obtain information about output buffering */ - case SNDCTL_DSP_GETOSPACE: - DPRINTK ("DSP_GETOSPACE\n"); - if (wr) - rc = via_dsp_ioctl_space (card, &card->ch_out, p); - break; - - /* obtain information about input hardware pointer */ - case SNDCTL_DSP_GETIPTR: - DPRINTK ("DSP_GETIPTR\n"); - if (rd) - rc = via_dsp_ioctl_ptr (card, &card->ch_in, p); - break; - - /* obtain information about output hardware pointer */ - case SNDCTL_DSP_GETOPTR: - DPRINTK ("DSP_GETOPTR\n"); - if (wr) - rc = via_dsp_ioctl_ptr (card, &card->ch_out, p); - break; - - /* return number of bytes remaining to be played by DMA engine */ - case SNDCTL_DSP_GETODELAY: - { - DPRINTK ("DSP_GETODELAY\n"); - - chan = &card->ch_out; - - if (!wr) - break; - - if (chan->is_active) { - - val = chan->frag_number - atomic_read (&chan->n_frags); - - assert(val >= 0); - - if (val > 0) { - val *= chan->frag_size; - val -= chan->frag_size - via_sg_offset(chan); - } - val += chan->slop_len % chan->frag_size; - } else - val = 0; - - assert (val <= (chan->frag_size * chan->frag_number)); - - DPRINTK ("GETODELAY EXIT, val = %d bytes\n", val); - rc = put_user (val, ip); - break; - } - - /* handle the quick-start of a channel, - * or the notification that a quick-start will - * occur in the future - */ - case SNDCTL_DSP_SETTRIGGER: - if (get_user(val, ip)) { - rc = -EFAULT; - break; - } - DPRINTK ("DSP_SETTRIGGER, rd=%d, wr=%d, act=%d/%d, en=%d/%d\n", - rd, wr, card->ch_in.is_active, card->ch_out.is_active, - card->ch_in.is_enabled, card->ch_out.is_enabled); - - rc = 0; - - if (rd) - rc = via_dsp_ioctl_trigger (&card->ch_in, val); - - if (!rc && wr) - rc = via_dsp_ioctl_trigger (&card->ch_out, val); - - break; - - case SNDCTL_DSP_GETTRIGGER: - val = 0; - if ((file->f_mode & FMODE_READ) && card->ch_in.is_enabled) - val |= PCM_ENABLE_INPUT; - if ((file->f_mode & FMODE_WRITE) && card->ch_out.is_enabled) - val |= PCM_ENABLE_OUTPUT; - rc = put_user(val, ip); - break; - - /* Enable full duplex. Since we do this as soon as we are opened - * with O_RDWR, this is mainly a no-op that always returns success. - */ - case SNDCTL_DSP_SETDUPLEX: - DPRINTK ("DSP_SETDUPLEX\n"); - if (!rd || !wr) - break; - rc = 0; - break; - - /* set fragment size. implemented as a successful no-op for now */ - case SNDCTL_DSP_SETFRAGMENT: - if (get_user(val, ip)) { - rc = -EFAULT; - break; - } - DPRINTK ("DSP_SETFRAGMENT, val==%d\n", val); - - if (rd) - rc = via_chan_set_buffering(card, &card->ch_in, val); - - if (wr) - rc = via_chan_set_buffering(card, &card->ch_out, val); - - DPRINTK ("SNDCTL_DSP_SETFRAGMENT (fragshift==0x%04X (%d), maxfrags==0x%04X (%d))\n", - val & 0xFFFF, - val & 0xFFFF, - (val >> 16) & 0xFFFF, - (val >> 16) & 0xFFFF); - - rc = 0; - break; - - /* inform device of an upcoming pause in input (or output). */ - case SNDCTL_DSP_POST: - DPRINTK ("DSP_POST\n"); - if (wr) { - if (card->ch_out.slop_len > 0) - via_chan_flush_frag (&card->ch_out); - via_chan_maybe_start (&card->ch_out); - } - - rc = 0; - break; - - /* not implemented */ - default: - DPRINTK ("unhandled ioctl, cmd==%u, arg==%p\n", - cmd, p); - break; - } - - mutex_unlock(&card->syscall_mutex); - DPRINTK ("EXIT, returning %d\n", rc); - return rc; -} - - -static int via_dsp_open (struct inode *inode, struct file *file) -{ - int minor = iminor(inode); - struct via_info *card; - struct pci_dev *pdev = NULL; - struct via_channel *chan; - struct pci_driver *drvr; - int nonblock = (file->f_flags & O_NONBLOCK); - - DPRINTK ("ENTER, minor=%d, file->f_mode=0x%x\n", minor, file->f_mode); - - if (!(file->f_mode & (FMODE_READ | FMODE_WRITE))) { - DPRINTK ("EXIT, returning -EINVAL\n"); - return -EINVAL; - } - - card = NULL; - while ((pdev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, pdev)) != NULL) { - drvr = pci_dev_driver (pdev); - if (drvr == &via_driver) { - assert (pci_get_drvdata (pdev) != NULL); - - card = pci_get_drvdata (pdev); - DPRINTK ("dev_dsp = %d, minor = %d, assn = %d\n", - card->dev_dsp, minor, - (card->dev_dsp ^ minor) & ~0xf); - - if (((card->dev_dsp ^ minor) & ~0xf) == 0) - goto match; - } - } - - DPRINTK ("no matching %s found\n", card ? "minor" : "driver"); - return -ENODEV; - -match: - pci_dev_put(pdev); - if (nonblock) { - if (!mutex_trylock(&card->open_mutex)) { - DPRINTK ("EXIT, returning -EAGAIN\n"); - return -EAGAIN; - } - } else { - if (mutex_lock_interruptible(&card->open_mutex)) { - DPRINTK ("EXIT, returning -ERESTARTSYS\n"); - return -ERESTARTSYS; - } - } - - file->private_data = card; - DPRINTK ("file->f_mode == 0x%x\n", file->f_mode); - - /* handle input from analog source */ - if (file->f_mode & FMODE_READ) { - chan = &card->ch_in; - - via_chan_init (card, chan); - - /* why is this forced to 16-bit stereo in all drivers? */ - chan->pcm_fmt = VIA_PCM_FMT_16BIT | VIA_PCM_FMT_STEREO; - chan->channels = 2; - - // TO DO - use FIFO: via_capture_fifo(card, 1); - via_chan_pcm_fmt (chan, 0); - via_set_rate (card->ac97, chan, 44100); - } - - /* handle output to analog source */ - if (file->f_mode & FMODE_WRITE) { - chan = &card->ch_out; - - via_chan_init (card, chan); - - if (file->f_mode & FMODE_READ) { - /* if in duplex mode make the recording and playback channels - have the same settings */ - chan->pcm_fmt = VIA_PCM_FMT_16BIT | VIA_PCM_FMT_STEREO; - chan->channels = 2; - via_chan_pcm_fmt (chan, 0); - via_set_rate (card->ac97, chan, 44100); - } else { - if ((minor & 0xf) == SND_DEV_DSP16) { - chan->pcm_fmt = VIA_PCM_FMT_16BIT; - via_chan_pcm_fmt (chan, 0); - via_set_rate (card->ac97, chan, 44100); - } else { - via_chan_pcm_fmt (chan, 1); - via_set_rate (card->ac97, chan, 8000); - } - } - } - - DPRINTK ("EXIT, returning 0\n"); - return nonseekable_open(inode, file); -} - - -static int via_dsp_release(struct inode *inode, struct file *file) -{ - struct via_info *card; - int nonblock = (file->f_flags & O_NONBLOCK); - int rc; - - DPRINTK ("ENTER\n"); - - assert (file != NULL); - card = file->private_data; - assert (card != NULL); - - rc = via_syscall_down (card, nonblock); - if (rc) { - DPRINTK ("EXIT (syscall_down error), rc=%d\n", rc); - return rc; - } - - if (file->f_mode & FMODE_WRITE) { - rc = via_dsp_drain_playback (card, &card->ch_out, nonblock); - if (rc && rc != -ERESTARTSYS) /* Nobody needs to know about ^C */ - printk (KERN_DEBUG "via_audio: ignoring drain playback error %d\n", rc); - - via_chan_free (card, &card->ch_out); - via_chan_buffer_free(card, &card->ch_out); - } - - if (file->f_mode & FMODE_READ) { - via_chan_free (card, &card->ch_in); - via_chan_buffer_free (card, &card->ch_in); - } - - mutex_unlock(&card->syscall_mutex); - mutex_unlock(&card->open_mutex); - - DPRINTK ("EXIT, returning 0\n"); - return 0; -} - - -/**************************************************************** - * - * Chip setup and kernel registration - * - * - */ - -static int __devinit via_init_one (struct pci_dev *pdev, const struct pci_device_id *id) -{ -#ifdef CONFIG_MIDI_VIA82CXXX - u8 r42; -#endif - int rc; - struct via_info *card; - static int printed_version; - - DPRINTK ("ENTER\n"); - - if (printed_version++ == 0) - printk (KERN_INFO "Via 686a/8233/8235 audio driver " VIA_VERSION "\n"); - - rc = pci_enable_device (pdev); - if (rc) - goto err_out; - - rc = pci_request_regions (pdev, "via82cxxx_audio"); - if (rc) - goto err_out_disable; - - rc = pci_set_dma_mask(pdev, DMA_32BIT_MASK); - if (rc) - goto err_out_res; - rc = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK); - if (rc) - goto err_out_res; - - card = kmalloc (sizeof (*card), GFP_KERNEL); - if (!card) { - printk (KERN_ERR PFX "out of memory, aborting\n"); - rc = -ENOMEM; - goto err_out_res; - } - - pci_set_drvdata (pdev, card); - - memset (card, 0, sizeof (*card)); - card->pdev = pdev; - card->baseaddr = pci_resource_start (pdev, 0); - card->card_num = via_num_cards++; - spin_lock_init (&card->lock); - spin_lock_init (&card->ac97_lock); - mutex_init(&card->syscall_mutex); - mutex_init(&card->open_mutex); - - /* we must init these now, in case the intr handler needs them */ - via_chan_init_defaults (card, &card->ch_out); - via_chan_init_defaults (card, &card->ch_in); - via_chan_init_defaults (card, &card->ch_fm); - - /* if BAR 2 is present, chip is Rev H or later, - * which means it has a few extra features */ - if (pci_resource_start (pdev, 2) > 0) - card->rev_h = 1; - - /* Overkill for now, but more flexible done right */ - - card->intmask = id->driver_data; - card->legacy = !card->intmask; - card->sixchannel = id->driver_data; - - if(card->sixchannel) - printk(KERN_INFO PFX "Six channel audio available\n"); - if (pdev->irq < 1) { - printk (KERN_ERR PFX "invalid PCI IRQ %d, aborting\n", pdev->irq); - rc = -ENODEV; - goto err_out_kfree; - } - - if (!(pci_resource_flags (pdev, 0) & IORESOURCE_IO)) { - printk (KERN_ERR PFX "unable to locate I/O resources, aborting\n"); - rc = -ENODEV; - goto err_out_kfree; - } - - pci_set_master(pdev); - - /* - * init AC97 mixer and codec - */ - rc = via_ac97_init (card); - if (rc) { - printk (KERN_ERR PFX "AC97 init failed, aborting\n"); - goto err_out_kfree; - } - - /* - * init DSP device - */ - rc = via_dsp_init (card); - if (rc) { - printk (KERN_ERR PFX "DSP device init failed, aborting\n"); - goto err_out_have_mixer; - } - - /* - * init and turn on interrupts, as the last thing we do - */ - rc = via_interrupt_init (card); - if (rc) { - printk (KERN_ERR PFX "interrupt init failed, aborting\n"); - goto err_out_have_dsp; - } - - printk (KERN_INFO PFX "board #%d at 0x%04lX, IRQ %d\n", - card->card_num + 1, card->baseaddr, pdev->irq); - -#ifdef CONFIG_MIDI_VIA82CXXX - /* Disable by default */ - card->midi_info.io_base = 0; - - if(card->legacy) - { - pci_read_config_byte (pdev, 0x42, &r42); - /* Disable MIDI interrupt */ - pci_write_config_byte (pdev, 0x42, r42 | VIA_CR42_MIDI_IRQMASK); - if (r42 & VIA_CR42_MIDI_ENABLE) - { - if (r42 & VIA_CR42_MIDI_PNP) /* Address selected by iobase 2 - not tested */ - card->midi_info.io_base = pci_resource_start (pdev, 2); - else /* Address selected by byte 0x43 */ - { - u8 r43; - pci_read_config_byte (pdev, 0x43, &r43); - card->midi_info.io_base = 0x300 + ((r43 & 0x0c) << 2); - } - - card->midi_info.irq = -pdev->irq; - if (probe_uart401(& card->midi_info, THIS_MODULE)) - { - card->midi_devc=midi_devs[card->midi_info.slots[4]]->devc; - pci_write_config_byte(pdev, 0x42, r42 & ~VIA_CR42_MIDI_IRQMASK); - printk("Enabled Via MIDI\n"); - } - } - } -#endif - - DPRINTK ("EXIT, returning 0\n"); - return 0; - -err_out_have_dsp: - via_dsp_cleanup (card); - -err_out_have_mixer: - via_ac97_cleanup (card); - -err_out_kfree: -#ifndef VIA_NDEBUG - memset (card, OSS_POISON_FREE, sizeof (*card)); /* poison memory */ -#endif - kfree (card); - -err_out_res: - pci_release_regions (pdev); - -err_out_disable: - pci_disable_device (pdev); - -err_out: - pci_set_drvdata (pdev, NULL); - DPRINTK ("EXIT - returning %d\n", rc); - return rc; -} - - -static void __devexit via_remove_one (struct pci_dev *pdev) -{ - struct via_info *card; - - DPRINTK ("ENTER\n"); - - assert (pdev != NULL); - card = pci_get_drvdata (pdev); - assert (card != NULL); - -#ifdef CONFIG_MIDI_VIA82CXXX - if (card->midi_info.io_base) - unload_uart401(&card->midi_info); -#endif - - free_irq (card->pdev->irq, card); - via_dsp_cleanup (card); - via_ac97_cleanup (card); - -#ifndef VIA_NDEBUG - memset (card, OSS_POISON_FREE, sizeof (*card)); /* poison memory */ -#endif - kfree (card); - - pci_set_drvdata (pdev, NULL); - - pci_release_regions (pdev); - pci_disable_device (pdev); - pci_set_power_state (pdev, 3); /* ...zzzzzz */ - - DPRINTK ("EXIT\n"); - return; -} - - -/**************************************************************** - * - * Driver initialization and cleanup - * - * - */ - -static int __init init_via82cxxx_audio(void) -{ - int rc; - - DPRINTK ("ENTER\n"); - - rc = pci_register_driver (&via_driver); - if (rc) { - DPRINTK ("EXIT, returning %d\n", rc); - return rc; - } - - DPRINTK ("EXIT, returning 0\n"); - return 0; -} - - -static void __exit cleanup_via82cxxx_audio(void) -{ - DPRINTK ("ENTER\n"); - - pci_unregister_driver (&via_driver); - - DPRINTK ("EXIT\n"); -} - - -module_init(init_via82cxxx_audio); -module_exit(cleanup_via82cxxx_audio); - -MODULE_AUTHOR("Jeff Garzik"); -MODULE_DESCRIPTION("DSP audio and mixer driver for Via 82Cxxx audio devices"); -MODULE_LICENSE("GPL"); - |