Merge /spare/repo/netdev-2.6 branch 'ieee80211'
This commit is contained in:
		
				commit
				
					
						aa8f6dfd35
					
				
			
		
					 322 changed files with 19316 additions and 15355 deletions
				
			
		
							
								
								
									
										176
									
								
								Documentation/block/ioprio.txt
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										176
									
								
								Documentation/block/ioprio.txt
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,176 @@
 | 
				
			||||||
 | 
					Block io priorities
 | 
				
			||||||
 | 
					===================
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Intro
 | 
				
			||||||
 | 
					-----
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					With the introduction of cfq v3 (aka cfq-ts or time sliced cfq), basic io
 | 
				
			||||||
 | 
					priorities is supported for reads on files. This enables users to io nice
 | 
				
			||||||
 | 
					processes or process groups, similar to what has been possible to cpu
 | 
				
			||||||
 | 
					scheduling for ages. This document mainly details the current possibilites
 | 
				
			||||||
 | 
					with cfq, other io schedulers do not support io priorities so far.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Scheduling classes
 | 
				
			||||||
 | 
					------------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					CFQ implements three generic scheduling classes that determine how io is
 | 
				
			||||||
 | 
					served for a process.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					IOPRIO_CLASS_RT: This is the realtime io class. This scheduling class is given
 | 
				
			||||||
 | 
					higher priority than any other in the system, processes from this class are
 | 
				
			||||||
 | 
					given first access to the disk every time. Thus it needs to be used with some
 | 
				
			||||||
 | 
					care, one io RT process can starve the entire system. Within the RT class,
 | 
				
			||||||
 | 
					there are 8 levels of class data that determine exactly how much time this
 | 
				
			||||||
 | 
					process needs the disk for on each service. In the future this might change
 | 
				
			||||||
 | 
					to be more directly mappable to performance, by passing in a wanted data
 | 
				
			||||||
 | 
					rate instead.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					IOPRIO_CLASS_BE: This is the best-effort scheduling class, which is the default
 | 
				
			||||||
 | 
					for any process that hasn't set a specific io priority. The class data
 | 
				
			||||||
 | 
					determines how much io bandwidth the process will get, it's directly mappable
 | 
				
			||||||
 | 
					to the cpu nice levels just more coarsely implemented. 0 is the highest
 | 
				
			||||||
 | 
					BE prio level, 7 is the lowest. The mapping between cpu nice level and io
 | 
				
			||||||
 | 
					nice level is determined as: io_nice = (cpu_nice + 20) / 5.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					IOPRIO_CLASS_IDLE: This is the idle scheduling class, processes running at this
 | 
				
			||||||
 | 
					level only get io time when no one else needs the disk. The idle class has no
 | 
				
			||||||
 | 
					class data, since it doesn't really apply here.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Tools
 | 
				
			||||||
 | 
					-----
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					See below for a sample ionice tool. Usage:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# ionice -c<class> -n<level> -p<pid>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					If pid isn't given, the current process is assumed. IO priority settings
 | 
				
			||||||
 | 
					are inherited on fork, so you can use ionice to start the process at a given
 | 
				
			||||||
 | 
					level:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# ionice -c2 -n0 /bin/ls
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					will run ls at the best-effort scheduling class at the highest priority.
 | 
				
			||||||
 | 
					For a running process, you can give the pid instead:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# ionice -c1 -n2 -p100
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					will change pid 100 to run at the realtime scheduling class, at priority 2.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					---> snip ionice.c tool <---
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <stdio.h>
 | 
				
			||||||
 | 
					#include <stdlib.h>
 | 
				
			||||||
 | 
					#include <errno.h>
 | 
				
			||||||
 | 
					#include <getopt.h>
 | 
				
			||||||
 | 
					#include <unistd.h>
 | 
				
			||||||
 | 
					#include <sys/ptrace.h>
 | 
				
			||||||
 | 
					#include <asm/unistd.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					extern int sys_ioprio_set(int, int, int);
 | 
				
			||||||
 | 
					extern int sys_ioprio_get(int, int);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#if defined(__i386__)
 | 
				
			||||||
 | 
					#define __NR_ioprio_set		289
 | 
				
			||||||
 | 
					#define __NR_ioprio_get		290
 | 
				
			||||||
 | 
					#elif defined(__ppc__)
 | 
				
			||||||
 | 
					#define __NR_ioprio_set		273
 | 
				
			||||||
 | 
					#define __NR_ioprio_get		274
 | 
				
			||||||
 | 
					#elif defined(__x86_64__)
 | 
				
			||||||
 | 
					#define __NR_ioprio_set		251
 | 
				
			||||||
 | 
					#define __NR_ioprio_get		252
 | 
				
			||||||
 | 
					#elif defined(__ia64__)
 | 
				
			||||||
 | 
					#define __NR_ioprio_set		1274
 | 
				
			||||||
 | 
					#define __NR_ioprio_get		1275
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
 | 
					#error "Unsupported arch"
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					_syscall3(int, ioprio_set, int, which, int, who, int, ioprio);
 | 
				
			||||||
 | 
					_syscall2(int, ioprio_get, int, which, int, who);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					enum {
 | 
				
			||||||
 | 
						IOPRIO_CLASS_NONE,
 | 
				
			||||||
 | 
						IOPRIO_CLASS_RT,
 | 
				
			||||||
 | 
						IOPRIO_CLASS_BE,
 | 
				
			||||||
 | 
						IOPRIO_CLASS_IDLE,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					enum {
 | 
				
			||||||
 | 
						IOPRIO_WHO_PROCESS = 1,
 | 
				
			||||||
 | 
						IOPRIO_WHO_PGRP,
 | 
				
			||||||
 | 
						IOPRIO_WHO_USER,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define IOPRIO_CLASS_SHIFT	13
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const char *to_prio[] = { "none", "realtime", "best-effort", "idle", };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int main(int argc, char *argv[])
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						int ioprio = 4, set = 0, ioprio_class = IOPRIO_CLASS_BE;
 | 
				
			||||||
 | 
						int c, pid = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						while ((c = getopt(argc, argv, "+n:c:p:")) != EOF) {
 | 
				
			||||||
 | 
							switch (c) {
 | 
				
			||||||
 | 
							case 'n':
 | 
				
			||||||
 | 
								ioprio = strtol(optarg, NULL, 10);
 | 
				
			||||||
 | 
								set = 1;
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							case 'c':
 | 
				
			||||||
 | 
								ioprio_class = strtol(optarg, NULL, 10);
 | 
				
			||||||
 | 
								set = 1;
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							case 'p':
 | 
				
			||||||
 | 
								pid = strtol(optarg, NULL, 10);
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						switch (ioprio_class) {
 | 
				
			||||||
 | 
							case IOPRIO_CLASS_NONE:
 | 
				
			||||||
 | 
								ioprio_class = IOPRIO_CLASS_BE;
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							case IOPRIO_CLASS_RT:
 | 
				
			||||||
 | 
							case IOPRIO_CLASS_BE:
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							case IOPRIO_CLASS_IDLE:
 | 
				
			||||||
 | 
								ioprio = 7;
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							default:
 | 
				
			||||||
 | 
								printf("bad prio class %d\n", ioprio_class);
 | 
				
			||||||
 | 
								return 1;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!set) {
 | 
				
			||||||
 | 
							if (!pid && argv[optind])
 | 
				
			||||||
 | 
								pid = strtol(argv[optind], NULL, 10);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							ioprio = ioprio_get(IOPRIO_WHO_PROCESS, pid);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							printf("pid=%d, %d\n", pid, ioprio);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (ioprio == -1)
 | 
				
			||||||
 | 
								perror("ioprio_get");
 | 
				
			||||||
 | 
							else {
 | 
				
			||||||
 | 
								ioprio_class = ioprio >> IOPRIO_CLASS_SHIFT;
 | 
				
			||||||
 | 
								ioprio = ioprio & 0xff;
 | 
				
			||||||
 | 
								printf("%s: prio %d\n", to_prio[ioprio_class], ioprio);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							if (ioprio_set(IOPRIO_WHO_PROCESS, pid, ioprio | ioprio_class << IOPRIO_CLASS_SHIFT) == -1) {
 | 
				
			||||||
 | 
								perror("ioprio_set");
 | 
				
			||||||
 | 
								return 1;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (argv[optind])
 | 
				
			||||||
 | 
								execvp(argv[optind], &argv[optind]);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					---> snip ionice.c tool <---
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					March 11 2005, Jens Axboe <axboe@suse.de>
 | 
				
			||||||
| 
						 | 
					@ -17,6 +17,7 @@ This driver is known to work with the following cards:
 | 
				
			||||||
	* SA P600
 | 
						* SA P600
 | 
				
			||||||
	* SA P800
 | 
						* SA P800
 | 
				
			||||||
	* SA E400
 | 
						* SA E400
 | 
				
			||||||
 | 
						* SA E300
 | 
				
			||||||
 | 
					
 | 
				
			||||||
If nodes are not already created in the /dev/cciss directory, run as root:
 | 
					If nodes are not already created in the /dev/cciss directory, run as root:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1115,7 +1115,7 @@ running once the system is up.
 | 
				
			||||||
			See Documentation/ramdisk.txt.
 | 
								See Documentation/ramdisk.txt.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	psmouse.proto=  [HW,MOUSE] Highest PS2 mouse protocol extension to
 | 
						psmouse.proto=  [HW,MOUSE] Highest PS2 mouse protocol extension to
 | 
				
			||||||
			probe for (bare|imps|exps).
 | 
								probe for (bare|imps|exps|lifebook|any).
 | 
				
			||||||
	psmouse.rate=	[HW,MOUSE] Set desired mouse report rate, in reports
 | 
						psmouse.rate=	[HW,MOUSE] Set desired mouse report rate, in reports
 | 
				
			||||||
			per second.
 | 
								per second.
 | 
				
			||||||
	psmouse.resetafter=
 | 
						psmouse.resetafter=
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1156,7 +1156,7 @@ S:	Maintained
 | 
				
			||||||
 | 
					
 | 
				
			||||||
INFINIBAND SUBSYSTEM
 | 
					INFINIBAND SUBSYSTEM
 | 
				
			||||||
P:	Roland Dreier
 | 
					P:	Roland Dreier
 | 
				
			||||||
M:	roland@topspin.com
 | 
					M:	rolandd@cisco.com
 | 
				
			||||||
P:	Sean Hefty
 | 
					P:	Sean Hefty
 | 
				
			||||||
M:	mshefty@ichips.intel.com
 | 
					M:	mshefty@ichips.intel.com
 | 
				
			||||||
P:	Hal Rosenstock
 | 
					P:	Hal Rosenstock
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -32,6 +32,7 @@
 | 
				
			||||||
#include <asm/leds.h>
 | 
					#include <asm/leds.h>
 | 
				
			||||||
#include <asm/processor.h>
 | 
					#include <asm/processor.h>
 | 
				
			||||||
#include <asm/uaccess.h>
 | 
					#include <asm/uaccess.h>
 | 
				
			||||||
 | 
					#include <asm/mach/time.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
extern const char *processor_modes[];
 | 
					extern const char *processor_modes[];
 | 
				
			||||||
extern void setup_mm_for_reboot(char mode);
 | 
					extern void setup_mm_for_reboot(char mode);
 | 
				
			||||||
| 
						 | 
					@ -85,8 +86,10 @@ EXPORT_SYMBOL(pm_power_off);
 | 
				
			||||||
void default_idle(void)
 | 
					void default_idle(void)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	local_irq_disable();
 | 
						local_irq_disable();
 | 
				
			||||||
	if (!need_resched() && !hlt_counter)
 | 
						if (!need_resched() && !hlt_counter) {
 | 
				
			||||||
 | 
							timer_dyn_reprogram();
 | 
				
			||||||
		arch_idle();
 | 
							arch_idle();
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
	local_irq_enable();
 | 
						local_irq_enable();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -424,15 +424,19 @@ static int timer_dyn_tick_disable(void)
 | 
				
			||||||
	return ret;
 | 
						return ret;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Reprogram the system timer for at least the calculated time interval.
 | 
				
			||||||
 | 
					 * This function should be called from the idle thread with IRQs disabled,
 | 
				
			||||||
 | 
					 * immediately before sleeping.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
void timer_dyn_reprogram(void)
 | 
					void timer_dyn_reprogram(void)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct dyn_tick_timer *dyn_tick = system_timer->dyn_tick;
 | 
						struct dyn_tick_timer *dyn_tick = system_timer->dyn_tick;
 | 
				
			||||||
	unsigned long flags;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	write_seqlock_irqsave(&xtime_lock, flags);
 | 
						write_seqlock(&xtime_lock);
 | 
				
			||||||
	if (dyn_tick->state & DYN_TICK_ENABLED)
 | 
						if (dyn_tick->state & DYN_TICK_ENABLED)
 | 
				
			||||||
		dyn_tick->reprogram(next_timer_interrupt() - jiffies);
 | 
							dyn_tick->reprogram(next_timer_interrupt() - jiffies);
 | 
				
			||||||
	write_sequnlock_irqrestore(&xtime_lock, flags);
 | 
						write_sequnlock(&xtime_lock);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static ssize_t timer_show_dyn_tick(struct sys_device *dev, char *buf)
 | 
					static ssize_t timer_show_dyn_tick(struct sys_device *dev, char *buf)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										1
									
								
								arch/arm/mach-aaec2000/Makefile.boot
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								arch/arm/mach-aaec2000/Makefile.boot
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1 @@
 | 
				
			||||||
 | 
						zreladdr-y := 0xf0008000
 | 
				
			||||||
| 
						 | 
					@ -288,8 +288,8 @@ static void usb_release(struct device *dev)
 | 
				
			||||||
static struct resource udc_resources[] = {
 | 
					static struct resource udc_resources[] = {
 | 
				
			||||||
	/* order is significant! */
 | 
						/* order is significant! */
 | 
				
			||||||
	{		/* registers */
 | 
						{		/* registers */
 | 
				
			||||||
		.start		= IO_ADDRESS(UDC_BASE),
 | 
							.start		= UDC_BASE,
 | 
				
			||||||
		.end		= IO_ADDRESS(UDC_BASE + 0xff),
 | 
							.end		= UDC_BASE + 0xff,
 | 
				
			||||||
		.flags		= IORESOURCE_MEM,
 | 
							.flags		= IORESOURCE_MEM,
 | 
				
			||||||
	}, {		/* general IRQ */
 | 
						}, {		/* general IRQ */
 | 
				
			||||||
		.start		= IH2_BASE + 20,
 | 
							.start		= IH2_BASE + 20,
 | 
				
			||||||
| 
						 | 
					@ -355,8 +355,8 @@ static struct platform_device ohci_device = {
 | 
				
			||||||
static struct resource otg_resources[] = {
 | 
					static struct resource otg_resources[] = {
 | 
				
			||||||
	/* order is significant! */
 | 
						/* order is significant! */
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		.start		= IO_ADDRESS(OTG_BASE),
 | 
							.start		= OTG_BASE,
 | 
				
			||||||
		.end		= IO_ADDRESS(OTG_BASE + 0xff),
 | 
							.end		= OTG_BASE + 0xff,
 | 
				
			||||||
		.flags		= IORESOURCE_MEM,
 | 
							.flags		= IORESOURCE_MEM,
 | 
				
			||||||
	}, {
 | 
						}, {
 | 
				
			||||||
		.start		= IH2_BASE + 8,
 | 
							.start		= IH2_BASE + 8,
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -522,6 +522,69 @@ static inline void free_area(unsigned long addr, unsigned long end, char *s)
 | 
				
			||||||
		printk(KERN_INFO "Freeing %s memory: %dK\n", s, size);
 | 
							printk(KERN_INFO "Freeing %s memory: %dK\n", s, size);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static inline void
 | 
				
			||||||
 | 
					free_memmap(int node, unsigned long start_pfn, unsigned long end_pfn)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct page *start_pg, *end_pg;
 | 
				
			||||||
 | 
						unsigned long pg, pgend;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/*
 | 
				
			||||||
 | 
						 * Convert start_pfn/end_pfn to a struct page pointer.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						start_pg = pfn_to_page(start_pfn);
 | 
				
			||||||
 | 
						end_pg = pfn_to_page(end_pfn);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/*
 | 
				
			||||||
 | 
						 * Convert to physical addresses, and
 | 
				
			||||||
 | 
						 * round start upwards and end downwards.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						pg = PAGE_ALIGN(__pa(start_pg));
 | 
				
			||||||
 | 
						pgend = __pa(end_pg) & PAGE_MASK;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/*
 | 
				
			||||||
 | 
						 * If there are free pages between these,
 | 
				
			||||||
 | 
						 * free the section of the memmap array.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						if (pg < pgend)
 | 
				
			||||||
 | 
							free_bootmem_node(NODE_DATA(node), pg, pgend - pg);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * The mem_map array can get very big.  Free the unused area of the memory map.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					static void __init free_unused_memmap_node(int node, struct meminfo *mi)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						unsigned long bank_start, prev_bank_end = 0;
 | 
				
			||||||
 | 
						unsigned int i;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/*
 | 
				
			||||||
 | 
						 * [FIXME] This relies on each bank being in address order.  This
 | 
				
			||||||
 | 
						 * may not be the case, especially if the user has provided the
 | 
				
			||||||
 | 
						 * information on the command line.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						for (i = 0; i < mi->nr_banks; i++) {
 | 
				
			||||||
 | 
							if (mi->bank[i].size == 0 || mi->bank[i].node != node)
 | 
				
			||||||
 | 
								continue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							bank_start = mi->bank[i].start >> PAGE_SHIFT;
 | 
				
			||||||
 | 
							if (bank_start < prev_bank_end) {
 | 
				
			||||||
 | 
								printk(KERN_ERR "MEM: unordered memory banks.  "
 | 
				
			||||||
 | 
									"Not freeing memmap.\n");
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							/*
 | 
				
			||||||
 | 
							 * If we had a previous bank, and there is a space
 | 
				
			||||||
 | 
							 * between the current bank and the previous, free it.
 | 
				
			||||||
 | 
							 */
 | 
				
			||||||
 | 
							if (prev_bank_end && prev_bank_end != bank_start)
 | 
				
			||||||
 | 
								free_memmap(node, prev_bank_end, bank_start);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							prev_bank_end = (mi->bank[i].start +
 | 
				
			||||||
 | 
									 mi->bank[i].size) >> PAGE_SHIFT;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 * mem_init() marks the free areas in the mem_map and tells us how much
 | 
					 * mem_init() marks the free areas in the mem_map and tells us how much
 | 
				
			||||||
 * memory is free.  This is done after various parts of the system have
 | 
					 * memory is free.  This is done after various parts of the system have
 | 
				
			||||||
| 
						 | 
					@ -540,16 +603,12 @@ void __init mem_init(void)
 | 
				
			||||||
	max_mapnr   = virt_to_page(high_memory) - mem_map;
 | 
						max_mapnr   = virt_to_page(high_memory) - mem_map;
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/*
 | 
					 | 
				
			||||||
	 * We may have non-contiguous memory.
 | 
					 | 
				
			||||||
	 */
 | 
					 | 
				
			||||||
	if (meminfo.nr_banks != 1)
 | 
					 | 
				
			||||||
		create_memmap_holes(&meminfo);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* this will put all unused low memory onto the freelists */
 | 
						/* this will put all unused low memory onto the freelists */
 | 
				
			||||||
	for_each_online_node(node) {
 | 
						for_each_online_node(node) {
 | 
				
			||||||
		pg_data_t *pgdat = NODE_DATA(node);
 | 
							pg_data_t *pgdat = NODE_DATA(node);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							free_unused_memmap_node(node, &meminfo);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (pgdat->node_spanned_pages != 0)
 | 
							if (pgdat->node_spanned_pages != 0)
 | 
				
			||||||
			totalram_pages += free_all_bootmem_node(pgdat);
 | 
								totalram_pages += free_all_bootmem_node(pgdat);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -169,7 +169,14 @@ pgd_t *get_pgd_slow(struct mm_struct *mm)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	memzero(new_pgd, FIRST_KERNEL_PGD_NR * sizeof(pgd_t));
 | 
						memzero(new_pgd, FIRST_KERNEL_PGD_NR * sizeof(pgd_t));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/*
 | 
				
			||||||
 | 
						 * Copy over the kernel and IO PGD entries
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
	init_pgd = pgd_offset_k(0);
 | 
						init_pgd = pgd_offset_k(0);
 | 
				
			||||||
 | 
						memcpy(new_pgd + FIRST_KERNEL_PGD_NR, init_pgd + FIRST_KERNEL_PGD_NR,
 | 
				
			||||||
 | 
							       (PTRS_PER_PGD - FIRST_KERNEL_PGD_NR) * sizeof(pgd_t));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						clean_dcache_area(new_pgd, PTRS_PER_PGD * sizeof(pgd_t));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!vectors_high()) {
 | 
						if (!vectors_high()) {
 | 
				
			||||||
		/*
 | 
							/*
 | 
				
			||||||
| 
						 | 
					@ -198,14 +205,6 @@ pgd_t *get_pgd_slow(struct mm_struct *mm)
 | 
				
			||||||
		spin_unlock(&mm->page_table_lock);
 | 
							spin_unlock(&mm->page_table_lock);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/*
 | 
					 | 
				
			||||||
	 * Copy over the kernel and IO PGD entries
 | 
					 | 
				
			||||||
	 */
 | 
					 | 
				
			||||||
	memcpy(new_pgd + FIRST_KERNEL_PGD_NR, init_pgd + FIRST_KERNEL_PGD_NR,
 | 
					 | 
				
			||||||
		       (PTRS_PER_PGD - FIRST_KERNEL_PGD_NR) * sizeof(pgd_t));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	clean_dcache_area(new_pgd, PTRS_PER_PGD * sizeof(pgd_t));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return new_pgd;
 | 
						return new_pgd;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
no_pte:
 | 
					no_pte:
 | 
				
			||||||
| 
						 | 
					@ -698,75 +697,3 @@ void __init iotable_init(struct map_desc *io_desc, int nr)
 | 
				
			||||||
	for (i = 0; i < nr; i++)
 | 
						for (i = 0; i < nr; i++)
 | 
				
			||||||
		create_mapping(io_desc + i);
 | 
							create_mapping(io_desc + i);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					 | 
				
			||||||
static inline void
 | 
					 | 
				
			||||||
free_memmap(int node, unsigned long start_pfn, unsigned long end_pfn)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	struct page *start_pg, *end_pg;
 | 
					 | 
				
			||||||
	unsigned long pg, pgend;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/*
 | 
					 | 
				
			||||||
	 * Convert start_pfn/end_pfn to a struct page pointer.
 | 
					 | 
				
			||||||
	 */
 | 
					 | 
				
			||||||
	start_pg = pfn_to_page(start_pfn);
 | 
					 | 
				
			||||||
	end_pg = pfn_to_page(end_pfn);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/*
 | 
					 | 
				
			||||||
	 * Convert to physical addresses, and
 | 
					 | 
				
			||||||
	 * round start upwards and end downwards.
 | 
					 | 
				
			||||||
	 */
 | 
					 | 
				
			||||||
	pg = PAGE_ALIGN(__pa(start_pg));
 | 
					 | 
				
			||||||
	pgend = __pa(end_pg) & PAGE_MASK;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/*
 | 
					 | 
				
			||||||
	 * If there are free pages between these,
 | 
					 | 
				
			||||||
	 * free the section of the memmap array.
 | 
					 | 
				
			||||||
	 */
 | 
					 | 
				
			||||||
	if (pg < pgend)
 | 
					 | 
				
			||||||
		free_bootmem_node(NODE_DATA(node), pg, pgend - pg);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static inline void free_unused_memmap_node(int node, struct meminfo *mi)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	unsigned long bank_start, prev_bank_end = 0;
 | 
					 | 
				
			||||||
	unsigned int i;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/*
 | 
					 | 
				
			||||||
	 * [FIXME] This relies on each bank being in address order.  This
 | 
					 | 
				
			||||||
	 * may not be the case, especially if the user has provided the
 | 
					 | 
				
			||||||
	 * information on the command line.
 | 
					 | 
				
			||||||
	 */
 | 
					 | 
				
			||||||
	for (i = 0; i < mi->nr_banks; i++) {
 | 
					 | 
				
			||||||
		if (mi->bank[i].size == 0 || mi->bank[i].node != node)
 | 
					 | 
				
			||||||
			continue;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		bank_start = mi->bank[i].start >> PAGE_SHIFT;
 | 
					 | 
				
			||||||
		if (bank_start < prev_bank_end) {
 | 
					 | 
				
			||||||
			printk(KERN_ERR "MEM: unordered memory banks.  "
 | 
					 | 
				
			||||||
				"Not freeing memmap.\n");
 | 
					 | 
				
			||||||
			break;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		/*
 | 
					 | 
				
			||||||
		 * If we had a previous bank, and there is a space
 | 
					 | 
				
			||||||
		 * between the current bank and the previous, free it.
 | 
					 | 
				
			||||||
		 */
 | 
					 | 
				
			||||||
		if (prev_bank_end && prev_bank_end != bank_start)
 | 
					 | 
				
			||||||
			free_memmap(node, prev_bank_end, bank_start);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		prev_bank_end = PAGE_ALIGN(mi->bank[i].start +
 | 
					 | 
				
			||||||
					   mi->bank[i].size) >> PAGE_SHIFT;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/*
 | 
					 | 
				
			||||||
 * The mem_map array can get very big.  Free
 | 
					 | 
				
			||||||
 * the unused area of the memory map.
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
void __init create_memmap_holes(struct meminfo *mi)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	int node;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	for_each_online_node(node)
 | 
					 | 
				
			||||||
		free_unused_memmap_node(node, mi);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -6,7 +6,7 @@
 | 
				
			||||||
# To add an entry into this database, please see Documentation/arm/README,
 | 
					# To add an entry into this database, please see Documentation/arm/README,
 | 
				
			||||||
# or contact rmk@arm.linux.org.uk
 | 
					# or contact rmk@arm.linux.org.uk
 | 
				
			||||||
#
 | 
					#
 | 
				
			||||||
# Last update: Thu Mar 24 14:34:50 2005
 | 
					# Last update: Thu Jun 23 20:19:33 2005
 | 
				
			||||||
#
 | 
					#
 | 
				
			||||||
# machine_is_xxx	CONFIG_xxxx		MACH_TYPE_xxx		number
 | 
					# machine_is_xxx	CONFIG_xxxx		MACH_TYPE_xxx		number
 | 
				
			||||||
#
 | 
					#
 | 
				
			||||||
| 
						 | 
					@ -243,7 +243,7 @@ yoho			ARCH_YOHO		YOHO			231
 | 
				
			||||||
jasper			ARCH_JASPER		JASPER			232
 | 
					jasper			ARCH_JASPER		JASPER			232
 | 
				
			||||||
dsc25			ARCH_DSC25		DSC25			233
 | 
					dsc25			ARCH_DSC25		DSC25			233
 | 
				
			||||||
omap_innovator		MACH_OMAP_INNOVATOR	OMAP_INNOVATOR		234
 | 
					omap_innovator		MACH_OMAP_INNOVATOR	OMAP_INNOVATOR		234
 | 
				
			||||||
ramses			ARCH_RAMSES		RAMSES			235
 | 
					mnci			ARCH_RAMSES		RAMSES			235
 | 
				
			||||||
s28x			ARCH_S28X		S28X			236
 | 
					s28x			ARCH_S28X		S28X			236
 | 
				
			||||||
mport3			ARCH_MPORT3		MPORT3			237
 | 
					mport3			ARCH_MPORT3		MPORT3			237
 | 
				
			||||||
pxa_eagle250		ARCH_PXA_EAGLE250	PXA_EAGLE250		238
 | 
					pxa_eagle250		ARCH_PXA_EAGLE250	PXA_EAGLE250		238
 | 
				
			||||||
| 
						 | 
					@ -323,7 +323,7 @@ nimbra29x		ARCH_NIMBRA29X		NIMBRA29X		311
 | 
				
			||||||
nimbra210		ARCH_NIMBRA210		NIMBRA210		312
 | 
					nimbra210		ARCH_NIMBRA210		NIMBRA210		312
 | 
				
			||||||
hhp_d95xx		ARCH_HHP_D95XX		HHP_D95XX		313
 | 
					hhp_d95xx		ARCH_HHP_D95XX		HHP_D95XX		313
 | 
				
			||||||
labarm			ARCH_LABARM		LABARM			314
 | 
					labarm			ARCH_LABARM		LABARM			314
 | 
				
			||||||
m825xx			ARCH_M825XX		M825XX			315
 | 
					comcerto		ARCH_M825XX		M825XX			315
 | 
				
			||||||
m7100			SA1100_M7100		M7100			316
 | 
					m7100			SA1100_M7100		M7100			316
 | 
				
			||||||
nipc2			ARCH_NIPC2		NIPC2			317
 | 
					nipc2			ARCH_NIPC2		NIPC2			317
 | 
				
			||||||
fu7202			ARCH_FU7202		FU7202			318
 | 
					fu7202			ARCH_FU7202		FU7202			318
 | 
				
			||||||
| 
						 | 
					@ -724,3 +724,66 @@ lpc22xx			MACH_LPC22XX		LPC22XX			715
 | 
				
			||||||
omap_comet3		MACH_COMET3		COMET3			716
 | 
					omap_comet3		MACH_COMET3		COMET3			716
 | 
				
			||||||
omap_comet4		MACH_COMET4		COMET4			717
 | 
					omap_comet4		MACH_COMET4		COMET4			717
 | 
				
			||||||
csb625			MACH_CSB625		CSB625			718
 | 
					csb625			MACH_CSB625		CSB625			718
 | 
				
			||||||
 | 
					fortunet2		MACH_FORTUNET2		FORTUNET2		719
 | 
				
			||||||
 | 
					s5h2200			MACH_S5H2200		S5H2200			720
 | 
				
			||||||
 | 
					optorm920		MACH_OPTORM920		OPTORM920		721
 | 
				
			||||||
 | 
					adsbitsyxb		MACH_ADSBITSYXB		ADSBITSYXB		722
 | 
				
			||||||
 | 
					adssphere		MACH_ADSSPHERE		ADSSPHERE		723
 | 
				
			||||||
 | 
					adsportal		MACH_ADSPORTAL		ADSPORTAL		724
 | 
				
			||||||
 | 
					ln2410sbc		MACH_LN2410SBC		LN2410SBC		725
 | 
				
			||||||
 | 
					cb3rufc			MACH_CB3RUFC		CB3RUFC			726
 | 
				
			||||||
 | 
					mp2usb			MACH_MP2USB		MP2USB			727
 | 
				
			||||||
 | 
					ntnp425c		MACH_NTNP425C		NTNP425C		728
 | 
				
			||||||
 | 
					colibri			MACH_COLIBRI		COLIBRI			729
 | 
				
			||||||
 | 
					pcm7220			MACH_PCM7220		PCM7220			730
 | 
				
			||||||
 | 
					gateway7001		MACH_GATEWAY7001	GATEWAY7001		731
 | 
				
			||||||
 | 
					pcm027			MACH_PCM027		PCM027			732
 | 
				
			||||||
 | 
					cmpxa			MACH_CMPXA		CMPXA			733
 | 
				
			||||||
 | 
					anubis			MACH_ANUBIS		ANUBIS			734
 | 
				
			||||||
 | 
					ite8152			MACH_ITE8152		ITE8152			735
 | 
				
			||||||
 | 
					lpc3xxx			MACH_LPC3XXX		LPC3XXX			736
 | 
				
			||||||
 | 
					puppeteer		MACH_PUPPETEER		PUPPETEER		737
 | 
				
			||||||
 | 
					vt001			MACH_MACH_VADATECH	MACH_VADATECH		738
 | 
				
			||||||
 | 
					e570			MACH_E570		E570			739
 | 
				
			||||||
 | 
					x50			MACH_X50		X50			740
 | 
				
			||||||
 | 
					recon			MACH_RECON		RECON			741
 | 
				
			||||||
 | 
					xboardgp8		MACH_XBOARDGP8		XBOARDGP8		742
 | 
				
			||||||
 | 
					fpic2			MACH_FPIC2		FPIC2			743
 | 
				
			||||||
 | 
					akita			MACH_AKITA		AKITA			744
 | 
				
			||||||
 | 
					a81			MACH_A81		A81			745
 | 
				
			||||||
 | 
					svm_sc25x		MACH_SVM_SC25X		SVM_SC25X		746
 | 
				
			||||||
 | 
					vt020			MACH_VADATECH020	VADATECH020		747
 | 
				
			||||||
 | 
					tli			MACH_TLI		TLI			748
 | 
				
			||||||
 | 
					edb9315lc		MACH_EDB9315LC		EDB9315LC		749
 | 
				
			||||||
 | 
					passec			MACH_PASSEC		PASSEC			750
 | 
				
			||||||
 | 
					ds_tiger		MACH_DS_TIGER		DS_TIGER		751
 | 
				
			||||||
 | 
					e310			MACH_E310		E310			752
 | 
				
			||||||
 | 
					e330			MACH_E330		E330			753
 | 
				
			||||||
 | 
					rt3000			MACH_RT3000		RT3000			754
 | 
				
			||||||
 | 
					nokia770		MACH_NOKIA770		NOKIA770		755
 | 
				
			||||||
 | 
					pnx0106			MACH_PNX0106		PNX0106			756
 | 
				
			||||||
 | 
					hx21xx			MACH_HX21XX		HX21XX			757
 | 
				
			||||||
 | 
					faraday			MACH_FARADAY		FARADAY			758
 | 
				
			||||||
 | 
					sbc9312			MACH_SBC9312		SBC9312			759
 | 
				
			||||||
 | 
					batman			MACH_BATMAN		BATMAN			760
 | 
				
			||||||
 | 
					jpd201			MACH_JPD201		JPD201			761
 | 
				
			||||||
 | 
					mipsa			MACH_MIPSA		MIPSA			762
 | 
				
			||||||
 | 
					kacom			MACH_KACOM		KACOM			763
 | 
				
			||||||
 | 
					swarcocpu		MACH_SWARCOCPU		SWARCOCPU		764
 | 
				
			||||||
 | 
					swarcodsl		MACH_SWARCODSL		SWARCODSL		765
 | 
				
			||||||
 | 
					blueangel		MACH_BLUEANGEL		BLUEANGEL		766
 | 
				
			||||||
 | 
					hairygrama		MACH_HAIRYGRAMA		HAIRYGRAMA		767
 | 
				
			||||||
 | 
					banff			MACH_BANFF		BANFF			768
 | 
				
			||||||
 | 
					carmeva			MACH_CARMEVA		CARMEVA			769
 | 
				
			||||||
 | 
					sam255			MACH_SAM255		SAM255			770
 | 
				
			||||||
 | 
					ppm10			MACH_PPM10		PPM10			771
 | 
				
			||||||
 | 
					edb9315a		MACH_EDB9315A		EDB9315A		772
 | 
				
			||||||
 | 
					sunset			MACH_SUNSET		SUNSET			773
 | 
				
			||||||
 | 
					stargate2		MACH_STARGATE2		STARGATE2		774
 | 
				
			||||||
 | 
					intelmote2		MACH_INTELMOTE2		INTELMOTE2		775
 | 
				
			||||||
 | 
					trizeps4		MACH_TRIZEPS4		TRIZEPS4		776
 | 
				
			||||||
 | 
					mainstone2		MACH_MAINSTONE2		MAINSTONE2		777
 | 
				
			||||||
 | 
					ez_ixp42x		MACH_EZ_IXP42X		EZ_IXP42X		778
 | 
				
			||||||
 | 
					tapwave_zodiac		MACH_TAPWAVE_ZODIAC	TAPWAVE_ZODIAC		779
 | 
				
			||||||
 | 
					universalmeter		MACH_UNIVERSALMETER	UNIVERSALMETER		780
 | 
				
			||||||
 | 
					hicoarm9		MACH_HICOARM9		HICOARM9		781
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -127,48 +127,23 @@ static inline void prepare_singlestep(struct kprobe *p, struct pt_regs *regs)
 | 
				
			||||||
		regs->eip = (unsigned long)&p->ainsn.insn;
 | 
							regs->eip = (unsigned long)&p->ainsn.insn;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct task_struct  *arch_get_kprobe_task(void *ptr)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	return ((struct thread_info *) (((unsigned long) ptr) &
 | 
					 | 
				
			||||||
					(~(THREAD_SIZE -1))))->task;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void arch_prepare_kretprobe(struct kretprobe *rp, struct pt_regs *regs)
 | 
					void arch_prepare_kretprobe(struct kretprobe *rp, struct pt_regs *regs)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	unsigned long *sara = (unsigned long *)®s->esp;
 | 
						unsigned long *sara = (unsigned long *)®s->esp;
 | 
				
			||||||
	struct kretprobe_instance *ri;
 | 
					        struct kretprobe_instance *ri;
 | 
				
			||||||
	static void *orig_ret_addr;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/*
 | 
					        if ((ri = get_free_rp_inst(rp)) != NULL) {
 | 
				
			||||||
	 * Save the return address when the return probe hits
 | 
					                ri->rp = rp;
 | 
				
			||||||
	 * the first time, and use it to populate the (krprobe
 | 
					                ri->task = current;
 | 
				
			||||||
	 * instance)->ret_addr for subsequent return probes at
 | 
							ri->ret_addr = (kprobe_opcode_t *) *sara;
 | 
				
			||||||
	 * the same addrress since stack address would have
 | 
					 | 
				
			||||||
	 * the kretprobe_trampoline by then.
 | 
					 | 
				
			||||||
	 */
 | 
					 | 
				
			||||||
	if (((void*) *sara) != kretprobe_trampoline)
 | 
					 | 
				
			||||||
		orig_ret_addr = (void*) *sara;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if ((ri = get_free_rp_inst(rp)) != NULL) {
 | 
					 | 
				
			||||||
		ri->rp = rp;
 | 
					 | 
				
			||||||
		ri->stack_addr = sara;
 | 
					 | 
				
			||||||
		ri->ret_addr = orig_ret_addr;
 | 
					 | 
				
			||||||
		add_rp_inst(ri);
 | 
					 | 
				
			||||||
		/* Replace the return addr with trampoline addr */
 | 
							/* Replace the return addr with trampoline addr */
 | 
				
			||||||
		*sara = (unsigned long) &kretprobe_trampoline;
 | 
							*sara = (unsigned long) &kretprobe_trampoline;
 | 
				
			||||||
	} else {
 | 
					 | 
				
			||||||
		rp->nmissed++;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
void arch_kprobe_flush_task(struct task_struct *tk)
 | 
					                add_rp_inst(ri);
 | 
				
			||||||
{
 | 
					        } else {
 | 
				
			||||||
	struct kretprobe_instance *ri;
 | 
					                rp->nmissed++;
 | 
				
			||||||
	while ((ri = get_rp_inst_tsk(tk)) != NULL) {
 | 
					        }
 | 
				
			||||||
		*((unsigned long *)(ri->stack_addr)) =
 | 
					 | 
				
			||||||
					(unsigned long) ri->ret_addr;
 | 
					 | 
				
			||||||
		recycle_rp_inst(ri);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
| 
						 | 
					@ -286,36 +261,59 @@ no_kprobe:
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
int trampoline_probe_handler(struct kprobe *p, struct pt_regs *regs)
 | 
					int trampoline_probe_handler(struct kprobe *p, struct pt_regs *regs)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct task_struct *tsk;
 | 
					        struct kretprobe_instance *ri = NULL;
 | 
				
			||||||
	struct kretprobe_instance *ri;
 | 
					        struct hlist_head *head;
 | 
				
			||||||
	struct hlist_head *head;
 | 
					        struct hlist_node *node, *tmp;
 | 
				
			||||||
	struct hlist_node *node;
 | 
						unsigned long orig_ret_address = 0;
 | 
				
			||||||
	unsigned long *sara = ((unsigned long *) ®s->esp) - 1;
 | 
						unsigned long trampoline_address =(unsigned long)&kretprobe_trampoline;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	tsk = arch_get_kprobe_task(sara);
 | 
					        head = kretprobe_inst_table_head(current);
 | 
				
			||||||
	head = kretprobe_inst_table_head(tsk);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	hlist_for_each_entry(ri, node, head, hlist) {
 | 
						/*
 | 
				
			||||||
		if (ri->stack_addr == sara && ri->rp) {
 | 
						 * It is possible to have multiple instances associated with a given
 | 
				
			||||||
			if (ri->rp->handler)
 | 
						 * task either because an multiple functions in the call path
 | 
				
			||||||
				ri->rp->handler(ri, regs);
 | 
						 * have a return probe installed on them, and/or more then one return
 | 
				
			||||||
		}
 | 
						 * return probe was registered for a target function.
 | 
				
			||||||
	}
 | 
						 *
 | 
				
			||||||
	return 0;
 | 
						 * We can handle this because:
 | 
				
			||||||
}
 | 
						 *     - instances are always inserted at the head of the list
 | 
				
			||||||
 | 
						 *     - when multiple return probes are registered for the same
 | 
				
			||||||
 | 
					         *       function, the first instance's ret_addr will point to the
 | 
				
			||||||
 | 
						 *       real return address, and all the rest will point to
 | 
				
			||||||
 | 
						 *       kretprobe_trampoline
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						hlist_for_each_entry_safe(ri, node, tmp, head, hlist) {
 | 
				
			||||||
 | 
					                if (ri->task != current)
 | 
				
			||||||
 | 
								/* another task is sharing our hash bucket */
 | 
				
			||||||
 | 
					                        continue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void trampoline_post_handler(struct kprobe *p, struct pt_regs *regs,
 | 
							if (ri->rp && ri->rp->handler)
 | 
				
			||||||
						unsigned long flags)
 | 
								ri->rp->handler(ri, regs);
 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	struct kretprobe_instance *ri;
 | 
					 | 
				
			||||||
	/* RA already popped */
 | 
					 | 
				
			||||||
	unsigned long *sara = ((unsigned long *)®s->esp) - 1;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	while ((ri = get_rp_inst(sara))) {
 | 
							orig_ret_address = (unsigned long)ri->ret_addr;
 | 
				
			||||||
		regs->eip = (unsigned long)ri->ret_addr;
 | 
					 | 
				
			||||||
		recycle_rp_inst(ri);
 | 
							recycle_rp_inst(ri);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (orig_ret_address != trampoline_address)
 | 
				
			||||||
 | 
								/*
 | 
				
			||||||
 | 
								 * This is the real return address. Any other
 | 
				
			||||||
 | 
								 * instances associated with this task are for
 | 
				
			||||||
 | 
								 * other calls deeper on the call stack
 | 
				
			||||||
 | 
								 */
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	regs->eflags &= ~TF_MASK;
 | 
					
 | 
				
			||||||
 | 
						BUG_ON(!orig_ret_address || (orig_ret_address == trampoline_address));
 | 
				
			||||||
 | 
						regs->eip = orig_ret_address;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						unlock_kprobes();
 | 
				
			||||||
 | 
						preempt_enable_no_resched();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        /*
 | 
				
			||||||
 | 
					         * By returning a non-zero value, we are telling
 | 
				
			||||||
 | 
					         * kprobe_handler() that we have handled unlocking
 | 
				
			||||||
 | 
					         * and re-enabling preemption.
 | 
				
			||||||
 | 
					         */
 | 
				
			||||||
 | 
					        return 1;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
| 
						 | 
					@ -403,8 +401,7 @@ static inline int post_kprobe_handler(struct pt_regs *regs)
 | 
				
			||||||
		current_kprobe->post_handler(current_kprobe, regs, 0);
 | 
							current_kprobe->post_handler(current_kprobe, regs, 0);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (current_kprobe->post_handler != trampoline_post_handler)
 | 
						resume_execution(current_kprobe, regs);
 | 
				
			||||||
		resume_execution(current_kprobe, regs);
 | 
					 | 
				
			||||||
	regs->eflags |= kprobe_saved_eflags;
 | 
						regs->eflags |= kprobe_saved_eflags;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/*Restore back the original saved kprobes variables and continue. */
 | 
						/*Restore back the original saved kprobes variables and continue. */
 | 
				
			||||||
| 
						 | 
					@ -534,3 +531,13 @@ int longjmp_break_handler(struct kprobe *p, struct pt_regs *regs)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static struct kprobe trampoline_p = {
 | 
				
			||||||
 | 
						.addr = (kprobe_opcode_t *) &kretprobe_trampoline,
 | 
				
			||||||
 | 
						.pre_handler = trampoline_probe_handler
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int __init arch_init(void)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						return register_kprobe(&trampoline_p);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -616,6 +616,33 @@ handle_io_bitmap(struct thread_struct *next, struct tss_struct *tss)
 | 
				
			||||||
	tss->io_bitmap_base = INVALID_IO_BITMAP_OFFSET_LAZY;
 | 
						tss->io_bitmap_base = INVALID_IO_BITMAP_OFFSET_LAZY;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * This function selects if the context switch from prev to next
 | 
				
			||||||
 | 
					 * has to tweak the TSC disable bit in the cr4.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					static inline void disable_tsc(struct task_struct *prev_p,
 | 
				
			||||||
 | 
								       struct task_struct *next_p)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct thread_info *prev, *next;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/*
 | 
				
			||||||
 | 
						 * gcc should eliminate the ->thread_info dereference if
 | 
				
			||||||
 | 
						 * has_secure_computing returns 0 at compile time (SECCOMP=n).
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						prev = prev_p->thread_info;
 | 
				
			||||||
 | 
						next = next_p->thread_info;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (has_secure_computing(prev) || has_secure_computing(next)) {
 | 
				
			||||||
 | 
							/* slow path here */
 | 
				
			||||||
 | 
							if (has_secure_computing(prev) &&
 | 
				
			||||||
 | 
							    !has_secure_computing(next)) {
 | 
				
			||||||
 | 
								write_cr4(read_cr4() & ~X86_CR4_TSD);
 | 
				
			||||||
 | 
							} else if (!has_secure_computing(prev) &&
 | 
				
			||||||
 | 
								   has_secure_computing(next))
 | 
				
			||||||
 | 
								write_cr4(read_cr4() | X86_CR4_TSD);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 *	switch_to(x,yn) should switch tasks from x to y.
 | 
					 *	switch_to(x,yn) should switch tasks from x to y.
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
| 
						 | 
					@ -695,6 +722,8 @@ struct task_struct fastcall * __switch_to(struct task_struct *prev_p, struct tas
 | 
				
			||||||
	if (unlikely(prev->io_bitmap_ptr || next->io_bitmap_ptr))
 | 
						if (unlikely(prev->io_bitmap_ptr || next->io_bitmap_ptr))
 | 
				
			||||||
		handle_io_bitmap(next, tss);
 | 
							handle_io_bitmap(next, tss);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						disable_tsc(prev_p, next_p);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return prev_p;
 | 
						return prev_p;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -289,3 +289,5 @@ ENTRY(sys_call_table)
 | 
				
			||||||
	.long sys_add_key
 | 
						.long sys_add_key
 | 
				
			||||||
	.long sys_request_key
 | 
						.long sys_request_key
 | 
				
			||||||
	.long sys_keyctl
 | 
						.long sys_keyctl
 | 
				
			||||||
 | 
						.long sys_ioprio_set
 | 
				
			||||||
 | 
						.long sys_ioprio_get		/* 290 */
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1577,8 +1577,8 @@ sys_call_table:
 | 
				
			||||||
	data8 sys_add_key
 | 
						data8 sys_add_key
 | 
				
			||||||
	data8 sys_request_key
 | 
						data8 sys_request_key
 | 
				
			||||||
	data8 sys_keyctl
 | 
						data8 sys_keyctl
 | 
				
			||||||
	data8 sys_ni_syscall
 | 
						data8 sys_ioprio_set
 | 
				
			||||||
	data8 sys_ni_syscall			// 1275
 | 
						data8 sys_ioprio_get			// 1275
 | 
				
			||||||
	data8 sys_set_zone_reclaim
 | 
						data8 sys_set_zone_reclaim
 | 
				
			||||||
	data8 sys_ni_syscall
 | 
						data8 sys_ni_syscall
 | 
				
			||||||
	data8 sys_ni_syscall
 | 
						data8 sys_ni_syscall
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -34,6 +34,7 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <asm/pgtable.h>
 | 
					#include <asm/pgtable.h>
 | 
				
			||||||
#include <asm/kdebug.h>
 | 
					#include <asm/kdebug.h>
 | 
				
			||||||
 | 
					#include <asm/sections.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
extern void jprobe_inst_return(void);
 | 
					extern void jprobe_inst_return(void);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -263,13 +264,33 @@ static inline void get_kprobe_inst(bundle_t *bundle, uint slot,
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Returns non-zero if the addr is in the Interrupt Vector Table */
 | 
				
			||||||
 | 
					static inline int in_ivt_functions(unsigned long addr)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						return (addr >= (unsigned long)__start_ivt_text
 | 
				
			||||||
 | 
							&& addr < (unsigned long)__end_ivt_text);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int valid_kprobe_addr(int template, int slot, unsigned long addr)
 | 
					static int valid_kprobe_addr(int template, int slot, unsigned long addr)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	if ((slot > 2) || ((bundle_encoding[template][1] == L) && slot > 1)) {
 | 
						if ((slot > 2) || ((bundle_encoding[template][1] == L) && slot > 1)) {
 | 
				
			||||||
		printk(KERN_WARNING "Attempting to insert unaligned kprobe at 0x%lx\n",
 | 
							printk(KERN_WARNING "Attempting to insert unaligned kprobe "
 | 
				
			||||||
				addr);
 | 
									"at 0x%lx\n", addr);
 | 
				
			||||||
		return -EINVAL;
 | 
							return -EINVAL;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 	if (in_ivt_functions(addr)) {
 | 
				
			||||||
 | 
					 		printk(KERN_WARNING "Kprobes can't be inserted inside "
 | 
				
			||||||
 | 
									"IVT functions at 0x%lx\n", addr);
 | 
				
			||||||
 | 
					 		return -EINVAL;
 | 
				
			||||||
 | 
					 	}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (slot == 1 && bundle_encoding[template][1] != L) {
 | 
				
			||||||
 | 
							printk(KERN_WARNING "Inserting kprobes on slot #1 "
 | 
				
			||||||
 | 
							       "is not supported\n");
 | 
				
			||||||
 | 
							return -EINVAL;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -290,6 +311,94 @@ static inline void set_current_kprobe(struct kprobe *p)
 | 
				
			||||||
	current_kprobe = p;
 | 
						current_kprobe = p;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void kretprobe_trampoline(void)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * At this point the target function has been tricked into
 | 
				
			||||||
 | 
					 * returning into our trampoline.  Lookup the associated instance
 | 
				
			||||||
 | 
					 * and then:
 | 
				
			||||||
 | 
					 *    - call the handler function
 | 
				
			||||||
 | 
					 *    - cleanup by marking the instance as unused
 | 
				
			||||||
 | 
					 *    - long jump back to the original return address
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					int trampoline_probe_handler(struct kprobe *p, struct pt_regs *regs)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct kretprobe_instance *ri = NULL;
 | 
				
			||||||
 | 
						struct hlist_head *head;
 | 
				
			||||||
 | 
						struct hlist_node *node, *tmp;
 | 
				
			||||||
 | 
						unsigned long orig_ret_address = 0;
 | 
				
			||||||
 | 
						unsigned long trampoline_address =
 | 
				
			||||||
 | 
							((struct fnptr *)kretprobe_trampoline)->ip;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        head = kretprobe_inst_table_head(current);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/*
 | 
				
			||||||
 | 
						 * It is possible to have multiple instances associated with a given
 | 
				
			||||||
 | 
						 * task either because an multiple functions in the call path
 | 
				
			||||||
 | 
						 * have a return probe installed on them, and/or more then one return
 | 
				
			||||||
 | 
						 * return probe was registered for a target function.
 | 
				
			||||||
 | 
						 *
 | 
				
			||||||
 | 
						 * We can handle this because:
 | 
				
			||||||
 | 
						 *     - instances are always inserted at the head of the list
 | 
				
			||||||
 | 
						 *     - when multiple return probes are registered for the same
 | 
				
			||||||
 | 
						 *       function, the first instance's ret_addr will point to the
 | 
				
			||||||
 | 
						 *       real return address, and all the rest will point to
 | 
				
			||||||
 | 
						 *       kretprobe_trampoline
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						hlist_for_each_entry_safe(ri, node, tmp, head, hlist) {
 | 
				
			||||||
 | 
					                if (ri->task != current)
 | 
				
			||||||
 | 
								/* another task is sharing our hash bucket */
 | 
				
			||||||
 | 
					                        continue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (ri->rp && ri->rp->handler)
 | 
				
			||||||
 | 
								ri->rp->handler(ri, regs);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							orig_ret_address = (unsigned long)ri->ret_addr;
 | 
				
			||||||
 | 
							recycle_rp_inst(ri);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (orig_ret_address != trampoline_address)
 | 
				
			||||||
 | 
								/*
 | 
				
			||||||
 | 
								 * This is the real return address. Any other
 | 
				
			||||||
 | 
								 * instances associated with this task are for
 | 
				
			||||||
 | 
								 * other calls deeper on the call stack
 | 
				
			||||||
 | 
								 */
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						BUG_ON(!orig_ret_address || (orig_ret_address == trampoline_address));
 | 
				
			||||||
 | 
						regs->cr_iip = orig_ret_address;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						unlock_kprobes();
 | 
				
			||||||
 | 
						preempt_enable_no_resched();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        /*
 | 
				
			||||||
 | 
					         * By returning a non-zero value, we are telling
 | 
				
			||||||
 | 
					         * kprobe_handler() that we have handled unlocking
 | 
				
			||||||
 | 
					         * and re-enabling preemption.
 | 
				
			||||||
 | 
					         */
 | 
				
			||||||
 | 
					        return 1;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void arch_prepare_kretprobe(struct kretprobe *rp, struct pt_regs *regs)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct kretprobe_instance *ri;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if ((ri = get_free_rp_inst(rp)) != NULL) {
 | 
				
			||||||
 | 
							ri->rp = rp;
 | 
				
			||||||
 | 
							ri->task = current;
 | 
				
			||||||
 | 
							ri->ret_addr = (kprobe_opcode_t *)regs->b0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							/* Replace the return addr with trampoline addr */
 | 
				
			||||||
 | 
							regs->b0 = ((struct fnptr *)kretprobe_trampoline)->ip;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							add_rp_inst(ri);
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							rp->nmissed++;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int arch_prepare_kprobe(struct kprobe *p)
 | 
					int arch_prepare_kprobe(struct kprobe *p)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	unsigned long addr = (unsigned long) p->addr;
 | 
						unsigned long addr = (unsigned long) p->addr;
 | 
				
			||||||
| 
						 | 
					@ -492,8 +601,8 @@ static int pre_kprobes_handler(struct die_args *args)
 | 
				
			||||||
	if (p->pre_handler && p->pre_handler(p, regs))
 | 
						if (p->pre_handler && p->pre_handler(p, regs))
 | 
				
			||||||
		/*
 | 
							/*
 | 
				
			||||||
		 * Our pre-handler is specifically requesting that we just
 | 
							 * Our pre-handler is specifically requesting that we just
 | 
				
			||||||
		 * do a return.  This is handling the case where the
 | 
							 * do a return.  This is used for both the jprobe pre-handler
 | 
				
			||||||
		 * pre-handler is really our special jprobe pre-handler.
 | 
							 * and the kretprobe trampoline
 | 
				
			||||||
		 */
 | 
							 */
 | 
				
			||||||
		return 1;
 | 
							return 1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -599,3 +708,14 @@ int longjmp_break_handler(struct kprobe *p, struct pt_regs *regs)
 | 
				
			||||||
	*regs = jprobe_saved_regs;
 | 
						*regs = jprobe_saved_regs;
 | 
				
			||||||
	return 1;
 | 
						return 1;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static struct kprobe trampoline_p = {
 | 
				
			||||||
 | 
						.pre_handler = trampoline_probe_handler
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int __init arch_init(void)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						trampoline_p.addr =
 | 
				
			||||||
 | 
							(kprobe_opcode_t *)((struct fnptr *)kretprobe_trampoline)->ip;
 | 
				
			||||||
 | 
						return register_kprobe(&trampoline_p);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -27,6 +27,7 @@
 | 
				
			||||||
#include <linux/efi.h>
 | 
					#include <linux/efi.h>
 | 
				
			||||||
#include <linux/interrupt.h>
 | 
					#include <linux/interrupt.h>
 | 
				
			||||||
#include <linux/delay.h>
 | 
					#include <linux/delay.h>
 | 
				
			||||||
 | 
					#include <linux/kprobes.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <asm/cpu.h>
 | 
					#include <asm/cpu.h>
 | 
				
			||||||
#include <asm/delay.h>
 | 
					#include <asm/delay.h>
 | 
				
			||||||
| 
						 | 
					@ -707,6 +708,13 @@ kernel_thread_helper (int (*fn)(void *), void *arg)
 | 
				
			||||||
void
 | 
					void
 | 
				
			||||||
flush_thread (void)
 | 
					flush_thread (void)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
						/*
 | 
				
			||||||
 | 
						 * Remove function-return probe instances associated with this task
 | 
				
			||||||
 | 
						 * and put them back on the free list. Do not insert an exit probe for
 | 
				
			||||||
 | 
						 * this function, it will be disabled by kprobe_flush_task if you do.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						kprobe_flush_task(current);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* drop floating-point and debug-register state if it exists: */
 | 
						/* drop floating-point and debug-register state if it exists: */
 | 
				
			||||||
	current->thread.flags &= ~(IA64_THREAD_FPH_VALID | IA64_THREAD_DBG_VALID);
 | 
						current->thread.flags &= ~(IA64_THREAD_FPH_VALID | IA64_THREAD_DBG_VALID);
 | 
				
			||||||
	ia64_drop_fpu(current);
 | 
						ia64_drop_fpu(current);
 | 
				
			||||||
| 
						 | 
					@ -721,6 +729,14 @@ flush_thread (void)
 | 
				
			||||||
void
 | 
					void
 | 
				
			||||||
exit_thread (void)
 | 
					exit_thread (void)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/*
 | 
				
			||||||
 | 
						 * Remove function-return probe instances associated with this task
 | 
				
			||||||
 | 
						 * and put them back on the free list. Do not insert an exit probe for
 | 
				
			||||||
 | 
						 * this function, it will be disabled by kprobe_flush_task if you do.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						kprobe_flush_task(current);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	ia64_drop_fpu(current);
 | 
						ia64_drop_fpu(current);
 | 
				
			||||||
#ifdef CONFIG_PERFMON
 | 
					#ifdef CONFIG_PERFMON
 | 
				
			||||||
       /* if needed, stop monitoring and flush state to perfmon context */
 | 
					       /* if needed, stop monitoring and flush state to perfmon context */
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -8,6 +8,11 @@
 | 
				
			||||||
#define LOAD_OFFSET	(KERNEL_START - KERNEL_TR_PAGE_SIZE)
 | 
					#define LOAD_OFFSET	(KERNEL_START - KERNEL_TR_PAGE_SIZE)
 | 
				
			||||||
#include <asm-generic/vmlinux.lds.h>
 | 
					#include <asm-generic/vmlinux.lds.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define IVT_TEXT							\
 | 
				
			||||||
 | 
							VMLINUX_SYMBOL(__start_ivt_text) = .;			\
 | 
				
			||||||
 | 
							*(.text.ivt)						\
 | 
				
			||||||
 | 
							VMLINUX_SYMBOL(__end_ivt_text) = .;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
OUTPUT_FORMAT("elf64-ia64-little")
 | 
					OUTPUT_FORMAT("elf64-ia64-little")
 | 
				
			||||||
OUTPUT_ARCH(ia64)
 | 
					OUTPUT_ARCH(ia64)
 | 
				
			||||||
ENTRY(phys_start)
 | 
					ENTRY(phys_start)
 | 
				
			||||||
| 
						 | 
					@ -39,7 +44,7 @@ SECTIONS
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  .text : AT(ADDR(.text) - LOAD_OFFSET)
 | 
					  .text : AT(ADDR(.text) - LOAD_OFFSET)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
	*(.text.ivt)
 | 
						IVT_TEXT
 | 
				
			||||||
	*(.text)
 | 
						*(.text)
 | 
				
			||||||
	SCHED_TEXT
 | 
						SCHED_TEXT
 | 
				
			||||||
	LOCK_TEXT
 | 
						LOCK_TEXT
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -457,7 +457,7 @@ static int do_signal(sigset_t *oldset, struct pt_regs *regs)
 | 
				
			||||||
	if (!user_mode(regs))
 | 
						if (!user_mode(regs))
 | 
				
			||||||
		return 1;
 | 
							return 1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (try_to_freeze(0))
 | 
						if (try_to_freeze())
 | 
				
			||||||
		goto no_signal;
 | 
							goto no_signal;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!oldset)
 | 
						if (!oldset)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1449,3 +1449,5 @@ _GLOBAL(sys_call_table)
 | 
				
			||||||
	.long sys_request_key		/* 270 */
 | 
						.long sys_request_key		/* 270 */
 | 
				
			||||||
	.long sys_keyctl
 | 
						.long sys_keyctl
 | 
				
			||||||
	.long sys_waitid
 | 
						.long sys_waitid
 | 
				
			||||||
 | 
						.long sys_ioprio_set
 | 
				
			||||||
 | 
						.long sys_ioprio_get
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -606,9 +606,19 @@ void update_mmu_cache(struct vm_area_struct *vma, unsigned long address,
 | 
				
			||||||
		struct page *page = pfn_to_page(pfn);
 | 
							struct page *page = pfn_to_page(pfn);
 | 
				
			||||||
		if (!PageReserved(page)
 | 
							if (!PageReserved(page)
 | 
				
			||||||
		    && !test_bit(PG_arch_1, &page->flags)) {
 | 
							    && !test_bit(PG_arch_1, &page->flags)) {
 | 
				
			||||||
			if (vma->vm_mm == current->active_mm)
 | 
								if (vma->vm_mm == current->active_mm) {
 | 
				
			||||||
 | 
					#ifdef CONFIG_8xx
 | 
				
			||||||
 | 
								/* On 8xx, cache control instructions (particularly 
 | 
				
			||||||
 | 
							 	 * "dcbst" from flush_dcache_icache) fault as write 
 | 
				
			||||||
 | 
								 * operation if there is an unpopulated TLB entry 
 | 
				
			||||||
 | 
								 * for the address in question. To workaround that, 
 | 
				
			||||||
 | 
								 * we invalidate the TLB here, thus avoiding dcbst 
 | 
				
			||||||
 | 
								 * misbehaviour.
 | 
				
			||||||
 | 
								 */
 | 
				
			||||||
 | 
									_tlbie(address);
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
				__flush_dcache_icache((void *) address);
 | 
									__flush_dcache_icache((void *) address);
 | 
				
			||||||
			else
 | 
								} else
 | 
				
			||||||
				flush_dcache_icache_page(page);
 | 
									flush_dcache_icache_page(page);
 | 
				
			||||||
			set_bit(PG_arch_1, &page->flags);
 | 
								set_bit(PG_arch_1, &page->flags);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -46,7 +46,7 @@
 | 
				
			||||||
	.section .text
 | 
						.section .text
 | 
				
			||||||
	.align	5
 | 
						.align	5
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#if defined(CONFIG_PMAC_PBOOK) || defined(CONFIG_CPU_FREQ_PMAC)
 | 
					#if defined(CONFIG_PM) || defined(CONFIG_CPU_FREQ_PMAC)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* This gets called by via-pmu.c late during the sleep process.
 | 
					/* This gets called by via-pmu.c late during the sleep process.
 | 
				
			||||||
 * The PMU was already send the sleep command and will shut us down
 | 
					 * The PMU was already send the sleep command and will shut us down
 | 
				
			||||||
| 
						 | 
					@ -382,7 +382,7 @@ turn_on_mmu:
 | 
				
			||||||
	isync
 | 
						isync
 | 
				
			||||||
	rfi
 | 
						rfi
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#endif /* defined(CONFIG_PMAC_PBOOK) || defined(CONFIG_CPU_FREQ) */
 | 
					#endif /* defined(CONFIG_PM) || defined(CONFIG_CPU_FREQ) */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	.section .data
 | 
						.section .data
 | 
				
			||||||
	.balign	L1_CACHE_LINE_SIZE
 | 
						.balign	L1_CACHE_LINE_SIZE
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -206,7 +206,7 @@ via_calibrate_decr(void)
 | 
				
			||||||
	return 1;
 | 
						return 1;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef CONFIG_PMAC_PBOOK
 | 
					#ifdef CONFIG_PM
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 * Reset the time after a sleep.
 | 
					 * Reset the time after a sleep.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
| 
						 | 
					@ -238,7 +238,7 @@ time_sleep_notify(struct pmu_sleep_notifier *self, int when)
 | 
				
			||||||
static struct pmu_sleep_notifier time_sleep_notifier __pmacdata = {
 | 
					static struct pmu_sleep_notifier time_sleep_notifier __pmacdata = {
 | 
				
			||||||
	time_sleep_notify, SLEEP_LEVEL_MISC,
 | 
						time_sleep_notify, SLEEP_LEVEL_MISC,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
#endif /* CONFIG_PMAC_PBOOK */
 | 
					#endif /* CONFIG_PM */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 * Query the OF and get the decr frequency.
 | 
					 * Query the OF and get the decr frequency.
 | 
				
			||||||
| 
						 | 
					@ -251,9 +251,9 @@ pmac_calibrate_decr(void)
 | 
				
			||||||
	struct device_node *cpu;
 | 
						struct device_node *cpu;
 | 
				
			||||||
	unsigned int freq, *fp;
 | 
						unsigned int freq, *fp;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef CONFIG_PMAC_PBOOK
 | 
					#ifdef CONFIG_PM
 | 
				
			||||||
	pmu_register_sleep_notifier(&time_sleep_notifier);
 | 
						pmu_register_sleep_notifier(&time_sleep_notifier);
 | 
				
			||||||
#endif /* CONFIG_PMAC_PBOOK */
 | 
					#endif /* CONFIG_PM */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* We assume MacRISC2 machines have correct device-tree
 | 
						/* We assume MacRISC2 machines have correct device-tree
 | 
				
			||||||
	 * calibration. That's better since the VIA itself seems
 | 
						 * calibration. That's better since the VIA itself seems
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -324,6 +324,7 @@ sandpoint_setup_arch(void)
 | 
				
			||||||
			pdata[1].irq = 0;
 | 
								pdata[1].irq = 0;
 | 
				
			||||||
			pdata[1].mapbase = 0;
 | 
								pdata[1].mapbase = 0;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	printk(KERN_INFO "Motorola SPS Sandpoint Test Platform\n");
 | 
						printk(KERN_INFO "Motorola SPS Sandpoint Test Platform\n");
 | 
				
			||||||
	printk(KERN_INFO "Port by MontaVista Software, Inc. (source@mvista.com)\n");
 | 
						printk(KERN_INFO "Port by MontaVista Software, Inc. (source@mvista.com)\n");
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -370,8 +370,9 @@ void __init openpic_init(int offset)
 | 
				
			||||||
	/* Initialize IPI interrupts */
 | 
						/* Initialize IPI interrupts */
 | 
				
			||||||
	if ( ppc_md.progress ) ppc_md.progress("openpic: ipi",0x3bb);
 | 
						if ( ppc_md.progress ) ppc_md.progress("openpic: ipi",0x3bb);
 | 
				
			||||||
	for (i = 0; i < OPENPIC_NUM_IPI; i++) {
 | 
						for (i = 0; i < OPENPIC_NUM_IPI; i++) {
 | 
				
			||||||
		/* Disabled, Priority 10..13 */
 | 
							/* Disabled, increased priorities 10..13 */
 | 
				
			||||||
		openpic_initipi(i, 10+i, OPENPIC_VEC_IPI+i+offset);
 | 
							openpic_initipi(i, OPENPIC_PRIORITY_IPI_BASE+i,
 | 
				
			||||||
 | 
									OPENPIC_VEC_IPI+i+offset);
 | 
				
			||||||
		/* IPIs are per-CPU */
 | 
							/* IPIs are per-CPU */
 | 
				
			||||||
		irq_desc[OPENPIC_VEC_IPI+i+offset].status |= IRQ_PER_CPU;
 | 
							irq_desc[OPENPIC_VEC_IPI+i+offset].status |= IRQ_PER_CPU;
 | 
				
			||||||
		irq_desc[OPENPIC_VEC_IPI+i+offset].handler = &open_pic_ipi;
 | 
							irq_desc[OPENPIC_VEC_IPI+i+offset].handler = &open_pic_ipi;
 | 
				
			||||||
| 
						 | 
					@ -399,8 +400,9 @@ void __init openpic_init(int offset)
 | 
				
			||||||
		if (sense & IRQ_SENSE_MASK)
 | 
							if (sense & IRQ_SENSE_MASK)
 | 
				
			||||||
			irq_desc[i+offset].status = IRQ_LEVEL;
 | 
								irq_desc[i+offset].status = IRQ_LEVEL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		/* Enabled, Priority 8 */
 | 
							/* Enabled, Default priority */
 | 
				
			||||||
		openpic_initirq(i, 8, i+offset, (sense & IRQ_POLARITY_MASK),
 | 
							openpic_initirq(i, OPENPIC_PRIORITY_DEFAULT, i+offset,
 | 
				
			||||||
 | 
									(sense & IRQ_POLARITY_MASK),
 | 
				
			||||||
				(sense & IRQ_SENSE_MASK));
 | 
									(sense & IRQ_SENSE_MASK));
 | 
				
			||||||
		/* Processor 0 */
 | 
							/* Processor 0 */
 | 
				
			||||||
		openpic_mapirq(i, CPU_MASK_CPU0, CPU_MASK_NONE);
 | 
							openpic_mapirq(i, CPU_MASK_CPU0, CPU_MASK_NONE);
 | 
				
			||||||
| 
						 | 
					@ -655,6 +657,18 @@ static void __init openpic_maptimer(u_int timer, cpumask_t cpumask)
 | 
				
			||||||
		      cpus_addr(phys)[0]);
 | 
							      cpus_addr(phys)[0]);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Change the priority of an interrupt
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					void __init
 | 
				
			||||||
 | 
					openpic_set_irq_priority(u_int irq, u_int pri)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						check_arg_irq(irq);
 | 
				
			||||||
 | 
						openpic_safe_writefield(&ISR[irq - open_pic_irq_offset]->Vector_Priority,
 | 
				
			||||||
 | 
									OPENPIC_PRIORITY_MASK,
 | 
				
			||||||
 | 
									pri << OPENPIC_PRIORITY_SHIFT);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 * Initalize the interrupt source which will generate an NMI.
 | 
					 * Initalize the interrupt source which will generate an NMI.
 | 
				
			||||||
 * This raises the interrupt's priority from 8 to 9.
 | 
					 * This raises the interrupt's priority from 8 to 9.
 | 
				
			||||||
| 
						 | 
					@ -665,9 +679,7 @@ void __init
 | 
				
			||||||
openpic_init_nmi_irq(u_int irq)
 | 
					openpic_init_nmi_irq(u_int irq)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	check_arg_irq(irq);
 | 
						check_arg_irq(irq);
 | 
				
			||||||
	openpic_safe_writefield(&ISR[irq - open_pic_irq_offset]->Vector_Priority,
 | 
						openpic_set_irq_priority(irq, OPENPIC_PRIORITY_NMI);
 | 
				
			||||||
				OPENPIC_PRIORITY_MASK,
 | 
					 | 
				
			||||||
				9 << OPENPIC_PRIORITY_SHIFT);
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -36,6 +36,8 @@
 | 
				
			||||||
#include <asm/kdebug.h>
 | 
					#include <asm/kdebug.h>
 | 
				
			||||||
#include <asm/sstep.h>
 | 
					#include <asm/sstep.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static DECLARE_MUTEX(kprobe_mutex);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static struct kprobe *current_kprobe;
 | 
					static struct kprobe *current_kprobe;
 | 
				
			||||||
static unsigned long kprobe_status, kprobe_saved_msr;
 | 
					static unsigned long kprobe_status, kprobe_saved_msr;
 | 
				
			||||||
static struct kprobe *kprobe_prev;
 | 
					static struct kprobe *kprobe_prev;
 | 
				
			||||||
| 
						 | 
					@ -54,6 +56,15 @@ int arch_prepare_kprobe(struct kprobe *p)
 | 
				
			||||||
		printk("Cannot register a kprobe on rfid or mtmsrd\n");
 | 
							printk("Cannot register a kprobe on rfid or mtmsrd\n");
 | 
				
			||||||
		ret = -EINVAL;
 | 
							ret = -EINVAL;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* insn must be on a special executable page on ppc64 */
 | 
				
			||||||
 | 
						if (!ret) {
 | 
				
			||||||
 | 
							up(&kprobe_mutex);
 | 
				
			||||||
 | 
							p->ainsn.insn = get_insn_slot();
 | 
				
			||||||
 | 
							down(&kprobe_mutex);
 | 
				
			||||||
 | 
							if (!p->ainsn.insn)
 | 
				
			||||||
 | 
								ret = -ENOMEM;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
	return ret;
 | 
						return ret;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -79,16 +90,22 @@ void arch_disarm_kprobe(struct kprobe *p)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void arch_remove_kprobe(struct kprobe *p)
 | 
					void arch_remove_kprobe(struct kprobe *p)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
						up(&kprobe_mutex);
 | 
				
			||||||
 | 
						free_insn_slot(p->ainsn.insn);
 | 
				
			||||||
 | 
						down(&kprobe_mutex);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static inline void prepare_singlestep(struct kprobe *p, struct pt_regs *regs)
 | 
					static inline void prepare_singlestep(struct kprobe *p, struct pt_regs *regs)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
						kprobe_opcode_t insn = *p->ainsn.insn;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	regs->msr |= MSR_SE;
 | 
						regs->msr |= MSR_SE;
 | 
				
			||||||
	/*single step inline if it a breakpoint instruction*/
 | 
					
 | 
				
			||||||
	if (p->opcode == BREAKPOINT_INSTRUCTION)
 | 
						/* single step inline if it is a trap variant */
 | 
				
			||||||
 | 
						if (IS_TW(insn) || IS_TD(insn) || IS_TWI(insn) || IS_TDI(insn))
 | 
				
			||||||
		regs->nip = (unsigned long)p->addr;
 | 
							regs->nip = (unsigned long)p->addr;
 | 
				
			||||||
	else
 | 
						else
 | 
				
			||||||
		regs->nip = (unsigned long)&p->ainsn.insn;
 | 
							regs->nip = (unsigned long)p->ainsn.insn;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static inline void save_previous_kprobe(void)
 | 
					static inline void save_previous_kprobe(void)
 | 
				
			||||||
| 
						 | 
					@ -105,6 +122,23 @@ static inline void restore_previous_kprobe(void)
 | 
				
			||||||
	kprobe_saved_msr = kprobe_saved_msr_prev;
 | 
						kprobe_saved_msr = kprobe_saved_msr_prev;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void arch_prepare_kretprobe(struct kretprobe *rp, struct pt_regs *regs)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct kretprobe_instance *ri;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if ((ri = get_free_rp_inst(rp)) != NULL) {
 | 
				
			||||||
 | 
							ri->rp = rp;
 | 
				
			||||||
 | 
							ri->task = current;
 | 
				
			||||||
 | 
							ri->ret_addr = (kprobe_opcode_t *)regs->link;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							/* Replace the return addr with trampoline addr */
 | 
				
			||||||
 | 
							regs->link = (unsigned long)kretprobe_trampoline;
 | 
				
			||||||
 | 
							add_rp_inst(ri);
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							rp->nmissed++;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static inline int kprobe_handler(struct pt_regs *regs)
 | 
					static inline int kprobe_handler(struct pt_regs *regs)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct kprobe *p;
 | 
						struct kprobe *p;
 | 
				
			||||||
| 
						 | 
					@ -194,6 +228,78 @@ no_kprobe:
 | 
				
			||||||
	return ret;
 | 
						return ret;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Function return probe trampoline:
 | 
				
			||||||
 | 
					 * 	- init_kprobes() establishes a probepoint here
 | 
				
			||||||
 | 
					 * 	- When the probed function returns, this probe
 | 
				
			||||||
 | 
					 * 		causes the handlers to fire
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					void kretprobe_trampoline_holder(void)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						asm volatile(".global kretprobe_trampoline\n"
 | 
				
			||||||
 | 
								"kretprobe_trampoline:\n"
 | 
				
			||||||
 | 
								"nop\n");
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Called when the probe at kretprobe trampoline is hit
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					int trampoline_probe_handler(struct kprobe *p, struct pt_regs *regs)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					        struct kretprobe_instance *ri = NULL;
 | 
				
			||||||
 | 
					        struct hlist_head *head;
 | 
				
			||||||
 | 
					        struct hlist_node *node, *tmp;
 | 
				
			||||||
 | 
						unsigned long orig_ret_address = 0;
 | 
				
			||||||
 | 
						unsigned long trampoline_address =(unsigned long)&kretprobe_trampoline;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        head = kretprobe_inst_table_head(current);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/*
 | 
				
			||||||
 | 
						 * It is possible to have multiple instances associated with a given
 | 
				
			||||||
 | 
						 * task either because an multiple functions in the call path
 | 
				
			||||||
 | 
						 * have a return probe installed on them, and/or more then one return
 | 
				
			||||||
 | 
						 * return probe was registered for a target function.
 | 
				
			||||||
 | 
						 *
 | 
				
			||||||
 | 
						 * We can handle this because:
 | 
				
			||||||
 | 
						 *     - instances are always inserted at the head of the list
 | 
				
			||||||
 | 
						 *     - when multiple return probes are registered for the same
 | 
				
			||||||
 | 
					         *       function, the first instance's ret_addr will point to the
 | 
				
			||||||
 | 
						 *       real return address, and all the rest will point to
 | 
				
			||||||
 | 
						 *       kretprobe_trampoline
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						hlist_for_each_entry_safe(ri, node, tmp, head, hlist) {
 | 
				
			||||||
 | 
					                if (ri->task != current)
 | 
				
			||||||
 | 
								/* another task is sharing our hash bucket */
 | 
				
			||||||
 | 
					                        continue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (ri->rp && ri->rp->handler)
 | 
				
			||||||
 | 
								ri->rp->handler(ri, regs);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							orig_ret_address = (unsigned long)ri->ret_addr;
 | 
				
			||||||
 | 
							recycle_rp_inst(ri);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (orig_ret_address != trampoline_address)
 | 
				
			||||||
 | 
								/*
 | 
				
			||||||
 | 
								 * This is the real return address. Any other
 | 
				
			||||||
 | 
								 * instances associated with this task are for
 | 
				
			||||||
 | 
								 * other calls deeper on the call stack
 | 
				
			||||||
 | 
								 */
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						BUG_ON(!orig_ret_address || (orig_ret_address == trampoline_address));
 | 
				
			||||||
 | 
						regs->nip = orig_ret_address;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						unlock_kprobes();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        /*
 | 
				
			||||||
 | 
					         * By returning a non-zero value, we are telling
 | 
				
			||||||
 | 
					         * kprobe_handler() that we have handled unlocking
 | 
				
			||||||
 | 
					         * and re-enabling preemption.
 | 
				
			||||||
 | 
					         */
 | 
				
			||||||
 | 
					        return 1;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 * Called after single-stepping.  p->addr is the address of the
 | 
					 * Called after single-stepping.  p->addr is the address of the
 | 
				
			||||||
 * instruction whose first byte has been replaced by the "breakpoint"
 | 
					 * instruction whose first byte has been replaced by the "breakpoint"
 | 
				
			||||||
| 
						 | 
					@ -205,9 +311,10 @@ no_kprobe:
 | 
				
			||||||
static void resume_execution(struct kprobe *p, struct pt_regs *regs)
 | 
					static void resume_execution(struct kprobe *p, struct pt_regs *regs)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	int ret;
 | 
						int ret;
 | 
				
			||||||
 | 
						unsigned int insn = *p->ainsn.insn;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	regs->nip = (unsigned long)p->addr;
 | 
						regs->nip = (unsigned long)p->addr;
 | 
				
			||||||
	ret = emulate_step(regs, p->ainsn.insn[0]);
 | 
						ret = emulate_step(regs, insn);
 | 
				
			||||||
	if (ret == 0)
 | 
						if (ret == 0)
 | 
				
			||||||
		regs->nip = (unsigned long)p->addr + 4;
 | 
							regs->nip = (unsigned long)p->addr + 4;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -331,3 +438,13 @@ int longjmp_break_handler(struct kprobe *p, struct pt_regs *regs)
 | 
				
			||||||
	memcpy(regs, &jprobe_saved_regs, sizeof(struct pt_regs));
 | 
						memcpy(regs, &jprobe_saved_regs, sizeof(struct pt_regs));
 | 
				
			||||||
	return 1;
 | 
						return 1;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static struct kprobe trampoline_p = {
 | 
				
			||||||
 | 
						.addr = (kprobe_opcode_t *) &kretprobe_trampoline,
 | 
				
			||||||
 | 
						.pre_handler = trampoline_probe_handler
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int __init arch_init(void)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						return register_kprobe(&trampoline_p);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -75,6 +75,7 @@ EXPORT_SYMBOL(giveup_fpu);
 | 
				
			||||||
EXPORT_SYMBOL(giveup_altivec);
 | 
					EXPORT_SYMBOL(giveup_altivec);
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
EXPORT_SYMBOL(__flush_icache_range);
 | 
					EXPORT_SYMBOL(__flush_icache_range);
 | 
				
			||||||
 | 
					EXPORT_SYMBOL(flush_dcache_range);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef CONFIG_SMP
 | 
					#ifdef CONFIG_SMP
 | 
				
			||||||
#ifdef CONFIG_PPC_ISERIES
 | 
					#ifdef CONFIG_PPC_ISERIES
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -36,6 +36,7 @@
 | 
				
			||||||
#include <linux/kallsyms.h>
 | 
					#include <linux/kallsyms.h>
 | 
				
			||||||
#include <linux/interrupt.h>
 | 
					#include <linux/interrupt.h>
 | 
				
			||||||
#include <linux/utsname.h>
 | 
					#include <linux/utsname.h>
 | 
				
			||||||
 | 
					#include <linux/kprobes.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <asm/pgtable.h>
 | 
					#include <asm/pgtable.h>
 | 
				
			||||||
#include <asm/uaccess.h>
 | 
					#include <asm/uaccess.h>
 | 
				
			||||||
| 
						 | 
					@ -307,6 +308,8 @@ void show_regs(struct pt_regs * regs)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void exit_thread(void)
 | 
					void exit_thread(void)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
						kprobe_flush_task(current);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifndef CONFIG_SMP
 | 
					#ifndef CONFIG_SMP
 | 
				
			||||||
	if (last_task_used_math == current)
 | 
						if (last_task_used_math == current)
 | 
				
			||||||
		last_task_used_math = NULL;
 | 
							last_task_used_math = NULL;
 | 
				
			||||||
| 
						 | 
					@ -321,6 +324,7 @@ void flush_thread(void)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct thread_info *t = current_thread_info();
 | 
						struct thread_info *t = current_thread_info();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						kprobe_flush_task(current);
 | 
				
			||||||
	if (t->flags & _TIF_ABI_PENDING)
 | 
						if (t->flags & _TIF_ABI_PENDING)
 | 
				
			||||||
		t->flags ^= (_TIF_ABI_PENDING | _TIF_32BIT);
 | 
							t->flags ^= (_TIF_ABI_PENDING | _TIF_32BIT);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -91,6 +91,7 @@ unsigned long tb_to_xs;
 | 
				
			||||||
unsigned      tb_to_us;
 | 
					unsigned      tb_to_us;
 | 
				
			||||||
unsigned long processor_freq;
 | 
					unsigned long processor_freq;
 | 
				
			||||||
DEFINE_SPINLOCK(rtc_lock);
 | 
					DEFINE_SPINLOCK(rtc_lock);
 | 
				
			||||||
 | 
					EXPORT_SYMBOL_GPL(rtc_lock);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
unsigned long tb_to_ns_scale;
 | 
					unsigned long tb_to_ns_scale;
 | 
				
			||||||
unsigned long tb_to_ns_shift;
 | 
					unsigned long tb_to_ns_shift;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -38,7 +38,7 @@
 | 
				
			||||||
#include <linux/string.h>
 | 
					#include <linux/string.h>
 | 
				
			||||||
#include <linux/slab.h>
 | 
					#include <linux/slab.h>
 | 
				
			||||||
#include <linux/preempt.h>
 | 
					#include <linux/preempt.h>
 | 
				
			||||||
#include <linux/moduleloader.h>
 | 
					
 | 
				
			||||||
#include <asm/cacheflush.h>
 | 
					#include <asm/cacheflush.h>
 | 
				
			||||||
#include <asm/pgtable.h>
 | 
					#include <asm/pgtable.h>
 | 
				
			||||||
#include <asm/kdebug.h>
 | 
					#include <asm/kdebug.h>
 | 
				
			||||||
| 
						 | 
					@ -51,8 +51,6 @@ static struct kprobe *kprobe_prev;
 | 
				
			||||||
static unsigned long kprobe_status_prev, kprobe_old_rflags_prev, kprobe_saved_rflags_prev;
 | 
					static unsigned long kprobe_status_prev, kprobe_old_rflags_prev, kprobe_saved_rflags_prev;
 | 
				
			||||||
static struct pt_regs jprobe_saved_regs;
 | 
					static struct pt_regs jprobe_saved_regs;
 | 
				
			||||||
static long *jprobe_saved_rsp;
 | 
					static long *jprobe_saved_rsp;
 | 
				
			||||||
static kprobe_opcode_t *get_insn_slot(void);
 | 
					 | 
				
			||||||
static void free_insn_slot(kprobe_opcode_t *slot);
 | 
					 | 
				
			||||||
void jprobe_return_end(void);
 | 
					void jprobe_return_end(void);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* copy of the kernel stack at the probe fire time */
 | 
					/* copy of the kernel stack at the probe fire time */
 | 
				
			||||||
| 
						 | 
					@ -274,48 +272,23 @@ static void prepare_singlestep(struct kprobe *p, struct pt_regs *regs)
 | 
				
			||||||
		regs->rip = (unsigned long)p->ainsn.insn;
 | 
							regs->rip = (unsigned long)p->ainsn.insn;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct task_struct  *arch_get_kprobe_task(void *ptr)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	return ((struct thread_info *) (((unsigned long) ptr) &
 | 
					 | 
				
			||||||
					(~(THREAD_SIZE -1))))->task;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void arch_prepare_kretprobe(struct kretprobe *rp, struct pt_regs *regs)
 | 
					void arch_prepare_kretprobe(struct kretprobe *rp, struct pt_regs *regs)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	unsigned long *sara = (unsigned long *)regs->rsp;
 | 
						unsigned long *sara = (unsigned long *)regs->rsp;
 | 
				
			||||||
	struct kretprobe_instance *ri;
 | 
					        struct kretprobe_instance *ri;
 | 
				
			||||||
	static void *orig_ret_addr;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/*
 | 
					        if ((ri = get_free_rp_inst(rp)) != NULL) {
 | 
				
			||||||
	 * Save the return address when the return probe hits
 | 
					                ri->rp = rp;
 | 
				
			||||||
	 * the first time, and use it to populate the (krprobe
 | 
					                ri->task = current;
 | 
				
			||||||
	 * instance)->ret_addr for subsequent return probes at
 | 
							ri->ret_addr = (kprobe_opcode_t *) *sara;
 | 
				
			||||||
	 * the same addrress since stack address would have
 | 
					 | 
				
			||||||
	 * the kretprobe_trampoline by then.
 | 
					 | 
				
			||||||
	 */
 | 
					 | 
				
			||||||
	if (((void*) *sara) != kretprobe_trampoline)
 | 
					 | 
				
			||||||
		orig_ret_addr = (void*) *sara;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if ((ri = get_free_rp_inst(rp)) != NULL) {
 | 
					 | 
				
			||||||
		ri->rp = rp;
 | 
					 | 
				
			||||||
		ri->stack_addr = sara;
 | 
					 | 
				
			||||||
		ri->ret_addr = orig_ret_addr;
 | 
					 | 
				
			||||||
		add_rp_inst(ri);
 | 
					 | 
				
			||||||
		/* Replace the return addr with trampoline addr */
 | 
							/* Replace the return addr with trampoline addr */
 | 
				
			||||||
		*sara = (unsigned long) &kretprobe_trampoline;
 | 
							*sara = (unsigned long) &kretprobe_trampoline;
 | 
				
			||||||
	} else {
 | 
					 | 
				
			||||||
		rp->nmissed++;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
void arch_kprobe_flush_task(struct task_struct *tk)
 | 
					                add_rp_inst(ri);
 | 
				
			||||||
{
 | 
					        } else {
 | 
				
			||||||
	struct kretprobe_instance *ri;
 | 
					                rp->nmissed++;
 | 
				
			||||||
	while ((ri = get_rp_inst_tsk(tk)) != NULL) {
 | 
					        }
 | 
				
			||||||
		*((unsigned long *)(ri->stack_addr)) =
 | 
					 | 
				
			||||||
					(unsigned long) ri->ret_addr;
 | 
					 | 
				
			||||||
		recycle_rp_inst(ri);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
| 
						 | 
					@ -428,36 +401,59 @@ no_kprobe:
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
int trampoline_probe_handler(struct kprobe *p, struct pt_regs *regs)
 | 
					int trampoline_probe_handler(struct kprobe *p, struct pt_regs *regs)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct task_struct *tsk;
 | 
					        struct kretprobe_instance *ri = NULL;
 | 
				
			||||||
	struct kretprobe_instance *ri;
 | 
					        struct hlist_head *head;
 | 
				
			||||||
	struct hlist_head *head;
 | 
					        struct hlist_node *node, *tmp;
 | 
				
			||||||
	struct hlist_node *node;
 | 
						unsigned long orig_ret_address = 0;
 | 
				
			||||||
	unsigned long *sara = (unsigned long *)regs->rsp - 1;
 | 
						unsigned long trampoline_address =(unsigned long)&kretprobe_trampoline;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	tsk = arch_get_kprobe_task(sara);
 | 
					        head = kretprobe_inst_table_head(current);
 | 
				
			||||||
	head = kretprobe_inst_table_head(tsk);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	hlist_for_each_entry(ri, node, head, hlist) {
 | 
						/*
 | 
				
			||||||
		if (ri->stack_addr == sara && ri->rp) {
 | 
						 * It is possible to have multiple instances associated with a given
 | 
				
			||||||
			if (ri->rp->handler)
 | 
						 * task either because an multiple functions in the call path
 | 
				
			||||||
				ri->rp->handler(ri, regs);
 | 
						 * have a return probe installed on them, and/or more then one return
 | 
				
			||||||
		}
 | 
						 * return probe was registered for a target function.
 | 
				
			||||||
	}
 | 
						 *
 | 
				
			||||||
	return 0;
 | 
						 * We can handle this because:
 | 
				
			||||||
}
 | 
						 *     - instances are always inserted at the head of the list
 | 
				
			||||||
 | 
						 *     - when multiple return probes are registered for the same
 | 
				
			||||||
 | 
					         *       function, the first instance's ret_addr will point to the
 | 
				
			||||||
 | 
						 *       real return address, and all the rest will point to
 | 
				
			||||||
 | 
						 *       kretprobe_trampoline
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						hlist_for_each_entry_safe(ri, node, tmp, head, hlist) {
 | 
				
			||||||
 | 
					                if (ri->task != current)
 | 
				
			||||||
 | 
								/* another task is sharing our hash bucket */
 | 
				
			||||||
 | 
					                        continue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void trampoline_post_handler(struct kprobe *p, struct pt_regs *regs,
 | 
							if (ri->rp && ri->rp->handler)
 | 
				
			||||||
						unsigned long flags)
 | 
								ri->rp->handler(ri, regs);
 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	struct kretprobe_instance *ri;
 | 
					 | 
				
			||||||
	/* RA already popped */
 | 
					 | 
				
			||||||
	unsigned long *sara = ((unsigned long *)regs->rsp) - 1;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	while ((ri = get_rp_inst(sara))) {
 | 
							orig_ret_address = (unsigned long)ri->ret_addr;
 | 
				
			||||||
		regs->rip = (unsigned long)ri->ret_addr;
 | 
					 | 
				
			||||||
		recycle_rp_inst(ri);
 | 
							recycle_rp_inst(ri);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (orig_ret_address != trampoline_address)
 | 
				
			||||||
 | 
								/*
 | 
				
			||||||
 | 
								 * This is the real return address. Any other
 | 
				
			||||||
 | 
								 * instances associated with this task are for
 | 
				
			||||||
 | 
								 * other calls deeper on the call stack
 | 
				
			||||||
 | 
								 */
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	regs->eflags &= ~TF_MASK;
 | 
					
 | 
				
			||||||
 | 
						BUG_ON(!orig_ret_address || (orig_ret_address == trampoline_address));
 | 
				
			||||||
 | 
						regs->rip = orig_ret_address;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						unlock_kprobes();
 | 
				
			||||||
 | 
						preempt_enable_no_resched();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        /*
 | 
				
			||||||
 | 
					         * By returning a non-zero value, we are telling
 | 
				
			||||||
 | 
					         * kprobe_handler() that we have handled unlocking
 | 
				
			||||||
 | 
					         * and re-enabling preemption.
 | 
				
			||||||
 | 
					         */
 | 
				
			||||||
 | 
					        return 1;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
| 
						 | 
					@ -550,8 +546,7 @@ int post_kprobe_handler(struct pt_regs *regs)
 | 
				
			||||||
		current_kprobe->post_handler(current_kprobe, regs, 0);
 | 
							current_kprobe->post_handler(current_kprobe, regs, 0);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (current_kprobe->post_handler != trampoline_post_handler)
 | 
						resume_execution(current_kprobe, regs);
 | 
				
			||||||
		resume_execution(current_kprobe, regs);
 | 
					 | 
				
			||||||
	regs->eflags |= kprobe_saved_rflags;
 | 
						regs->eflags |= kprobe_saved_rflags;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Restore the original saved kprobes variables and continue. */
 | 
						/* Restore the original saved kprobes variables and continue. */
 | 
				
			||||||
| 
						 | 
					@ -682,111 +677,12 @@ int longjmp_break_handler(struct kprobe *p, struct pt_regs *regs)
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					static struct kprobe trampoline_p = {
 | 
				
			||||||
 * kprobe->ainsn.insn points to the copy of the instruction to be single-stepped.
 | 
						.addr = (kprobe_opcode_t *) &kretprobe_trampoline,
 | 
				
			||||||
 * By default on x86_64, pages we get from kmalloc or vmalloc are not
 | 
						.pre_handler = trampoline_probe_handler
 | 
				
			||||||
 * executable.  Single-stepping an instruction on such a page yields an
 | 
					 | 
				
			||||||
 * oops.  So instead of storing the instruction copies in their respective
 | 
					 | 
				
			||||||
 * kprobe objects, we allocate a page, map it executable, and store all the
 | 
					 | 
				
			||||||
 * instruction copies there.  (We can allocate additional pages if somebody
 | 
					 | 
				
			||||||
 * inserts a huge number of probes.)  Each page can hold up to INSNS_PER_PAGE
 | 
					 | 
				
			||||||
 * instruction slots, each of which is MAX_INSN_SIZE*sizeof(kprobe_opcode_t)
 | 
					 | 
				
			||||||
 * bytes.
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
#define INSNS_PER_PAGE (PAGE_SIZE/(MAX_INSN_SIZE*sizeof(kprobe_opcode_t)))
 | 
					 | 
				
			||||||
struct kprobe_insn_page {
 | 
					 | 
				
			||||||
	struct hlist_node hlist;
 | 
					 | 
				
			||||||
	kprobe_opcode_t *insns;		/* page of instruction slots */
 | 
					 | 
				
			||||||
	char slot_used[INSNS_PER_PAGE];
 | 
					 | 
				
			||||||
	int nused;
 | 
					 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static struct hlist_head kprobe_insn_pages;
 | 
					int __init arch_init(void)
 | 
				
			||||||
 | 
					 | 
				
			||||||
/**
 | 
					 | 
				
			||||||
 * get_insn_slot() - Find a slot on an executable page for an instruction.
 | 
					 | 
				
			||||||
 * We allocate an executable page if there's no room on existing ones.
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
static kprobe_opcode_t *get_insn_slot(void)
 | 
					 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct kprobe_insn_page *kip;
 | 
						return register_kprobe(&trampoline_p);
 | 
				
			||||||
	struct hlist_node *pos;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	hlist_for_each(pos, &kprobe_insn_pages) {
 | 
					 | 
				
			||||||
		kip = hlist_entry(pos, struct kprobe_insn_page, hlist);
 | 
					 | 
				
			||||||
		if (kip->nused < INSNS_PER_PAGE) {
 | 
					 | 
				
			||||||
			int i;
 | 
					 | 
				
			||||||
			for (i = 0; i < INSNS_PER_PAGE; i++) {
 | 
					 | 
				
			||||||
				if (!kip->slot_used[i]) {
 | 
					 | 
				
			||||||
					kip->slot_used[i] = 1;
 | 
					 | 
				
			||||||
					kip->nused++;
 | 
					 | 
				
			||||||
					return kip->insns + (i*MAX_INSN_SIZE);
 | 
					 | 
				
			||||||
				}
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
			/* Surprise!  No unused slots.  Fix kip->nused. */
 | 
					 | 
				
			||||||
			kip->nused = INSNS_PER_PAGE;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* All out of space.  Need to allocate a new page. Use slot 0.*/
 | 
					 | 
				
			||||||
	kip = kmalloc(sizeof(struct kprobe_insn_page), GFP_KERNEL);
 | 
					 | 
				
			||||||
	if (!kip) {
 | 
					 | 
				
			||||||
		return NULL;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/*
 | 
					 | 
				
			||||||
	 * For the %rip-relative displacement fixups to be doable, we
 | 
					 | 
				
			||||||
	 * need our instruction copy to be within +/- 2GB of any data it
 | 
					 | 
				
			||||||
	 * might access via %rip.  That is, within 2GB of where the
 | 
					 | 
				
			||||||
	 * kernel image and loaded module images reside.  So we allocate
 | 
					 | 
				
			||||||
	 * a page in the module loading area.
 | 
					 | 
				
			||||||
	 */
 | 
					 | 
				
			||||||
	kip->insns = module_alloc(PAGE_SIZE);
 | 
					 | 
				
			||||||
	if (!kip->insns) {
 | 
					 | 
				
			||||||
		kfree(kip);
 | 
					 | 
				
			||||||
		return NULL;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	INIT_HLIST_NODE(&kip->hlist);
 | 
					 | 
				
			||||||
	hlist_add_head(&kip->hlist, &kprobe_insn_pages);
 | 
					 | 
				
			||||||
	memset(kip->slot_used, 0, INSNS_PER_PAGE);
 | 
					 | 
				
			||||||
	kip->slot_used[0] = 1;
 | 
					 | 
				
			||||||
	kip->nused = 1;
 | 
					 | 
				
			||||||
	return kip->insns;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/**
 | 
					 | 
				
			||||||
 * free_insn_slot() - Free instruction slot obtained from get_insn_slot().
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
static void free_insn_slot(kprobe_opcode_t *slot)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	struct kprobe_insn_page *kip;
 | 
					 | 
				
			||||||
	struct hlist_node *pos;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	hlist_for_each(pos, &kprobe_insn_pages) {
 | 
					 | 
				
			||||||
		kip = hlist_entry(pos, struct kprobe_insn_page, hlist);
 | 
					 | 
				
			||||||
		if (kip->insns <= slot
 | 
					 | 
				
			||||||
		    && slot < kip->insns+(INSNS_PER_PAGE*MAX_INSN_SIZE)) {
 | 
					 | 
				
			||||||
			int i = (slot - kip->insns) / MAX_INSN_SIZE;
 | 
					 | 
				
			||||||
			kip->slot_used[i] = 0;
 | 
					 | 
				
			||||||
			kip->nused--;
 | 
					 | 
				
			||||||
			if (kip->nused == 0) {
 | 
					 | 
				
			||||||
				/*
 | 
					 | 
				
			||||||
				 * Page is no longer in use.  Free it unless
 | 
					 | 
				
			||||||
				 * it's the last one.  We keep the last one
 | 
					 | 
				
			||||||
				 * so as not to have to set it up again the
 | 
					 | 
				
			||||||
				 * next time somebody inserts a probe.
 | 
					 | 
				
			||||||
				 */
 | 
					 | 
				
			||||||
				hlist_del(&kip->hlist);
 | 
					 | 
				
			||||||
				if (hlist_empty(&kprobe_insn_pages)) {
 | 
					 | 
				
			||||||
					INIT_HLIST_NODE(&kip->hlist);
 | 
					 | 
				
			||||||
					hlist_add_head(&kip->hlist,
 | 
					 | 
				
			||||||
						&kprobe_insn_pages);
 | 
					 | 
				
			||||||
				} else {
 | 
					 | 
				
			||||||
					module_free(NULL, kip->insns);
 | 
					 | 
				
			||||||
					kfree(kip);
 | 
					 | 
				
			||||||
				}
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
			return;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -481,6 +481,33 @@ out:
 | 
				
			||||||
	return err;
 | 
						return err;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * This function selects if the context switch from prev to next
 | 
				
			||||||
 | 
					 * has to tweak the TSC disable bit in the cr4.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					static inline void disable_tsc(struct task_struct *prev_p,
 | 
				
			||||||
 | 
								       struct task_struct *next_p)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct thread_info *prev, *next;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/*
 | 
				
			||||||
 | 
						 * gcc should eliminate the ->thread_info dereference if
 | 
				
			||||||
 | 
						 * has_secure_computing returns 0 at compile time (SECCOMP=n).
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						prev = prev_p->thread_info;
 | 
				
			||||||
 | 
						next = next_p->thread_info;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (has_secure_computing(prev) || has_secure_computing(next)) {
 | 
				
			||||||
 | 
							/* slow path here */
 | 
				
			||||||
 | 
							if (has_secure_computing(prev) &&
 | 
				
			||||||
 | 
							    !has_secure_computing(next)) {
 | 
				
			||||||
 | 
								write_cr4(read_cr4() & ~X86_CR4_TSD);
 | 
				
			||||||
 | 
							} else if (!has_secure_computing(prev) &&
 | 
				
			||||||
 | 
								   has_secure_computing(next))
 | 
				
			||||||
 | 
								write_cr4(read_cr4() | X86_CR4_TSD);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 * This special macro can be used to load a debugging register
 | 
					 * This special macro can be used to load a debugging register
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
| 
						 | 
					@ -599,6 +626,8 @@ struct task_struct *__switch_to(struct task_struct *prev_p, struct task_struct *
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						disable_tsc(prev_p, next_p);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return prev_p;
 | 
						return prev_p;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1806,7 +1806,8 @@ static void as_put_request(request_queue_t *q, struct request *rq)
 | 
				
			||||||
	rq->elevator_private = NULL;
 | 
						rq->elevator_private = NULL;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int as_set_request(request_queue_t *q, struct request *rq, int gfp_mask)
 | 
					static int as_set_request(request_queue_t *q, struct request *rq,
 | 
				
			||||||
 | 
								  struct bio *bio, int gfp_mask)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct as_data *ad = q->elevator->elevator_data;
 | 
						struct as_data *ad = q->elevator->elevator_data;
 | 
				
			||||||
	struct as_rq *arq = mempool_alloc(ad->arq_pool, gfp_mask);
 | 
						struct as_rq *arq = mempool_alloc(ad->arq_pool, gfp_mask);
 | 
				
			||||||
| 
						 | 
					@ -1827,7 +1828,7 @@ static int as_set_request(request_queue_t *q, struct request *rq, int gfp_mask)
 | 
				
			||||||
	return 1;
 | 
						return 1;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int as_may_queue(request_queue_t *q, int rw)
 | 
					static int as_may_queue(request_queue_t *q, int rw, struct bio *bio)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	int ret = ELV_MQUEUE_MAY;
 | 
						int ret = ELV_MQUEUE_MAY;
 | 
				
			||||||
	struct as_data *ad = q->elevator->elevator_data;
 | 
						struct as_data *ad = q->elevator->elevator_data;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,6 +1,6 @@
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 *    Disk Array driver for HP SA 5xxx and 6xxx Controllers
 | 
					 *    Disk Array driver for HP SA 5xxx and 6xxx Controllers
 | 
				
			||||||
 *    Copyright 2000, 2002 Hewlett-Packard Development Company, L.P.
 | 
					 *    Copyright 2000, 2005 Hewlett-Packard Development Company, L.P.
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 *    This program is free software; you can redistribute it and/or modify
 | 
					 *    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
 | 
					 *    it under the terms of the GNU General Public License as published by
 | 
				
			||||||
| 
						 | 
					@ -54,7 +54,7 @@
 | 
				
			||||||
MODULE_AUTHOR("Hewlett-Packard Company");
 | 
					MODULE_AUTHOR("Hewlett-Packard Company");
 | 
				
			||||||
MODULE_DESCRIPTION("Driver for HP Controller SA5xxx SA6xxx version 2.6.6");
 | 
					MODULE_DESCRIPTION("Driver for HP Controller SA5xxx SA6xxx version 2.6.6");
 | 
				
			||||||
MODULE_SUPPORTED_DEVICE("HP SA5i SA5i+ SA532 SA5300 SA5312 SA641 SA642 SA6400"
 | 
					MODULE_SUPPORTED_DEVICE("HP SA5i SA5i+ SA532 SA5300 SA5312 SA641 SA642 SA6400"
 | 
				
			||||||
			" SA6i P600 P800 E400");
 | 
								" SA6i P600 P800 E400 E300");
 | 
				
			||||||
MODULE_LICENSE("GPL");
 | 
					MODULE_LICENSE("GPL");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "cciss_cmd.h"
 | 
					#include "cciss_cmd.h"
 | 
				
			||||||
| 
						 | 
					@ -85,8 +85,10 @@ static const struct pci_device_id cciss_pci_device_id[] = {
 | 
				
			||||||
		0x103C, 0x3225, 0, 0, 0},
 | 
							0x103C, 0x3225, 0, 0, 0},
 | 
				
			||||||
	{ PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSB,
 | 
						{ PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSB,
 | 
				
			||||||
		0x103c, 0x3223, 0, 0, 0},
 | 
							0x103c, 0x3223, 0, 0, 0},
 | 
				
			||||||
	{ PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSB,
 | 
						{ PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSC,
 | 
				
			||||||
		0x103c, 0x3231, 0, 0, 0},
 | 
							0x103c, 0x3231, 0, 0, 0},
 | 
				
			||||||
 | 
						{ PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSC,
 | 
				
			||||||
 | 
							0x103c, 0x3233, 0, 0, 0},
 | 
				
			||||||
	{0,}
 | 
						{0,}
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
MODULE_DEVICE_TABLE(pci, cciss_pci_device_id);
 | 
					MODULE_DEVICE_TABLE(pci, cciss_pci_device_id);
 | 
				
			||||||
| 
						 | 
					@ -110,6 +112,7 @@ static struct board_type products[] = {
 | 
				
			||||||
	{ 0x3225103C, "Smart Array P600", &SA5_access},
 | 
						{ 0x3225103C, "Smart Array P600", &SA5_access},
 | 
				
			||||||
	{ 0x3223103C, "Smart Array P800", &SA5_access},
 | 
						{ 0x3223103C, "Smart Array P800", &SA5_access},
 | 
				
			||||||
	{ 0x3231103C, "Smart Array E400", &SA5_access},
 | 
						{ 0x3231103C, "Smart Array E400", &SA5_access},
 | 
				
			||||||
 | 
						{ 0x3233103C, "Smart Array E300", &SA5_access},
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* How long to wait (in millesconds) for board to go into simple mode */
 | 
					/* How long to wait (in millesconds) for board to go into simple mode */
 | 
				
			||||||
| 
						 | 
					@ -635,6 +638,7 @@ static int cciss_ioctl(struct inode *inode, struct file *filep,
 | 
				
			||||||
		cciss_pci_info_struct pciinfo;
 | 
							cciss_pci_info_struct pciinfo;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (!arg) return -EINVAL;
 | 
							if (!arg) return -EINVAL;
 | 
				
			||||||
 | 
							pciinfo.domain = pci_domain_nr(host->pdev->bus);
 | 
				
			||||||
		pciinfo.bus = host->pdev->bus->number;
 | 
							pciinfo.bus = host->pdev->bus->number;
 | 
				
			||||||
		pciinfo.dev_fn = host->pdev->devfn;
 | 
							pciinfo.dev_fn = host->pdev->devfn;
 | 
				
			||||||
		pciinfo.board_id = host->board_id;
 | 
							pciinfo.board_id = host->board_id;
 | 
				
			||||||
| 
						 | 
					@ -787,13 +791,6 @@ static int cciss_ioctl(struct inode *inode, struct file *filep,
 | 
				
			||||||
 		luninfo.LunID = drv->LunID;
 | 
					 		luninfo.LunID = drv->LunID;
 | 
				
			||||||
 		luninfo.num_opens = drv->usage_count;
 | 
					 		luninfo.num_opens = drv->usage_count;
 | 
				
			||||||
 		luninfo.num_parts = 0;
 | 
					 		luninfo.num_parts = 0;
 | 
				
			||||||
 		/* count partitions 1 to 15 with sizes > 0 */
 | 
					 | 
				
			||||||
 		for (i = 0; i < MAX_PART - 1; i++) {
 | 
					 | 
				
			||||||
			if (!disk->part[i])
 | 
					 | 
				
			||||||
				continue;
 | 
					 | 
				
			||||||
			if (disk->part[i]->nr_sects != 0)
 | 
					 | 
				
			||||||
				luninfo.num_parts++;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 		if (copy_to_user(argp, &luninfo,
 | 
					 		if (copy_to_user(argp, &luninfo,
 | 
				
			||||||
 				sizeof(LogvolInfo_struct)))
 | 
					 				sizeof(LogvolInfo_struct)))
 | 
				
			||||||
 			return -EFAULT;
 | 
					 			return -EFAULT;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							| 
						 | 
					@ -760,7 +760,8 @@ static void deadline_put_request(request_queue_t *q, struct request *rq)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int
 | 
					static int
 | 
				
			||||||
deadline_set_request(request_queue_t *q, struct request *rq, int gfp_mask)
 | 
					deadline_set_request(request_queue_t *q, struct request *rq, struct bio *bio,
 | 
				
			||||||
 | 
							     int gfp_mask)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct deadline_data *dd = q->elevator->elevator_data;
 | 
						struct deadline_data *dd = q->elevator->elevator_data;
 | 
				
			||||||
	struct deadline_rq *drq;
 | 
						struct deadline_rq *drq;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -486,12 +486,13 @@ struct request *elv_former_request(request_queue_t *q, struct request *rq)
 | 
				
			||||||
	return NULL;
 | 
						return NULL;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int elv_set_request(request_queue_t *q, struct request *rq, int gfp_mask)
 | 
					int elv_set_request(request_queue_t *q, struct request *rq, struct bio *bio,
 | 
				
			||||||
 | 
							    int gfp_mask)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	elevator_t *e = q->elevator;
 | 
						elevator_t *e = q->elevator;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (e->ops->elevator_set_req_fn)
 | 
						if (e->ops->elevator_set_req_fn)
 | 
				
			||||||
		return e->ops->elevator_set_req_fn(q, rq, gfp_mask);
 | 
							return e->ops->elevator_set_req_fn(q, rq, bio, gfp_mask);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	rq->elevator_private = NULL;
 | 
						rq->elevator_private = NULL;
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
| 
						 | 
					@ -505,12 +506,12 @@ void elv_put_request(request_queue_t *q, struct request *rq)
 | 
				
			||||||
		e->ops->elevator_put_req_fn(q, rq);
 | 
							e->ops->elevator_put_req_fn(q, rq);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int elv_may_queue(request_queue_t *q, int rw)
 | 
					int elv_may_queue(request_queue_t *q, int rw, struct bio *bio)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	elevator_t *e = q->elevator;
 | 
						elevator_t *e = q->elevator;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (e->ops->elevator_may_queue_fn)
 | 
						if (e->ops->elevator_may_queue_fn)
 | 
				
			||||||
		return e->ops->elevator_may_queue_fn(q, rw);
 | 
							return e->ops->elevator_may_queue_fn(q, rw, bio);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return ELV_MQUEUE_MAY;
 | 
						return ELV_MQUEUE_MAY;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -276,6 +276,7 @@ static inline void rq_init(request_queue_t *q, struct request *rq)
 | 
				
			||||||
	rq->errors = 0;
 | 
						rq->errors = 0;
 | 
				
			||||||
	rq->rq_status = RQ_ACTIVE;
 | 
						rq->rq_status = RQ_ACTIVE;
 | 
				
			||||||
	rq->bio = rq->biotail = NULL;
 | 
						rq->bio = rq->biotail = NULL;
 | 
				
			||||||
 | 
						rq->ioprio = 0;
 | 
				
			||||||
	rq->buffer = NULL;
 | 
						rq->buffer = NULL;
 | 
				
			||||||
	rq->ref_count = 1;
 | 
						rq->ref_count = 1;
 | 
				
			||||||
	rq->q = q;
 | 
						rq->q = q;
 | 
				
			||||||
| 
						 | 
					@ -1442,11 +1443,7 @@ void __generic_unplug_device(request_queue_t *q)
 | 
				
			||||||
	if (!blk_remove_plug(q))
 | 
						if (!blk_remove_plug(q))
 | 
				
			||||||
		return;
 | 
							return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/*
 | 
						q->request_fn(q);
 | 
				
			||||||
	 * was plugged, fire request_fn if queue has stuff to do
 | 
					 | 
				
			||||||
	 */
 | 
					 | 
				
			||||||
	if (elv_next_request(q))
 | 
					 | 
				
			||||||
		q->request_fn(q);
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
EXPORT_SYMBOL(__generic_unplug_device);
 | 
					EXPORT_SYMBOL(__generic_unplug_device);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1776,8 +1773,8 @@ static inline void blk_free_request(request_queue_t *q, struct request *rq)
 | 
				
			||||||
	mempool_free(rq, q->rq.rq_pool);
 | 
						mempool_free(rq, q->rq.rq_pool);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static inline struct request *blk_alloc_request(request_queue_t *q, int rw,
 | 
					static inline struct request *
 | 
				
			||||||
						int gfp_mask)
 | 
					blk_alloc_request(request_queue_t *q, int rw, struct bio *bio, int gfp_mask)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct request *rq = mempool_alloc(q->rq.rq_pool, gfp_mask);
 | 
						struct request *rq = mempool_alloc(q->rq.rq_pool, gfp_mask);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1790,7 +1787,7 @@ static inline struct request *blk_alloc_request(request_queue_t *q, int rw,
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
	rq->flags = rw;
 | 
						rq->flags = rw;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!elv_set_request(q, rq, gfp_mask))
 | 
						if (!elv_set_request(q, rq, bio, gfp_mask))
 | 
				
			||||||
		return rq;
 | 
							return rq;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	mempool_free(rq, q->rq.rq_pool);
 | 
						mempool_free(rq, q->rq.rq_pool);
 | 
				
			||||||
| 
						 | 
					@ -1872,7 +1869,8 @@ static void freed_request(request_queue_t *q, int rw)
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 * Get a free request, queue_lock must not be held
 | 
					 * Get a free request, queue_lock must not be held
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
static struct request *get_request(request_queue_t *q, int rw, int gfp_mask)
 | 
					static struct request *get_request(request_queue_t *q, int rw, struct bio *bio,
 | 
				
			||||||
 | 
									   int gfp_mask)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct request *rq = NULL;
 | 
						struct request *rq = NULL;
 | 
				
			||||||
	struct request_list *rl = &q->rq;
 | 
						struct request_list *rl = &q->rq;
 | 
				
			||||||
| 
						 | 
					@ -1895,7 +1893,7 @@ static struct request *get_request(request_queue_t *q, int rw, int gfp_mask)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	switch (elv_may_queue(q, rw)) {
 | 
						switch (elv_may_queue(q, rw, bio)) {
 | 
				
			||||||
		case ELV_MQUEUE_NO:
 | 
							case ELV_MQUEUE_NO:
 | 
				
			||||||
			goto rq_starved;
 | 
								goto rq_starved;
 | 
				
			||||||
		case ELV_MQUEUE_MAY:
 | 
							case ELV_MQUEUE_MAY:
 | 
				
			||||||
| 
						 | 
					@ -1920,7 +1918,7 @@ get_rq:
 | 
				
			||||||
		set_queue_congested(q, rw);
 | 
							set_queue_congested(q, rw);
 | 
				
			||||||
	spin_unlock_irq(q->queue_lock);
 | 
						spin_unlock_irq(q->queue_lock);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	rq = blk_alloc_request(q, rw, gfp_mask);
 | 
						rq = blk_alloc_request(q, rw, bio, gfp_mask);
 | 
				
			||||||
	if (!rq) {
 | 
						if (!rq) {
 | 
				
			||||||
		/*
 | 
							/*
 | 
				
			||||||
		 * Allocation failed presumably due to memory. Undo anything
 | 
							 * Allocation failed presumably due to memory. Undo anything
 | 
				
			||||||
| 
						 | 
					@ -1961,7 +1959,8 @@ out:
 | 
				
			||||||
 * No available requests for this queue, unplug the device and wait for some
 | 
					 * No available requests for this queue, unplug the device and wait for some
 | 
				
			||||||
 * requests to become available.
 | 
					 * requests to become available.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
static struct request *get_request_wait(request_queue_t *q, int rw)
 | 
					static struct request *get_request_wait(request_queue_t *q, int rw,
 | 
				
			||||||
 | 
										struct bio *bio)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	DEFINE_WAIT(wait);
 | 
						DEFINE_WAIT(wait);
 | 
				
			||||||
	struct request *rq;
 | 
						struct request *rq;
 | 
				
			||||||
| 
						 | 
					@ -1972,7 +1971,7 @@ static struct request *get_request_wait(request_queue_t *q, int rw)
 | 
				
			||||||
		prepare_to_wait_exclusive(&rl->wait[rw], &wait,
 | 
							prepare_to_wait_exclusive(&rl->wait[rw], &wait,
 | 
				
			||||||
				TASK_UNINTERRUPTIBLE);
 | 
									TASK_UNINTERRUPTIBLE);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		rq = get_request(q, rw, GFP_NOIO);
 | 
							rq = get_request(q, rw, bio, GFP_NOIO);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (!rq) {
 | 
							if (!rq) {
 | 
				
			||||||
			struct io_context *ioc;
 | 
								struct io_context *ioc;
 | 
				
			||||||
| 
						 | 
					@ -2003,9 +2002,9 @@ struct request *blk_get_request(request_queue_t *q, int rw, int gfp_mask)
 | 
				
			||||||
	BUG_ON(rw != READ && rw != WRITE);
 | 
						BUG_ON(rw != READ && rw != WRITE);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (gfp_mask & __GFP_WAIT)
 | 
						if (gfp_mask & __GFP_WAIT)
 | 
				
			||||||
		rq = get_request_wait(q, rw);
 | 
							rq = get_request_wait(q, rw, NULL);
 | 
				
			||||||
	else
 | 
						else
 | 
				
			||||||
		rq = get_request(q, rw, gfp_mask);
 | 
							rq = get_request(q, rw, NULL, gfp_mask);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return rq;
 | 
						return rq;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -2333,7 +2332,6 @@ static void __blk_put_request(request_queue_t *q, struct request *req)
 | 
				
			||||||
		return;
 | 
							return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	req->rq_status = RQ_INACTIVE;
 | 
						req->rq_status = RQ_INACTIVE;
 | 
				
			||||||
	req->q = NULL;
 | 
					 | 
				
			||||||
	req->rl = NULL;
 | 
						req->rl = NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/*
 | 
						/*
 | 
				
			||||||
| 
						 | 
					@ -2462,6 +2460,8 @@ static int attempt_merge(request_queue_t *q, struct request *req,
 | 
				
			||||||
		req->rq_disk->in_flight--;
 | 
							req->rq_disk->in_flight--;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						req->ioprio = ioprio_best(req->ioprio, next->ioprio);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	__blk_put_request(q, next);
 | 
						__blk_put_request(q, next);
 | 
				
			||||||
	return 1;
 | 
						return 1;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -2514,11 +2514,13 @@ static int __make_request(request_queue_t *q, struct bio *bio)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct request *req, *freereq = NULL;
 | 
						struct request *req, *freereq = NULL;
 | 
				
			||||||
	int el_ret, rw, nr_sectors, cur_nr_sectors, barrier, err, sync;
 | 
						int el_ret, rw, nr_sectors, cur_nr_sectors, barrier, err, sync;
 | 
				
			||||||
 | 
						unsigned short prio;
 | 
				
			||||||
	sector_t sector;
 | 
						sector_t sector;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	sector = bio->bi_sector;
 | 
						sector = bio->bi_sector;
 | 
				
			||||||
	nr_sectors = bio_sectors(bio);
 | 
						nr_sectors = bio_sectors(bio);
 | 
				
			||||||
	cur_nr_sectors = bio_cur_sectors(bio);
 | 
						cur_nr_sectors = bio_cur_sectors(bio);
 | 
				
			||||||
 | 
						prio = bio_prio(bio);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	rw = bio_data_dir(bio);
 | 
						rw = bio_data_dir(bio);
 | 
				
			||||||
	sync = bio_sync(bio);
 | 
						sync = bio_sync(bio);
 | 
				
			||||||
| 
						 | 
					@ -2559,6 +2561,7 @@ again:
 | 
				
			||||||
			req->biotail->bi_next = bio;
 | 
								req->biotail->bi_next = bio;
 | 
				
			||||||
			req->biotail = bio;
 | 
								req->biotail = bio;
 | 
				
			||||||
			req->nr_sectors = req->hard_nr_sectors += nr_sectors;
 | 
								req->nr_sectors = req->hard_nr_sectors += nr_sectors;
 | 
				
			||||||
 | 
								req->ioprio = ioprio_best(req->ioprio, prio);
 | 
				
			||||||
			drive_stat_acct(req, nr_sectors, 0);
 | 
								drive_stat_acct(req, nr_sectors, 0);
 | 
				
			||||||
			if (!attempt_back_merge(q, req))
 | 
								if (!attempt_back_merge(q, req))
 | 
				
			||||||
				elv_merged_request(q, req);
 | 
									elv_merged_request(q, req);
 | 
				
			||||||
| 
						 | 
					@ -2583,6 +2586,7 @@ again:
 | 
				
			||||||
			req->hard_cur_sectors = cur_nr_sectors;
 | 
								req->hard_cur_sectors = cur_nr_sectors;
 | 
				
			||||||
			req->sector = req->hard_sector = sector;
 | 
								req->sector = req->hard_sector = sector;
 | 
				
			||||||
			req->nr_sectors = req->hard_nr_sectors += nr_sectors;
 | 
								req->nr_sectors = req->hard_nr_sectors += nr_sectors;
 | 
				
			||||||
 | 
								req->ioprio = ioprio_best(req->ioprio, prio);
 | 
				
			||||||
			drive_stat_acct(req, nr_sectors, 0);
 | 
								drive_stat_acct(req, nr_sectors, 0);
 | 
				
			||||||
			if (!attempt_front_merge(q, req))
 | 
								if (!attempt_front_merge(q, req))
 | 
				
			||||||
				elv_merged_request(q, req);
 | 
									elv_merged_request(q, req);
 | 
				
			||||||
| 
						 | 
					@ -2610,7 +2614,7 @@ get_rq:
 | 
				
			||||||
		freereq = NULL;
 | 
							freereq = NULL;
 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
		spin_unlock_irq(q->queue_lock);
 | 
							spin_unlock_irq(q->queue_lock);
 | 
				
			||||||
		if ((freereq = get_request(q, rw, GFP_ATOMIC)) == NULL) {
 | 
							if ((freereq = get_request(q, rw, bio, GFP_ATOMIC)) == NULL) {
 | 
				
			||||||
			/*
 | 
								/*
 | 
				
			||||||
			 * READA bit set
 | 
								 * READA bit set
 | 
				
			||||||
			 */
 | 
								 */
 | 
				
			||||||
| 
						 | 
					@ -2618,7 +2622,7 @@ get_rq:
 | 
				
			||||||
			if (bio_rw_ahead(bio))
 | 
								if (bio_rw_ahead(bio))
 | 
				
			||||||
				goto end_io;
 | 
									goto end_io;
 | 
				
			||||||
	
 | 
						
 | 
				
			||||||
			freereq = get_request_wait(q, rw);
 | 
								freereq = get_request_wait(q, rw, bio);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		goto again;
 | 
							goto again;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					@ -2646,6 +2650,7 @@ get_rq:
 | 
				
			||||||
	req->buffer = bio_data(bio);	/* see ->buffer comment above */
 | 
						req->buffer = bio_data(bio);	/* see ->buffer comment above */
 | 
				
			||||||
	req->waiting = NULL;
 | 
						req->waiting = NULL;
 | 
				
			||||||
	req->bio = req->biotail = bio;
 | 
						req->bio = req->biotail = bio;
 | 
				
			||||||
 | 
						req->ioprio = prio;
 | 
				
			||||||
	req->rq_disk = bio->bi_bdev->bd_disk;
 | 
						req->rq_disk = bio->bi_bdev->bd_disk;
 | 
				
			||||||
	req->start_time = jiffies;
 | 
						req->start_time = jiffies;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -2674,7 +2679,7 @@ static inline void blk_partition_remap(struct bio *bio)
 | 
				
			||||||
	if (bdev != bdev->bd_contains) {
 | 
						if (bdev != bdev->bd_contains) {
 | 
				
			||||||
		struct hd_struct *p = bdev->bd_part;
 | 
							struct hd_struct *p = bdev->bd_part;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		switch (bio->bi_rw) {
 | 
							switch (bio_data_dir(bio)) {
 | 
				
			||||||
		case READ:
 | 
							case READ:
 | 
				
			||||||
			p->read_sectors += bio_sectors(bio);
 | 
								p->read_sectors += bio_sectors(bio);
 | 
				
			||||||
			p->reads++;
 | 
								p->reads++;
 | 
				
			||||||
| 
						 | 
					@ -2693,6 +2698,7 @@ void blk_finish_queue_drain(request_queue_t *q)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct request_list *rl = &q->rq;
 | 
						struct request_list *rl = &q->rq;
 | 
				
			||||||
	struct request *rq;
 | 
						struct request *rq;
 | 
				
			||||||
 | 
						int requeued = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	spin_lock_irq(q->queue_lock);
 | 
						spin_lock_irq(q->queue_lock);
 | 
				
			||||||
	clear_bit(QUEUE_FLAG_DRAIN, &q->queue_flags);
 | 
						clear_bit(QUEUE_FLAG_DRAIN, &q->queue_flags);
 | 
				
			||||||
| 
						 | 
					@ -2701,9 +2707,13 @@ void blk_finish_queue_drain(request_queue_t *q)
 | 
				
			||||||
		rq = list_entry_rq(q->drain_list.next);
 | 
							rq = list_entry_rq(q->drain_list.next);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		list_del_init(&rq->queuelist);
 | 
							list_del_init(&rq->queuelist);
 | 
				
			||||||
		__elv_add_request(q, rq, ELEVATOR_INSERT_BACK, 1);
 | 
							elv_requeue_request(q, rq);
 | 
				
			||||||
 | 
							requeued++;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (requeued)
 | 
				
			||||||
 | 
							q->request_fn(q);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	spin_unlock_irq(q->queue_lock);
 | 
						spin_unlock_irq(q->queue_lock);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	wake_up(&rl->wait[0]);
 | 
						wake_up(&rl->wait[0]);
 | 
				
			||||||
| 
						 | 
					@ -2900,7 +2910,7 @@ void submit_bio(int rw, struct bio *bio)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	BIO_BUG_ON(!bio->bi_size);
 | 
						BIO_BUG_ON(!bio->bi_size);
 | 
				
			||||||
	BIO_BUG_ON(!bio->bi_io_vec);
 | 
						BIO_BUG_ON(!bio->bi_io_vec);
 | 
				
			||||||
	bio->bi_rw = rw;
 | 
						bio->bi_rw |= rw;
 | 
				
			||||||
	if (rw & WRITE)
 | 
						if (rw & WRITE)
 | 
				
			||||||
		mod_page_state(pgpgout, count);
 | 
							mod_page_state(pgpgout, count);
 | 
				
			||||||
	else
 | 
						else
 | 
				
			||||||
| 
						 | 
					@ -3257,8 +3267,11 @@ void exit_io_context(void)
 | 
				
			||||||
	struct io_context *ioc;
 | 
						struct io_context *ioc;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	local_irq_save(flags);
 | 
						local_irq_save(flags);
 | 
				
			||||||
 | 
						task_lock(current);
 | 
				
			||||||
	ioc = current->io_context;
 | 
						ioc = current->io_context;
 | 
				
			||||||
	current->io_context = NULL;
 | 
						current->io_context = NULL;
 | 
				
			||||||
 | 
						ioc->task = NULL;
 | 
				
			||||||
 | 
						task_unlock(current);
 | 
				
			||||||
	local_irq_restore(flags);
 | 
						local_irq_restore(flags);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (ioc->aic && ioc->aic->exit)
 | 
						if (ioc->aic && ioc->aic->exit)
 | 
				
			||||||
| 
						 | 
					@ -3293,12 +3306,12 @@ struct io_context *get_io_context(int gfp_flags)
 | 
				
			||||||
	ret = kmem_cache_alloc(iocontext_cachep, gfp_flags);
 | 
						ret = kmem_cache_alloc(iocontext_cachep, gfp_flags);
 | 
				
			||||||
	if (ret) {
 | 
						if (ret) {
 | 
				
			||||||
		atomic_set(&ret->refcount, 1);
 | 
							atomic_set(&ret->refcount, 1);
 | 
				
			||||||
		ret->pid = tsk->pid;
 | 
							ret->task = current;
 | 
				
			||||||
 | 
							ret->set_ioprio = NULL;
 | 
				
			||||||
		ret->last_waited = jiffies; /* doesn't matter... */
 | 
							ret->last_waited = jiffies; /* doesn't matter... */
 | 
				
			||||||
		ret->nr_batch_requests = 0; /* because this is 0 */
 | 
							ret->nr_batch_requests = 0; /* because this is 0 */
 | 
				
			||||||
		ret->aic = NULL;
 | 
							ret->aic = NULL;
 | 
				
			||||||
		ret->cic = NULL;
 | 
							ret->cic = NULL;
 | 
				
			||||||
		spin_lock_init(&ret->lock);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
		local_irq_save(flags);
 | 
							local_irq_save(flags);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -253,7 +253,7 @@ static int floppy_revalidate(struct gendisk *disk);
 | 
				
			||||||
static int swim3_add_device(struct device_node *swims);
 | 
					static int swim3_add_device(struct device_node *swims);
 | 
				
			||||||
int swim3_init(void);
 | 
					int swim3_init(void);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifndef CONFIG_PMAC_PBOOK
 | 
					#ifndef CONFIG_PMAC_MEDIABAY
 | 
				
			||||||
#define check_media_bay(which, what)	1
 | 
					#define check_media_bay(which, what)	1
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -297,9 +297,11 @@ static void do_fd_request(request_queue_t * q)
 | 
				
			||||||
	int i;
 | 
						int i;
 | 
				
			||||||
	for(i=0;i<floppy_count;i++)
 | 
						for(i=0;i<floppy_count;i++)
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
 | 
					#ifdef CONFIG_PMAC_MEDIABAY
 | 
				
			||||||
		if (floppy_states[i].media_bay &&
 | 
							if (floppy_states[i].media_bay &&
 | 
				
			||||||
			check_media_bay(floppy_states[i].media_bay, MB_FD))
 | 
								check_media_bay(floppy_states[i].media_bay, MB_FD))
 | 
				
			||||||
			continue;
 | 
								continue;
 | 
				
			||||||
 | 
					#endif /* CONFIG_PMAC_MEDIABAY */
 | 
				
			||||||
		start_request(&floppy_states[i]);
 | 
							start_request(&floppy_states[i]);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	sti();
 | 
						sti();
 | 
				
			||||||
| 
						 | 
					@ -856,8 +858,10 @@ static int floppy_ioctl(struct inode *inode, struct file *filp,
 | 
				
			||||||
	if ((cmd & 0x80) && !capable(CAP_SYS_ADMIN))
 | 
						if ((cmd & 0x80) && !capable(CAP_SYS_ADMIN))
 | 
				
			||||||
		return -EPERM;
 | 
							return -EPERM;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef CONFIG_PMAC_MEDIABAY
 | 
				
			||||||
	if (fs->media_bay && check_media_bay(fs->media_bay, MB_FD))
 | 
						if (fs->media_bay && check_media_bay(fs->media_bay, MB_FD))
 | 
				
			||||||
		return -ENXIO;
 | 
							return -ENXIO;
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	switch (cmd) {
 | 
						switch (cmd) {
 | 
				
			||||||
	case FDEJECT:
 | 
						case FDEJECT:
 | 
				
			||||||
| 
						 | 
					@ -881,8 +885,10 @@ static int floppy_open(struct inode *inode, struct file *filp)
 | 
				
			||||||
	int n, err = 0;
 | 
						int n, err = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (fs->ref_count == 0) {
 | 
						if (fs->ref_count == 0) {
 | 
				
			||||||
 | 
					#ifdef CONFIG_PMAC_MEDIABAY
 | 
				
			||||||
		if (fs->media_bay && check_media_bay(fs->media_bay, MB_FD))
 | 
							if (fs->media_bay && check_media_bay(fs->media_bay, MB_FD))
 | 
				
			||||||
			return -ENXIO;
 | 
								return -ENXIO;
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
		out_8(&sw->setup, S_IBM_DRIVE | S_FCLK_DIV2);
 | 
							out_8(&sw->setup, S_IBM_DRIVE | S_FCLK_DIV2);
 | 
				
			||||||
		out_8(&sw->control_bic, 0xff);
 | 
							out_8(&sw->control_bic, 0xff);
 | 
				
			||||||
		out_8(&sw->mode, 0x95);
 | 
							out_8(&sw->mode, 0x95);
 | 
				
			||||||
| 
						 | 
					@ -967,8 +973,10 @@ static int floppy_revalidate(struct gendisk *disk)
 | 
				
			||||||
	struct swim3 __iomem *sw;
 | 
						struct swim3 __iomem *sw;
 | 
				
			||||||
	int ret, n;
 | 
						int ret, n;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef CONFIG_PMAC_MEDIABAY
 | 
				
			||||||
	if (fs->media_bay && check_media_bay(fs->media_bay, MB_FD))
 | 
						if (fs->media_bay && check_media_bay(fs->media_bay, MB_FD))
 | 
				
			||||||
		return -ENXIO;
 | 
							return -ENXIO;
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	sw = fs->swim3;
 | 
						sw = fs->swim3;
 | 
				
			||||||
	grab_drive(fs, revalidating, 0);
 | 
						grab_drive(fs, revalidating, 0);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -26,6 +26,7 @@
 | 
				
			||||||
#include <linux/delay.h>
 | 
					#include <linux/delay.h>
 | 
				
			||||||
#include <linux/time.h>
 | 
					#include <linux/time.h>
 | 
				
			||||||
#include <linux/hdreg.h>
 | 
					#include <linux/hdreg.h>
 | 
				
			||||||
 | 
					#include <linux/dma-mapping.h>
 | 
				
			||||||
#include <asm/io.h>
 | 
					#include <asm/io.h>
 | 
				
			||||||
#include <asm/semaphore.h>
 | 
					#include <asm/semaphore.h>
 | 
				
			||||||
#include <asm/uaccess.h>
 | 
					#include <asm/uaccess.h>
 | 
				
			||||||
| 
						 | 
					@ -1582,9 +1583,9 @@ static int carm_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
 | 
				
			||||||
		goto err_out;
 | 
							goto err_out;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#if IF_64BIT_DMA_IS_POSSIBLE /* grrrr... */
 | 
					#if IF_64BIT_DMA_IS_POSSIBLE /* grrrr... */
 | 
				
			||||||
	rc = pci_set_dma_mask(pdev, 0xffffffffffffffffULL);
 | 
						rc = pci_set_dma_mask(pdev, DMA_64BIT_MASK);
 | 
				
			||||||
	if (!rc) {
 | 
						if (!rc) {
 | 
				
			||||||
		rc = pci_set_consistent_dma_mask(pdev, 0xffffffffffffffffULL);
 | 
							rc = pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK);
 | 
				
			||||||
		if (rc) {
 | 
							if (rc) {
 | 
				
			||||||
			printk(KERN_ERR DRV_NAME "(%s): consistent DMA mask failure\n",
 | 
								printk(KERN_ERR DRV_NAME "(%s): consistent DMA mask failure\n",
 | 
				
			||||||
				pci_name(pdev));
 | 
									pci_name(pdev));
 | 
				
			||||||
| 
						 | 
					@ -1593,7 +1594,7 @@ static int carm_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
 | 
				
			||||||
		pci_dac = 1;
 | 
							pci_dac = 1;
 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
		rc = pci_set_dma_mask(pdev, 0xffffffffULL);
 | 
							rc = pci_set_dma_mask(pdev, DMA_32BIT_MASK);
 | 
				
			||||||
		if (rc) {
 | 
							if (rc) {
 | 
				
			||||||
			printk(KERN_ERR DRV_NAME "(%s): DMA mask failure\n",
 | 
								printk(KERN_ERR DRV_NAME "(%s): DMA mask failure\n",
 | 
				
			||||||
				pci_name(pdev));
 | 
									pci_name(pdev));
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -308,9 +308,6 @@ static int __init misc_init(void)
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
#ifdef CONFIG_BVME6000
 | 
					#ifdef CONFIG_BVME6000
 | 
				
			||||||
	rtc_DP8570A_init();
 | 
						rtc_DP8570A_init();
 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
#ifdef CONFIG_PMAC_PBOOK
 | 
					 | 
				
			||||||
	pmu_device_init();
 | 
					 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
	if (register_chrdev(MISC_MAJOR,"misc",&misc_fops)) {
 | 
						if (register_chrdev(MISC_MAJOR,"misc",&misc_fops)) {
 | 
				
			||||||
		printk("unable to get major %d for misc devices\n",
 | 
							printk("unable to get major %d for misc devices\n",
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1324,9 +1324,9 @@ pmac_ide_setup_device(pmac_ide_hwif_t *pmif, ide_hwif_t *hwif)
 | 
				
			||||||
	/* XXX FIXME: Media bay stuff need re-organizing */
 | 
						/* XXX FIXME: Media bay stuff need re-organizing */
 | 
				
			||||||
	if (np->parent && np->parent->name
 | 
						if (np->parent && np->parent->name
 | 
				
			||||||
	    && strcasecmp(np->parent->name, "media-bay") == 0) {
 | 
						    && strcasecmp(np->parent->name, "media-bay") == 0) {
 | 
				
			||||||
#ifdef CONFIG_PMAC_PBOOK
 | 
					#ifdef CONFIG_PMAC_MEDIABAY
 | 
				
			||||||
		media_bay_set_ide_infos(np->parent, pmif->regbase, pmif->irq, hwif->index);
 | 
							media_bay_set_ide_infos(np->parent, pmif->regbase, pmif->irq, hwif->index);
 | 
				
			||||||
#endif /* CONFIG_PMAC_PBOOK */
 | 
					#endif /* CONFIG_PMAC_MEDIABAY */
 | 
				
			||||||
		pmif->mediabay = 1;
 | 
							pmif->mediabay = 1;
 | 
				
			||||||
		if (!bidp)
 | 
							if (!bidp)
 | 
				
			||||||
			pmif->aapl_bus_id = 1;
 | 
								pmif->aapl_bus_id = 1;
 | 
				
			||||||
| 
						 | 
					@ -1382,10 +1382,10 @@ pmac_ide_setup_device(pmac_ide_hwif_t *pmif, ide_hwif_t *hwif)
 | 
				
			||||||
	       hwif->index, model_name[pmif->kind], pmif->aapl_bus_id,
 | 
						       hwif->index, model_name[pmif->kind], pmif->aapl_bus_id,
 | 
				
			||||||
	       pmif->mediabay ? " (mediabay)" : "", hwif->irq);
 | 
						       pmif->mediabay ? " (mediabay)" : "", hwif->irq);
 | 
				
			||||||
			
 | 
								
 | 
				
			||||||
#ifdef CONFIG_PMAC_PBOOK
 | 
					#ifdef CONFIG_PMAC_MEDIABAY
 | 
				
			||||||
	if (pmif->mediabay && check_media_bay_by_base(pmif->regbase, MB_CD) == 0)
 | 
						if (pmif->mediabay && check_media_bay_by_base(pmif->regbase, MB_CD) == 0)
 | 
				
			||||||
		hwif->noprobe = 0;
 | 
							hwif->noprobe = 0;
 | 
				
			||||||
#endif /* CONFIG_PMAC_PBOOK */
 | 
					#endif /* CONFIG_PMAC_MEDIABAY */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	hwif->sg_max_nents = MAX_DCMDS;
 | 
						hwif->sg_max_nents = MAX_DCMDS;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -3538,8 +3538,8 @@ static void ohci1394_pci_remove(struct pci_dev *pdev)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int ohci1394_pci_resume (struct pci_dev *pdev)
 | 
					static int ohci1394_pci_resume (struct pci_dev *pdev)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
#ifdef CONFIG_PMAC_PBOOK
 | 
					#ifdef CONFIG_PPC_PMAC
 | 
				
			||||||
	{
 | 
						if (_machine == _MACH_Pmac) {
 | 
				
			||||||
		struct device_node *of_node;
 | 
							struct device_node *of_node;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		/* Re-enable 1394 */
 | 
							/* Re-enable 1394 */
 | 
				
			||||||
| 
						 | 
					@ -3547,7 +3547,7 @@ static int ohci1394_pci_resume (struct pci_dev *pdev)
 | 
				
			||||||
		if (of_node)
 | 
							if (of_node)
 | 
				
			||||||
			pmac_call_feature (PMAC_FTR_1394_ENABLE, of_node, 0, 1);
 | 
								pmac_call_feature (PMAC_FTR_1394_ENABLE, of_node, 0, 1);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
#endif
 | 
					#endif /* CONFIG_PPC_PMAC */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	pci_enable_device(pdev);
 | 
						pci_enable_device(pdev);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -3557,8 +3557,8 @@ static int ohci1394_pci_resume (struct pci_dev *pdev)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int ohci1394_pci_suspend (struct pci_dev *pdev, pm_message_t state)
 | 
					static int ohci1394_pci_suspend (struct pci_dev *pdev, pm_message_t state)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
#ifdef CONFIG_PMAC_PBOOK
 | 
					#ifdef CONFIG_PPC_PMAC
 | 
				
			||||||
	{
 | 
						if (_machine == _MACH_Pmac) {
 | 
				
			||||||
		struct device_node *of_node;
 | 
							struct device_node *of_node;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		/* Disable 1394 */
 | 
							/* Disable 1394 */
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -96,7 +96,7 @@ void ib_pack(const struct ib_field        *desc,
 | 
				
			||||||
			else
 | 
								else
 | 
				
			||||||
				val = 0;
 | 
									val = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			mask = cpu_to_be64(((1ull << desc[i].size_bits) - 1) << shift);
 | 
								mask = cpu_to_be64((~0ull >> (64 - desc[i].size_bits)) << shift);
 | 
				
			||||||
			addr = (__be64 *) ((__be32 *) buf + desc[i].offset_words);
 | 
								addr = (__be64 *) ((__be32 *) buf + desc[i].offset_words);
 | 
				
			||||||
			*addr = (*addr & ~mask) | (cpu_to_be64(val) & mask);
 | 
								*addr = (*addr & ~mask) | (cpu_to_be64(val) & mask);
 | 
				
			||||||
		} else {
 | 
							} else {
 | 
				
			||||||
| 
						 | 
					@ -176,7 +176,7 @@ void ib_unpack(const struct ib_field        *desc,
 | 
				
			||||||
			__be64 *addr;
 | 
								__be64 *addr;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			shift = 64 - desc[i].offset_bits - desc[i].size_bits;
 | 
								shift = 64 - desc[i].offset_bits - desc[i].size_bits;
 | 
				
			||||||
			mask = ((1ull << desc[i].size_bits) - 1) << shift;
 | 
								mask = (~0ull >> (64 - desc[i].size_bits)) << shift;
 | 
				
			||||||
			addr = (__be64 *) buf + desc[i].offset_words;
 | 
								addr = (__be64 *) buf + desc[i].offset_words;
 | 
				
			||||||
			val = (be64_to_cpup(addr) & mask) >> shift;
 | 
								val = (be64_to_cpup(addr) & mask) >> shift;
 | 
				
			||||||
			value_write(desc[i].struct_offset_bytes,
 | 
								value_write(desc[i].struct_offset_bytes,
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -507,7 +507,13 @@ retry:
 | 
				
			||||||
		spin_unlock_irqrestore(&idr_lock, flags);
 | 
							spin_unlock_irqrestore(&idr_lock, flags);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return ret;
 | 
						/*
 | 
				
			||||||
 | 
						 * It's not safe to dereference query any more, because the
 | 
				
			||||||
 | 
						 * send may already have completed and freed the query in
 | 
				
			||||||
 | 
						 * another context.  So use wr.wr_id, which has a copy of the
 | 
				
			||||||
 | 
						 * query's id.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						return ret ? ret : wr.wr_id;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void ib_sa_path_rec_callback(struct ib_sa_query *sa_query,
 | 
					static void ib_sa_path_rec_callback(struct ib_sa_query *sa_query,
 | 
				
			||||||
| 
						 | 
					@ -598,14 +604,15 @@ int ib_sa_path_rec_get(struct ib_device *device, u8 port_num,
 | 
				
			||||||
		rec, query->sa_query.mad->data);
 | 
							rec, query->sa_query.mad->data);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	*sa_query = &query->sa_query;
 | 
						*sa_query = &query->sa_query;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	ret = send_mad(&query->sa_query, timeout_ms);
 | 
						ret = send_mad(&query->sa_query, timeout_ms);
 | 
				
			||||||
	if (ret) {
 | 
						if (ret < 0) {
 | 
				
			||||||
		*sa_query = NULL;
 | 
							*sa_query = NULL;
 | 
				
			||||||
		kfree(query->sa_query.mad);
 | 
							kfree(query->sa_query.mad);
 | 
				
			||||||
		kfree(query);
 | 
							kfree(query);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return ret ? ret : query->sa_query.id;
 | 
						return ret;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
EXPORT_SYMBOL(ib_sa_path_rec_get);
 | 
					EXPORT_SYMBOL(ib_sa_path_rec_get);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -674,14 +681,15 @@ int ib_sa_mcmember_rec_query(struct ib_device *device, u8 port_num,
 | 
				
			||||||
		rec, query->sa_query.mad->data);
 | 
							rec, query->sa_query.mad->data);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	*sa_query = &query->sa_query;
 | 
						*sa_query = &query->sa_query;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	ret = send_mad(&query->sa_query, timeout_ms);
 | 
						ret = send_mad(&query->sa_query, timeout_ms);
 | 
				
			||||||
	if (ret) {
 | 
						if (ret < 0) {
 | 
				
			||||||
		*sa_query = NULL;
 | 
							*sa_query = NULL;
 | 
				
			||||||
		kfree(query->sa_query.mad);
 | 
							kfree(query->sa_query.mad);
 | 
				
			||||||
		kfree(query);
 | 
							kfree(query);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return ret ? ret : query->sa_query.id;
 | 
						return ret;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
EXPORT_SYMBOL(ib_sa_mcmember_rec_query);
 | 
					EXPORT_SYMBOL(ib_sa_mcmember_rec_query);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,5 +1,6 @@
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 * Copyright (c) 2004 Topspin Communications.  All rights reserved.
 | 
					 * Copyright (c) 2004 Topspin Communications.  All rights reserved.
 | 
				
			||||||
 | 
					 * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved.
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * This software is available to you under a choice of one of two
 | 
					 * This software is available to you under a choice of one of two
 | 
				
			||||||
 * licenses.  You may choose to be licensed under the terms of the GNU
 | 
					 * licenses.  You may choose to be licensed under the terms of the GNU
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -431,6 +431,36 @@ static int mthca_cmd_imm(struct mthca_dev *dev,
 | 
				
			||||||
				      timeout, status);
 | 
									      timeout, status);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int mthca_cmd_init(struct mthca_dev *dev)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						sema_init(&dev->cmd.hcr_sem, 1);
 | 
				
			||||||
 | 
						sema_init(&dev->cmd.poll_sem, 1);
 | 
				
			||||||
 | 
						dev->cmd.use_events = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						dev->hcr = ioremap(pci_resource_start(dev->pdev, 0) + MTHCA_HCR_BASE,
 | 
				
			||||||
 | 
								   MTHCA_HCR_SIZE);
 | 
				
			||||||
 | 
						if (!dev->hcr) {
 | 
				
			||||||
 | 
							mthca_err(dev, "Couldn't map command register.");
 | 
				
			||||||
 | 
							return -ENOMEM;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						dev->cmd.pool = pci_pool_create("mthca_cmd", dev->pdev,
 | 
				
			||||||
 | 
										MTHCA_MAILBOX_SIZE,
 | 
				
			||||||
 | 
										MTHCA_MAILBOX_SIZE, 0);
 | 
				
			||||||
 | 
						if (!dev->cmd.pool) {
 | 
				
			||||||
 | 
							iounmap(dev->hcr);
 | 
				
			||||||
 | 
							return -ENOMEM;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void mthca_cmd_cleanup(struct mthca_dev *dev)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						pci_pool_destroy(dev->cmd.pool);
 | 
				
			||||||
 | 
						iounmap(dev->hcr);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 * Switch to using events to issue FW commands (should be called after
 | 
					 * Switch to using events to issue FW commands (should be called after
 | 
				
			||||||
 * event queue to command events has been initialized).
 | 
					 * event queue to command events has been initialized).
 | 
				
			||||||
| 
						 | 
					@ -489,6 +519,33 @@ void mthca_cmd_use_polling(struct mthca_dev *dev)
 | 
				
			||||||
	up(&dev->cmd.poll_sem);
 | 
						up(&dev->cmd.poll_sem);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct mthca_mailbox *mthca_alloc_mailbox(struct mthca_dev *dev,
 | 
				
			||||||
 | 
										  unsigned int gfp_mask)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct mthca_mailbox *mailbox;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						mailbox = kmalloc(sizeof *mailbox, gfp_mask);
 | 
				
			||||||
 | 
						if (!mailbox)
 | 
				
			||||||
 | 
							return ERR_PTR(-ENOMEM);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						mailbox->buf = pci_pool_alloc(dev->cmd.pool, gfp_mask, &mailbox->dma);
 | 
				
			||||||
 | 
						if (!mailbox->buf) {
 | 
				
			||||||
 | 
							kfree(mailbox);
 | 
				
			||||||
 | 
							return ERR_PTR(-ENOMEM);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return mailbox;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void mthca_free_mailbox(struct mthca_dev *dev, struct mthca_mailbox *mailbox)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						if (!mailbox)
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						pci_pool_free(dev->cmd.pool, mailbox->buf, mailbox->dma);
 | 
				
			||||||
 | 
						kfree(mailbox);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int mthca_SYS_EN(struct mthca_dev *dev, u8 *status)
 | 
					int mthca_SYS_EN(struct mthca_dev *dev, u8 *status)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	u64 out;
 | 
						u64 out;
 | 
				
			||||||
| 
						 | 
					@ -513,20 +570,20 @@ int mthca_SYS_DIS(struct mthca_dev *dev, u8 *status)
 | 
				
			||||||
static int mthca_map_cmd(struct mthca_dev *dev, u16 op, struct mthca_icm *icm,
 | 
					static int mthca_map_cmd(struct mthca_dev *dev, u16 op, struct mthca_icm *icm,
 | 
				
			||||||
			 u64 virt, u8 *status)
 | 
								 u64 virt, u8 *status)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	u32 *inbox;
 | 
						struct mthca_mailbox *mailbox;
 | 
				
			||||||
	dma_addr_t indma;
 | 
					 | 
				
			||||||
	struct mthca_icm_iter iter;
 | 
						struct mthca_icm_iter iter;
 | 
				
			||||||
 | 
						__be64 *pages;
 | 
				
			||||||
	int lg;
 | 
						int lg;
 | 
				
			||||||
	int nent = 0;
 | 
						int nent = 0;
 | 
				
			||||||
	int i;
 | 
						int i;
 | 
				
			||||||
	int err = 0;
 | 
						int err = 0;
 | 
				
			||||||
	int ts = 0, tc = 0;
 | 
						int ts = 0, tc = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	inbox = pci_alloc_consistent(dev->pdev, PAGE_SIZE, &indma);
 | 
						mailbox = mthca_alloc_mailbox(dev, GFP_KERNEL);
 | 
				
			||||||
	if (!inbox)
 | 
						if (IS_ERR(mailbox))
 | 
				
			||||||
		return -ENOMEM;
 | 
							return PTR_ERR(mailbox);
 | 
				
			||||||
 | 
						memset(mailbox->buf, 0, MTHCA_MAILBOX_SIZE);
 | 
				
			||||||
	memset(inbox, 0, PAGE_SIZE);
 | 
						pages = mailbox->buf;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for (mthca_icm_first(icm, &iter);
 | 
						for (mthca_icm_first(icm, &iter);
 | 
				
			||||||
	     !mthca_icm_last(&iter);
 | 
						     !mthca_icm_last(&iter);
 | 
				
			||||||
| 
						 | 
					@ -546,19 +603,17 @@ static int mthca_map_cmd(struct mthca_dev *dev, u16 op, struct mthca_icm *icm,
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		for (i = 0; i < mthca_icm_size(&iter) / (1 << lg); ++i, ++nent) {
 | 
							for (i = 0; i < mthca_icm_size(&iter) / (1 << lg); ++i, ++nent) {
 | 
				
			||||||
			if (virt != -1) {
 | 
								if (virt != -1) {
 | 
				
			||||||
				*((__be64 *) (inbox + nent * 4)) =
 | 
									pages[nent * 2] = cpu_to_be64(virt);
 | 
				
			||||||
					cpu_to_be64(virt);
 | 
					 | 
				
			||||||
				virt += 1 << lg;
 | 
									virt += 1 << lg;
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			*((__be64 *) (inbox + nent * 4 + 2)) =
 | 
								pages[nent * 2 + 1] = cpu_to_be64((mthca_icm_addr(&iter) +
 | 
				
			||||||
				cpu_to_be64((mthca_icm_addr(&iter) +
 | 
												   (i << lg)) | (lg - 12));
 | 
				
			||||||
					     (i << lg)) | (lg - 12));
 | 
					 | 
				
			||||||
			ts += 1 << (lg - 10);
 | 
								ts += 1 << (lg - 10);
 | 
				
			||||||
			++tc;
 | 
								++tc;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			if (nent == PAGE_SIZE / 16) {
 | 
								if (nent == MTHCA_MAILBOX_SIZE / 16) {
 | 
				
			||||||
				err = mthca_cmd(dev, indma, nent, 0, op,
 | 
									err = mthca_cmd(dev, mailbox->dma, nent, 0, op,
 | 
				
			||||||
						CMD_TIME_CLASS_B, status);
 | 
											CMD_TIME_CLASS_B, status);
 | 
				
			||||||
				if (err || *status)
 | 
									if (err || *status)
 | 
				
			||||||
					goto out;
 | 
										goto out;
 | 
				
			||||||
| 
						 | 
					@ -568,7 +623,7 @@ static int mthca_map_cmd(struct mthca_dev *dev, u16 op, struct mthca_icm *icm,
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (nent)
 | 
						if (nent)
 | 
				
			||||||
		err = mthca_cmd(dev, indma, nent, 0, op,
 | 
							err = mthca_cmd(dev, mailbox->dma, nent, 0, op,
 | 
				
			||||||
				CMD_TIME_CLASS_B, status);
 | 
									CMD_TIME_CLASS_B, status);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	switch (op) {
 | 
						switch (op) {
 | 
				
			||||||
| 
						 | 
					@ -585,7 +640,7 @@ static int mthca_map_cmd(struct mthca_dev *dev, u16 op, struct mthca_icm *icm,
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
out:
 | 
					out:
 | 
				
			||||||
	pci_free_consistent(dev->pdev, PAGE_SIZE, inbox, indma);
 | 
						mthca_free_mailbox(dev, mailbox);
 | 
				
			||||||
	return err;
 | 
						return err;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -606,8 +661,8 @@ int mthca_RUN_FW(struct mthca_dev *dev, u8 *status)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int mthca_QUERY_FW(struct mthca_dev *dev, u8 *status)
 | 
					int mthca_QUERY_FW(struct mthca_dev *dev, u8 *status)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
						struct mthca_mailbox *mailbox;
 | 
				
			||||||
	u32 *outbox;
 | 
						u32 *outbox;
 | 
				
			||||||
	dma_addr_t outdma;
 | 
					 | 
				
			||||||
	int err = 0;
 | 
						int err = 0;
 | 
				
			||||||
	u8 lg;
 | 
						u8 lg;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -625,12 +680,12 @@ int mthca_QUERY_FW(struct mthca_dev *dev, u8 *status)
 | 
				
			||||||
#define QUERY_FW_EQ_ARM_BASE_OFFSET    0x40
 | 
					#define QUERY_FW_EQ_ARM_BASE_OFFSET    0x40
 | 
				
			||||||
#define QUERY_FW_EQ_SET_CI_BASE_OFFSET 0x48
 | 
					#define QUERY_FW_EQ_SET_CI_BASE_OFFSET 0x48
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	outbox = pci_alloc_consistent(dev->pdev, QUERY_FW_OUT_SIZE, &outdma);
 | 
						mailbox = mthca_alloc_mailbox(dev, GFP_KERNEL);
 | 
				
			||||||
	if (!outbox) {
 | 
						if (IS_ERR(mailbox))
 | 
				
			||||||
		return -ENOMEM;
 | 
							return PTR_ERR(mailbox);
 | 
				
			||||||
	}
 | 
						outbox = mailbox->buf;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	err = mthca_cmd_box(dev, 0, outdma, 0, 0, CMD_QUERY_FW,
 | 
						err = mthca_cmd_box(dev, 0, mailbox->dma, 0, 0, CMD_QUERY_FW,
 | 
				
			||||||
			    CMD_TIME_CLASS_A, status);
 | 
								    CMD_TIME_CLASS_A, status);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (err)
 | 
						if (err)
 | 
				
			||||||
| 
						 | 
					@ -681,15 +736,15 @@ int mthca_QUERY_FW(struct mthca_dev *dev, u8 *status)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
out:
 | 
					out:
 | 
				
			||||||
	pci_free_consistent(dev->pdev, QUERY_FW_OUT_SIZE, outbox, outdma);
 | 
						mthca_free_mailbox(dev, mailbox);
 | 
				
			||||||
	return err;
 | 
						return err;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int mthca_ENABLE_LAM(struct mthca_dev *dev, u8 *status)
 | 
					int mthca_ENABLE_LAM(struct mthca_dev *dev, u8 *status)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
						struct mthca_mailbox *mailbox;
 | 
				
			||||||
	u8 info;
 | 
						u8 info;
 | 
				
			||||||
	u32 *outbox;
 | 
						u32 *outbox;
 | 
				
			||||||
	dma_addr_t outdma;
 | 
					 | 
				
			||||||
	int err = 0;
 | 
						int err = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define ENABLE_LAM_OUT_SIZE         0x100
 | 
					#define ENABLE_LAM_OUT_SIZE         0x100
 | 
				
			||||||
| 
						 | 
					@ -700,11 +755,12 @@ int mthca_ENABLE_LAM(struct mthca_dev *dev, u8 *status)
 | 
				
			||||||
#define ENABLE_LAM_INFO_HIDDEN_FLAG (1 << 4)
 | 
					#define ENABLE_LAM_INFO_HIDDEN_FLAG (1 << 4)
 | 
				
			||||||
#define ENABLE_LAM_INFO_ECC_MASK    0x3
 | 
					#define ENABLE_LAM_INFO_ECC_MASK    0x3
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	outbox = pci_alloc_consistent(dev->pdev, ENABLE_LAM_OUT_SIZE, &outdma);
 | 
						mailbox = mthca_alloc_mailbox(dev, GFP_KERNEL);
 | 
				
			||||||
	if (!outbox)
 | 
						if (IS_ERR(mailbox))
 | 
				
			||||||
		return -ENOMEM;
 | 
							return PTR_ERR(mailbox);
 | 
				
			||||||
 | 
						outbox = mailbox->buf;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	err = mthca_cmd_box(dev, 0, outdma, 0, 0, CMD_ENABLE_LAM,
 | 
						err = mthca_cmd_box(dev, 0, mailbox->dma, 0, 0, CMD_ENABLE_LAM,
 | 
				
			||||||
			    CMD_TIME_CLASS_C, status);
 | 
								    CMD_TIME_CLASS_C, status);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (err)
 | 
						if (err)
 | 
				
			||||||
| 
						 | 
					@ -733,7 +789,7 @@ int mthca_ENABLE_LAM(struct mthca_dev *dev, u8 *status)
 | 
				
			||||||
		  (unsigned long long) dev->ddr_end);
 | 
							  (unsigned long long) dev->ddr_end);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
out:
 | 
					out:
 | 
				
			||||||
	pci_free_consistent(dev->pdev, ENABLE_LAM_OUT_SIZE, outbox, outdma);
 | 
						mthca_free_mailbox(dev, mailbox);
 | 
				
			||||||
	return err;
 | 
						return err;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -744,9 +800,9 @@ int mthca_DISABLE_LAM(struct mthca_dev *dev, u8 *status)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int mthca_QUERY_DDR(struct mthca_dev *dev, u8 *status)
 | 
					int mthca_QUERY_DDR(struct mthca_dev *dev, u8 *status)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
						struct mthca_mailbox *mailbox;
 | 
				
			||||||
	u8 info;
 | 
						u8 info;
 | 
				
			||||||
	u32 *outbox;
 | 
						u32 *outbox;
 | 
				
			||||||
	dma_addr_t outdma;
 | 
					 | 
				
			||||||
	int err = 0;
 | 
						int err = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define QUERY_DDR_OUT_SIZE         0x100
 | 
					#define QUERY_DDR_OUT_SIZE         0x100
 | 
				
			||||||
| 
						 | 
					@ -757,11 +813,12 @@ int mthca_QUERY_DDR(struct mthca_dev *dev, u8 *status)
 | 
				
			||||||
#define QUERY_DDR_INFO_HIDDEN_FLAG (1 << 4)
 | 
					#define QUERY_DDR_INFO_HIDDEN_FLAG (1 << 4)
 | 
				
			||||||
#define QUERY_DDR_INFO_ECC_MASK    0x3
 | 
					#define QUERY_DDR_INFO_ECC_MASK    0x3
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	outbox = pci_alloc_consistent(dev->pdev, QUERY_DDR_OUT_SIZE, &outdma);
 | 
						mailbox = mthca_alloc_mailbox(dev, GFP_KERNEL);
 | 
				
			||||||
	if (!outbox)
 | 
						if (IS_ERR(mailbox))
 | 
				
			||||||
		return -ENOMEM;
 | 
							return PTR_ERR(mailbox);
 | 
				
			||||||
 | 
						outbox = mailbox->buf;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	err = mthca_cmd_box(dev, 0, outdma, 0, 0, CMD_QUERY_DDR,
 | 
						err = mthca_cmd_box(dev, 0, mailbox->dma, 0, 0, CMD_QUERY_DDR,
 | 
				
			||||||
			    CMD_TIME_CLASS_A, status);
 | 
								    CMD_TIME_CLASS_A, status);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (err)
 | 
						if (err)
 | 
				
			||||||
| 
						 | 
					@ -787,15 +844,15 @@ int mthca_QUERY_DDR(struct mthca_dev *dev, u8 *status)
 | 
				
			||||||
		  (unsigned long long) dev->ddr_end);
 | 
							  (unsigned long long) dev->ddr_end);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
out:
 | 
					out:
 | 
				
			||||||
	pci_free_consistent(dev->pdev, QUERY_DDR_OUT_SIZE, outbox, outdma);
 | 
						mthca_free_mailbox(dev, mailbox);
 | 
				
			||||||
	return err;
 | 
						return err;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int mthca_QUERY_DEV_LIM(struct mthca_dev *dev,
 | 
					int mthca_QUERY_DEV_LIM(struct mthca_dev *dev,
 | 
				
			||||||
			struct mthca_dev_lim *dev_lim, u8 *status)
 | 
								struct mthca_dev_lim *dev_lim, u8 *status)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
						struct mthca_mailbox *mailbox;
 | 
				
			||||||
	u32 *outbox;
 | 
						u32 *outbox;
 | 
				
			||||||
	dma_addr_t outdma;
 | 
					 | 
				
			||||||
	u8 field;
 | 
						u8 field;
 | 
				
			||||||
	u16 size;
 | 
						u16 size;
 | 
				
			||||||
	int err;
 | 
						int err;
 | 
				
			||||||
| 
						 | 
					@ -860,11 +917,12 @@ int mthca_QUERY_DEV_LIM(struct mthca_dev *dev,
 | 
				
			||||||
#define QUERY_DEV_LIM_LAMR_OFFSET           0x9f
 | 
					#define QUERY_DEV_LIM_LAMR_OFFSET           0x9f
 | 
				
			||||||
#define QUERY_DEV_LIM_MAX_ICM_SZ_OFFSET     0xa0
 | 
					#define QUERY_DEV_LIM_MAX_ICM_SZ_OFFSET     0xa0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	outbox = pci_alloc_consistent(dev->pdev, QUERY_DEV_LIM_OUT_SIZE, &outdma);
 | 
						mailbox = mthca_alloc_mailbox(dev, GFP_KERNEL);
 | 
				
			||||||
	if (!outbox)
 | 
						if (IS_ERR(mailbox))
 | 
				
			||||||
		return -ENOMEM;
 | 
							return PTR_ERR(mailbox);
 | 
				
			||||||
 | 
						outbox = mailbox->buf;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	err = mthca_cmd_box(dev, 0, outdma, 0, 0, CMD_QUERY_DEV_LIM,
 | 
						err = mthca_cmd_box(dev, 0, mailbox->dma, 0, 0, CMD_QUERY_DEV_LIM,
 | 
				
			||||||
			    CMD_TIME_CLASS_A, status);
 | 
								    CMD_TIME_CLASS_A, status);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (err)
 | 
						if (err)
 | 
				
			||||||
| 
						 | 
					@ -1020,15 +1078,15 @@ int mthca_QUERY_DEV_LIM(struct mthca_dev *dev,
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
out:
 | 
					out:
 | 
				
			||||||
	pci_free_consistent(dev->pdev, QUERY_DEV_LIM_OUT_SIZE, outbox, outdma);
 | 
						mthca_free_mailbox(dev, mailbox);
 | 
				
			||||||
	return err;
 | 
						return err;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int mthca_QUERY_ADAPTER(struct mthca_dev *dev,
 | 
					int mthca_QUERY_ADAPTER(struct mthca_dev *dev,
 | 
				
			||||||
			struct mthca_adapter *adapter, u8 *status)
 | 
								struct mthca_adapter *adapter, u8 *status)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
						struct mthca_mailbox *mailbox;
 | 
				
			||||||
	u32 *outbox;
 | 
						u32 *outbox;
 | 
				
			||||||
	dma_addr_t outdma;
 | 
					 | 
				
			||||||
	int err;
 | 
						int err;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define QUERY_ADAPTER_OUT_SIZE             0x100
 | 
					#define QUERY_ADAPTER_OUT_SIZE             0x100
 | 
				
			||||||
| 
						 | 
					@ -1037,23 +1095,24 @@ int mthca_QUERY_ADAPTER(struct mthca_dev *dev,
 | 
				
			||||||
#define QUERY_ADAPTER_REVISION_ID_OFFSET   0x08
 | 
					#define QUERY_ADAPTER_REVISION_ID_OFFSET   0x08
 | 
				
			||||||
#define QUERY_ADAPTER_INTA_PIN_OFFSET      0x10
 | 
					#define QUERY_ADAPTER_INTA_PIN_OFFSET      0x10
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	outbox = pci_alloc_consistent(dev->pdev, QUERY_ADAPTER_OUT_SIZE, &outdma);
 | 
						mailbox = mthca_alloc_mailbox(dev, GFP_KERNEL);
 | 
				
			||||||
	if (!outbox)
 | 
						if (IS_ERR(mailbox))
 | 
				
			||||||
		return -ENOMEM;
 | 
							return PTR_ERR(mailbox);
 | 
				
			||||||
 | 
						outbox = mailbox->buf;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	err = mthca_cmd_box(dev, 0, outdma, 0, 0, CMD_QUERY_ADAPTER,
 | 
						err = mthca_cmd_box(dev, 0, mailbox->dma, 0, 0, CMD_QUERY_ADAPTER,
 | 
				
			||||||
			    CMD_TIME_CLASS_A, status);
 | 
								    CMD_TIME_CLASS_A, status);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (err)
 | 
						if (err)
 | 
				
			||||||
		goto out;
 | 
							goto out;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	MTHCA_GET(adapter->vendor_id, outbox, QUERY_ADAPTER_VENDOR_ID_OFFSET);
 | 
						MTHCA_GET(adapter->vendor_id, outbox,   QUERY_ADAPTER_VENDOR_ID_OFFSET);
 | 
				
			||||||
	MTHCA_GET(adapter->device_id, outbox, QUERY_ADAPTER_DEVICE_ID_OFFSET);
 | 
						MTHCA_GET(adapter->device_id, outbox,   QUERY_ADAPTER_DEVICE_ID_OFFSET);
 | 
				
			||||||
	MTHCA_GET(adapter->revision_id, outbox, QUERY_ADAPTER_REVISION_ID_OFFSET);
 | 
						MTHCA_GET(adapter->revision_id, outbox, QUERY_ADAPTER_REVISION_ID_OFFSET);
 | 
				
			||||||
	MTHCA_GET(adapter->inta_pin, outbox, QUERY_ADAPTER_INTA_PIN_OFFSET);
 | 
						MTHCA_GET(adapter->inta_pin, outbox,    QUERY_ADAPTER_INTA_PIN_OFFSET);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
out:
 | 
					out:
 | 
				
			||||||
	pci_free_consistent(dev->pdev, QUERY_DEV_LIM_OUT_SIZE, outbox, outdma);
 | 
						mthca_free_mailbox(dev, mailbox);
 | 
				
			||||||
	return err;
 | 
						return err;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1061,8 +1120,8 @@ int mthca_INIT_HCA(struct mthca_dev *dev,
 | 
				
			||||||
		   struct mthca_init_hca_param *param,
 | 
							   struct mthca_init_hca_param *param,
 | 
				
			||||||
		   u8 *status)
 | 
							   u8 *status)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
						struct mthca_mailbox *mailbox;
 | 
				
			||||||
	u32 *inbox;
 | 
						u32 *inbox;
 | 
				
			||||||
	dma_addr_t indma;
 | 
					 | 
				
			||||||
	int err;
 | 
						int err;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define INIT_HCA_IN_SIZE             	 0x200
 | 
					#define INIT_HCA_IN_SIZE             	 0x200
 | 
				
			||||||
| 
						 | 
					@ -1102,9 +1161,10 @@ int mthca_INIT_HCA(struct mthca_dev *dev,
 | 
				
			||||||
#define  INIT_HCA_UAR_SCATCH_BASE_OFFSET (INIT_HCA_UAR_OFFSET + 0x10)
 | 
					#define  INIT_HCA_UAR_SCATCH_BASE_OFFSET (INIT_HCA_UAR_OFFSET + 0x10)
 | 
				
			||||||
#define  INIT_HCA_UAR_CTX_BASE_OFFSET    (INIT_HCA_UAR_OFFSET + 0x18)
 | 
					#define  INIT_HCA_UAR_CTX_BASE_OFFSET    (INIT_HCA_UAR_OFFSET + 0x18)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	inbox = pci_alloc_consistent(dev->pdev, INIT_HCA_IN_SIZE, &indma);
 | 
						mailbox = mthca_alloc_mailbox(dev, GFP_KERNEL);
 | 
				
			||||||
	if (!inbox)
 | 
						if (IS_ERR(mailbox))
 | 
				
			||||||
		return -ENOMEM;
 | 
							return PTR_ERR(mailbox);
 | 
				
			||||||
 | 
						inbox = mailbox->buf;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	memset(inbox, 0, INIT_HCA_IN_SIZE);
 | 
						memset(inbox, 0, INIT_HCA_IN_SIZE);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1167,10 +1227,9 @@ int mthca_INIT_HCA(struct mthca_dev *dev,
 | 
				
			||||||
		MTHCA_PUT(inbox, param->uarc_base,   INIT_HCA_UAR_CTX_BASE_OFFSET);
 | 
							MTHCA_PUT(inbox, param->uarc_base,   INIT_HCA_UAR_CTX_BASE_OFFSET);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	err = mthca_cmd(dev, indma, 0, 0, CMD_INIT_HCA,
 | 
						err = mthca_cmd(dev, mailbox->dma, 0, 0, CMD_INIT_HCA, HZ, status);
 | 
				
			||||||
			HZ, status);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	pci_free_consistent(dev->pdev, INIT_HCA_IN_SIZE, inbox, indma);
 | 
						mthca_free_mailbox(dev, mailbox);
 | 
				
			||||||
	return err;
 | 
						return err;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1178,8 +1237,8 @@ int mthca_INIT_IB(struct mthca_dev *dev,
 | 
				
			||||||
		  struct mthca_init_ib_param *param,
 | 
							  struct mthca_init_ib_param *param,
 | 
				
			||||||
		  int port, u8 *status)
 | 
							  int port, u8 *status)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
						struct mthca_mailbox *mailbox;
 | 
				
			||||||
	u32 *inbox;
 | 
						u32 *inbox;
 | 
				
			||||||
	dma_addr_t indma;
 | 
					 | 
				
			||||||
	int err;
 | 
						int err;
 | 
				
			||||||
	u32 flags;
 | 
						u32 flags;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1199,9 +1258,10 @@ int mthca_INIT_IB(struct mthca_dev *dev,
 | 
				
			||||||
#define INIT_IB_NODE_GUID_OFFSET 0x18
 | 
					#define INIT_IB_NODE_GUID_OFFSET 0x18
 | 
				
			||||||
#define INIT_IB_SI_GUID_OFFSET   0x20
 | 
					#define INIT_IB_SI_GUID_OFFSET   0x20
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	inbox = pci_alloc_consistent(dev->pdev, INIT_IB_IN_SIZE, &indma);
 | 
						mailbox = mthca_alloc_mailbox(dev, GFP_KERNEL);
 | 
				
			||||||
	if (!inbox)
 | 
						if (IS_ERR(mailbox))
 | 
				
			||||||
		return -ENOMEM;
 | 
							return PTR_ERR(mailbox);
 | 
				
			||||||
 | 
						inbox = mailbox->buf;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	memset(inbox, 0, INIT_IB_IN_SIZE);
 | 
						memset(inbox, 0, INIT_IB_IN_SIZE);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1221,10 +1281,10 @@ int mthca_INIT_IB(struct mthca_dev *dev,
 | 
				
			||||||
	MTHCA_PUT(inbox, param->node_guid, INIT_IB_NODE_GUID_OFFSET);
 | 
						MTHCA_PUT(inbox, param->node_guid, INIT_IB_NODE_GUID_OFFSET);
 | 
				
			||||||
	MTHCA_PUT(inbox, param->si_guid,   INIT_IB_SI_GUID_OFFSET);
 | 
						MTHCA_PUT(inbox, param->si_guid,   INIT_IB_SI_GUID_OFFSET);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	err = mthca_cmd(dev, indma, port, 0, CMD_INIT_IB,
 | 
						err = mthca_cmd(dev, mailbox->dma, port, 0, CMD_INIT_IB,
 | 
				
			||||||
			CMD_TIME_CLASS_A, status);
 | 
								CMD_TIME_CLASS_A, status);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	pci_free_consistent(dev->pdev, INIT_HCA_IN_SIZE, inbox, indma);
 | 
						mthca_free_mailbox(dev, mailbox);
 | 
				
			||||||
	return err;
 | 
						return err;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1241,8 +1301,8 @@ int mthca_CLOSE_HCA(struct mthca_dev *dev, int panic, u8 *status)
 | 
				
			||||||
int mthca_SET_IB(struct mthca_dev *dev, struct mthca_set_ib_param *param,
 | 
					int mthca_SET_IB(struct mthca_dev *dev, struct mthca_set_ib_param *param,
 | 
				
			||||||
		 int port, u8 *status)
 | 
							 int port, u8 *status)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
						struct mthca_mailbox *mailbox;
 | 
				
			||||||
	u32 *inbox;
 | 
						u32 *inbox;
 | 
				
			||||||
	dma_addr_t indma;
 | 
					 | 
				
			||||||
	int err;
 | 
						int err;
 | 
				
			||||||
	u32 flags = 0;
 | 
						u32 flags = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1253,9 +1313,10 @@ int mthca_SET_IB(struct mthca_dev *dev, struct mthca_set_ib_param *param,
 | 
				
			||||||
#define SET_IB_CAP_MASK_OFFSET 0x04
 | 
					#define SET_IB_CAP_MASK_OFFSET 0x04
 | 
				
			||||||
#define SET_IB_SI_GUID_OFFSET  0x08
 | 
					#define SET_IB_SI_GUID_OFFSET  0x08
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	inbox = pci_alloc_consistent(dev->pdev, SET_IB_IN_SIZE, &indma);
 | 
						mailbox = mthca_alloc_mailbox(dev, GFP_KERNEL);
 | 
				
			||||||
	if (!inbox)
 | 
						if (IS_ERR(mailbox))
 | 
				
			||||||
		return -ENOMEM;
 | 
							return PTR_ERR(mailbox);
 | 
				
			||||||
 | 
						inbox = mailbox->buf;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	memset(inbox, 0, SET_IB_IN_SIZE);
 | 
						memset(inbox, 0, SET_IB_IN_SIZE);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1266,10 +1327,10 @@ int mthca_SET_IB(struct mthca_dev *dev, struct mthca_set_ib_param *param,
 | 
				
			||||||
	MTHCA_PUT(inbox, param->cap_mask, SET_IB_CAP_MASK_OFFSET);
 | 
						MTHCA_PUT(inbox, param->cap_mask, SET_IB_CAP_MASK_OFFSET);
 | 
				
			||||||
	MTHCA_PUT(inbox, param->si_guid,  SET_IB_SI_GUID_OFFSET);
 | 
						MTHCA_PUT(inbox, param->si_guid,  SET_IB_SI_GUID_OFFSET);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	err = mthca_cmd(dev, indma, port, 0, CMD_SET_IB,
 | 
						err = mthca_cmd(dev, mailbox->dma, port, 0, CMD_SET_IB,
 | 
				
			||||||
			CMD_TIME_CLASS_B, status);
 | 
								CMD_TIME_CLASS_B, status);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	pci_free_consistent(dev->pdev, INIT_HCA_IN_SIZE, inbox, indma);
 | 
						mthca_free_mailbox(dev, mailbox);
 | 
				
			||||||
	return err;
 | 
						return err;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1280,20 +1341,22 @@ int mthca_MAP_ICM(struct mthca_dev *dev, struct mthca_icm *icm, u64 virt, u8 *st
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int mthca_MAP_ICM_page(struct mthca_dev *dev, u64 dma_addr, u64 virt, u8 *status)
 | 
					int mthca_MAP_ICM_page(struct mthca_dev *dev, u64 dma_addr, u64 virt, u8 *status)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
						struct mthca_mailbox *mailbox;
 | 
				
			||||||
	u64 *inbox;
 | 
						u64 *inbox;
 | 
				
			||||||
	dma_addr_t indma;
 | 
					 | 
				
			||||||
	int err;
 | 
						int err;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	inbox = pci_alloc_consistent(dev->pdev, 16, &indma);
 | 
						mailbox = mthca_alloc_mailbox(dev, GFP_KERNEL);
 | 
				
			||||||
	if (!inbox)
 | 
						if (IS_ERR(mailbox))
 | 
				
			||||||
		return -ENOMEM;
 | 
							return PTR_ERR(mailbox);
 | 
				
			||||||
 | 
						inbox = mailbox->buf;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	inbox[0] = cpu_to_be64(virt);
 | 
						inbox[0] = cpu_to_be64(virt);
 | 
				
			||||||
	inbox[1] = cpu_to_be64(dma_addr);
 | 
						inbox[1] = cpu_to_be64(dma_addr);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	err = mthca_cmd(dev, indma, 1, 0, CMD_MAP_ICM, CMD_TIME_CLASS_B, status);
 | 
						err = mthca_cmd(dev, mailbox->dma, 1, 0, CMD_MAP_ICM,
 | 
				
			||||||
 | 
								CMD_TIME_CLASS_B, status);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	pci_free_consistent(dev->pdev, 16, inbox, indma);
 | 
						mthca_free_mailbox(dev, mailbox);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!err)
 | 
						if (!err)
 | 
				
			||||||
		mthca_dbg(dev, "Mapped page at %llx to %llx for ICM.\n",
 | 
							mthca_dbg(dev, "Mapped page at %llx to %llx for ICM.\n",
 | 
				
			||||||
| 
						 | 
					@ -1338,69 +1401,26 @@ int mthca_SET_ICM_SIZE(struct mthca_dev *dev, u64 icm_size, u64 *aux_pages,
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int mthca_SW2HW_MPT(struct mthca_dev *dev, void *mpt_entry,
 | 
					int mthca_SW2HW_MPT(struct mthca_dev *dev, struct mthca_mailbox *mailbox,
 | 
				
			||||||
		    int mpt_index, u8 *status)
 | 
							    int mpt_index, u8 *status)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	dma_addr_t indma;
 | 
						return mthca_cmd(dev, mailbox->dma, mpt_index, 0, CMD_SW2HW_MPT,
 | 
				
			||||||
	int err;
 | 
								 CMD_TIME_CLASS_B, status);
 | 
				
			||||||
 | 
					 | 
				
			||||||
	indma = pci_map_single(dev->pdev, mpt_entry,
 | 
					 | 
				
			||||||
			       MTHCA_MPT_ENTRY_SIZE,
 | 
					 | 
				
			||||||
			       PCI_DMA_TODEVICE);
 | 
					 | 
				
			||||||
	if (pci_dma_mapping_error(indma))
 | 
					 | 
				
			||||||
		return -ENOMEM;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	err = mthca_cmd(dev, indma, mpt_index, 0, CMD_SW2HW_MPT,
 | 
					 | 
				
			||||||
			CMD_TIME_CLASS_B, status);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	pci_unmap_single(dev->pdev, indma,
 | 
					 | 
				
			||||||
			 MTHCA_MPT_ENTRY_SIZE, PCI_DMA_TODEVICE);
 | 
					 | 
				
			||||||
	return err;
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int mthca_HW2SW_MPT(struct mthca_dev *dev, void *mpt_entry,
 | 
					int mthca_HW2SW_MPT(struct mthca_dev *dev, struct mthca_mailbox *mailbox,
 | 
				
			||||||
		    int mpt_index, u8 *status)
 | 
							    int mpt_index, u8 *status)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	dma_addr_t outdma = 0;
 | 
						return mthca_cmd_box(dev, 0, mailbox ? mailbox->dma : 0, mpt_index,
 | 
				
			||||||
	int err;
 | 
								     !mailbox, CMD_HW2SW_MPT,
 | 
				
			||||||
 | 
								     CMD_TIME_CLASS_B, status);
 | 
				
			||||||
	if (mpt_entry) {
 | 
					 | 
				
			||||||
		outdma = pci_map_single(dev->pdev, mpt_entry,
 | 
					 | 
				
			||||||
					MTHCA_MPT_ENTRY_SIZE,
 | 
					 | 
				
			||||||
					PCI_DMA_FROMDEVICE);
 | 
					 | 
				
			||||||
		if (pci_dma_mapping_error(outdma))
 | 
					 | 
				
			||||||
			return -ENOMEM;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	err = mthca_cmd_box(dev, 0, outdma, mpt_index, !mpt_entry,
 | 
					 | 
				
			||||||
			    CMD_HW2SW_MPT,
 | 
					 | 
				
			||||||
			    CMD_TIME_CLASS_B, status);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (mpt_entry)
 | 
					 | 
				
			||||||
		pci_unmap_single(dev->pdev, outdma,
 | 
					 | 
				
			||||||
				 MTHCA_MPT_ENTRY_SIZE,
 | 
					 | 
				
			||||||
				 PCI_DMA_FROMDEVICE);
 | 
					 | 
				
			||||||
	return err;
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int mthca_WRITE_MTT(struct mthca_dev *dev, u64 *mtt_entry,
 | 
					int mthca_WRITE_MTT(struct mthca_dev *dev, struct mthca_mailbox *mailbox,
 | 
				
			||||||
		    int num_mtt, u8 *status)
 | 
							    int num_mtt, u8 *status)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	dma_addr_t indma;
 | 
						return mthca_cmd(dev, mailbox->dma, num_mtt, 0, CMD_WRITE_MTT,
 | 
				
			||||||
	int err;
 | 
								 CMD_TIME_CLASS_B, status);
 | 
				
			||||||
 | 
					 | 
				
			||||||
	indma = pci_map_single(dev->pdev, mtt_entry,
 | 
					 | 
				
			||||||
			       (num_mtt + 2) * 8,
 | 
					 | 
				
			||||||
			       PCI_DMA_TODEVICE);
 | 
					 | 
				
			||||||
	if (pci_dma_mapping_error(indma))
 | 
					 | 
				
			||||||
		return -ENOMEM;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	err = mthca_cmd(dev, indma, num_mtt, 0, CMD_WRITE_MTT,
 | 
					 | 
				
			||||||
			CMD_TIME_CLASS_B, status);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	pci_unmap_single(dev->pdev, indma,
 | 
					 | 
				
			||||||
			 (num_mtt + 2) * 8, PCI_DMA_TODEVICE);
 | 
					 | 
				
			||||||
	return err;
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int mthca_SYNC_TPT(struct mthca_dev *dev, u8 *status)
 | 
					int mthca_SYNC_TPT(struct mthca_dev *dev, u8 *status)
 | 
				
			||||||
| 
						 | 
					@ -1418,92 +1438,38 @@ int mthca_MAP_EQ(struct mthca_dev *dev, u64 event_mask, int unmap,
 | 
				
			||||||
			 0, CMD_MAP_EQ, CMD_TIME_CLASS_B, status);
 | 
								 0, CMD_MAP_EQ, CMD_TIME_CLASS_B, status);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int mthca_SW2HW_EQ(struct mthca_dev *dev, void *eq_context,
 | 
					int mthca_SW2HW_EQ(struct mthca_dev *dev, struct mthca_mailbox *mailbox,
 | 
				
			||||||
		   int eq_num, u8 *status)
 | 
							   int eq_num, u8 *status)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	dma_addr_t indma;
 | 
						return mthca_cmd(dev, mailbox->dma, eq_num, 0, CMD_SW2HW_EQ,
 | 
				
			||||||
	int err;
 | 
								 CMD_TIME_CLASS_A, status);
 | 
				
			||||||
 | 
					 | 
				
			||||||
	indma = pci_map_single(dev->pdev, eq_context,
 | 
					 | 
				
			||||||
			       MTHCA_EQ_CONTEXT_SIZE,
 | 
					 | 
				
			||||||
			       PCI_DMA_TODEVICE);
 | 
					 | 
				
			||||||
	if (pci_dma_mapping_error(indma))
 | 
					 | 
				
			||||||
		return -ENOMEM;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	err = mthca_cmd(dev, indma, eq_num, 0, CMD_SW2HW_EQ,
 | 
					 | 
				
			||||||
			CMD_TIME_CLASS_A, status);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	pci_unmap_single(dev->pdev, indma,
 | 
					 | 
				
			||||||
			 MTHCA_EQ_CONTEXT_SIZE, PCI_DMA_TODEVICE);
 | 
					 | 
				
			||||||
	return err;
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int mthca_HW2SW_EQ(struct mthca_dev *dev, void *eq_context,
 | 
					int mthca_HW2SW_EQ(struct mthca_dev *dev, struct mthca_mailbox *mailbox,
 | 
				
			||||||
		   int eq_num, u8 *status)
 | 
							   int eq_num, u8 *status)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	dma_addr_t outdma = 0;
 | 
						return mthca_cmd_box(dev, 0, mailbox->dma, eq_num, 0,
 | 
				
			||||||
	int err;
 | 
								     CMD_HW2SW_EQ,
 | 
				
			||||||
 | 
								     CMD_TIME_CLASS_A, status);
 | 
				
			||||||
	outdma = pci_map_single(dev->pdev, eq_context,
 | 
					 | 
				
			||||||
				MTHCA_EQ_CONTEXT_SIZE,
 | 
					 | 
				
			||||||
				PCI_DMA_FROMDEVICE);
 | 
					 | 
				
			||||||
	if (pci_dma_mapping_error(outdma))
 | 
					 | 
				
			||||||
		return -ENOMEM;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	err = mthca_cmd_box(dev, 0, outdma, eq_num, 0,
 | 
					 | 
				
			||||||
			    CMD_HW2SW_EQ,
 | 
					 | 
				
			||||||
			    CMD_TIME_CLASS_A, status);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	pci_unmap_single(dev->pdev, outdma,
 | 
					 | 
				
			||||||
			 MTHCA_EQ_CONTEXT_SIZE,
 | 
					 | 
				
			||||||
			 PCI_DMA_FROMDEVICE);
 | 
					 | 
				
			||||||
	return err;
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int mthca_SW2HW_CQ(struct mthca_dev *dev, void *cq_context,
 | 
					int mthca_SW2HW_CQ(struct mthca_dev *dev, struct mthca_mailbox *mailbox,
 | 
				
			||||||
		   int cq_num, u8 *status)
 | 
							   int cq_num, u8 *status)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	dma_addr_t indma;
 | 
						return mthca_cmd(dev, mailbox->dma, cq_num, 0, CMD_SW2HW_CQ,
 | 
				
			||||||
	int err;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	indma = pci_map_single(dev->pdev, cq_context,
 | 
					 | 
				
			||||||
			       MTHCA_CQ_CONTEXT_SIZE,
 | 
					 | 
				
			||||||
			       PCI_DMA_TODEVICE);
 | 
					 | 
				
			||||||
	if (pci_dma_mapping_error(indma))
 | 
					 | 
				
			||||||
		return -ENOMEM;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	err = mthca_cmd(dev, indma, cq_num, 0, CMD_SW2HW_CQ,
 | 
					 | 
				
			||||||
			CMD_TIME_CLASS_A, status);
 | 
								CMD_TIME_CLASS_A, status);
 | 
				
			||||||
 | 
					 | 
				
			||||||
	pci_unmap_single(dev->pdev, indma,
 | 
					 | 
				
			||||||
			 MTHCA_CQ_CONTEXT_SIZE, PCI_DMA_TODEVICE);
 | 
					 | 
				
			||||||
	return err;
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int mthca_HW2SW_CQ(struct mthca_dev *dev, void *cq_context,
 | 
					int mthca_HW2SW_CQ(struct mthca_dev *dev, struct mthca_mailbox *mailbox,
 | 
				
			||||||
		   int cq_num, u8 *status)
 | 
							   int cq_num, u8 *status)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	dma_addr_t outdma = 0;
 | 
						return mthca_cmd_box(dev, 0, mailbox->dma, cq_num, 0,
 | 
				
			||||||
	int err;
 | 
								     CMD_HW2SW_CQ,
 | 
				
			||||||
 | 
								     CMD_TIME_CLASS_A, status);
 | 
				
			||||||
	outdma = pci_map_single(dev->pdev, cq_context,
 | 
					 | 
				
			||||||
				MTHCA_CQ_CONTEXT_SIZE,
 | 
					 | 
				
			||||||
				PCI_DMA_FROMDEVICE);
 | 
					 | 
				
			||||||
	if (pci_dma_mapping_error(outdma))
 | 
					 | 
				
			||||||
		return -ENOMEM;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	err = mthca_cmd_box(dev, 0, outdma, cq_num, 0,
 | 
					 | 
				
			||||||
			    CMD_HW2SW_CQ,
 | 
					 | 
				
			||||||
			    CMD_TIME_CLASS_A, status);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	pci_unmap_single(dev->pdev, outdma,
 | 
					 | 
				
			||||||
			 MTHCA_CQ_CONTEXT_SIZE,
 | 
					 | 
				
			||||||
			 PCI_DMA_FROMDEVICE);
 | 
					 | 
				
			||||||
	return err;
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int mthca_MODIFY_QP(struct mthca_dev *dev, int trans, u32 num,
 | 
					int mthca_MODIFY_QP(struct mthca_dev *dev, int trans, u32 num,
 | 
				
			||||||
		    int is_ee, void *qp_context, u32 optmask,
 | 
							    int is_ee, struct mthca_mailbox *mailbox, u32 optmask,
 | 
				
			||||||
		    u8 *status)
 | 
							    u8 *status)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	static const u16 op[] = {
 | 
						static const u16 op[] = {
 | 
				
			||||||
| 
						 | 
					@ -1520,36 +1486,34 @@ int mthca_MODIFY_QP(struct mthca_dev *dev, int trans, u32 num,
 | 
				
			||||||
		[MTHCA_TRANS_ANY2RST]   = CMD_ERR2RST_QPEE
 | 
							[MTHCA_TRANS_ANY2RST]   = CMD_ERR2RST_QPEE
 | 
				
			||||||
	};
 | 
						};
 | 
				
			||||||
	u8 op_mod = 0;
 | 
						u8 op_mod = 0;
 | 
				
			||||||
 | 
						int my_mailbox = 0;
 | 
				
			||||||
	dma_addr_t indma;
 | 
					 | 
				
			||||||
	int err;
 | 
						int err;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (trans < 0 || trans >= ARRAY_SIZE(op))
 | 
						if (trans < 0 || trans >= ARRAY_SIZE(op))
 | 
				
			||||||
		return -EINVAL;
 | 
							return -EINVAL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (trans == MTHCA_TRANS_ANY2RST) {
 | 
						if (trans == MTHCA_TRANS_ANY2RST) {
 | 
				
			||||||
		indma  = 0;
 | 
					 | 
				
			||||||
		op_mod = 3;	/* don't write outbox, any->reset */
 | 
							op_mod = 3;	/* don't write outbox, any->reset */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		/* For debugging */
 | 
							/* For debugging */
 | 
				
			||||||
		qp_context = pci_alloc_consistent(dev->pdev, MTHCA_QP_CONTEXT_SIZE,
 | 
							if (!mailbox) {
 | 
				
			||||||
						  &indma);
 | 
								mailbox = mthca_alloc_mailbox(dev, GFP_KERNEL);
 | 
				
			||||||
		op_mod = 2;	/* write outbox, any->reset */
 | 
								if (!IS_ERR(mailbox)) {
 | 
				
			||||||
 | 
									my_mailbox = 1;
 | 
				
			||||||
 | 
									op_mod     = 2;	/* write outbox, any->reset */
 | 
				
			||||||
 | 
								} else
 | 
				
			||||||
 | 
									mailbox = NULL;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
		indma = pci_map_single(dev->pdev, qp_context,
 | 
					 | 
				
			||||||
				       MTHCA_QP_CONTEXT_SIZE,
 | 
					 | 
				
			||||||
				       PCI_DMA_TODEVICE);
 | 
					 | 
				
			||||||
		if (pci_dma_mapping_error(indma))
 | 
					 | 
				
			||||||
			return -ENOMEM;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		if (0) {
 | 
							if (0) {
 | 
				
			||||||
			int i;
 | 
								int i;
 | 
				
			||||||
			mthca_dbg(dev, "Dumping QP context:\n");
 | 
								mthca_dbg(dev, "Dumping QP context:\n");
 | 
				
			||||||
			printk("  opt param mask: %08x\n", be32_to_cpup(qp_context));
 | 
								printk("  opt param mask: %08x\n", be32_to_cpup(mailbox->buf));
 | 
				
			||||||
			for (i = 0; i < 0x100 / 4; ++i) {
 | 
								for (i = 0; i < 0x100 / 4; ++i) {
 | 
				
			||||||
				if (i % 8 == 0)
 | 
									if (i % 8 == 0)
 | 
				
			||||||
					printk("  [%02x] ", i * 4);
 | 
										printk("  [%02x] ", i * 4);
 | 
				
			||||||
				printk(" %08x", be32_to_cpu(((u32 *) qp_context)[i + 2]));
 | 
									printk(" %08x",
 | 
				
			||||||
 | 
									       be32_to_cpu(((u32 *) mailbox->buf)[i + 2]));
 | 
				
			||||||
				if ((i + 1) % 8 == 0)
 | 
									if ((i + 1) % 8 == 0)
 | 
				
			||||||
					printk("\n");
 | 
										printk("\n");
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
| 
						 | 
					@ -1557,55 +1521,39 @@ int mthca_MODIFY_QP(struct mthca_dev *dev, int trans, u32 num,
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (trans == MTHCA_TRANS_ANY2RST) {
 | 
						if (trans == MTHCA_TRANS_ANY2RST) {
 | 
				
			||||||
		err = mthca_cmd_box(dev, 0, indma, (!!is_ee << 24) | num,
 | 
							err = mthca_cmd_box(dev, 0, mailbox ? mailbox->dma : 0,
 | 
				
			||||||
				    op_mod, op[trans], CMD_TIME_CLASS_C, status);
 | 
									    (!!is_ee << 24) | num, op_mod,
 | 
				
			||||||
 | 
									    op[trans], CMD_TIME_CLASS_C, status);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (0) {
 | 
							if (0 && mailbox) {
 | 
				
			||||||
			int i;
 | 
								int i;
 | 
				
			||||||
			mthca_dbg(dev, "Dumping QP context:\n");
 | 
								mthca_dbg(dev, "Dumping QP context:\n");
 | 
				
			||||||
			printk(" %08x\n", be32_to_cpup(qp_context));
 | 
								printk(" %08x\n", be32_to_cpup(mailbox->buf));
 | 
				
			||||||
			for (i = 0; i < 0x100 / 4; ++i) {
 | 
								for (i = 0; i < 0x100 / 4; ++i) {
 | 
				
			||||||
				if (i % 8 == 0)
 | 
									if (i % 8 == 0)
 | 
				
			||||||
					printk("[%02x] ", i * 4);
 | 
										printk("[%02x] ", i * 4);
 | 
				
			||||||
				printk(" %08x", be32_to_cpu(((u32 *) qp_context)[i + 2]));
 | 
									printk(" %08x",
 | 
				
			||||||
 | 
									       be32_to_cpu(((u32 *) mailbox->buf)[i + 2]));
 | 
				
			||||||
				if ((i + 1) % 8 == 0)
 | 
									if ((i + 1) % 8 == 0)
 | 
				
			||||||
					printk("\n");
 | 
										printk("\n");
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	} else
 | 
						} else
 | 
				
			||||||
		err = mthca_cmd(dev, indma, (!!is_ee << 24) | num,
 | 
							err = mthca_cmd(dev, mailbox->dma, (!!is_ee << 24) | num,
 | 
				
			||||||
				op_mod, op[trans], CMD_TIME_CLASS_C, status);
 | 
									op_mod, op[trans], CMD_TIME_CLASS_C, status);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (trans != MTHCA_TRANS_ANY2RST)
 | 
						if (my_mailbox)
 | 
				
			||||||
		pci_unmap_single(dev->pdev, indma,
 | 
							mthca_free_mailbox(dev, mailbox);
 | 
				
			||||||
				 MTHCA_QP_CONTEXT_SIZE, PCI_DMA_TODEVICE);
 | 
					
 | 
				
			||||||
	else
 | 
					 | 
				
			||||||
		pci_free_consistent(dev->pdev, MTHCA_QP_CONTEXT_SIZE,
 | 
					 | 
				
			||||||
				    qp_context, indma);
 | 
					 | 
				
			||||||
	return err;
 | 
						return err;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int mthca_QUERY_QP(struct mthca_dev *dev, u32 num, int is_ee,
 | 
					int mthca_QUERY_QP(struct mthca_dev *dev, u32 num, int is_ee,
 | 
				
			||||||
		   void *qp_context, u8 *status)
 | 
							   struct mthca_mailbox *mailbox, u8 *status)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	dma_addr_t outdma = 0;
 | 
						return mthca_cmd_box(dev, 0, mailbox->dma, (!!is_ee << 24) | num, 0,
 | 
				
			||||||
	int err;
 | 
								     CMD_QUERY_QPEE, CMD_TIME_CLASS_A, status);
 | 
				
			||||||
 | 
					 | 
				
			||||||
	outdma = pci_map_single(dev->pdev, qp_context,
 | 
					 | 
				
			||||||
				MTHCA_QP_CONTEXT_SIZE,
 | 
					 | 
				
			||||||
				PCI_DMA_FROMDEVICE);
 | 
					 | 
				
			||||||
	if (pci_dma_mapping_error(outdma))
 | 
					 | 
				
			||||||
		return -ENOMEM;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	err = mthca_cmd_box(dev, 0, outdma, (!!is_ee << 24) | num, 0,
 | 
					 | 
				
			||||||
			    CMD_QUERY_QPEE,
 | 
					 | 
				
			||||||
			    CMD_TIME_CLASS_A, status);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	pci_unmap_single(dev->pdev, outdma,
 | 
					 | 
				
			||||||
			 MTHCA_QP_CONTEXT_SIZE,
 | 
					 | 
				
			||||||
			 PCI_DMA_FROMDEVICE);
 | 
					 | 
				
			||||||
	return err;
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int mthca_CONF_SPECIAL_QP(struct mthca_dev *dev, int type, u32 qpn,
 | 
					int mthca_CONF_SPECIAL_QP(struct mthca_dev *dev, int type, u32 qpn,
 | 
				
			||||||
| 
						 | 
					@ -1635,11 +1583,11 @@ int mthca_CONF_SPECIAL_QP(struct mthca_dev *dev, int type, u32 qpn,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int mthca_MAD_IFC(struct mthca_dev *dev, int ignore_mkey, int ignore_bkey,
 | 
					int mthca_MAD_IFC(struct mthca_dev *dev, int ignore_mkey, int ignore_bkey,
 | 
				
			||||||
		  int port, struct ib_wc* in_wc, struct ib_grh* in_grh,
 | 
							  int port, struct ib_wc *in_wc, struct ib_grh *in_grh,
 | 
				
			||||||
		  void *in_mad, void *response_mad, u8 *status)
 | 
							  void *in_mad, void *response_mad, u8 *status)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	void *box;
 | 
						struct mthca_mailbox *inmailbox, *outmailbox;
 | 
				
			||||||
	dma_addr_t dma;
 | 
						void *inbox;
 | 
				
			||||||
	int err;
 | 
						int err;
 | 
				
			||||||
	u32 in_modifier = port;
 | 
						u32 in_modifier = port;
 | 
				
			||||||
	u8 op_modifier = 0;
 | 
						u8 op_modifier = 0;
 | 
				
			||||||
| 
						 | 
					@ -1653,11 +1601,18 @@ int mthca_MAD_IFC(struct mthca_dev *dev, int ignore_mkey, int ignore_bkey,
 | 
				
			||||||
#define MAD_IFC_PKEY_OFFSET   0x10e
 | 
					#define MAD_IFC_PKEY_OFFSET   0x10e
 | 
				
			||||||
#define MAD_IFC_GRH_OFFSET    0x140
 | 
					#define MAD_IFC_GRH_OFFSET    0x140
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	box = pci_alloc_consistent(dev->pdev, MAD_IFC_BOX_SIZE, &dma);
 | 
						inmailbox = mthca_alloc_mailbox(dev, GFP_KERNEL);
 | 
				
			||||||
	if (!box)
 | 
						if (IS_ERR(inmailbox))
 | 
				
			||||||
		return -ENOMEM;
 | 
							return PTR_ERR(inmailbox);
 | 
				
			||||||
 | 
						inbox = inmailbox->buf;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	memcpy(box, in_mad, 256);
 | 
						outmailbox = mthca_alloc_mailbox(dev, GFP_KERNEL);
 | 
				
			||||||
 | 
						if (IS_ERR(outmailbox)) {
 | 
				
			||||||
 | 
							mthca_free_mailbox(dev, inmailbox);
 | 
				
			||||||
 | 
							return PTR_ERR(outmailbox);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						memcpy(inbox, in_mad, 256);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/*
 | 
						/*
 | 
				
			||||||
	 * Key check traps can't be generated unless we have in_wc to
 | 
						 * Key check traps can't be generated unless we have in_wc to
 | 
				
			||||||
| 
						 | 
					@ -1671,97 +1626,65 @@ int mthca_MAD_IFC(struct mthca_dev *dev, int ignore_mkey, int ignore_bkey,
 | 
				
			||||||
	if (in_wc) {
 | 
						if (in_wc) {
 | 
				
			||||||
		u8 val;
 | 
							u8 val;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		memset(box + 256, 0, 256);
 | 
							memset(inbox + 256, 0, 256);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		MTHCA_PUT(box, in_wc->qp_num, 	  MAD_IFC_MY_QPN_OFFSET);
 | 
							MTHCA_PUT(inbox, in_wc->qp_num,     MAD_IFC_MY_QPN_OFFSET);
 | 
				
			||||||
		MTHCA_PUT(box, in_wc->src_qp, 	  MAD_IFC_RQPN_OFFSET);
 | 
							MTHCA_PUT(inbox, in_wc->src_qp,     MAD_IFC_RQPN_OFFSET);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		val = in_wc->sl << 4;
 | 
							val = in_wc->sl << 4;
 | 
				
			||||||
		MTHCA_PUT(box, val,               MAD_IFC_SL_OFFSET);
 | 
							MTHCA_PUT(inbox, val,               MAD_IFC_SL_OFFSET);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		val = in_wc->dlid_path_bits |
 | 
							val = in_wc->dlid_path_bits |
 | 
				
			||||||
			(in_wc->wc_flags & IB_WC_GRH ? 0x80 : 0);
 | 
								(in_wc->wc_flags & IB_WC_GRH ? 0x80 : 0);
 | 
				
			||||||
		MTHCA_PUT(box, val,               MAD_IFC_GRH_OFFSET);
 | 
							MTHCA_PUT(inbox, val,               MAD_IFC_GRH_OFFSET);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		MTHCA_PUT(box, in_wc->slid,       MAD_IFC_RLID_OFFSET);
 | 
							MTHCA_PUT(inbox, in_wc->slid,       MAD_IFC_RLID_OFFSET);
 | 
				
			||||||
		MTHCA_PUT(box, in_wc->pkey_index, MAD_IFC_PKEY_OFFSET);
 | 
							MTHCA_PUT(inbox, in_wc->pkey_index, MAD_IFC_PKEY_OFFSET);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (in_grh)
 | 
							if (in_grh)
 | 
				
			||||||
			memcpy((u8 *) box + MAD_IFC_GRH_OFFSET, in_grh, 40);
 | 
								memcpy(inbox + MAD_IFC_GRH_OFFSET, in_grh, 40);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		op_modifier |= 0x10;
 | 
							op_modifier |= 0x10;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		in_modifier |= in_wc->slid << 16;
 | 
							in_modifier |= in_wc->slid << 16;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	err = mthca_cmd_box(dev, dma, dma + 512, in_modifier, op_modifier,
 | 
						err = mthca_cmd_box(dev, inmailbox->dma, outmailbox->dma,
 | 
				
			||||||
 | 
								    in_modifier, op_modifier,
 | 
				
			||||||
			    CMD_MAD_IFC, CMD_TIME_CLASS_C, status);
 | 
								    CMD_MAD_IFC, CMD_TIME_CLASS_C, status);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!err && !*status)
 | 
						if (!err && !*status)
 | 
				
			||||||
		memcpy(response_mad, box + 512, 256);
 | 
							memcpy(response_mad, outmailbox->buf, 256);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	pci_free_consistent(dev->pdev, MAD_IFC_BOX_SIZE, box, dma);
 | 
						mthca_free_mailbox(dev, inmailbox);
 | 
				
			||||||
 | 
						mthca_free_mailbox(dev, outmailbox);
 | 
				
			||||||
	return err;
 | 
						return err;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int mthca_READ_MGM(struct mthca_dev *dev, int index, void *mgm,
 | 
					int mthca_READ_MGM(struct mthca_dev *dev, int index,
 | 
				
			||||||
		   u8 *status)
 | 
							   struct mthca_mailbox *mailbox, u8 *status)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	dma_addr_t outdma = 0;
 | 
						return mthca_cmd_box(dev, 0, mailbox->dma, index, 0,
 | 
				
			||||||
	int err;
 | 
								     CMD_READ_MGM, CMD_TIME_CLASS_A, status);
 | 
				
			||||||
 | 
					 | 
				
			||||||
	outdma = pci_map_single(dev->pdev, mgm,
 | 
					 | 
				
			||||||
				MTHCA_MGM_ENTRY_SIZE,
 | 
					 | 
				
			||||||
				PCI_DMA_FROMDEVICE);
 | 
					 | 
				
			||||||
	if (pci_dma_mapping_error(outdma))
 | 
					 | 
				
			||||||
		return -ENOMEM;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	err = mthca_cmd_box(dev, 0, outdma, index, 0,
 | 
					 | 
				
			||||||
			    CMD_READ_MGM,
 | 
					 | 
				
			||||||
			    CMD_TIME_CLASS_A, status);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	pci_unmap_single(dev->pdev, outdma,
 | 
					 | 
				
			||||||
			 MTHCA_MGM_ENTRY_SIZE,
 | 
					 | 
				
			||||||
			 PCI_DMA_FROMDEVICE);
 | 
					 | 
				
			||||||
	return err;
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int mthca_WRITE_MGM(struct mthca_dev *dev, int index, void *mgm,
 | 
					int mthca_WRITE_MGM(struct mthca_dev *dev, int index,
 | 
				
			||||||
		    u8 *status)
 | 
							    struct mthca_mailbox *mailbox, u8 *status)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	dma_addr_t indma;
 | 
						return mthca_cmd(dev, mailbox->dma, index, 0, CMD_WRITE_MGM,
 | 
				
			||||||
	int err;
 | 
								 CMD_TIME_CLASS_A, status);
 | 
				
			||||||
 | 
					 | 
				
			||||||
	indma = pci_map_single(dev->pdev, mgm,
 | 
					 | 
				
			||||||
			       MTHCA_MGM_ENTRY_SIZE,
 | 
					 | 
				
			||||||
			       PCI_DMA_TODEVICE);
 | 
					 | 
				
			||||||
	if (pci_dma_mapping_error(indma))
 | 
					 | 
				
			||||||
		return -ENOMEM;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	err = mthca_cmd(dev, indma, index, 0, CMD_WRITE_MGM,
 | 
					 | 
				
			||||||
			CMD_TIME_CLASS_A, status);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	pci_unmap_single(dev->pdev, indma,
 | 
					 | 
				
			||||||
			 MTHCA_MGM_ENTRY_SIZE, PCI_DMA_TODEVICE);
 | 
					 | 
				
			||||||
	return err;
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int mthca_MGID_HASH(struct mthca_dev *dev, void *gid, u16 *hash,
 | 
					int mthca_MGID_HASH(struct mthca_dev *dev, struct mthca_mailbox *mailbox,
 | 
				
			||||||
		    u8 *status)
 | 
							    u16 *hash, u8 *status)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	dma_addr_t indma;
 | 
					 | 
				
			||||||
	u64 imm;
 | 
						u64 imm;
 | 
				
			||||||
	int err;
 | 
						int err;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	indma = pci_map_single(dev->pdev, gid, 16, PCI_DMA_TODEVICE);
 | 
						err = mthca_cmd_imm(dev, mailbox->dma, &imm, 0, 0, CMD_MGID_HASH,
 | 
				
			||||||
	if (pci_dma_mapping_error(indma))
 | 
					 | 
				
			||||||
		return -ENOMEM;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	err = mthca_cmd_imm(dev, indma, &imm, 0, 0, CMD_MGID_HASH,
 | 
					 | 
				
			||||||
			    CMD_TIME_CLASS_A, status);
 | 
								    CMD_TIME_CLASS_A, status);
 | 
				
			||||||
	*hash = imm;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	pci_unmap_single(dev->pdev, indma, 16, PCI_DMA_TODEVICE);
 | 
						*hash = imm;
 | 
				
			||||||
	return err;
 | 
						return err;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -37,8 +37,7 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <ib_verbs.h>
 | 
					#include <ib_verbs.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define MTHCA_CMD_MAILBOX_ALIGN 16UL
 | 
					#define MTHCA_MAILBOX_SIZE 4096
 | 
				
			||||||
#define MTHCA_CMD_MAILBOX_EXTRA (MTHCA_CMD_MAILBOX_ALIGN - 1)
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
enum {
 | 
					enum {
 | 
				
			||||||
	/* command completed successfully: */
 | 
						/* command completed successfully: */
 | 
				
			||||||
| 
						 | 
					@ -112,6 +111,11 @@ enum {
 | 
				
			||||||
	DEV_LIM_FLAG_UD_MULTI           = 1 << 21,
 | 
						DEV_LIM_FLAG_UD_MULTI           = 1 << 21,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct mthca_mailbox {
 | 
				
			||||||
 | 
						dma_addr_t dma;
 | 
				
			||||||
 | 
						void      *buf;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct mthca_dev_lim {
 | 
					struct mthca_dev_lim {
 | 
				
			||||||
	int max_srq_sz;
 | 
						int max_srq_sz;
 | 
				
			||||||
	int max_qp_sz;
 | 
						int max_qp_sz;
 | 
				
			||||||
| 
						 | 
					@ -235,11 +239,17 @@ struct mthca_set_ib_param {
 | 
				
			||||||
	u32 cap_mask;
 | 
						u32 cap_mask;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int mthca_cmd_init(struct mthca_dev *dev);
 | 
				
			||||||
 | 
					void mthca_cmd_cleanup(struct mthca_dev *dev);
 | 
				
			||||||
int mthca_cmd_use_events(struct mthca_dev *dev);
 | 
					int mthca_cmd_use_events(struct mthca_dev *dev);
 | 
				
			||||||
void mthca_cmd_use_polling(struct mthca_dev *dev);
 | 
					void mthca_cmd_use_polling(struct mthca_dev *dev);
 | 
				
			||||||
void mthca_cmd_event(struct mthca_dev *dev, u16 token,
 | 
					void mthca_cmd_event(struct mthca_dev *dev, u16 token,
 | 
				
			||||||
		     u8  status, u64 out_param);
 | 
							     u8  status, u64 out_param);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct mthca_mailbox *mthca_alloc_mailbox(struct mthca_dev *dev,
 | 
				
			||||||
 | 
										  unsigned int gfp_mask);
 | 
				
			||||||
 | 
					void mthca_free_mailbox(struct mthca_dev *dev, struct mthca_mailbox *mailbox);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int mthca_SYS_EN(struct mthca_dev *dev, u8 *status);
 | 
					int mthca_SYS_EN(struct mthca_dev *dev, u8 *status);
 | 
				
			||||||
int mthca_SYS_DIS(struct mthca_dev *dev, u8 *status);
 | 
					int mthca_SYS_DIS(struct mthca_dev *dev, u8 *status);
 | 
				
			||||||
int mthca_MAP_FA(struct mthca_dev *dev, struct mthca_icm *icm, u8 *status);
 | 
					int mthca_MAP_FA(struct mthca_dev *dev, struct mthca_icm *icm, u8 *status);
 | 
				
			||||||
| 
						 | 
					@ -270,41 +280,39 @@ int mthca_MAP_ICM_AUX(struct mthca_dev *dev, struct mthca_icm *icm, u8 *status);
 | 
				
			||||||
int mthca_UNMAP_ICM_AUX(struct mthca_dev *dev, u8 *status);
 | 
					int mthca_UNMAP_ICM_AUX(struct mthca_dev *dev, u8 *status);
 | 
				
			||||||
int mthca_SET_ICM_SIZE(struct mthca_dev *dev, u64 icm_size, u64 *aux_pages,
 | 
					int mthca_SET_ICM_SIZE(struct mthca_dev *dev, u64 icm_size, u64 *aux_pages,
 | 
				
			||||||
		       u8 *status);
 | 
							       u8 *status);
 | 
				
			||||||
int mthca_SW2HW_MPT(struct mthca_dev *dev, void *mpt_entry,
 | 
					int mthca_SW2HW_MPT(struct mthca_dev *dev, struct mthca_mailbox *mailbox,
 | 
				
			||||||
		    int mpt_index, u8 *status);
 | 
							    int mpt_index, u8 *status);
 | 
				
			||||||
int mthca_HW2SW_MPT(struct mthca_dev *dev, void *mpt_entry,
 | 
					int mthca_HW2SW_MPT(struct mthca_dev *dev, struct mthca_mailbox *mailbox,
 | 
				
			||||||
		    int mpt_index, u8 *status);
 | 
							    int mpt_index, u8 *status);
 | 
				
			||||||
int mthca_WRITE_MTT(struct mthca_dev *dev, u64 *mtt_entry,
 | 
					int mthca_WRITE_MTT(struct mthca_dev *dev, struct mthca_mailbox *mailbox,
 | 
				
			||||||
		    int num_mtt, u8 *status);
 | 
							    int num_mtt, u8 *status);
 | 
				
			||||||
int mthca_SYNC_TPT(struct mthca_dev *dev, u8 *status);
 | 
					int mthca_SYNC_TPT(struct mthca_dev *dev, u8 *status);
 | 
				
			||||||
int mthca_MAP_EQ(struct mthca_dev *dev, u64 event_mask, int unmap,
 | 
					int mthca_MAP_EQ(struct mthca_dev *dev, u64 event_mask, int unmap,
 | 
				
			||||||
		 int eq_num, u8 *status);
 | 
							 int eq_num, u8 *status);
 | 
				
			||||||
int mthca_SW2HW_EQ(struct mthca_dev *dev, void *eq_context,
 | 
					int mthca_SW2HW_EQ(struct mthca_dev *dev, struct mthca_mailbox *mailbox,
 | 
				
			||||||
		   int eq_num, u8 *status);
 | 
							   int eq_num, u8 *status);
 | 
				
			||||||
int mthca_HW2SW_EQ(struct mthca_dev *dev, void *eq_context,
 | 
					int mthca_HW2SW_EQ(struct mthca_dev *dev, struct mthca_mailbox *mailbox,
 | 
				
			||||||
		   int eq_num, u8 *status);
 | 
							   int eq_num, u8 *status);
 | 
				
			||||||
int mthca_SW2HW_CQ(struct mthca_dev *dev, void *cq_context,
 | 
					int mthca_SW2HW_CQ(struct mthca_dev *dev, struct mthca_mailbox *mailbox,
 | 
				
			||||||
		   int cq_num, u8 *status);
 | 
							   int cq_num, u8 *status);
 | 
				
			||||||
int mthca_HW2SW_CQ(struct mthca_dev *dev, void *cq_context,
 | 
					int mthca_HW2SW_CQ(struct mthca_dev *dev, struct mthca_mailbox *mailbox,
 | 
				
			||||||
		   int cq_num, u8 *status);
 | 
							   int cq_num, u8 *status);
 | 
				
			||||||
int mthca_MODIFY_QP(struct mthca_dev *dev, int trans, u32 num,
 | 
					int mthca_MODIFY_QP(struct mthca_dev *dev, int trans, u32 num,
 | 
				
			||||||
		    int is_ee, void *qp_context, u32 optmask,
 | 
							    int is_ee, struct mthca_mailbox *mailbox, u32 optmask,
 | 
				
			||||||
		    u8 *status);
 | 
							    u8 *status);
 | 
				
			||||||
int mthca_QUERY_QP(struct mthca_dev *dev, u32 num, int is_ee,
 | 
					int mthca_QUERY_QP(struct mthca_dev *dev, u32 num, int is_ee,
 | 
				
			||||||
		   void *qp_context, u8 *status);
 | 
							   struct mthca_mailbox *mailbox, u8 *status);
 | 
				
			||||||
int mthca_CONF_SPECIAL_QP(struct mthca_dev *dev, int type, u32 qpn,
 | 
					int mthca_CONF_SPECIAL_QP(struct mthca_dev *dev, int type, u32 qpn,
 | 
				
			||||||
			  u8 *status);
 | 
								  u8 *status);
 | 
				
			||||||
int mthca_MAD_IFC(struct mthca_dev *dev, int ignore_mkey, int ignore_bkey,
 | 
					int mthca_MAD_IFC(struct mthca_dev *dev, int ignore_mkey, int ignore_bkey,
 | 
				
			||||||
		  int port, struct ib_wc* in_wc, struct ib_grh* in_grh,
 | 
							  int port, struct ib_wc *in_wc, struct ib_grh *in_grh,
 | 
				
			||||||
		  void *in_mad, void *response_mad, u8 *status);
 | 
							  void *in_mad, void *response_mad, u8 *status);
 | 
				
			||||||
int mthca_READ_MGM(struct mthca_dev *dev, int index, void *mgm,
 | 
					int mthca_READ_MGM(struct mthca_dev *dev, int index,
 | 
				
			||||||
		   u8 *status);
 | 
							   struct mthca_mailbox *mailbox, u8 *status);
 | 
				
			||||||
int mthca_WRITE_MGM(struct mthca_dev *dev, int index, void *mgm,
 | 
					int mthca_WRITE_MGM(struct mthca_dev *dev, int index,
 | 
				
			||||||
		    u8 *status);
 | 
							    struct mthca_mailbox *mailbox, u8 *status);
 | 
				
			||||||
int mthca_MGID_HASH(struct mthca_dev *dev, void *gid, u16 *hash,
 | 
					int mthca_MGID_HASH(struct mthca_dev *dev, struct mthca_mailbox *mailbox,
 | 
				
			||||||
		    u8 *status);
 | 
							    u16 *hash, u8 *status);
 | 
				
			||||||
int mthca_NOP(struct mthca_dev *dev, u8 *status);
 | 
					int mthca_NOP(struct mthca_dev *dev, u8 *status);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define MAILBOX_ALIGN(x) ((void *) ALIGN((unsigned long) (x), MTHCA_CMD_MAILBOX_ALIGN))
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#endif /* MTHCA_CMD_H */
 | 
					#endif /* MTHCA_CMD_H */
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,5 +1,6 @@
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 * Copyright (c) 2004, 2005 Topspin Communications.  All rights reserved.
 | 
					 * Copyright (c) 2004, 2005 Topspin Communications.  All rights reserved.
 | 
				
			||||||
 | 
					 * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved.
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * This software is available to you under a choice of one of two
 | 
					 * This software is available to you under a choice of one of two
 | 
				
			||||||
 * licenses.  You may choose to be licensed under the terms of the GNU
 | 
					 * licenses.  You may choose to be licensed under the terms of the GNU
 | 
				
			||||||
| 
						 | 
					@ -171,6 +172,17 @@ static inline void set_cqe_hw(struct mthca_cqe *cqe)
 | 
				
			||||||
	cqe->owner = MTHCA_CQ_ENTRY_OWNER_HW;
 | 
						cqe->owner = MTHCA_CQ_ENTRY_OWNER_HW;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void dump_cqe(struct mthca_dev *dev, void *cqe_ptr)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						__be32 *cqe = cqe_ptr;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						(void) cqe;	/* avoid warning if mthca_dbg compiled away... */
 | 
				
			||||||
 | 
						mthca_dbg(dev, "CQE contents %08x %08x %08x %08x %08x %08x %08x %08x\n",
 | 
				
			||||||
 | 
							  be32_to_cpu(cqe[0]), be32_to_cpu(cqe[1]), be32_to_cpu(cqe[2]),
 | 
				
			||||||
 | 
							  be32_to_cpu(cqe[3]), be32_to_cpu(cqe[4]), be32_to_cpu(cqe[5]),
 | 
				
			||||||
 | 
							  be32_to_cpu(cqe[6]), be32_to_cpu(cqe[7]));
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 * incr is ignored in native Arbel (mem-free) mode, so cq->cons_index
 | 
					 * incr is ignored in native Arbel (mem-free) mode, so cq->cons_index
 | 
				
			||||||
 * should be correct before calling update_cons_index().
 | 
					 * should be correct before calling update_cons_index().
 | 
				
			||||||
| 
						 | 
					@ -280,16 +292,12 @@ static int handle_error_cqe(struct mthca_dev *dev, struct mthca_cq *cq,
 | 
				
			||||||
	int dbd;
 | 
						int dbd;
 | 
				
			||||||
	u32 new_wqe;
 | 
						u32 new_wqe;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (1 && cqe->syndrome != SYNDROME_WR_FLUSH_ERR) {
 | 
						if (cqe->syndrome == SYNDROME_LOCAL_QP_OP_ERR) {
 | 
				
			||||||
		int j;
 | 
							mthca_dbg(dev, "local QP operation err "
 | 
				
			||||||
 | 
								  "(QPN %06x, WQE @ %08x, CQN %06x, index %d)\n",
 | 
				
			||||||
		mthca_dbg(dev, "%x/%d: error CQE -> QPN %06x, WQE @ %08x\n",
 | 
								  be32_to_cpu(cqe->my_qpn), be32_to_cpu(cqe->wqe),
 | 
				
			||||||
			  cq->cqn, cq->cons_index, be32_to_cpu(cqe->my_qpn),
 | 
								  cq->cqn, cq->cons_index);
 | 
				
			||||||
			  be32_to_cpu(cqe->wqe));
 | 
							dump_cqe(dev, cqe);
 | 
				
			||||||
 | 
					 | 
				
			||||||
		for (j = 0; j < 8; ++j)
 | 
					 | 
				
			||||||
			printk(KERN_DEBUG "  [%2x] %08x\n",
 | 
					 | 
				
			||||||
			       j * 4, be32_to_cpu(((u32 *) cqe)[j]));
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/*
 | 
						/*
 | 
				
			||||||
| 
						 | 
					@ -377,15 +385,6 @@ static int handle_error_cqe(struct mthca_dev *dev, struct mthca_cq *cq,
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void dump_cqe(struct mthca_cqe *cqe)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	int j;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	for (j = 0; j < 8; ++j)
 | 
					 | 
				
			||||||
		printk(KERN_DEBUG "  [%2x] %08x\n",
 | 
					 | 
				
			||||||
		       j * 4, be32_to_cpu(((u32 *) cqe)[j]));
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static inline int mthca_poll_one(struct mthca_dev *dev,
 | 
					static inline int mthca_poll_one(struct mthca_dev *dev,
 | 
				
			||||||
				 struct mthca_cq *cq,
 | 
									 struct mthca_cq *cq,
 | 
				
			||||||
				 struct mthca_qp **cur_qp,
 | 
									 struct mthca_qp **cur_qp,
 | 
				
			||||||
| 
						 | 
					@ -414,8 +413,7 @@ static inline int mthca_poll_one(struct mthca_dev *dev,
 | 
				
			||||||
		mthca_dbg(dev, "%x/%d: CQE -> QPN %06x, WQE @ %08x\n",
 | 
							mthca_dbg(dev, "%x/%d: CQE -> QPN %06x, WQE @ %08x\n",
 | 
				
			||||||
			  cq->cqn, cq->cons_index, be32_to_cpu(cqe->my_qpn),
 | 
								  cq->cqn, cq->cons_index, be32_to_cpu(cqe->my_qpn),
 | 
				
			||||||
			  be32_to_cpu(cqe->wqe));
 | 
								  be32_to_cpu(cqe->wqe));
 | 
				
			||||||
 | 
							dump_cqe(dev, cqe);
 | 
				
			||||||
		dump_cqe(cqe);
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	is_error = (cqe->opcode & MTHCA_ERROR_CQE_OPCODE_MASK) ==
 | 
						is_error = (cqe->opcode & MTHCA_ERROR_CQE_OPCODE_MASK) ==
 | 
				
			||||||
| 
						 | 
					@ -638,19 +636,19 @@ static void mthca_free_cq_buf(struct mthca_dev *dev, struct mthca_cq *cq)
 | 
				
			||||||
	int size;
 | 
						int size;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (cq->is_direct)
 | 
						if (cq->is_direct)
 | 
				
			||||||
		pci_free_consistent(dev->pdev,
 | 
							dma_free_coherent(&dev->pdev->dev,
 | 
				
			||||||
				    (cq->ibcq.cqe + 1) * MTHCA_CQ_ENTRY_SIZE,
 | 
									  (cq->ibcq.cqe + 1) * MTHCA_CQ_ENTRY_SIZE,
 | 
				
			||||||
				    cq->queue.direct.buf,
 | 
									  cq->queue.direct.buf,
 | 
				
			||||||
				    pci_unmap_addr(&cq->queue.direct,
 | 
									  pci_unmap_addr(&cq->queue.direct,
 | 
				
			||||||
						   mapping));
 | 
											 mapping));
 | 
				
			||||||
	else {
 | 
						else {
 | 
				
			||||||
		size = (cq->ibcq.cqe + 1) * MTHCA_CQ_ENTRY_SIZE;
 | 
							size = (cq->ibcq.cqe + 1) * MTHCA_CQ_ENTRY_SIZE;
 | 
				
			||||||
		for (i = 0; i < (size + PAGE_SIZE - 1) / PAGE_SIZE; ++i)
 | 
							for (i = 0; i < (size + PAGE_SIZE - 1) / PAGE_SIZE; ++i)
 | 
				
			||||||
			if (cq->queue.page_list[i].buf)
 | 
								if (cq->queue.page_list[i].buf)
 | 
				
			||||||
				pci_free_consistent(dev->pdev, PAGE_SIZE,
 | 
									dma_free_coherent(&dev->pdev->dev, PAGE_SIZE,
 | 
				
			||||||
						    cq->queue.page_list[i].buf,
 | 
											  cq->queue.page_list[i].buf,
 | 
				
			||||||
						    pci_unmap_addr(&cq->queue.page_list[i],
 | 
											  pci_unmap_addr(&cq->queue.page_list[i],
 | 
				
			||||||
								   mapping));
 | 
													 mapping));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		kfree(cq->queue.page_list);
 | 
							kfree(cq->queue.page_list);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					@ -670,8 +668,8 @@ static int mthca_alloc_cq_buf(struct mthca_dev *dev, int size,
 | 
				
			||||||
		npages        = 1;
 | 
							npages        = 1;
 | 
				
			||||||
		shift         = get_order(size) + PAGE_SHIFT;
 | 
							shift         = get_order(size) + PAGE_SHIFT;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		cq->queue.direct.buf = pci_alloc_consistent(dev->pdev,
 | 
							cq->queue.direct.buf = dma_alloc_coherent(&dev->pdev->dev,
 | 
				
			||||||
							    size, &t);
 | 
												  size, &t, GFP_KERNEL);
 | 
				
			||||||
		if (!cq->queue.direct.buf)
 | 
							if (!cq->queue.direct.buf)
 | 
				
			||||||
			return -ENOMEM;
 | 
								return -ENOMEM;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -709,7 +707,8 @@ static int mthca_alloc_cq_buf(struct mthca_dev *dev, int size,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		for (i = 0; i < npages; ++i) {
 | 
							for (i = 0; i < npages; ++i) {
 | 
				
			||||||
			cq->queue.page_list[i].buf =
 | 
								cq->queue.page_list[i].buf =
 | 
				
			||||||
				pci_alloc_consistent(dev->pdev, PAGE_SIZE, &t);
 | 
									dma_alloc_coherent(&dev->pdev->dev, PAGE_SIZE,
 | 
				
			||||||
 | 
											   &t, GFP_KERNEL);
 | 
				
			||||||
			if (!cq->queue.page_list[i].buf)
 | 
								if (!cq->queue.page_list[i].buf)
 | 
				
			||||||
				goto err_free;
 | 
									goto err_free;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -746,7 +745,7 @@ int mthca_init_cq(struct mthca_dev *dev, int nent,
 | 
				
			||||||
		  struct mthca_cq *cq)
 | 
							  struct mthca_cq *cq)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	int size = nent * MTHCA_CQ_ENTRY_SIZE;
 | 
						int size = nent * MTHCA_CQ_ENTRY_SIZE;
 | 
				
			||||||
	void *mailbox = NULL;
 | 
						struct mthca_mailbox *mailbox;
 | 
				
			||||||
	struct mthca_cq_context *cq_context;
 | 
						struct mthca_cq_context *cq_context;
 | 
				
			||||||
	int err = -ENOMEM;
 | 
						int err = -ENOMEM;
 | 
				
			||||||
	u8 status;
 | 
						u8 status;
 | 
				
			||||||
| 
						 | 
					@ -780,12 +779,11 @@ int mthca_init_cq(struct mthca_dev *dev, int nent,
 | 
				
			||||||
			goto err_out_ci;
 | 
								goto err_out_ci;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	mailbox = kmalloc(sizeof (struct mthca_cq_context) + MTHCA_CMD_MAILBOX_EXTRA,
 | 
						mailbox = mthca_alloc_mailbox(dev, GFP_KERNEL);
 | 
				
			||||||
			  GFP_KERNEL);
 | 
						if (IS_ERR(mailbox))
 | 
				
			||||||
	if (!mailbox)
 | 
							goto err_out_arm;
 | 
				
			||||||
		goto err_out_mailbox;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	cq_context = MAILBOX_ALIGN(mailbox);
 | 
						cq_context = mailbox->buf;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	err = mthca_alloc_cq_buf(dev, size, cq);
 | 
						err = mthca_alloc_cq_buf(dev, size, cq);
 | 
				
			||||||
	if (err)
 | 
						if (err)
 | 
				
			||||||
| 
						 | 
					@ -816,7 +814,7 @@ int mthca_init_cq(struct mthca_dev *dev, int nent,
 | 
				
			||||||
		cq_context->state_db = cpu_to_be32(cq->arm_db_index);
 | 
							cq_context->state_db = cpu_to_be32(cq->arm_db_index);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	err = mthca_SW2HW_CQ(dev, cq_context, cq->cqn, &status);
 | 
						err = mthca_SW2HW_CQ(dev, mailbox, cq->cqn, &status);
 | 
				
			||||||
	if (err) {
 | 
						if (err) {
 | 
				
			||||||
		mthca_warn(dev, "SW2HW_CQ failed (%d)\n", err);
 | 
							mthca_warn(dev, "SW2HW_CQ failed (%d)\n", err);
 | 
				
			||||||
		goto err_out_free_mr;
 | 
							goto err_out_free_mr;
 | 
				
			||||||
| 
						 | 
					@ -840,7 +838,7 @@ int mthca_init_cq(struct mthca_dev *dev, int nent,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	cq->cons_index = 0;
 | 
						cq->cons_index = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	kfree(mailbox);
 | 
						mthca_free_mailbox(dev, mailbox);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -849,8 +847,9 @@ err_out_free_mr:
 | 
				
			||||||
	mthca_free_cq_buf(dev, cq);
 | 
						mthca_free_cq_buf(dev, cq);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
err_out_mailbox:
 | 
					err_out_mailbox:
 | 
				
			||||||
	kfree(mailbox);
 | 
						mthca_free_mailbox(dev, mailbox);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					err_out_arm:
 | 
				
			||||||
	if (mthca_is_memfree(dev))
 | 
						if (mthca_is_memfree(dev))
 | 
				
			||||||
		mthca_free_db(dev, MTHCA_DB_TYPE_CQ_ARM, cq->arm_db_index);
 | 
							mthca_free_db(dev, MTHCA_DB_TYPE_CQ_ARM, cq->arm_db_index);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -870,28 +869,26 @@ err_out:
 | 
				
			||||||
void mthca_free_cq(struct mthca_dev *dev,
 | 
					void mthca_free_cq(struct mthca_dev *dev,
 | 
				
			||||||
		   struct mthca_cq *cq)
 | 
							   struct mthca_cq *cq)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	void *mailbox;
 | 
						struct mthca_mailbox *mailbox;
 | 
				
			||||||
	int err;
 | 
						int err;
 | 
				
			||||||
	u8 status;
 | 
						u8 status;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	might_sleep();
 | 
						might_sleep();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	mailbox = kmalloc(sizeof (struct mthca_cq_context) + MTHCA_CMD_MAILBOX_EXTRA,
 | 
						mailbox = mthca_alloc_mailbox(dev, GFP_KERNEL);
 | 
				
			||||||
			  GFP_KERNEL);
 | 
						if (IS_ERR(mailbox)) {
 | 
				
			||||||
	if (!mailbox) {
 | 
					 | 
				
			||||||
		mthca_warn(dev, "No memory for mailbox to free CQ.\n");
 | 
							mthca_warn(dev, "No memory for mailbox to free CQ.\n");
 | 
				
			||||||
		return;
 | 
							return;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	err = mthca_HW2SW_CQ(dev, MAILBOX_ALIGN(mailbox), cq->cqn, &status);
 | 
						err = mthca_HW2SW_CQ(dev, mailbox, cq->cqn, &status);
 | 
				
			||||||
	if (err)
 | 
						if (err)
 | 
				
			||||||
		mthca_warn(dev, "HW2SW_CQ failed (%d)\n", err);
 | 
							mthca_warn(dev, "HW2SW_CQ failed (%d)\n", err);
 | 
				
			||||||
	else if (status)
 | 
						else if (status)
 | 
				
			||||||
		mthca_warn(dev, "HW2SW_CQ returned status 0x%02x\n",
 | 
							mthca_warn(dev, "HW2SW_CQ returned status 0x%02x\n", status);
 | 
				
			||||||
			   status);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (0) {
 | 
						if (0) {
 | 
				
			||||||
		u32 *ctx = MAILBOX_ALIGN(mailbox);
 | 
							u32 *ctx = mailbox->buf;
 | 
				
			||||||
		int j;
 | 
							int j;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		printk(KERN_ERR "context for CQN %x (cons index %x, next sw %d)\n",
 | 
							printk(KERN_ERR "context for CQN %x (cons index %x, next sw %d)\n",
 | 
				
			||||||
| 
						 | 
					@ -919,11 +916,11 @@ void mthca_free_cq(struct mthca_dev *dev,
 | 
				
			||||||
	if (mthca_is_memfree(dev)) {
 | 
						if (mthca_is_memfree(dev)) {
 | 
				
			||||||
		mthca_free_db(dev, MTHCA_DB_TYPE_CQ_ARM,    cq->arm_db_index);
 | 
							mthca_free_db(dev, MTHCA_DB_TYPE_CQ_ARM,    cq->arm_db_index);
 | 
				
			||||||
		mthca_free_db(dev, MTHCA_DB_TYPE_CQ_SET_CI, cq->set_ci_db_index);
 | 
							mthca_free_db(dev, MTHCA_DB_TYPE_CQ_SET_CI, cq->set_ci_db_index);
 | 
				
			||||||
		mthca_table_put(dev, dev->cq_table.table, cq->cqn);
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						mthca_table_put(dev, dev->cq_table.table, cq->cqn);
 | 
				
			||||||
	mthca_free(&dev->cq_table.alloc, cq->cqn);
 | 
						mthca_free(&dev->cq_table.alloc, cq->cqn);
 | 
				
			||||||
	kfree(mailbox);
 | 
						mthca_free_mailbox(dev, mailbox);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int __devinit mthca_init_cq_table(struct mthca_dev *dev)
 | 
					int __devinit mthca_init_cq_table(struct mthca_dev *dev)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,5 +1,6 @@
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 * Copyright (c) 2004, 2005 Topspin Communications.  All rights reserved.
 | 
					 * Copyright (c) 2004, 2005 Topspin Communications.  All rights reserved.
 | 
				
			||||||
 | 
					 * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved.
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * This software is available to you under a choice of one of two
 | 
					 * This software is available to you under a choice of one of two
 | 
				
			||||||
 * licenses.  You may choose to be licensed under the terms of the GNU
 | 
					 * licenses.  You may choose to be licensed under the terms of the GNU
 | 
				
			||||||
| 
						 | 
					@ -46,8 +47,8 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define DRV_NAME	"ib_mthca"
 | 
					#define DRV_NAME	"ib_mthca"
 | 
				
			||||||
#define PFX		DRV_NAME ": "
 | 
					#define PFX		DRV_NAME ": "
 | 
				
			||||||
#define DRV_VERSION	"0.06-pre"
 | 
					#define DRV_VERSION	"0.06"
 | 
				
			||||||
#define DRV_RELDATE	"November 8, 2004"
 | 
					#define DRV_RELDATE	"June 23, 2005"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
enum {
 | 
					enum {
 | 
				
			||||||
	MTHCA_FLAG_DDR_HIDDEN = 1 << 1,
 | 
						MTHCA_FLAG_DDR_HIDDEN = 1 << 1,
 | 
				
			||||||
| 
						 | 
					@ -98,6 +99,7 @@ enum {
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct mthca_cmd {
 | 
					struct mthca_cmd {
 | 
				
			||||||
 | 
						struct pci_pool          *pool;
 | 
				
			||||||
	int                       use_events;
 | 
						int                       use_events;
 | 
				
			||||||
	struct semaphore          hcr_sem;
 | 
						struct semaphore          hcr_sem;
 | 
				
			||||||
	struct semaphore 	  poll_sem;
 | 
						struct semaphore 	  poll_sem;
 | 
				
			||||||
| 
						 | 
					@ -379,6 +381,12 @@ void mthca_uar_free(struct mthca_dev *dev, struct mthca_uar *uar);
 | 
				
			||||||
int mthca_pd_alloc(struct mthca_dev *dev, struct mthca_pd *pd);
 | 
					int mthca_pd_alloc(struct mthca_dev *dev, struct mthca_pd *pd);
 | 
				
			||||||
void mthca_pd_free(struct mthca_dev *dev, struct mthca_pd *pd);
 | 
					void mthca_pd_free(struct mthca_dev *dev, struct mthca_pd *pd);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct mthca_mtt *mthca_alloc_mtt(struct mthca_dev *dev, int size);
 | 
				
			||||||
 | 
					void mthca_free_mtt(struct mthca_dev *dev, struct mthca_mtt *mtt);
 | 
				
			||||||
 | 
					int mthca_write_mtt(struct mthca_dev *dev, struct mthca_mtt *mtt,
 | 
				
			||||||
 | 
							    int start_index, u64 *buffer_list, int list_len);
 | 
				
			||||||
 | 
					int mthca_mr_alloc(struct mthca_dev *dev, u32 pd, int buffer_size_shift,
 | 
				
			||||||
 | 
							   u64 iova, u64 total_size, u32 access, struct mthca_mr *mr);
 | 
				
			||||||
int mthca_mr_alloc_notrans(struct mthca_dev *dev, u32 pd,
 | 
					int mthca_mr_alloc_notrans(struct mthca_dev *dev, u32 pd,
 | 
				
			||||||
			   u32 access, struct mthca_mr *mr);
 | 
								   u32 access, struct mthca_mr *mr);
 | 
				
			||||||
int mthca_mr_alloc_phys(struct mthca_dev *dev, u32 pd,
 | 
					int mthca_mr_alloc_phys(struct mthca_dev *dev, u32 pd,
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,5 +1,6 @@
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 * Copyright (c) 2004 Topspin Communications.  All rights reserved.
 | 
					 * Copyright (c) 2004 Topspin Communications.  All rights reserved.
 | 
				
			||||||
 | 
					 * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved.
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * This software is available to you under a choice of one of two
 | 
					 * This software is available to you under a choice of one of two
 | 
				
			||||||
 * licenses.  You may choose to be licensed under the terms of the GNU
 | 
					 * licenses.  You may choose to be licensed under the terms of the GNU
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -469,7 +469,7 @@ static int __devinit mthca_create_eq(struct mthca_dev *dev,
 | 
				
			||||||
		PAGE_SIZE;
 | 
							PAGE_SIZE;
 | 
				
			||||||
	u64 *dma_list = NULL;
 | 
						u64 *dma_list = NULL;
 | 
				
			||||||
	dma_addr_t t;
 | 
						dma_addr_t t;
 | 
				
			||||||
	void *mailbox = NULL;
 | 
						struct mthca_mailbox *mailbox;
 | 
				
			||||||
	struct mthca_eq_context *eq_context;
 | 
						struct mthca_eq_context *eq_context;
 | 
				
			||||||
	int err = -ENOMEM;
 | 
						int err = -ENOMEM;
 | 
				
			||||||
	int i;
 | 
						int i;
 | 
				
			||||||
| 
						 | 
					@ -494,17 +494,16 @@ static int __devinit mthca_create_eq(struct mthca_dev *dev,
 | 
				
			||||||
	if (!dma_list)
 | 
						if (!dma_list)
 | 
				
			||||||
		goto err_out_free;
 | 
							goto err_out_free;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	mailbox = kmalloc(sizeof *eq_context + MTHCA_CMD_MAILBOX_EXTRA,
 | 
						mailbox = mthca_alloc_mailbox(dev, GFP_KERNEL);
 | 
				
			||||||
			  GFP_KERNEL);
 | 
						if (IS_ERR(mailbox))
 | 
				
			||||||
	if (!mailbox)
 | 
					 | 
				
			||||||
		goto err_out_free;
 | 
							goto err_out_free;
 | 
				
			||||||
	eq_context = MAILBOX_ALIGN(mailbox);
 | 
						eq_context = mailbox->buf;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for (i = 0; i < npages; ++i) {
 | 
						for (i = 0; i < npages; ++i) {
 | 
				
			||||||
		eq->page_list[i].buf = pci_alloc_consistent(dev->pdev,
 | 
							eq->page_list[i].buf = dma_alloc_coherent(&dev->pdev->dev,
 | 
				
			||||||
							    PAGE_SIZE, &t);
 | 
												  PAGE_SIZE, &t, GFP_KERNEL);
 | 
				
			||||||
		if (!eq->page_list[i].buf)
 | 
							if (!eq->page_list[i].buf)
 | 
				
			||||||
			goto err_out_free;
 | 
								goto err_out_free_pages;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		dma_list[i] = t;
 | 
							dma_list[i] = t;
 | 
				
			||||||
		pci_unmap_addr_set(&eq->page_list[i], mapping, t);
 | 
							pci_unmap_addr_set(&eq->page_list[i], mapping, t);
 | 
				
			||||||
| 
						 | 
					@ -517,7 +516,7 @@ static int __devinit mthca_create_eq(struct mthca_dev *dev,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	eq->eqn = mthca_alloc(&dev->eq_table.alloc);
 | 
						eq->eqn = mthca_alloc(&dev->eq_table.alloc);
 | 
				
			||||||
	if (eq->eqn == -1)
 | 
						if (eq->eqn == -1)
 | 
				
			||||||
		goto err_out_free;
 | 
							goto err_out_free_pages;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	err = mthca_mr_alloc_phys(dev, dev->driver_pd.pd_num,
 | 
						err = mthca_mr_alloc_phys(dev, dev->driver_pd.pd_num,
 | 
				
			||||||
				  dma_list, PAGE_SHIFT, npages,
 | 
									  dma_list, PAGE_SHIFT, npages,
 | 
				
			||||||
| 
						 | 
					@ -548,7 +547,7 @@ static int __devinit mthca_create_eq(struct mthca_dev *dev,
 | 
				
			||||||
	eq_context->intr            = intr;
 | 
						eq_context->intr            = intr;
 | 
				
			||||||
	eq_context->lkey            = cpu_to_be32(eq->mr.ibmr.lkey);
 | 
						eq_context->lkey            = cpu_to_be32(eq->mr.ibmr.lkey);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	err = mthca_SW2HW_EQ(dev, eq_context, eq->eqn, &status);
 | 
						err = mthca_SW2HW_EQ(dev, mailbox, eq->eqn, &status);
 | 
				
			||||||
	if (err) {
 | 
						if (err) {
 | 
				
			||||||
		mthca_warn(dev, "SW2HW_EQ failed (%d)\n", err);
 | 
							mthca_warn(dev, "SW2HW_EQ failed (%d)\n", err);
 | 
				
			||||||
		goto err_out_free_mr;
 | 
							goto err_out_free_mr;
 | 
				
			||||||
| 
						 | 
					@ -561,7 +560,7 @@ static int __devinit mthca_create_eq(struct mthca_dev *dev,
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	kfree(dma_list);
 | 
						kfree(dma_list);
 | 
				
			||||||
	kfree(mailbox);
 | 
						mthca_free_mailbox(dev, mailbox);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	eq->eqn_mask   = swab32(1 << eq->eqn);
 | 
						eq->eqn_mask   = swab32(1 << eq->eqn);
 | 
				
			||||||
	eq->cons_index = 0;
 | 
						eq->cons_index = 0;
 | 
				
			||||||
| 
						 | 
					@ -579,17 +578,19 @@ static int __devinit mthca_create_eq(struct mthca_dev *dev,
 | 
				
			||||||
 err_out_free_eq:
 | 
					 err_out_free_eq:
 | 
				
			||||||
	mthca_free(&dev->eq_table.alloc, eq->eqn);
 | 
						mthca_free(&dev->eq_table.alloc, eq->eqn);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 err_out_free:
 | 
					 err_out_free_pages:
 | 
				
			||||||
	for (i = 0; i < npages; ++i)
 | 
						for (i = 0; i < npages; ++i)
 | 
				
			||||||
		if (eq->page_list[i].buf)
 | 
							if (eq->page_list[i].buf)
 | 
				
			||||||
			pci_free_consistent(dev->pdev, PAGE_SIZE,
 | 
								dma_free_coherent(&dev->pdev->dev, PAGE_SIZE,
 | 
				
			||||||
					    eq->page_list[i].buf,
 | 
										  eq->page_list[i].buf,
 | 
				
			||||||
					    pci_unmap_addr(&eq->page_list[i],
 | 
										  pci_unmap_addr(&eq->page_list[i],
 | 
				
			||||||
							   mapping));
 | 
												 mapping));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						mthca_free_mailbox(dev, mailbox);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 err_out_free:
 | 
				
			||||||
	kfree(eq->page_list);
 | 
						kfree(eq->page_list);
 | 
				
			||||||
	kfree(dma_list);
 | 
						kfree(dma_list);
 | 
				
			||||||
	kfree(mailbox);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 err_out:
 | 
					 err_out:
 | 
				
			||||||
	return err;
 | 
						return err;
 | 
				
			||||||
| 
						 | 
					@ -598,25 +599,22 @@ static int __devinit mthca_create_eq(struct mthca_dev *dev,
 | 
				
			||||||
static void mthca_free_eq(struct mthca_dev *dev,
 | 
					static void mthca_free_eq(struct mthca_dev *dev,
 | 
				
			||||||
			  struct mthca_eq *eq)
 | 
								  struct mthca_eq *eq)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	void *mailbox = NULL;
 | 
						struct mthca_mailbox *mailbox;
 | 
				
			||||||
	int err;
 | 
						int err;
 | 
				
			||||||
	u8 status;
 | 
						u8 status;
 | 
				
			||||||
	int npages = (eq->nent * MTHCA_EQ_ENTRY_SIZE + PAGE_SIZE - 1) /
 | 
						int npages = (eq->nent * MTHCA_EQ_ENTRY_SIZE + PAGE_SIZE - 1) /
 | 
				
			||||||
		PAGE_SIZE;
 | 
							PAGE_SIZE;
 | 
				
			||||||
	int i;
 | 
						int i;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	mailbox = kmalloc(sizeof (struct mthca_eq_context) + MTHCA_CMD_MAILBOX_EXTRA,
 | 
						mailbox = mthca_alloc_mailbox(dev, GFP_KERNEL);
 | 
				
			||||||
			  GFP_KERNEL);
 | 
						if (IS_ERR(mailbox))
 | 
				
			||||||
	if (!mailbox)
 | 
					 | 
				
			||||||
		return;
 | 
							return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	err = mthca_HW2SW_EQ(dev, MAILBOX_ALIGN(mailbox),
 | 
						err = mthca_HW2SW_EQ(dev, mailbox, eq->eqn, &status);
 | 
				
			||||||
			     eq->eqn, &status);
 | 
					 | 
				
			||||||
	if (err)
 | 
						if (err)
 | 
				
			||||||
		mthca_warn(dev, "HW2SW_EQ failed (%d)\n", err);
 | 
							mthca_warn(dev, "HW2SW_EQ failed (%d)\n", err);
 | 
				
			||||||
	if (status)
 | 
						if (status)
 | 
				
			||||||
		mthca_warn(dev, "HW2SW_EQ returned status 0x%02x\n",
 | 
							mthca_warn(dev, "HW2SW_EQ returned status 0x%02x\n", status);
 | 
				
			||||||
			   status);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	dev->eq_table.arm_mask &= ~eq->eqn_mask;
 | 
						dev->eq_table.arm_mask &= ~eq->eqn_mask;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -625,7 +623,7 @@ static void mthca_free_eq(struct mthca_dev *dev,
 | 
				
			||||||
		for (i = 0; i < sizeof (struct mthca_eq_context) / 4; ++i) {
 | 
							for (i = 0; i < sizeof (struct mthca_eq_context) / 4; ++i) {
 | 
				
			||||||
			if (i % 4 == 0)
 | 
								if (i % 4 == 0)
 | 
				
			||||||
				printk("[%02x] ", i * 4);
 | 
									printk("[%02x] ", i * 4);
 | 
				
			||||||
			printk(" %08x", be32_to_cpup(MAILBOX_ALIGN(mailbox) + i * 4));
 | 
								printk(" %08x", be32_to_cpup(mailbox->buf + i * 4));
 | 
				
			||||||
			if ((i + 1) % 4 == 0)
 | 
								if ((i + 1) % 4 == 0)
 | 
				
			||||||
				printk("\n");
 | 
									printk("\n");
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
| 
						 | 
					@ -638,7 +636,7 @@ static void mthca_free_eq(struct mthca_dev *dev,
 | 
				
			||||||
				    pci_unmap_addr(&eq->page_list[i], mapping));
 | 
									    pci_unmap_addr(&eq->page_list[i], mapping));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	kfree(eq->page_list);
 | 
						kfree(eq->page_list);
 | 
				
			||||||
	kfree(mailbox);
 | 
						mthca_free_mailbox(dev, mailbox);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void mthca_free_irqs(struct mthca_dev *dev)
 | 
					static void mthca_free_irqs(struct mthca_dev *dev)
 | 
				
			||||||
| 
						 | 
					@ -709,8 +707,7 @@ static int __devinit mthca_map_eq_regs(struct mthca_dev *dev)
 | 
				
			||||||
		if (mthca_map_reg(dev, ((pci_resource_len(dev->pdev, 0) - 1) &
 | 
							if (mthca_map_reg(dev, ((pci_resource_len(dev->pdev, 0) - 1) &
 | 
				
			||||||
					dev->fw.arbel.eq_arm_base) + 4, 4,
 | 
										dev->fw.arbel.eq_arm_base) + 4, 4,
 | 
				
			||||||
				  &dev->eq_regs.arbel.eq_arm)) {
 | 
									  &dev->eq_regs.arbel.eq_arm)) {
 | 
				
			||||||
			mthca_err(dev, "Couldn't map interrupt clear register, "
 | 
								mthca_err(dev, "Couldn't map EQ arm register, aborting.\n");
 | 
				
			||||||
				  "aborting.\n");
 | 
					 | 
				
			||||||
			mthca_unmap_reg(dev, (pci_resource_len(dev->pdev, 0) - 1) &
 | 
								mthca_unmap_reg(dev, (pci_resource_len(dev->pdev, 0) - 1) &
 | 
				
			||||||
					dev->fw.arbel.clr_int_base, MTHCA_CLR_INT_SIZE,
 | 
										dev->fw.arbel.clr_int_base, MTHCA_CLR_INT_SIZE,
 | 
				
			||||||
					dev->clr_base);
 | 
										dev->clr_base);
 | 
				
			||||||
| 
						 | 
					@ -721,8 +718,7 @@ static int __devinit mthca_map_eq_regs(struct mthca_dev *dev)
 | 
				
			||||||
				  dev->fw.arbel.eq_set_ci_base,
 | 
									  dev->fw.arbel.eq_set_ci_base,
 | 
				
			||||||
				  MTHCA_EQ_SET_CI_SIZE,
 | 
									  MTHCA_EQ_SET_CI_SIZE,
 | 
				
			||||||
				  &dev->eq_regs.arbel.eq_set_ci_base)) {
 | 
									  &dev->eq_regs.arbel.eq_set_ci_base)) {
 | 
				
			||||||
			mthca_err(dev, "Couldn't map interrupt clear register, "
 | 
								mthca_err(dev, "Couldn't map EQ CI register, aborting.\n");
 | 
				
			||||||
				  "aborting.\n");
 | 
					 | 
				
			||||||
			mthca_unmap_reg(dev, ((pci_resource_len(dev->pdev, 0) - 1) &
 | 
								mthca_unmap_reg(dev, ((pci_resource_len(dev->pdev, 0) - 1) &
 | 
				
			||||||
					      dev->fw.arbel.eq_arm_base) + 4, 4,
 | 
										      dev->fw.arbel.eq_arm_base) + 4, 4,
 | 
				
			||||||
					dev->eq_regs.arbel.eq_arm);
 | 
										dev->eq_regs.arbel.eq_arm);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,5 +1,6 @@
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 * Copyright (c) 2004, 2005 Topspin Communications.  All rights reserved.
 | 
					 * Copyright (c) 2004, 2005 Topspin Communications.  All rights reserved.
 | 
				
			||||||
 | 
					 * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved.
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * This software is available to you under a choice of one of two
 | 
					 * This software is available to you under a choice of one of two
 | 
				
			||||||
 * licenses.  You may choose to be licensed under the terms of the GNU
 | 
					 * licenses.  You may choose to be licensed under the terms of the GNU
 | 
				
			||||||
| 
						 | 
					@ -69,7 +70,7 @@ MODULE_PARM_DESC(msi, "attempt to use MSI if nonzero");
 | 
				
			||||||
#endif /* CONFIG_PCI_MSI */
 | 
					#endif /* CONFIG_PCI_MSI */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static const char mthca_version[] __devinitdata =
 | 
					static const char mthca_version[] __devinitdata =
 | 
				
			||||||
	"ib_mthca: Mellanox InfiniBand HCA driver v"
 | 
						DRV_NAME ": Mellanox InfiniBand HCA driver v"
 | 
				
			||||||
	DRV_VERSION " (" DRV_RELDATE ")\n";
 | 
						DRV_VERSION " (" DRV_RELDATE ")\n";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static struct mthca_profile default_profile = {
 | 
					static struct mthca_profile default_profile = {
 | 
				
			||||||
| 
						 | 
					@ -927,13 +928,13 @@ static int __devinit mthca_init_one(struct pci_dev *pdev,
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
	if (!(pci_resource_flags(pdev, 0) & IORESOURCE_MEM) ||
 | 
						if (!(pci_resource_flags(pdev, 0) & IORESOURCE_MEM) ||
 | 
				
			||||||
	    pci_resource_len(pdev, 0) != 1 << 20) {
 | 
						    pci_resource_len(pdev, 0) != 1 << 20) {
 | 
				
			||||||
		dev_err(&pdev->dev, "Missing DCS, aborting.");
 | 
							dev_err(&pdev->dev, "Missing DCS, aborting.\n");
 | 
				
			||||||
		err = -ENODEV;
 | 
							err = -ENODEV;
 | 
				
			||||||
		goto err_disable_pdev;
 | 
							goto err_disable_pdev;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if (!(pci_resource_flags(pdev, 2) & IORESOURCE_MEM) ||
 | 
						if (!(pci_resource_flags(pdev, 2) & IORESOURCE_MEM) ||
 | 
				
			||||||
	    pci_resource_len(pdev, 2) != 1 << 23) {
 | 
						    pci_resource_len(pdev, 2) != 1 << 23) {
 | 
				
			||||||
		dev_err(&pdev->dev, "Missing UAR, aborting.");
 | 
							dev_err(&pdev->dev, "Missing UAR, aborting.\n");
 | 
				
			||||||
		err = -ENODEV;
 | 
							err = -ENODEV;
 | 
				
			||||||
		goto err_disable_pdev;
 | 
							goto err_disable_pdev;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					@ -1004,25 +1005,18 @@ static int __devinit mthca_init_one(struct pci_dev *pdev,
 | 
				
			||||||
	    !pci_enable_msi(pdev))
 | 
						    !pci_enable_msi(pdev))
 | 
				
			||||||
		mdev->mthca_flags |= MTHCA_FLAG_MSI;
 | 
							mdev->mthca_flags |= MTHCA_FLAG_MSI;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	sema_init(&mdev->cmd.hcr_sem, 1);
 | 
						if (mthca_cmd_init(mdev)) {
 | 
				
			||||||
	sema_init(&mdev->cmd.poll_sem, 1);
 | 
							mthca_err(mdev, "Failed to init command interface, aborting.\n");
 | 
				
			||||||
	mdev->cmd.use_events = 0;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	mdev->hcr = ioremap(pci_resource_start(pdev, 0) + MTHCA_HCR_BASE, MTHCA_HCR_SIZE);
 | 
					 | 
				
			||||||
	if (!mdev->hcr) {
 | 
					 | 
				
			||||||
		mthca_err(mdev, "Couldn't map command register, "
 | 
					 | 
				
			||||||
			  "aborting.\n");
 | 
					 | 
				
			||||||
		err = -ENOMEM;
 | 
					 | 
				
			||||||
		goto err_free_dev;
 | 
							goto err_free_dev;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	err = mthca_tune_pci(mdev);
 | 
						err = mthca_tune_pci(mdev);
 | 
				
			||||||
	if (err)
 | 
						if (err)
 | 
				
			||||||
		goto err_iounmap;
 | 
							goto err_cmd;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	err = mthca_init_hca(mdev);
 | 
						err = mthca_init_hca(mdev);
 | 
				
			||||||
	if (err)
 | 
						if (err)
 | 
				
			||||||
		goto err_iounmap;
 | 
							goto err_cmd;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (mdev->fw_ver < mthca_hca_table[id->driver_data].latest_fw) {
 | 
						if (mdev->fw_ver < mthca_hca_table[id->driver_data].latest_fw) {
 | 
				
			||||||
		mthca_warn(mdev, "HCA FW version %x.%x.%x is old (%x.%x.%x is current).\n",
 | 
							mthca_warn(mdev, "HCA FW version %x.%x.%x is old (%x.%x.%x is current).\n",
 | 
				
			||||||
| 
						 | 
					@ -1070,8 +1064,8 @@ err_cleanup:
 | 
				
			||||||
err_close:
 | 
					err_close:
 | 
				
			||||||
	mthca_close_hca(mdev);
 | 
						mthca_close_hca(mdev);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
err_iounmap:
 | 
					err_cmd:
 | 
				
			||||||
	iounmap(mdev->hcr);
 | 
						mthca_cmd_cleanup(mdev);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
err_free_dev:
 | 
					err_free_dev:
 | 
				
			||||||
	if (mdev->mthca_flags & MTHCA_FLAG_MSI_X)
 | 
						if (mdev->mthca_flags & MTHCA_FLAG_MSI_X)
 | 
				
			||||||
| 
						 | 
					@ -1118,10 +1112,8 @@ static void __devexit mthca_remove_one(struct pci_dev *pdev)
 | 
				
			||||||
		iounmap(mdev->kar);
 | 
							iounmap(mdev->kar);
 | 
				
			||||||
		mthca_uar_free(mdev, &mdev->driver_uar);
 | 
							mthca_uar_free(mdev, &mdev->driver_uar);
 | 
				
			||||||
		mthca_cleanup_uar_table(mdev);
 | 
							mthca_cleanup_uar_table(mdev);
 | 
				
			||||||
 | 
					 | 
				
			||||||
		mthca_close_hca(mdev);
 | 
							mthca_close_hca(mdev);
 | 
				
			||||||
 | 
							mthca_cmd_cleanup(mdev);
 | 
				
			||||||
		iounmap(mdev->hcr);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (mdev->mthca_flags & MTHCA_FLAG_MSI_X)
 | 
							if (mdev->mthca_flags & MTHCA_FLAG_MSI_X)
 | 
				
			||||||
			pci_disable_msix(pdev);
 | 
								pci_disable_msix(pdev);
 | 
				
			||||||
| 
						 | 
					@ -1163,7 +1155,7 @@ static struct pci_device_id mthca_pci_table[] = {
 | 
				
			||||||
MODULE_DEVICE_TABLE(pci, mthca_pci_table);
 | 
					MODULE_DEVICE_TABLE(pci, mthca_pci_table);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static struct pci_driver mthca_driver = {
 | 
					static struct pci_driver mthca_driver = {
 | 
				
			||||||
	.name		= "ib_mthca",
 | 
						.name		= DRV_NAME,
 | 
				
			||||||
	.id_table	= mthca_pci_table,
 | 
						.id_table	= mthca_pci_table,
 | 
				
			||||||
	.probe		= mthca_init_one,
 | 
						.probe		= mthca_init_one,
 | 
				
			||||||
	.remove		= __devexit_p(mthca_remove_one)
 | 
						.remove		= __devexit_p(mthca_remove_one)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -66,22 +66,23 @@ static const u8 zero_gid[16];	/* automatically initialized to 0 */
 | 
				
			||||||
 * entry in hash chain and *mgm holds end of hash chain.
 | 
					 * entry in hash chain and *mgm holds end of hash chain.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
static int find_mgm(struct mthca_dev *dev,
 | 
					static int find_mgm(struct mthca_dev *dev,
 | 
				
			||||||
		    u8 *gid, struct mthca_mgm *mgm,
 | 
							    u8 *gid, struct mthca_mailbox *mgm_mailbox,
 | 
				
			||||||
		    u16 *hash, int *prev, int *index)
 | 
							    u16 *hash, int *prev, int *index)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	void *mailbox;
 | 
						struct mthca_mailbox *mailbox;
 | 
				
			||||||
 | 
						struct mthca_mgm *mgm = mgm_mailbox->buf;
 | 
				
			||||||
	u8 *mgid;
 | 
						u8 *mgid;
 | 
				
			||||||
	int err;
 | 
						int err;
 | 
				
			||||||
	u8 status;
 | 
						u8 status;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	mailbox = kmalloc(16 + MTHCA_CMD_MAILBOX_EXTRA, GFP_KERNEL);
 | 
						mailbox = mthca_alloc_mailbox(dev, GFP_KERNEL);
 | 
				
			||||||
	if (!mailbox)
 | 
						if (IS_ERR(mailbox))
 | 
				
			||||||
		return -ENOMEM;
 | 
							return -ENOMEM;
 | 
				
			||||||
	mgid = MAILBOX_ALIGN(mailbox);
 | 
						mgid = mailbox->buf;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	memcpy(mgid, gid, 16);
 | 
						memcpy(mgid, gid, 16);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	err = mthca_MGID_HASH(dev, mgid, hash, &status);
 | 
						err = mthca_MGID_HASH(dev, mailbox, hash, &status);
 | 
				
			||||||
	if (err)
 | 
						if (err)
 | 
				
			||||||
		goto out;
 | 
							goto out;
 | 
				
			||||||
	if (status) {
 | 
						if (status) {
 | 
				
			||||||
| 
						 | 
					@ -103,7 +104,7 @@ static int find_mgm(struct mthca_dev *dev,
 | 
				
			||||||
	*prev  = -1;
 | 
						*prev  = -1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	do {
 | 
						do {
 | 
				
			||||||
		err = mthca_READ_MGM(dev, *index, mgm, &status);
 | 
							err = mthca_READ_MGM(dev, *index, mgm_mailbox, &status);
 | 
				
			||||||
		if (err)
 | 
							if (err)
 | 
				
			||||||
			goto out;
 | 
								goto out;
 | 
				
			||||||
		if (status) {
 | 
							if (status) {
 | 
				
			||||||
| 
						 | 
					@ -129,14 +130,14 @@ static int find_mgm(struct mthca_dev *dev,
 | 
				
			||||||
	*index = -1;
 | 
						*index = -1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 out:
 | 
					 out:
 | 
				
			||||||
	kfree(mailbox);
 | 
						mthca_free_mailbox(dev, mailbox);
 | 
				
			||||||
	return err;
 | 
						return err;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int mthca_multicast_attach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid)
 | 
					int mthca_multicast_attach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct mthca_dev *dev = to_mdev(ibqp->device);
 | 
						struct mthca_dev *dev = to_mdev(ibqp->device);
 | 
				
			||||||
	void *mailbox;
 | 
						struct mthca_mailbox *mailbox;
 | 
				
			||||||
	struct mthca_mgm *mgm;
 | 
						struct mthca_mgm *mgm;
 | 
				
			||||||
	u16 hash;
 | 
						u16 hash;
 | 
				
			||||||
	int index, prev;
 | 
						int index, prev;
 | 
				
			||||||
| 
						 | 
					@ -145,15 +146,15 @@ int mthca_multicast_attach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid)
 | 
				
			||||||
	int err;
 | 
						int err;
 | 
				
			||||||
	u8 status;
 | 
						u8 status;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	mailbox = kmalloc(sizeof *mgm + MTHCA_CMD_MAILBOX_EXTRA, GFP_KERNEL);
 | 
						mailbox = mthca_alloc_mailbox(dev, GFP_KERNEL);
 | 
				
			||||||
	if (!mailbox)
 | 
						if (IS_ERR(mailbox))
 | 
				
			||||||
		return -ENOMEM;
 | 
							return PTR_ERR(mailbox);
 | 
				
			||||||
	mgm = MAILBOX_ALIGN(mailbox);
 | 
						mgm = mailbox->buf;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (down_interruptible(&dev->mcg_table.sem))
 | 
						if (down_interruptible(&dev->mcg_table.sem))
 | 
				
			||||||
		return -EINTR;
 | 
							return -EINTR;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	err = find_mgm(dev, gid->raw, mgm, &hash, &prev, &index);
 | 
						err = find_mgm(dev, gid->raw, mailbox, &hash, &prev, &index);
 | 
				
			||||||
	if (err)
 | 
						if (err)
 | 
				
			||||||
		goto out;
 | 
							goto out;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -170,7 +171,7 @@ int mthca_multicast_attach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid)
 | 
				
			||||||
			goto out;
 | 
								goto out;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		err = mthca_READ_MGM(dev, index, mgm, &status);
 | 
							err = mthca_READ_MGM(dev, index, mailbox, &status);
 | 
				
			||||||
		if (err)
 | 
							if (err)
 | 
				
			||||||
			goto out;
 | 
								goto out;
 | 
				
			||||||
		if (status) {
 | 
							if (status) {
 | 
				
			||||||
| 
						 | 
					@ -195,7 +196,7 @@ int mthca_multicast_attach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid)
 | 
				
			||||||
		goto out;
 | 
							goto out;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	err = mthca_WRITE_MGM(dev, index, mgm, &status);
 | 
						err = mthca_WRITE_MGM(dev, index, mailbox, &status);
 | 
				
			||||||
	if (err)
 | 
						if (err)
 | 
				
			||||||
		goto out;
 | 
							goto out;
 | 
				
			||||||
	if (status) {
 | 
						if (status) {
 | 
				
			||||||
| 
						 | 
					@ -206,7 +207,7 @@ int mthca_multicast_attach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid)
 | 
				
			||||||
	if (!link)
 | 
						if (!link)
 | 
				
			||||||
		goto out;
 | 
							goto out;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	err = mthca_READ_MGM(dev, prev, mgm, &status);
 | 
						err = mthca_READ_MGM(dev, prev, mailbox, &status);
 | 
				
			||||||
	if (err)
 | 
						if (err)
 | 
				
			||||||
		goto out;
 | 
							goto out;
 | 
				
			||||||
	if (status) {
 | 
						if (status) {
 | 
				
			||||||
| 
						 | 
					@ -217,7 +218,7 @@ int mthca_multicast_attach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	mgm->next_gid_index = cpu_to_be32(index << 5);
 | 
						mgm->next_gid_index = cpu_to_be32(index << 5);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	err = mthca_WRITE_MGM(dev, prev, mgm, &status);
 | 
						err = mthca_WRITE_MGM(dev, prev, mailbox, &status);
 | 
				
			||||||
	if (err)
 | 
						if (err)
 | 
				
			||||||
		goto out;
 | 
							goto out;
 | 
				
			||||||
	if (status) {
 | 
						if (status) {
 | 
				
			||||||
| 
						 | 
					@ -227,14 +228,14 @@ int mthca_multicast_attach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 out:
 | 
					 out:
 | 
				
			||||||
	up(&dev->mcg_table.sem);
 | 
						up(&dev->mcg_table.sem);
 | 
				
			||||||
	kfree(mailbox);
 | 
						mthca_free_mailbox(dev, mailbox);
 | 
				
			||||||
	return err;
 | 
						return err;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int mthca_multicast_detach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid)
 | 
					int mthca_multicast_detach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct mthca_dev *dev = to_mdev(ibqp->device);
 | 
						struct mthca_dev *dev = to_mdev(ibqp->device);
 | 
				
			||||||
	void *mailbox;
 | 
						struct mthca_mailbox *mailbox;
 | 
				
			||||||
	struct mthca_mgm *mgm;
 | 
						struct mthca_mgm *mgm;
 | 
				
			||||||
	u16 hash;
 | 
						u16 hash;
 | 
				
			||||||
	int prev, index;
 | 
						int prev, index;
 | 
				
			||||||
| 
						 | 
					@ -242,15 +243,15 @@ int mthca_multicast_detach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid)
 | 
				
			||||||
	int err;
 | 
						int err;
 | 
				
			||||||
	u8 status;
 | 
						u8 status;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	mailbox = kmalloc(sizeof *mgm + MTHCA_CMD_MAILBOX_EXTRA, GFP_KERNEL);
 | 
						mailbox = mthca_alloc_mailbox(dev, GFP_KERNEL);
 | 
				
			||||||
	if (!mailbox)
 | 
						if (IS_ERR(mailbox))
 | 
				
			||||||
		return -ENOMEM;
 | 
							return PTR_ERR(mailbox);
 | 
				
			||||||
	mgm = MAILBOX_ALIGN(mailbox);
 | 
						mgm = mailbox->buf;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (down_interruptible(&dev->mcg_table.sem))
 | 
						if (down_interruptible(&dev->mcg_table.sem))
 | 
				
			||||||
		return -EINTR;
 | 
							return -EINTR;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	err = find_mgm(dev, gid->raw, mgm, &hash, &prev, &index);
 | 
						err = find_mgm(dev, gid->raw, mailbox, &hash, &prev, &index);
 | 
				
			||||||
	if (err)
 | 
						if (err)
 | 
				
			||||||
		goto out;
 | 
							goto out;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -285,7 +286,7 @@ int mthca_multicast_detach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid)
 | 
				
			||||||
	mgm->qp[loc]   = mgm->qp[i - 1];
 | 
						mgm->qp[loc]   = mgm->qp[i - 1];
 | 
				
			||||||
	mgm->qp[i - 1] = 0;
 | 
						mgm->qp[i - 1] = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	err = mthca_WRITE_MGM(dev, index, mgm, &status);
 | 
						err = mthca_WRITE_MGM(dev, index, mailbox, &status);
 | 
				
			||||||
	if (err)
 | 
						if (err)
 | 
				
			||||||
		goto out;
 | 
							goto out;
 | 
				
			||||||
	if (status) {
 | 
						if (status) {
 | 
				
			||||||
| 
						 | 
					@ -304,7 +305,7 @@ int mthca_multicast_detach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid)
 | 
				
			||||||
		if (be32_to_cpu(mgm->next_gid_index) >> 5) {
 | 
							if (be32_to_cpu(mgm->next_gid_index) >> 5) {
 | 
				
			||||||
			err = mthca_READ_MGM(dev,
 | 
								err = mthca_READ_MGM(dev,
 | 
				
			||||||
					     be32_to_cpu(mgm->next_gid_index) >> 5,
 | 
										     be32_to_cpu(mgm->next_gid_index) >> 5,
 | 
				
			||||||
					     mgm, &status);
 | 
										     mailbox, &status);
 | 
				
			||||||
			if (err)
 | 
								if (err)
 | 
				
			||||||
				goto out;
 | 
									goto out;
 | 
				
			||||||
			if (status) {
 | 
								if (status) {
 | 
				
			||||||
| 
						 | 
					@ -316,7 +317,7 @@ int mthca_multicast_detach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid)
 | 
				
			||||||
		} else
 | 
							} else
 | 
				
			||||||
			memset(mgm->gid, 0, 16);
 | 
								memset(mgm->gid, 0, 16);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		err = mthca_WRITE_MGM(dev, index, mgm, &status);
 | 
							err = mthca_WRITE_MGM(dev, index, mailbox, &status);
 | 
				
			||||||
		if (err)
 | 
							if (err)
 | 
				
			||||||
			goto out;
 | 
								goto out;
 | 
				
			||||||
		if (status) {
 | 
							if (status) {
 | 
				
			||||||
| 
						 | 
					@ -327,7 +328,7 @@ int mthca_multicast_detach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid)
 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
		/* Remove entry from AMGM */
 | 
							/* Remove entry from AMGM */
 | 
				
			||||||
		index = be32_to_cpu(mgm->next_gid_index) >> 5;
 | 
							index = be32_to_cpu(mgm->next_gid_index) >> 5;
 | 
				
			||||||
		err = mthca_READ_MGM(dev, prev, mgm, &status);
 | 
							err = mthca_READ_MGM(dev, prev, mailbox, &status);
 | 
				
			||||||
		if (err)
 | 
							if (err)
 | 
				
			||||||
			goto out;
 | 
								goto out;
 | 
				
			||||||
		if (status) {
 | 
							if (status) {
 | 
				
			||||||
| 
						 | 
					@ -338,7 +339,7 @@ int mthca_multicast_detach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		mgm->next_gid_index = cpu_to_be32(index << 5);
 | 
							mgm->next_gid_index = cpu_to_be32(index << 5);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		err = mthca_WRITE_MGM(dev, prev, mgm, &status);
 | 
							err = mthca_WRITE_MGM(dev, prev, mailbox, &status);
 | 
				
			||||||
		if (err)
 | 
							if (err)
 | 
				
			||||||
			goto out;
 | 
								goto out;
 | 
				
			||||||
		if (status) {
 | 
							if (status) {
 | 
				
			||||||
| 
						 | 
					@ -350,7 +351,7 @@ int mthca_multicast_detach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 out:
 | 
					 out:
 | 
				
			||||||
	up(&dev->mcg_table.sem);
 | 
						up(&dev->mcg_table.sem);
 | 
				
			||||||
	kfree(mailbox);
 | 
						mthca_free_mailbox(dev, mailbox);
 | 
				
			||||||
	return err;
 | 
						return err;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -179,9 +179,14 @@ out:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void mthca_table_put(struct mthca_dev *dev, struct mthca_icm_table *table, int obj)
 | 
					void mthca_table_put(struct mthca_dev *dev, struct mthca_icm_table *table, int obj)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	int i = (obj & (table->num_obj - 1)) * table->obj_size / MTHCA_TABLE_CHUNK_SIZE;
 | 
						int i;
 | 
				
			||||||
	u8 status;
 | 
						u8 status;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!mthca_is_memfree(dev))
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						i = (obj & (table->num_obj - 1)) * table->obj_size / MTHCA_TABLE_CHUNK_SIZE;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	down(&table->mutex);
 | 
						down(&table->mutex);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (--table->icm[i]->refcount == 0) {
 | 
						if (--table->icm[i]->refcount == 0) {
 | 
				
			||||||
| 
						 | 
					@ -256,6 +261,9 @@ void mthca_table_put_range(struct mthca_dev *dev, struct mthca_icm_table *table,
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	int i;
 | 
						int i;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!mthca_is_memfree(dev))
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for (i = start; i <= end; i += MTHCA_TABLE_CHUNK_SIZE / table->obj_size)
 | 
						for (i = start; i <= end; i += MTHCA_TABLE_CHUNK_SIZE / table->obj_size)
 | 
				
			||||||
		mthca_table_put(dev, table, i);
 | 
							mthca_table_put(dev, table, i);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -40,6 +40,12 @@
 | 
				
			||||||
#include "mthca_cmd.h"
 | 
					#include "mthca_cmd.h"
 | 
				
			||||||
#include "mthca_memfree.h"
 | 
					#include "mthca_memfree.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct mthca_mtt {
 | 
				
			||||||
 | 
						struct mthca_buddy *buddy;
 | 
				
			||||||
 | 
						int                 order;
 | 
				
			||||||
 | 
						u32                 first_seg;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 * Must be packed because mtt_seg is 64 bits but only aligned to 32 bits.
 | 
					 * Must be packed because mtt_seg is 64 bits but only aligned to 32 bits.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
| 
						 | 
					@ -173,8 +179,8 @@ static void __devexit mthca_buddy_cleanup(struct mthca_buddy *buddy)
 | 
				
			||||||
	kfree(buddy->bits);
 | 
						kfree(buddy->bits);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static u32 mthca_alloc_mtt(struct mthca_dev *dev, int order,
 | 
					static u32 mthca_alloc_mtt_range(struct mthca_dev *dev, int order,
 | 
				
			||||||
			   struct mthca_buddy *buddy)
 | 
									 struct mthca_buddy *buddy)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	u32 seg = mthca_buddy_alloc(buddy, order);
 | 
						u32 seg = mthca_buddy_alloc(buddy, order);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -191,14 +197,102 @@ static u32 mthca_alloc_mtt(struct mthca_dev *dev, int order,
 | 
				
			||||||
	return seg;
 | 
						return seg;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void mthca_free_mtt(struct mthca_dev *dev, u32 seg, int order,
 | 
					static struct mthca_mtt *__mthca_alloc_mtt(struct mthca_dev *dev, int size,
 | 
				
			||||||
			   struct mthca_buddy* buddy)
 | 
										   struct mthca_buddy *buddy)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	mthca_buddy_free(buddy, seg, order);
 | 
						struct mthca_mtt *mtt;
 | 
				
			||||||
 | 
						int i;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (mthca_is_memfree(dev))
 | 
						if (size <= 0)
 | 
				
			||||||
		mthca_table_put_range(dev, dev->mr_table.mtt_table, seg,
 | 
							return ERR_PTR(-EINVAL);
 | 
				
			||||||
				      seg + (1 << order) - 1);
 | 
					
 | 
				
			||||||
 | 
						mtt = kmalloc(sizeof *mtt, GFP_KERNEL);
 | 
				
			||||||
 | 
						if (!mtt)
 | 
				
			||||||
 | 
							return ERR_PTR(-ENOMEM);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						mtt->buddy = buddy;
 | 
				
			||||||
 | 
						mtt->order = 0;
 | 
				
			||||||
 | 
						for (i = MTHCA_MTT_SEG_SIZE / 8; i < size; i <<= 1)
 | 
				
			||||||
 | 
							++mtt->order;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						mtt->first_seg = mthca_alloc_mtt_range(dev, mtt->order, buddy);
 | 
				
			||||||
 | 
						if (mtt->first_seg == -1) {
 | 
				
			||||||
 | 
							kfree(mtt);
 | 
				
			||||||
 | 
							return ERR_PTR(-ENOMEM);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return mtt;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct mthca_mtt *mthca_alloc_mtt(struct mthca_dev *dev, int size)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						return __mthca_alloc_mtt(dev, size, &dev->mr_table.mtt_buddy);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void mthca_free_mtt(struct mthca_dev *dev, struct mthca_mtt *mtt)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						if (!mtt)
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						mthca_buddy_free(mtt->buddy, mtt->first_seg, mtt->order);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						mthca_table_put_range(dev, dev->mr_table.mtt_table,
 | 
				
			||||||
 | 
								      mtt->first_seg,
 | 
				
			||||||
 | 
								      mtt->first_seg + (1 << mtt->order) - 1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						kfree(mtt);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int mthca_write_mtt(struct mthca_dev *dev, struct mthca_mtt *mtt,
 | 
				
			||||||
 | 
							    int start_index, u64 *buffer_list, int list_len)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct mthca_mailbox *mailbox;
 | 
				
			||||||
 | 
						u64 *mtt_entry;
 | 
				
			||||||
 | 
						int err = 0;
 | 
				
			||||||
 | 
						u8 status;
 | 
				
			||||||
 | 
						int i;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						mailbox = mthca_alloc_mailbox(dev, GFP_KERNEL);
 | 
				
			||||||
 | 
						if (IS_ERR(mailbox))
 | 
				
			||||||
 | 
							return PTR_ERR(mailbox);
 | 
				
			||||||
 | 
						mtt_entry = mailbox->buf;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						while (list_len > 0) {
 | 
				
			||||||
 | 
							mtt_entry[0] = cpu_to_be64(dev->mr_table.mtt_base +
 | 
				
			||||||
 | 
										   mtt->first_seg * MTHCA_MTT_SEG_SIZE +
 | 
				
			||||||
 | 
										   start_index * 8);
 | 
				
			||||||
 | 
							mtt_entry[1] = 0;
 | 
				
			||||||
 | 
							for (i = 0; i < list_len && i < MTHCA_MAILBOX_SIZE / 8 - 2; ++i)
 | 
				
			||||||
 | 
								mtt_entry[i + 2] = cpu_to_be64(buffer_list[i] |
 | 
				
			||||||
 | 
											       MTHCA_MTT_FLAG_PRESENT);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							/*
 | 
				
			||||||
 | 
							 * If we have an odd number of entries to write, add
 | 
				
			||||||
 | 
							 * one more dummy entry for firmware efficiency.
 | 
				
			||||||
 | 
							 */
 | 
				
			||||||
 | 
							if (i & 1)
 | 
				
			||||||
 | 
								mtt_entry[i + 2] = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							err = mthca_WRITE_MTT(dev, mailbox, (i + 1) & ~1, &status);
 | 
				
			||||||
 | 
							if (err) {
 | 
				
			||||||
 | 
								mthca_warn(dev, "WRITE_MTT failed (%d)\n", err);
 | 
				
			||||||
 | 
								goto out;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if (status) {
 | 
				
			||||||
 | 
								mthca_warn(dev, "WRITE_MTT returned status 0x%02x\n",
 | 
				
			||||||
 | 
									   status);
 | 
				
			||||||
 | 
								err = -EINVAL;
 | 
				
			||||||
 | 
								goto out;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							list_len    -= i;
 | 
				
			||||||
 | 
							start_index += i;
 | 
				
			||||||
 | 
							buffer_list += i;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					out:
 | 
				
			||||||
 | 
						mthca_free_mailbox(dev, mailbox);
 | 
				
			||||||
 | 
						return err;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static inline u32 tavor_hw_index_to_key(u32 ind)
 | 
					static inline u32 tavor_hw_index_to_key(u32 ind)
 | 
				
			||||||
| 
						 | 
					@ -237,91 +331,18 @@ static inline u32 key_to_hw_index(struct mthca_dev *dev, u32 key)
 | 
				
			||||||
		return tavor_key_to_hw_index(key);
 | 
							return tavor_key_to_hw_index(key);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int mthca_mr_alloc_notrans(struct mthca_dev *dev, u32 pd,
 | 
					int mthca_mr_alloc(struct mthca_dev *dev, u32 pd, int buffer_size_shift,
 | 
				
			||||||
			   u32 access, struct mthca_mr *mr)
 | 
							   u64 iova, u64 total_size, u32 access, struct mthca_mr *mr)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	void *mailbox = NULL;
 | 
						struct mthca_mailbox *mailbox;
 | 
				
			||||||
	struct mthca_mpt_entry *mpt_entry;
 | 
						struct mthca_mpt_entry *mpt_entry;
 | 
				
			||||||
	u32 key;
 | 
						u32 key;
 | 
				
			||||||
 | 
						int i;
 | 
				
			||||||
	int err;
 | 
						int err;
 | 
				
			||||||
	u8 status;
 | 
						u8 status;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	might_sleep();
 | 
						might_sleep();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	mr->order = -1;
 | 
					 | 
				
			||||||
	key = mthca_alloc(&dev->mr_table.mpt_alloc);
 | 
					 | 
				
			||||||
	if (key == -1)
 | 
					 | 
				
			||||||
		return -ENOMEM;
 | 
					 | 
				
			||||||
	mr->ibmr.rkey = mr->ibmr.lkey = hw_index_to_key(dev, key);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (mthca_is_memfree(dev)) {
 | 
					 | 
				
			||||||
		err = mthca_table_get(dev, dev->mr_table.mpt_table, key);
 | 
					 | 
				
			||||||
		if (err)
 | 
					 | 
				
			||||||
			goto err_out_mpt_free;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	mailbox = kmalloc(sizeof *mpt_entry + MTHCA_CMD_MAILBOX_EXTRA,
 | 
					 | 
				
			||||||
			  GFP_KERNEL);
 | 
					 | 
				
			||||||
	if (!mailbox) {
 | 
					 | 
				
			||||||
		err = -ENOMEM;
 | 
					 | 
				
			||||||
		goto err_out_table;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	mpt_entry = MAILBOX_ALIGN(mailbox);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	mpt_entry->flags = cpu_to_be32(MTHCA_MPT_FLAG_SW_OWNS     |
 | 
					 | 
				
			||||||
				       MTHCA_MPT_FLAG_MIO         |
 | 
					 | 
				
			||||||
				       MTHCA_MPT_FLAG_PHYSICAL    |
 | 
					 | 
				
			||||||
				       MTHCA_MPT_FLAG_REGION      |
 | 
					 | 
				
			||||||
				       access);
 | 
					 | 
				
			||||||
	mpt_entry->page_size = 0;
 | 
					 | 
				
			||||||
	mpt_entry->key       = cpu_to_be32(key);
 | 
					 | 
				
			||||||
	mpt_entry->pd        = cpu_to_be32(pd);
 | 
					 | 
				
			||||||
	mpt_entry->start     = 0;
 | 
					 | 
				
			||||||
	mpt_entry->length    = ~0ULL;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	memset(&mpt_entry->lkey, 0,
 | 
					 | 
				
			||||||
	       sizeof *mpt_entry - offsetof(struct mthca_mpt_entry, lkey));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	err = mthca_SW2HW_MPT(dev, mpt_entry,
 | 
					 | 
				
			||||||
			      key & (dev->limits.num_mpts - 1),
 | 
					 | 
				
			||||||
			      &status);
 | 
					 | 
				
			||||||
	if (err) {
 | 
					 | 
				
			||||||
		mthca_warn(dev, "SW2HW_MPT failed (%d)\n", err);
 | 
					 | 
				
			||||||
		goto err_out_table;
 | 
					 | 
				
			||||||
	} else if (status) {
 | 
					 | 
				
			||||||
		mthca_warn(dev, "SW2HW_MPT returned status 0x%02x\n",
 | 
					 | 
				
			||||||
			   status);
 | 
					 | 
				
			||||||
		err = -EINVAL;
 | 
					 | 
				
			||||||
		goto err_out_table;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	kfree(mailbox);
 | 
					 | 
				
			||||||
	return err;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
err_out_table:
 | 
					 | 
				
			||||||
	if (mthca_is_memfree(dev))
 | 
					 | 
				
			||||||
		mthca_table_put(dev, dev->mr_table.mpt_table, key);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
err_out_mpt_free:
 | 
					 | 
				
			||||||
	mthca_free(&dev->mr_table.mpt_alloc, key);
 | 
					 | 
				
			||||||
	kfree(mailbox);
 | 
					 | 
				
			||||||
	return err;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
int mthca_mr_alloc_phys(struct mthca_dev *dev, u32 pd,
 | 
					 | 
				
			||||||
			u64 *buffer_list, int buffer_size_shift,
 | 
					 | 
				
			||||||
			int list_len, u64 iova, u64 total_size,
 | 
					 | 
				
			||||||
			u32 access, struct mthca_mr *mr)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	void *mailbox;
 | 
					 | 
				
			||||||
	u64 *mtt_entry;
 | 
					 | 
				
			||||||
	struct mthca_mpt_entry *mpt_entry;
 | 
					 | 
				
			||||||
	u32 key;
 | 
					 | 
				
			||||||
	int err = -ENOMEM;
 | 
					 | 
				
			||||||
	u8 status;
 | 
					 | 
				
			||||||
	int i;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	might_sleep();
 | 
					 | 
				
			||||||
	WARN_ON(buffer_size_shift >= 32);
 | 
						WARN_ON(buffer_size_shift >= 32);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	key = mthca_alloc(&dev->mr_table.mpt_alloc);
 | 
						key = mthca_alloc(&dev->mr_table.mpt_alloc);
 | 
				
			||||||
| 
						 | 
					@ -335,75 +356,33 @@ int mthca_mr_alloc_phys(struct mthca_dev *dev, u32 pd,
 | 
				
			||||||
			goto err_out_mpt_free;
 | 
								goto err_out_mpt_free;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for (i = MTHCA_MTT_SEG_SIZE / 8, mr->order = 0;
 | 
						mailbox = mthca_alloc_mailbox(dev, GFP_KERNEL);
 | 
				
			||||||
	     i < list_len;
 | 
						if (IS_ERR(mailbox)) {
 | 
				
			||||||
	     i <<= 1, ++mr->order)
 | 
							err = PTR_ERR(mailbox);
 | 
				
			||||||
		; /* nothing */
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	mr->first_seg = mthca_alloc_mtt(dev, mr->order,
 | 
					 | 
				
			||||||
				       	&dev->mr_table.mtt_buddy);
 | 
					 | 
				
			||||||
	if (mr->first_seg == -1)
 | 
					 | 
				
			||||||
		goto err_out_table;
 | 
							goto err_out_table;
 | 
				
			||||||
 | 
					 | 
				
			||||||
	/*
 | 
					 | 
				
			||||||
	 * If list_len is odd, we add one more dummy entry for
 | 
					 | 
				
			||||||
	 * firmware efficiency.
 | 
					 | 
				
			||||||
	 */
 | 
					 | 
				
			||||||
	mailbox = kmalloc(max(sizeof *mpt_entry,
 | 
					 | 
				
			||||||
			      (size_t) 8 * (list_len + (list_len & 1) + 2)) +
 | 
					 | 
				
			||||||
			  MTHCA_CMD_MAILBOX_EXTRA,
 | 
					 | 
				
			||||||
			  GFP_KERNEL);
 | 
					 | 
				
			||||||
	if (!mailbox)
 | 
					 | 
				
			||||||
		goto err_out_free_mtt;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	mtt_entry = MAILBOX_ALIGN(mailbox);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	mtt_entry[0] = cpu_to_be64(dev->mr_table.mtt_base +
 | 
					 | 
				
			||||||
				   mr->first_seg * MTHCA_MTT_SEG_SIZE);
 | 
					 | 
				
			||||||
	mtt_entry[1] = 0;
 | 
					 | 
				
			||||||
	for (i = 0; i < list_len; ++i)
 | 
					 | 
				
			||||||
		mtt_entry[i + 2] = cpu_to_be64(buffer_list[i] |
 | 
					 | 
				
			||||||
					       MTHCA_MTT_FLAG_PRESENT);
 | 
					 | 
				
			||||||
	if (list_len & 1) {
 | 
					 | 
				
			||||||
		mtt_entry[i + 2] = 0;
 | 
					 | 
				
			||||||
		++list_len;
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
						mpt_entry = mailbox->buf;
 | 
				
			||||||
	if (0) {
 | 
					 | 
				
			||||||
		mthca_dbg(dev, "Dumping MPT entry\n");
 | 
					 | 
				
			||||||
		for (i = 0; i < list_len + 2; ++i)
 | 
					 | 
				
			||||||
			printk(KERN_ERR "[%2d] %016llx\n",
 | 
					 | 
				
			||||||
			       i, (unsigned long long) be64_to_cpu(mtt_entry[i]));
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	err = mthca_WRITE_MTT(dev, mtt_entry, list_len, &status);
 | 
					 | 
				
			||||||
	if (err) {
 | 
					 | 
				
			||||||
		mthca_warn(dev, "WRITE_MTT failed (%d)\n", err);
 | 
					 | 
				
			||||||
		goto err_out_mailbox_free;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	if (status) {
 | 
					 | 
				
			||||||
		mthca_warn(dev, "WRITE_MTT returned status 0x%02x\n",
 | 
					 | 
				
			||||||
			   status);
 | 
					 | 
				
			||||||
		err = -EINVAL;
 | 
					 | 
				
			||||||
		goto err_out_mailbox_free;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	mpt_entry = MAILBOX_ALIGN(mailbox);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	mpt_entry->flags = cpu_to_be32(MTHCA_MPT_FLAG_SW_OWNS     |
 | 
						mpt_entry->flags = cpu_to_be32(MTHCA_MPT_FLAG_SW_OWNS     |
 | 
				
			||||||
				       MTHCA_MPT_FLAG_MIO         |
 | 
									       MTHCA_MPT_FLAG_MIO         |
 | 
				
			||||||
				       MTHCA_MPT_FLAG_REGION      |
 | 
									       MTHCA_MPT_FLAG_REGION      |
 | 
				
			||||||
				       access);
 | 
									       access);
 | 
				
			||||||
 | 
						if (!mr->mtt)
 | 
				
			||||||
 | 
							mpt_entry->flags |= cpu_to_be32(MTHCA_MPT_FLAG_PHYSICAL);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	mpt_entry->page_size = cpu_to_be32(buffer_size_shift - 12);
 | 
						mpt_entry->page_size = cpu_to_be32(buffer_size_shift - 12);
 | 
				
			||||||
	mpt_entry->key       = cpu_to_be32(key);
 | 
						mpt_entry->key       = cpu_to_be32(key);
 | 
				
			||||||
	mpt_entry->pd        = cpu_to_be32(pd);
 | 
						mpt_entry->pd        = cpu_to_be32(pd);
 | 
				
			||||||
	mpt_entry->start     = cpu_to_be64(iova);
 | 
						mpt_entry->start     = cpu_to_be64(iova);
 | 
				
			||||||
	mpt_entry->length    = cpu_to_be64(total_size);
 | 
						mpt_entry->length    = cpu_to_be64(total_size);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	memset(&mpt_entry->lkey, 0,
 | 
						memset(&mpt_entry->lkey, 0,
 | 
				
			||||||
	       sizeof *mpt_entry - offsetof(struct mthca_mpt_entry, lkey));
 | 
						       sizeof *mpt_entry - offsetof(struct mthca_mpt_entry, lkey));
 | 
				
			||||||
	mpt_entry->mtt_seg   = cpu_to_be64(dev->mr_table.mtt_base +
 | 
					
 | 
				
			||||||
					   mr->first_seg * MTHCA_MTT_SEG_SIZE);
 | 
						if (mr->mtt)
 | 
				
			||||||
 | 
							mpt_entry->mtt_seg =
 | 
				
			||||||
 | 
								cpu_to_be64(dev->mr_table.mtt_base +
 | 
				
			||||||
 | 
									    mr->mtt->first_seg * MTHCA_MTT_SEG_SIZE);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (0) {
 | 
						if (0) {
 | 
				
			||||||
		mthca_dbg(dev, "Dumping MPT entry %08x:\n", mr->ibmr.lkey);
 | 
							mthca_dbg(dev, "Dumping MPT entry %08x:\n", mr->ibmr.lkey);
 | 
				
			||||||
| 
						 | 
					@ -416,45 +395,70 @@ int mthca_mr_alloc_phys(struct mthca_dev *dev, u32 pd,
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	err = mthca_SW2HW_MPT(dev, mpt_entry,
 | 
						err = mthca_SW2HW_MPT(dev, mailbox,
 | 
				
			||||||
			      key & (dev->limits.num_mpts - 1),
 | 
								      key & (dev->limits.num_mpts - 1),
 | 
				
			||||||
			      &status);
 | 
								      &status);
 | 
				
			||||||
	if (err)
 | 
						if (err) {
 | 
				
			||||||
		mthca_warn(dev, "SW2HW_MPT failed (%d)\n", err);
 | 
							mthca_warn(dev, "SW2HW_MPT failed (%d)\n", err);
 | 
				
			||||||
	else if (status) {
 | 
							goto err_out_mailbox;
 | 
				
			||||||
 | 
						} else if (status) {
 | 
				
			||||||
		mthca_warn(dev, "SW2HW_MPT returned status 0x%02x\n",
 | 
							mthca_warn(dev, "SW2HW_MPT returned status 0x%02x\n",
 | 
				
			||||||
			   status);
 | 
								   status);
 | 
				
			||||||
		err = -EINVAL;
 | 
							err = -EINVAL;
 | 
				
			||||||
 | 
							goto err_out_mailbox;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	kfree(mailbox);
 | 
						mthca_free_mailbox(dev, mailbox);
 | 
				
			||||||
	return err;
 | 
						return err;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
err_out_mailbox_free:
 | 
					err_out_mailbox:
 | 
				
			||||||
	kfree(mailbox);
 | 
						mthca_free_mailbox(dev, mailbox);
 | 
				
			||||||
 | 
					 | 
				
			||||||
err_out_free_mtt:
 | 
					 | 
				
			||||||
	mthca_free_mtt(dev, mr->first_seg, mr->order, &dev->mr_table.mtt_buddy);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
err_out_table:
 | 
					err_out_table:
 | 
				
			||||||
	if (mthca_is_memfree(dev))
 | 
						mthca_table_put(dev, dev->mr_table.mpt_table, key);
 | 
				
			||||||
		mthca_table_put(dev, dev->mr_table.mpt_table, key);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
err_out_mpt_free:
 | 
					err_out_mpt_free:
 | 
				
			||||||
	mthca_free(&dev->mr_table.mpt_alloc, key);
 | 
						mthca_free(&dev->mr_table.mpt_alloc, key);
 | 
				
			||||||
	return err;
 | 
						return err;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Free mr or fmr */
 | 
					int mthca_mr_alloc_notrans(struct mthca_dev *dev, u32 pd,
 | 
				
			||||||
static void mthca_free_region(struct mthca_dev *dev, u32 lkey, int order,
 | 
								   u32 access, struct mthca_mr *mr)
 | 
				
			||||||
			      u32 first_seg, struct mthca_buddy *buddy)
 | 
					 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	if (order >= 0)
 | 
						mr->mtt = NULL;
 | 
				
			||||||
		mthca_free_mtt(dev, first_seg, order, buddy);
 | 
						return mthca_mr_alloc(dev, pd, 12, 0, ~0ULL, access, mr);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (mthca_is_memfree(dev))
 | 
					int mthca_mr_alloc_phys(struct mthca_dev *dev, u32 pd,
 | 
				
			||||||
		mthca_table_put(dev, dev->mr_table.mpt_table,
 | 
								u64 *buffer_list, int buffer_size_shift,
 | 
				
			||||||
				arbel_key_to_hw_index(lkey));
 | 
								int list_len, u64 iova, u64 total_size,
 | 
				
			||||||
 | 
								u32 access, struct mthca_mr *mr)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						int err;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						mr->mtt = mthca_alloc_mtt(dev, list_len);
 | 
				
			||||||
 | 
						if (IS_ERR(mr->mtt))
 | 
				
			||||||
 | 
							return PTR_ERR(mr->mtt);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						err = mthca_write_mtt(dev, mr->mtt, 0, buffer_list, list_len);
 | 
				
			||||||
 | 
						if (err) {
 | 
				
			||||||
 | 
							mthca_free_mtt(dev, mr->mtt);
 | 
				
			||||||
 | 
							return err;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						err = mthca_mr_alloc(dev, pd, buffer_size_shift, iova,
 | 
				
			||||||
 | 
								     total_size, access, mr);
 | 
				
			||||||
 | 
						if (err)
 | 
				
			||||||
 | 
							mthca_free_mtt(dev, mr->mtt);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return err;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Free mr or fmr */
 | 
				
			||||||
 | 
					static void mthca_free_region(struct mthca_dev *dev, u32 lkey)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						mthca_table_put(dev, dev->mr_table.mpt_table,
 | 
				
			||||||
 | 
								arbel_key_to_hw_index(lkey));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	mthca_free(&dev->mr_table.mpt_alloc, key_to_hw_index(dev, lkey));
 | 
						mthca_free(&dev->mr_table.mpt_alloc, key_to_hw_index(dev, lkey));
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -476,15 +480,15 @@ void mthca_free_mr(struct mthca_dev *dev, struct mthca_mr *mr)
 | 
				
			||||||
		mthca_warn(dev, "HW2SW_MPT returned status 0x%02x\n",
 | 
							mthca_warn(dev, "HW2SW_MPT returned status 0x%02x\n",
 | 
				
			||||||
			   status);
 | 
								   status);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	mthca_free_region(dev, mr->ibmr.lkey, mr->order, mr->first_seg,
 | 
						mthca_free_region(dev, mr->ibmr.lkey);
 | 
				
			||||||
			  &dev->mr_table.mtt_buddy);
 | 
						mthca_free_mtt(dev, mr->mtt);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int mthca_fmr_alloc(struct mthca_dev *dev, u32 pd,
 | 
					int mthca_fmr_alloc(struct mthca_dev *dev, u32 pd,
 | 
				
			||||||
		    u32 access, struct mthca_fmr *mr)
 | 
							    u32 access, struct mthca_fmr *mr)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct mthca_mpt_entry *mpt_entry;
 | 
						struct mthca_mpt_entry *mpt_entry;
 | 
				
			||||||
	void *mailbox;
 | 
						struct mthca_mailbox *mailbox;
 | 
				
			||||||
	u64 mtt_seg;
 | 
						u64 mtt_seg;
 | 
				
			||||||
	u32 key, idx;
 | 
						u32 key, idx;
 | 
				
			||||||
	u8 status;
 | 
						u8 status;
 | 
				
			||||||
| 
						 | 
					@ -522,31 +526,24 @@ int mthca_fmr_alloc(struct mthca_dev *dev, u32 pd,
 | 
				
			||||||
		mr->mem.tavor.mpt = dev->mr_table.tavor_fmr.mpt_base +
 | 
							mr->mem.tavor.mpt = dev->mr_table.tavor_fmr.mpt_base +
 | 
				
			||||||
		       	sizeof *(mr->mem.tavor.mpt) * idx;
 | 
							       	sizeof *(mr->mem.tavor.mpt) * idx;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for (i = MTHCA_MTT_SEG_SIZE / 8, mr->order = 0;
 | 
						mr->mtt = __mthca_alloc_mtt(dev, list_len, dev->mr_table.fmr_mtt_buddy);
 | 
				
			||||||
	     i < list_len;
 | 
						if (IS_ERR(mr->mtt))
 | 
				
			||||||
	     i <<= 1, ++mr->order)
 | 
					 | 
				
			||||||
		; /* nothing */
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	mr->first_seg = mthca_alloc_mtt(dev, mr->order,
 | 
					 | 
				
			||||||
				       	dev->mr_table.fmr_mtt_buddy);
 | 
					 | 
				
			||||||
	if (mr->first_seg == -1)
 | 
					 | 
				
			||||||
		goto err_out_table;
 | 
							goto err_out_table;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	mtt_seg = mr->first_seg * MTHCA_MTT_SEG_SIZE;
 | 
						mtt_seg = mr->mtt->first_seg * MTHCA_MTT_SEG_SIZE;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (mthca_is_memfree(dev)) {
 | 
						if (mthca_is_memfree(dev)) {
 | 
				
			||||||
		mr->mem.arbel.mtts = mthca_table_find(dev->mr_table.mtt_table,
 | 
							mr->mem.arbel.mtts = mthca_table_find(dev->mr_table.mtt_table,
 | 
				
			||||||
						      mr->first_seg);
 | 
											      mr->mtt->first_seg);
 | 
				
			||||||
		BUG_ON(!mr->mem.arbel.mtts);
 | 
							BUG_ON(!mr->mem.arbel.mtts);
 | 
				
			||||||
	} else
 | 
						} else
 | 
				
			||||||
		mr->mem.tavor.mtts = dev->mr_table.tavor_fmr.mtt_base + mtt_seg;
 | 
							mr->mem.tavor.mtts = dev->mr_table.tavor_fmr.mtt_base + mtt_seg;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	mailbox = kmalloc(sizeof *mpt_entry + MTHCA_CMD_MAILBOX_EXTRA,
 | 
						mailbox = mthca_alloc_mailbox(dev, GFP_KERNEL);
 | 
				
			||||||
			  GFP_KERNEL);
 | 
						if (IS_ERR(mailbox))
 | 
				
			||||||
	if (!mailbox)
 | 
					 | 
				
			||||||
		goto err_out_free_mtt;
 | 
							goto err_out_free_mtt;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	mpt_entry = MAILBOX_ALIGN(mailbox);
 | 
						mpt_entry = mailbox->buf;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	mpt_entry->flags = cpu_to_be32(MTHCA_MPT_FLAG_SW_OWNS     |
 | 
						mpt_entry->flags = cpu_to_be32(MTHCA_MPT_FLAG_SW_OWNS     |
 | 
				
			||||||
				       MTHCA_MPT_FLAG_MIO         |
 | 
									       MTHCA_MPT_FLAG_MIO         |
 | 
				
			||||||
| 
						 | 
					@ -571,7 +568,7 @@ int mthca_fmr_alloc(struct mthca_dev *dev, u32 pd,
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	err = mthca_SW2HW_MPT(dev, mpt_entry,
 | 
						err = mthca_SW2HW_MPT(dev, mailbox,
 | 
				
			||||||
			      key & (dev->limits.num_mpts - 1),
 | 
								      key & (dev->limits.num_mpts - 1),
 | 
				
			||||||
			      &status);
 | 
								      &status);
 | 
				
			||||||
	if (err) {
 | 
						if (err) {
 | 
				
			||||||
| 
						 | 
					@ -585,19 +582,17 @@ int mthca_fmr_alloc(struct mthca_dev *dev, u32 pd,
 | 
				
			||||||
		goto err_out_mailbox_free;
 | 
							goto err_out_mailbox_free;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	kfree(mailbox);
 | 
						mthca_free_mailbox(dev, mailbox);
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
err_out_mailbox_free:
 | 
					err_out_mailbox_free:
 | 
				
			||||||
	kfree(mailbox);
 | 
						mthca_free_mailbox(dev, mailbox);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
err_out_free_mtt:
 | 
					err_out_free_mtt:
 | 
				
			||||||
	mthca_free_mtt(dev, mr->first_seg, mr->order,
 | 
						mthca_free_mtt(dev, mr->mtt);
 | 
				
			||||||
		       dev->mr_table.fmr_mtt_buddy);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
err_out_table:
 | 
					err_out_table:
 | 
				
			||||||
	if (mthca_is_memfree(dev))
 | 
						mthca_table_put(dev, dev->mr_table.mpt_table, key);
 | 
				
			||||||
		mthca_table_put(dev, dev->mr_table.mpt_table, key);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
err_out_mpt_free:
 | 
					err_out_mpt_free:
 | 
				
			||||||
	mthca_free(&dev->mr_table.mpt_alloc, mr->ibmr.lkey);
 | 
						mthca_free(&dev->mr_table.mpt_alloc, mr->ibmr.lkey);
 | 
				
			||||||
| 
						 | 
					@ -609,8 +604,9 @@ int mthca_free_fmr(struct mthca_dev *dev, struct mthca_fmr *fmr)
 | 
				
			||||||
	if (fmr->maps)
 | 
						if (fmr->maps)
 | 
				
			||||||
		return -EBUSY;
 | 
							return -EBUSY;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	mthca_free_region(dev, fmr->ibmr.lkey, fmr->order, fmr->first_seg,
 | 
						mthca_free_region(dev, fmr->ibmr.lkey);
 | 
				
			||||||
			  dev->mr_table.fmr_mtt_buddy);
 | 
						mthca_free_mtt(dev, fmr->mtt);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -826,7 +822,8 @@ int __devinit mthca_init_mr_table(struct mthca_dev *dev)
 | 
				
			||||||
	if (dev->limits.reserved_mtts) {
 | 
						if (dev->limits.reserved_mtts) {
 | 
				
			||||||
		i = fls(dev->limits.reserved_mtts - 1);
 | 
							i = fls(dev->limits.reserved_mtts - 1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (mthca_alloc_mtt(dev, i, dev->mr_table.fmr_mtt_buddy) == -1) {
 | 
							if (mthca_alloc_mtt_range(dev, i,
 | 
				
			||||||
 | 
										  dev->mr_table.fmr_mtt_buddy) == -1) {
 | 
				
			||||||
			mthca_warn(dev, "MTT table of order %d is too small.\n",
 | 
								mthca_warn(dev, "MTT table of order %d is too small.\n",
 | 
				
			||||||
				  dev->mr_table.fmr_mtt_buddy->max_order);
 | 
									  dev->mr_table.fmr_mtt_buddy->max_order);
 | 
				
			||||||
			err = -ENOMEM;
 | 
								err = -ENOMEM;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,5 +1,6 @@
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 * Copyright (c) 2004, 2005 Topspin Communications.  All rights reserved.
 | 
					 * Copyright (c) 2004, 2005 Topspin Communications.  All rights reserved.
 | 
				
			||||||
 | 
					 * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved.
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * This software is available to you under a choice of one of two
 | 
					 * This software is available to you under a choice of one of two
 | 
				
			||||||
 * licenses.  You may choose to be licensed under the terms of the GNU
 | 
					 * licenses.  You may choose to be licensed under the terms of the GNU
 | 
				
			||||||
| 
						 | 
					@ -52,7 +53,7 @@ static int mthca_query_device(struct ib_device *ibdev,
 | 
				
			||||||
	if (!in_mad || !out_mad)
 | 
						if (!in_mad || !out_mad)
 | 
				
			||||||
		goto out;
 | 
							goto out;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	memset(props, 0, sizeof props);
 | 
						memset(props, 0, sizeof *props);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	props->fw_ver              = mdev->fw_ver;
 | 
						props->fw_ver              = mdev->fw_ver;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -558,6 +559,7 @@ static struct ib_mr *mthca_reg_phys_mr(struct ib_pd       *pd,
 | 
				
			||||||
				  convert_access(acc), mr);
 | 
									  convert_access(acc), mr);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (err) {
 | 
						if (err) {
 | 
				
			||||||
 | 
							kfree(page_list);
 | 
				
			||||||
		kfree(mr);
 | 
							kfree(mr);
 | 
				
			||||||
		return ERR_PTR(err);
 | 
							return ERR_PTR(err);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -54,18 +54,18 @@ struct mthca_uar {
 | 
				
			||||||
	int           index;
 | 
						int           index;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct mthca_mtt;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct mthca_mr {
 | 
					struct mthca_mr {
 | 
				
			||||||
	struct ib_mr ibmr;
 | 
						struct ib_mr      ibmr;
 | 
				
			||||||
	int order;
 | 
						struct mthca_mtt *mtt;
 | 
				
			||||||
	u32 first_seg;
 | 
					 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct mthca_fmr {
 | 
					struct mthca_fmr {
 | 
				
			||||||
	struct ib_fmr ibmr;
 | 
						struct ib_fmr      ibmr;
 | 
				
			||||||
	struct ib_fmr_attr attr;
 | 
						struct ib_fmr_attr attr;
 | 
				
			||||||
	int order;
 | 
						struct mthca_mtt  *mtt;
 | 
				
			||||||
	u32 first_seg;
 | 
						int                maps;
 | 
				
			||||||
	int maps;
 | 
					 | 
				
			||||||
	union {
 | 
						union {
 | 
				
			||||||
		struct {
 | 
							struct {
 | 
				
			||||||
			struct mthca_mpt_entry __iomem *mpt;
 | 
								struct mthca_mpt_entry __iomem *mpt;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -357,6 +357,9 @@ static const struct {
 | 
				
			||||||
				[UD]  = (IB_QP_PKEY_INDEX |
 | 
									[UD]  = (IB_QP_PKEY_INDEX |
 | 
				
			||||||
					 IB_QP_PORT       |
 | 
										 IB_QP_PORT       |
 | 
				
			||||||
					 IB_QP_QKEY),
 | 
										 IB_QP_QKEY),
 | 
				
			||||||
 | 
									[UC]  = (IB_QP_PKEY_INDEX |
 | 
				
			||||||
 | 
										 IB_QP_PORT       |
 | 
				
			||||||
 | 
										 IB_QP_ACCESS_FLAGS),
 | 
				
			||||||
				[RC]  = (IB_QP_PKEY_INDEX |
 | 
									[RC]  = (IB_QP_PKEY_INDEX |
 | 
				
			||||||
					 IB_QP_PORT       |
 | 
										 IB_QP_PORT       |
 | 
				
			||||||
					 IB_QP_ACCESS_FLAGS),
 | 
										 IB_QP_ACCESS_FLAGS),
 | 
				
			||||||
| 
						 | 
					@ -378,6 +381,9 @@ static const struct {
 | 
				
			||||||
				[UD]  = (IB_QP_PKEY_INDEX |
 | 
									[UD]  = (IB_QP_PKEY_INDEX |
 | 
				
			||||||
					 IB_QP_PORT       |
 | 
										 IB_QP_PORT       |
 | 
				
			||||||
					 IB_QP_QKEY),
 | 
										 IB_QP_QKEY),
 | 
				
			||||||
 | 
									[UC]  = (IB_QP_PKEY_INDEX |
 | 
				
			||||||
 | 
										 IB_QP_PORT       |
 | 
				
			||||||
 | 
										 IB_QP_ACCESS_FLAGS),
 | 
				
			||||||
				[RC]  = (IB_QP_PKEY_INDEX |
 | 
									[RC]  = (IB_QP_PKEY_INDEX |
 | 
				
			||||||
					 IB_QP_PORT       |
 | 
										 IB_QP_PORT       |
 | 
				
			||||||
					 IB_QP_ACCESS_FLAGS),
 | 
										 IB_QP_ACCESS_FLAGS),
 | 
				
			||||||
| 
						 | 
					@ -388,6 +394,11 @@ static const struct {
 | 
				
			||||||
		[IB_QPS_RTR]   = {
 | 
							[IB_QPS_RTR]   = {
 | 
				
			||||||
			.trans = MTHCA_TRANS_INIT2RTR,
 | 
								.trans = MTHCA_TRANS_INIT2RTR,
 | 
				
			||||||
			.req_param = {
 | 
								.req_param = {
 | 
				
			||||||
 | 
									[UC]  = (IB_QP_AV                  |
 | 
				
			||||||
 | 
										 IB_QP_PATH_MTU            |
 | 
				
			||||||
 | 
										 IB_QP_DEST_QPN            |
 | 
				
			||||||
 | 
										 IB_QP_RQ_PSN              |
 | 
				
			||||||
 | 
										 IB_QP_MAX_DEST_RD_ATOMIC),
 | 
				
			||||||
				[RC]  = (IB_QP_AV                  |
 | 
									[RC]  = (IB_QP_AV                  |
 | 
				
			||||||
					 IB_QP_PATH_MTU            |
 | 
										 IB_QP_PATH_MTU            |
 | 
				
			||||||
					 IB_QP_DEST_QPN            |
 | 
										 IB_QP_DEST_QPN            |
 | 
				
			||||||
| 
						 | 
					@ -398,6 +409,9 @@ static const struct {
 | 
				
			||||||
			.opt_param = {
 | 
								.opt_param = {
 | 
				
			||||||
				[UD]  = (IB_QP_PKEY_INDEX |
 | 
									[UD]  = (IB_QP_PKEY_INDEX |
 | 
				
			||||||
					 IB_QP_QKEY),
 | 
										 IB_QP_QKEY),
 | 
				
			||||||
 | 
									[UC]  = (IB_QP_ALT_PATH     |
 | 
				
			||||||
 | 
										 IB_QP_ACCESS_FLAGS |
 | 
				
			||||||
 | 
										 IB_QP_PKEY_INDEX),
 | 
				
			||||||
				[RC]  = (IB_QP_ALT_PATH     |
 | 
									[RC]  = (IB_QP_ALT_PATH     |
 | 
				
			||||||
					 IB_QP_ACCESS_FLAGS |
 | 
										 IB_QP_ACCESS_FLAGS |
 | 
				
			||||||
					 IB_QP_PKEY_INDEX),
 | 
										 IB_QP_PKEY_INDEX),
 | 
				
			||||||
| 
						 | 
					@ -413,6 +427,8 @@ static const struct {
 | 
				
			||||||
			.trans = MTHCA_TRANS_RTR2RTS,
 | 
								.trans = MTHCA_TRANS_RTR2RTS,
 | 
				
			||||||
			.req_param = {
 | 
								.req_param = {
 | 
				
			||||||
				[UD]  = IB_QP_SQ_PSN,
 | 
									[UD]  = IB_QP_SQ_PSN,
 | 
				
			||||||
 | 
									[UC]  = (IB_QP_SQ_PSN            |
 | 
				
			||||||
 | 
										 IB_QP_MAX_QP_RD_ATOMIC),
 | 
				
			||||||
				[RC]  = (IB_QP_TIMEOUT           |
 | 
									[RC]  = (IB_QP_TIMEOUT           |
 | 
				
			||||||
					 IB_QP_RETRY_CNT         |
 | 
										 IB_QP_RETRY_CNT         |
 | 
				
			||||||
					 IB_QP_RNR_RETRY         |
 | 
										 IB_QP_RNR_RETRY         |
 | 
				
			||||||
| 
						 | 
					@ -423,6 +439,11 @@ static const struct {
 | 
				
			||||||
			.opt_param = {
 | 
								.opt_param = {
 | 
				
			||||||
				[UD]  = (IB_QP_CUR_STATE             |
 | 
									[UD]  = (IB_QP_CUR_STATE             |
 | 
				
			||||||
					 IB_QP_QKEY),
 | 
										 IB_QP_QKEY),
 | 
				
			||||||
 | 
									[UC]  = (IB_QP_CUR_STATE             |
 | 
				
			||||||
 | 
										 IB_QP_ALT_PATH              |
 | 
				
			||||||
 | 
										 IB_QP_ACCESS_FLAGS          |
 | 
				
			||||||
 | 
										 IB_QP_PKEY_INDEX            |
 | 
				
			||||||
 | 
										 IB_QP_PATH_MIG_STATE),
 | 
				
			||||||
				[RC]  = (IB_QP_CUR_STATE             |
 | 
									[RC]  = (IB_QP_CUR_STATE             |
 | 
				
			||||||
					 IB_QP_ALT_PATH              |
 | 
										 IB_QP_ALT_PATH              |
 | 
				
			||||||
					 IB_QP_ACCESS_FLAGS          |
 | 
										 IB_QP_ACCESS_FLAGS          |
 | 
				
			||||||
| 
						 | 
					@ -442,6 +463,9 @@ static const struct {
 | 
				
			||||||
			.opt_param = {
 | 
								.opt_param = {
 | 
				
			||||||
				[UD]  = (IB_QP_CUR_STATE             |
 | 
									[UD]  = (IB_QP_CUR_STATE             |
 | 
				
			||||||
					 IB_QP_QKEY),
 | 
										 IB_QP_QKEY),
 | 
				
			||||||
 | 
									[UC]  = (IB_QP_ACCESS_FLAGS          |
 | 
				
			||||||
 | 
										 IB_QP_ALT_PATH              |
 | 
				
			||||||
 | 
										 IB_QP_PATH_MIG_STATE),
 | 
				
			||||||
				[RC]  = (IB_QP_ACCESS_FLAGS          |
 | 
									[RC]  = (IB_QP_ACCESS_FLAGS          |
 | 
				
			||||||
					 IB_QP_ALT_PATH              |
 | 
										 IB_QP_ALT_PATH              |
 | 
				
			||||||
					 IB_QP_PATH_MIG_STATE        |
 | 
										 IB_QP_PATH_MIG_STATE        |
 | 
				
			||||||
| 
						 | 
					@ -462,6 +486,10 @@ static const struct {
 | 
				
			||||||
			.opt_param = {
 | 
								.opt_param = {
 | 
				
			||||||
				[UD]  = (IB_QP_CUR_STATE             |
 | 
									[UD]  = (IB_QP_CUR_STATE             |
 | 
				
			||||||
					 IB_QP_QKEY),
 | 
										 IB_QP_QKEY),
 | 
				
			||||||
 | 
									[UC]  = (IB_QP_CUR_STATE             |
 | 
				
			||||||
 | 
										 IB_QP_ALT_PATH              |
 | 
				
			||||||
 | 
										 IB_QP_ACCESS_FLAGS          |
 | 
				
			||||||
 | 
										 IB_QP_PATH_MIG_STATE),
 | 
				
			||||||
				[RC]  = (IB_QP_CUR_STATE             |
 | 
									[RC]  = (IB_QP_CUR_STATE             |
 | 
				
			||||||
					 IB_QP_ALT_PATH              |
 | 
										 IB_QP_ALT_PATH              |
 | 
				
			||||||
					 IB_QP_ACCESS_FLAGS          |
 | 
										 IB_QP_ACCESS_FLAGS          |
 | 
				
			||||||
| 
						 | 
					@ -476,6 +504,14 @@ static const struct {
 | 
				
			||||||
			.opt_param = {
 | 
								.opt_param = {
 | 
				
			||||||
				[UD]  = (IB_QP_PKEY_INDEX            |
 | 
									[UD]  = (IB_QP_PKEY_INDEX            |
 | 
				
			||||||
					 IB_QP_QKEY),
 | 
										 IB_QP_QKEY),
 | 
				
			||||||
 | 
									[UC]  = (IB_QP_AV                    |
 | 
				
			||||||
 | 
										 IB_QP_MAX_QP_RD_ATOMIC      |
 | 
				
			||||||
 | 
										 IB_QP_MAX_DEST_RD_ATOMIC    |
 | 
				
			||||||
 | 
										 IB_QP_CUR_STATE             |
 | 
				
			||||||
 | 
										 IB_QP_ALT_PATH              |
 | 
				
			||||||
 | 
										 IB_QP_ACCESS_FLAGS          |
 | 
				
			||||||
 | 
										 IB_QP_PKEY_INDEX            |
 | 
				
			||||||
 | 
										 IB_QP_PATH_MIG_STATE),
 | 
				
			||||||
				[RC]  = (IB_QP_AV                    |
 | 
									[RC]  = (IB_QP_AV                    |
 | 
				
			||||||
					 IB_QP_TIMEOUT               |
 | 
										 IB_QP_TIMEOUT               |
 | 
				
			||||||
					 IB_QP_RETRY_CNT             |
 | 
										 IB_QP_RETRY_CNT             |
 | 
				
			||||||
| 
						 | 
					@ -501,6 +537,7 @@ static const struct {
 | 
				
			||||||
			.opt_param = {
 | 
								.opt_param = {
 | 
				
			||||||
				[UD]  = (IB_QP_CUR_STATE             |
 | 
									[UD]  = (IB_QP_CUR_STATE             |
 | 
				
			||||||
					 IB_QP_QKEY),
 | 
										 IB_QP_QKEY),
 | 
				
			||||||
 | 
									[UC]  = (IB_QP_CUR_STATE),
 | 
				
			||||||
				[RC]  = (IB_QP_CUR_STATE             |
 | 
									[RC]  = (IB_QP_CUR_STATE             |
 | 
				
			||||||
					 IB_QP_MIN_RNR_TIMER),
 | 
										 IB_QP_MIN_RNR_TIMER),
 | 
				
			||||||
				[MLX] = (IB_QP_CUR_STATE             |
 | 
									[MLX] = (IB_QP_CUR_STATE             |
 | 
				
			||||||
| 
						 | 
					@ -552,7 +589,7 @@ int mthca_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, int attr_mask)
 | 
				
			||||||
	struct mthca_dev *dev = to_mdev(ibqp->device);
 | 
						struct mthca_dev *dev = to_mdev(ibqp->device);
 | 
				
			||||||
	struct mthca_qp *qp = to_mqp(ibqp);
 | 
						struct mthca_qp *qp = to_mqp(ibqp);
 | 
				
			||||||
	enum ib_qp_state cur_state, new_state;
 | 
						enum ib_qp_state cur_state, new_state;
 | 
				
			||||||
	void *mailbox = NULL;
 | 
						struct mthca_mailbox *mailbox;
 | 
				
			||||||
	struct mthca_qp_param *qp_param;
 | 
						struct mthca_qp_param *qp_param;
 | 
				
			||||||
	struct mthca_qp_context *qp_context;
 | 
						struct mthca_qp_context *qp_context;
 | 
				
			||||||
	u32 req_param, opt_param;
 | 
						u32 req_param, opt_param;
 | 
				
			||||||
| 
						 | 
					@ -609,10 +646,10 @@ int mthca_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, int attr_mask)
 | 
				
			||||||
		return -EINVAL;
 | 
							return -EINVAL;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	mailbox = kmalloc(sizeof (*qp_param) + MTHCA_CMD_MAILBOX_EXTRA, GFP_KERNEL);
 | 
						mailbox = mthca_alloc_mailbox(dev, GFP_KERNEL);
 | 
				
			||||||
	if (!mailbox)
 | 
						if (IS_ERR(mailbox))
 | 
				
			||||||
		return -ENOMEM;
 | 
							return PTR_ERR(mailbox);
 | 
				
			||||||
	qp_param = MAILBOX_ALIGN(mailbox);
 | 
						qp_param = mailbox->buf;
 | 
				
			||||||
	qp_context = &qp_param->context;
 | 
						qp_context = &qp_param->context;
 | 
				
			||||||
	memset(qp_param, 0, sizeof *qp_param);
 | 
						memset(qp_param, 0, sizeof *qp_param);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -683,7 +720,7 @@ int mthca_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, int attr_mask)
 | 
				
			||||||
	if (attr_mask & IB_QP_AV) {
 | 
						if (attr_mask & IB_QP_AV) {
 | 
				
			||||||
		qp_context->pri_path.g_mylmc     = attr->ah_attr.src_path_bits & 0x7f;
 | 
							qp_context->pri_path.g_mylmc     = attr->ah_attr.src_path_bits & 0x7f;
 | 
				
			||||||
		qp_context->pri_path.rlid        = cpu_to_be16(attr->ah_attr.dlid);
 | 
							qp_context->pri_path.rlid        = cpu_to_be16(attr->ah_attr.dlid);
 | 
				
			||||||
		qp_context->pri_path.static_rate = (!!attr->ah_attr.static_rate) << 3;
 | 
							qp_context->pri_path.static_rate = !!attr->ah_attr.static_rate;
 | 
				
			||||||
		if (attr->ah_attr.ah_flags & IB_AH_GRH) {
 | 
							if (attr->ah_attr.ah_flags & IB_AH_GRH) {
 | 
				
			||||||
			qp_context->pri_path.g_mylmc |= 1 << 7;
 | 
								qp_context->pri_path.g_mylmc |= 1 << 7;
 | 
				
			||||||
			qp_context->pri_path.mgid_index = attr->ah_attr.grh.sgid_index;
 | 
								qp_context->pri_path.mgid_index = attr->ah_attr.grh.sgid_index;
 | 
				
			||||||
| 
						 | 
					@ -724,9 +761,9 @@ int mthca_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, int attr_mask)
 | 
				
			||||||
		qp_param->opt_param_mask |= cpu_to_be32(MTHCA_QP_OPTPAR_RETRY_COUNT);
 | 
							qp_param->opt_param_mask |= cpu_to_be32(MTHCA_QP_OPTPAR_RETRY_COUNT);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (attr_mask & IB_QP_MAX_DEST_RD_ATOMIC) {
 | 
						if (attr_mask & IB_QP_MAX_QP_RD_ATOMIC) {
 | 
				
			||||||
		qp_context->params1 |= cpu_to_be32(min(attr->max_dest_rd_atomic ?
 | 
							qp_context->params1 |= cpu_to_be32(min(attr->max_rd_atomic ?
 | 
				
			||||||
						       ffs(attr->max_dest_rd_atomic) - 1 : 0,
 | 
											       ffs(attr->max_rd_atomic) - 1 : 0,
 | 
				
			||||||
						       7) << 21);
 | 
											       7) << 21);
 | 
				
			||||||
		qp_param->opt_param_mask |= cpu_to_be32(MTHCA_QP_OPTPAR_SRA_MAX);
 | 
							qp_param->opt_param_mask |= cpu_to_be32(MTHCA_QP_OPTPAR_SRA_MAX);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					@ -764,10 +801,10 @@ int mthca_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, int attr_mask)
 | 
				
			||||||
		qp->atomic_rd_en = attr->qp_access_flags;
 | 
							qp->atomic_rd_en = attr->qp_access_flags;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (attr_mask & IB_QP_MAX_QP_RD_ATOMIC) {
 | 
						if (attr_mask & IB_QP_MAX_DEST_RD_ATOMIC) {
 | 
				
			||||||
		u8 rra_max;
 | 
							u8 rra_max;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (qp->resp_depth && !attr->max_rd_atomic) {
 | 
							if (qp->resp_depth && !attr->max_dest_rd_atomic) {
 | 
				
			||||||
			/*
 | 
								/*
 | 
				
			||||||
			 * Lowering our responder resources to zero.
 | 
								 * Lowering our responder resources to zero.
 | 
				
			||||||
			 * Turn off RDMA/atomics as responder.
 | 
								 * Turn off RDMA/atomics as responder.
 | 
				
			||||||
| 
						 | 
					@ -778,7 +815,7 @@ int mthca_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, int attr_mask)
 | 
				
			||||||
								MTHCA_QP_OPTPAR_RAE);
 | 
													MTHCA_QP_OPTPAR_RAE);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (!qp->resp_depth && attr->max_rd_atomic) {
 | 
							if (!qp->resp_depth && attr->max_dest_rd_atomic) {
 | 
				
			||||||
			/*
 | 
								/*
 | 
				
			||||||
			 * Increasing our responder resources from
 | 
								 * Increasing our responder resources from
 | 
				
			||||||
			 * zero.  Turn on RDMA/atomics as appropriate.
 | 
								 * zero.  Turn on RDMA/atomics as appropriate.
 | 
				
			||||||
| 
						 | 
					@ -799,7 +836,7 @@ int mthca_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, int attr_mask)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		for (rra_max = 0;
 | 
							for (rra_max = 0;
 | 
				
			||||||
		     1 << rra_max < attr->max_rd_atomic &&
 | 
							     1 << rra_max < attr->max_dest_rd_atomic &&
 | 
				
			||||||
			     rra_max < dev->qp_table.rdb_shift;
 | 
								     rra_max < dev->qp_table.rdb_shift;
 | 
				
			||||||
		     ++rra_max)
 | 
							     ++rra_max)
 | 
				
			||||||
			; /* nothing */
 | 
								; /* nothing */
 | 
				
			||||||
| 
						 | 
					@ -807,7 +844,7 @@ int mthca_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, int attr_mask)
 | 
				
			||||||
		qp_context->params2      |= cpu_to_be32(rra_max << 21);
 | 
							qp_context->params2      |= cpu_to_be32(rra_max << 21);
 | 
				
			||||||
		qp_param->opt_param_mask |= cpu_to_be32(MTHCA_QP_OPTPAR_RRA_MAX);
 | 
							qp_param->opt_param_mask |= cpu_to_be32(MTHCA_QP_OPTPAR_RRA_MAX);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		qp->resp_depth = attr->max_rd_atomic;
 | 
							qp->resp_depth = attr->max_dest_rd_atomic;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	qp_context->params2 |= cpu_to_be32(MTHCA_QP_BIT_RSC);
 | 
						qp_context->params2 |= cpu_to_be32(MTHCA_QP_BIT_RSC);
 | 
				
			||||||
| 
						 | 
					@ -835,7 +872,7 @@ int mthca_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, int attr_mask)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	err = mthca_MODIFY_QP(dev, state_table[cur_state][new_state].trans,
 | 
						err = mthca_MODIFY_QP(dev, state_table[cur_state][new_state].trans,
 | 
				
			||||||
			      qp->qpn, 0, qp_param, 0, &status);
 | 
								      qp->qpn, 0, mailbox, 0, &status);
 | 
				
			||||||
	if (status) {
 | 
						if (status) {
 | 
				
			||||||
		mthca_warn(dev, "modify QP %d returned status %02x.\n",
 | 
							mthca_warn(dev, "modify QP %d returned status %02x.\n",
 | 
				
			||||||
			   state_table[cur_state][new_state].trans, status);
 | 
								   state_table[cur_state][new_state].trans, status);
 | 
				
			||||||
| 
						 | 
					@ -845,7 +882,7 @@ int mthca_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, int attr_mask)
 | 
				
			||||||
	if (!err)
 | 
						if (!err)
 | 
				
			||||||
		qp->state = new_state;
 | 
							qp->state = new_state;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	kfree(mailbox);
 | 
						mthca_free_mailbox(dev, mailbox);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (is_sqp(dev, qp))
 | 
						if (is_sqp(dev, qp))
 | 
				
			||||||
		store_attrs(to_msqp(qp), attr, attr_mask);
 | 
							store_attrs(to_msqp(qp), attr, attr_mask);
 | 
				
			||||||
| 
						 | 
					@ -934,7 +971,8 @@ static int mthca_alloc_wqe_buf(struct mthca_dev *dev,
 | 
				
			||||||
			mthca_dbg(dev, "Creating direct QP of size %d (shift %d)\n",
 | 
								mthca_dbg(dev, "Creating direct QP of size %d (shift %d)\n",
 | 
				
			||||||
				  size, shift);
 | 
									  size, shift);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		qp->queue.direct.buf = pci_alloc_consistent(dev->pdev, size, &t);
 | 
							qp->queue.direct.buf = dma_alloc_coherent(&dev->pdev->dev, size,
 | 
				
			||||||
 | 
												  &t, GFP_KERNEL);
 | 
				
			||||||
		if (!qp->queue.direct.buf)
 | 
							if (!qp->queue.direct.buf)
 | 
				
			||||||
			goto err_out;
 | 
								goto err_out;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -973,7 +1011,8 @@ static int mthca_alloc_wqe_buf(struct mthca_dev *dev,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		for (i = 0; i < npages; ++i) {
 | 
							for (i = 0; i < npages; ++i) {
 | 
				
			||||||
			qp->queue.page_list[i].buf =
 | 
								qp->queue.page_list[i].buf =
 | 
				
			||||||
				pci_alloc_consistent(dev->pdev, PAGE_SIZE, &t);
 | 
									dma_alloc_coherent(&dev->pdev->dev, PAGE_SIZE,
 | 
				
			||||||
 | 
											   &t, GFP_KERNEL);
 | 
				
			||||||
			if (!qp->queue.page_list[i].buf)
 | 
								if (!qp->queue.page_list[i].buf)
 | 
				
			||||||
				goto err_out_free;
 | 
									goto err_out_free;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -996,16 +1035,15 @@ static int mthca_alloc_wqe_buf(struct mthca_dev *dev,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 err_out_free:
 | 
					 err_out_free:
 | 
				
			||||||
	if (qp->is_direct) {
 | 
						if (qp->is_direct) {
 | 
				
			||||||
		pci_free_consistent(dev->pdev, size,
 | 
							dma_free_coherent(&dev->pdev->dev, size, qp->queue.direct.buf,
 | 
				
			||||||
				    qp->queue.direct.buf,
 | 
									  pci_unmap_addr(&qp->queue.direct, mapping));
 | 
				
			||||||
				    pci_unmap_addr(&qp->queue.direct, mapping));
 | 
					 | 
				
			||||||
	} else
 | 
						} else
 | 
				
			||||||
		for (i = 0; i < npages; ++i) {
 | 
							for (i = 0; i < npages; ++i) {
 | 
				
			||||||
			if (qp->queue.page_list[i].buf)
 | 
								if (qp->queue.page_list[i].buf)
 | 
				
			||||||
				pci_free_consistent(dev->pdev, PAGE_SIZE,
 | 
									dma_free_coherent(&dev->pdev->dev, PAGE_SIZE,
 | 
				
			||||||
						    qp->queue.page_list[i].buf,
 | 
											  qp->queue.page_list[i].buf,
 | 
				
			||||||
						    pci_unmap_addr(&qp->queue.page_list[i],
 | 
											  pci_unmap_addr(&qp->queue.page_list[i],
 | 
				
			||||||
								   mapping));
 | 
													 mapping));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1073,11 +1111,12 @@ static void mthca_free_memfree(struct mthca_dev *dev,
 | 
				
			||||||
	if (mthca_is_memfree(dev)) {
 | 
						if (mthca_is_memfree(dev)) {
 | 
				
			||||||
		mthca_free_db(dev, MTHCA_DB_TYPE_SQ, qp->sq.db_index);
 | 
							mthca_free_db(dev, MTHCA_DB_TYPE_SQ, qp->sq.db_index);
 | 
				
			||||||
		mthca_free_db(dev, MTHCA_DB_TYPE_RQ, qp->rq.db_index);
 | 
							mthca_free_db(dev, MTHCA_DB_TYPE_RQ, qp->rq.db_index);
 | 
				
			||||||
		mthca_table_put(dev, dev->qp_table.rdb_table,
 | 
					 | 
				
			||||||
				qp->qpn << dev->qp_table.rdb_shift);
 | 
					 | 
				
			||||||
		mthca_table_put(dev, dev->qp_table.eqp_table, qp->qpn);
 | 
					 | 
				
			||||||
		mthca_table_put(dev, dev->qp_table.qp_table, qp->qpn);
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						mthca_table_put(dev, dev->qp_table.rdb_table,
 | 
				
			||||||
 | 
								qp->qpn << dev->qp_table.rdb_shift);
 | 
				
			||||||
 | 
						mthca_table_put(dev, dev->qp_table.eqp_table, qp->qpn);
 | 
				
			||||||
 | 
						mthca_table_put(dev, dev->qp_table.qp_table, qp->qpn);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void mthca_wq_init(struct mthca_wq* wq)
 | 
					static void mthca_wq_init(struct mthca_wq* wq)
 | 
				
			||||||
| 
						 | 
					@ -1529,6 +1568,26 @@ int mthca_tavor_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							case UC:
 | 
				
			||||||
 | 
								switch (wr->opcode) {
 | 
				
			||||||
 | 
								case IB_WR_RDMA_WRITE:
 | 
				
			||||||
 | 
								case IB_WR_RDMA_WRITE_WITH_IMM:
 | 
				
			||||||
 | 
									((struct mthca_raddr_seg *) wqe)->raddr =
 | 
				
			||||||
 | 
										cpu_to_be64(wr->wr.rdma.remote_addr);
 | 
				
			||||||
 | 
									((struct mthca_raddr_seg *) wqe)->rkey =
 | 
				
			||||||
 | 
										cpu_to_be32(wr->wr.rdma.rkey);
 | 
				
			||||||
 | 
									((struct mthca_raddr_seg *) wqe)->reserved = 0;
 | 
				
			||||||
 | 
									wqe += sizeof (struct mthca_raddr_seg);
 | 
				
			||||||
 | 
									size += sizeof (struct mthca_raddr_seg) / 16;
 | 
				
			||||||
 | 
									break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								default:
 | 
				
			||||||
 | 
									/* No extra segments required for sends */
 | 
				
			||||||
 | 
									break;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		case UD:
 | 
							case UD:
 | 
				
			||||||
			((struct mthca_tavor_ud_seg *) wqe)->lkey =
 | 
								((struct mthca_tavor_ud_seg *) wqe)->lkey =
 | 
				
			||||||
				cpu_to_be32(to_mah(wr->wr.ud.ah)->key);
 | 
									cpu_to_be32(to_mah(wr->wr.ud.ah)->key);
 | 
				
			||||||
| 
						 | 
					@ -1814,9 +1873,29 @@ int mthca_arbel_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr,
 | 
				
			||||||
					sizeof (struct mthca_atomic_seg);
 | 
										sizeof (struct mthca_atomic_seg);
 | 
				
			||||||
				break;
 | 
									break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								case IB_WR_RDMA_READ:
 | 
				
			||||||
 | 
								case IB_WR_RDMA_WRITE:
 | 
				
			||||||
 | 
								case IB_WR_RDMA_WRITE_WITH_IMM:
 | 
				
			||||||
 | 
									((struct mthca_raddr_seg *) wqe)->raddr =
 | 
				
			||||||
 | 
										cpu_to_be64(wr->wr.rdma.remote_addr);
 | 
				
			||||||
 | 
									((struct mthca_raddr_seg *) wqe)->rkey =
 | 
				
			||||||
 | 
										cpu_to_be32(wr->wr.rdma.rkey);
 | 
				
			||||||
 | 
									((struct mthca_raddr_seg *) wqe)->reserved = 0;
 | 
				
			||||||
 | 
									wqe += sizeof (struct mthca_raddr_seg);
 | 
				
			||||||
 | 
									size += sizeof (struct mthca_raddr_seg) / 16;
 | 
				
			||||||
 | 
									break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								default:
 | 
				
			||||||
 | 
									/* No extra segments required for sends */
 | 
				
			||||||
 | 
									break;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							case UC:
 | 
				
			||||||
 | 
								switch (wr->opcode) {
 | 
				
			||||||
			case IB_WR_RDMA_WRITE:
 | 
								case IB_WR_RDMA_WRITE:
 | 
				
			||||||
			case IB_WR_RDMA_WRITE_WITH_IMM:
 | 
								case IB_WR_RDMA_WRITE_WITH_IMM:
 | 
				
			||||||
			case IB_WR_RDMA_READ:
 | 
					 | 
				
			||||||
				((struct mthca_raddr_seg *) wqe)->raddr =
 | 
									((struct mthca_raddr_seg *) wqe)->raddr =
 | 
				
			||||||
					cpu_to_be64(wr->wr.rdma.remote_addr);
 | 
										cpu_to_be64(wr->wr.rdma.remote_addr);
 | 
				
			||||||
				((struct mthca_raddr_seg *) wqe)->rkey =
 | 
									((struct mthca_raddr_seg *) wqe)->rkey =
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -21,6 +21,7 @@
 | 
				
			||||||
#include <linux/smp_lock.h>
 | 
					#include <linux/smp_lock.h>
 | 
				
			||||||
#include <linux/device.h>
 | 
					#include <linux/device.h>
 | 
				
			||||||
#include <linux/devfs_fs_kernel.h>
 | 
					#include <linux/devfs_fs_kernel.h>
 | 
				
			||||||
 | 
					#include <linux/compat.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct evdev {
 | 
					struct evdev {
 | 
				
			||||||
	int exist;
 | 
						int exist;
 | 
				
			||||||
| 
						 | 
					@ -145,6 +146,41 @@ static int evdev_open(struct inode * inode, struct file * file)
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef CONFIG_COMPAT
 | 
				
			||||||
 | 
					struct input_event_compat {
 | 
				
			||||||
 | 
						struct compat_timeval time;
 | 
				
			||||||
 | 
						__u16 type;
 | 
				
			||||||
 | 
						__u16 code;
 | 
				
			||||||
 | 
						__s32 value;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef CONFIG_X86_64
 | 
				
			||||||
 | 
					#  define COMPAT_TEST test_thread_flag(TIF_IA32)
 | 
				
			||||||
 | 
					#elif defined(CONFIG_IA64)
 | 
				
			||||||
 | 
					#  define COMPAT_TEST IS_IA32_PROCESS(ia64_task_regs(current))
 | 
				
			||||||
 | 
					#elif defined(CONFIG_ARCH_S390)
 | 
				
			||||||
 | 
					#  define COMPAT_TEST test_thread_flag(TIF_31BIT)
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
 | 
					#  define COMPAT_TEST test_thread_flag(TIF_32BIT)
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static ssize_t evdev_write_compat(struct file * file, const char __user * buffer, size_t count, loff_t *ppos)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct evdev_list *list = file->private_data;
 | 
				
			||||||
 | 
						struct input_event_compat event;
 | 
				
			||||||
 | 
						int retval = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						while (retval < count) {
 | 
				
			||||||
 | 
							if (copy_from_user(&event, buffer + retval, sizeof(struct input_event_compat)))
 | 
				
			||||||
 | 
								return -EFAULT;
 | 
				
			||||||
 | 
							input_event(list->evdev->handle.dev, event.type, event.code, event.value);
 | 
				
			||||||
 | 
							retval += sizeof(struct input_event_compat);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return retval;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static ssize_t evdev_write(struct file * file, const char __user * buffer, size_t count, loff_t *ppos)
 | 
					static ssize_t evdev_write(struct file * file, const char __user * buffer, size_t count, loff_t *ppos)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct evdev_list *list = file->private_data;
 | 
						struct evdev_list *list = file->private_data;
 | 
				
			||||||
| 
						 | 
					@ -153,6 +189,11 @@ static ssize_t evdev_write(struct file * file, const char __user * buffer, size_
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!list->evdev->exist) return -ENODEV;
 | 
						if (!list->evdev->exist) return -ENODEV;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef CONFIG_COMPAT
 | 
				
			||||||
 | 
						if (COMPAT_TEST)
 | 
				
			||||||
 | 
							return evdev_write_compat(file, buffer, count, ppos);
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	while (retval < count) {
 | 
						while (retval < count) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (copy_from_user(&event, buffer + retval, sizeof(struct input_event)))
 | 
							if (copy_from_user(&event, buffer + retval, sizeof(struct input_event)))
 | 
				
			||||||
| 
						 | 
					@ -164,11 +205,56 @@ static ssize_t evdev_write(struct file * file, const char __user * buffer, size_
 | 
				
			||||||
	return retval;
 | 
						return retval;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef CONFIG_COMPAT
 | 
				
			||||||
 | 
					static ssize_t evdev_read_compat(struct file * file, char __user * buffer, size_t count, loff_t *ppos)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct evdev_list *list = file->private_data;
 | 
				
			||||||
 | 
						int retval;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (count < sizeof(struct input_event_compat))
 | 
				
			||||||
 | 
							return -EINVAL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (list->head == list->tail && list->evdev->exist && (file->f_flags & O_NONBLOCK))
 | 
				
			||||||
 | 
							return -EAGAIN;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						retval = wait_event_interruptible(list->evdev->wait,
 | 
				
			||||||
 | 
							list->head != list->tail || (!list->evdev->exist));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (retval)
 | 
				
			||||||
 | 
							return retval;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!list->evdev->exist)
 | 
				
			||||||
 | 
							return -ENODEV;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						while (list->head != list->tail && retval + sizeof(struct input_event_compat) <= count) {
 | 
				
			||||||
 | 
							struct input_event *event = (struct input_event *) list->buffer + list->tail;
 | 
				
			||||||
 | 
							struct input_event_compat event_compat;
 | 
				
			||||||
 | 
							event_compat.time.tv_sec = event->time.tv_sec;
 | 
				
			||||||
 | 
							event_compat.time.tv_usec = event->time.tv_usec;
 | 
				
			||||||
 | 
							event_compat.type = event->type;
 | 
				
			||||||
 | 
							event_compat.code = event->code;
 | 
				
			||||||
 | 
							event_compat.value = event->value;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (copy_to_user(buffer + retval, &event_compat,
 | 
				
			||||||
 | 
								sizeof(struct input_event_compat))) return -EFAULT;
 | 
				
			||||||
 | 
							list->tail = (list->tail + 1) & (EVDEV_BUFFER_SIZE - 1);
 | 
				
			||||||
 | 
							retval += sizeof(struct input_event_compat);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return retval;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static ssize_t evdev_read(struct file * file, char __user * buffer, size_t count, loff_t *ppos)
 | 
					static ssize_t evdev_read(struct file * file, char __user * buffer, size_t count, loff_t *ppos)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct evdev_list *list = file->private_data;
 | 
						struct evdev_list *list = file->private_data;
 | 
				
			||||||
	int retval;
 | 
						int retval;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef CONFIG_COMPAT
 | 
				
			||||||
 | 
						if (COMPAT_TEST)
 | 
				
			||||||
 | 
							return evdev_read_compat(file, buffer, count, ppos);
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (count < sizeof(struct input_event))
 | 
						if (count < sizeof(struct input_event))
 | 
				
			||||||
		return -EINVAL;
 | 
							return -EINVAL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -186,7 +272,7 @@ static ssize_t evdev_read(struct file * file, char __user * buffer, size_t count
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	while (list->head != list->tail && retval + sizeof(struct input_event) <= count) {
 | 
						while (list->head != list->tail && retval + sizeof(struct input_event) <= count) {
 | 
				
			||||||
		if (copy_to_user(buffer + retval, list->buffer + list->tail,
 | 
							if (copy_to_user(buffer + retval, list->buffer + list->tail,
 | 
				
			||||||
			 sizeof(struct input_event))) return -EFAULT;
 | 
								sizeof(struct input_event))) return -EFAULT;
 | 
				
			||||||
		list->tail = (list->tail + 1) & (EVDEV_BUFFER_SIZE - 1);
 | 
							list->tail = (list->tail + 1) & (EVDEV_BUFFER_SIZE - 1);
 | 
				
			||||||
		retval += sizeof(struct input_event);
 | 
							retval += sizeof(struct input_event);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					@ -203,7 +289,7 @@ static unsigned int evdev_poll(struct file *file, poll_table *wait)
 | 
				
			||||||
		(list->evdev->exist ? 0 : (POLLHUP | POLLERR));
 | 
							(list->evdev->exist ? 0 : (POLLHUP | POLLERR));
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int evdev_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
 | 
					static long evdev_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct evdev_list *list = file->private_data;
 | 
						struct evdev_list *list = file->private_data;
 | 
				
			||||||
	struct evdev *evdev = list->evdev;
 | 
						struct evdev *evdev = list->evdev;
 | 
				
			||||||
| 
						 | 
					@ -285,110 +371,268 @@ static int evdev_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		default:
 | 
							default:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			if (_IOC_TYPE(cmd) != 'E' || _IOC_DIR(cmd) != _IOC_READ)
 | 
								if (_IOC_TYPE(cmd) != 'E')
 | 
				
			||||||
				return -EINVAL;
 | 
									return -EINVAL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			if ((_IOC_NR(cmd) & ~EV_MAX) == _IOC_NR(EVIOCGBIT(0,0))) {
 | 
								if (_IOC_DIR(cmd) == _IOC_READ) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
				long *bits;
 | 
									if ((_IOC_NR(cmd) & ~EV_MAX) == _IOC_NR(EVIOCGBIT(0,0))) {
 | 
				
			||||||
				int len;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
				switch (_IOC_NR(cmd) & EV_MAX) {
 | 
										long *bits;
 | 
				
			||||||
					case      0: bits = dev->evbit;  len = EV_MAX;  break;
 | 
										int len;
 | 
				
			||||||
					case EV_KEY: bits = dev->keybit; len = KEY_MAX; break;
 | 
					
 | 
				
			||||||
					case EV_REL: bits = dev->relbit; len = REL_MAX; break;
 | 
										switch (_IOC_NR(cmd) & EV_MAX) {
 | 
				
			||||||
					case EV_ABS: bits = dev->absbit; len = ABS_MAX; break;
 | 
											case      0: bits = dev->evbit;  len = EV_MAX;  break;
 | 
				
			||||||
					case EV_MSC: bits = dev->mscbit; len = MSC_MAX; break;
 | 
											case EV_KEY: bits = dev->keybit; len = KEY_MAX; break;
 | 
				
			||||||
					case EV_LED: bits = dev->ledbit; len = LED_MAX; break;
 | 
											case EV_REL: bits = dev->relbit; len = REL_MAX; break;
 | 
				
			||||||
					case EV_SND: bits = dev->sndbit; len = SND_MAX; break;
 | 
											case EV_ABS: bits = dev->absbit; len = ABS_MAX; break;
 | 
				
			||||||
					case EV_FF:  bits = dev->ffbit;  len = FF_MAX;  break;
 | 
											case EV_MSC: bits = dev->mscbit; len = MSC_MAX; break;
 | 
				
			||||||
					default: return -EINVAL;
 | 
											case EV_LED: bits = dev->ledbit; len = LED_MAX; break;
 | 
				
			||||||
 | 
											case EV_SND: bits = dev->sndbit; len = SND_MAX; break;
 | 
				
			||||||
 | 
											case EV_FF:  bits = dev->ffbit;  len = FF_MAX;  break;
 | 
				
			||||||
 | 
											default: return -EINVAL;
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
										len = NBITS(len) * sizeof(long);
 | 
				
			||||||
 | 
										if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd);
 | 
				
			||||||
 | 
										return copy_to_user(p, bits, len) ? -EFAULT : len;
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
				len = NBITS(len) * sizeof(long);
 | 
					
 | 
				
			||||||
				if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd);
 | 
									if (_IOC_NR(cmd) == _IOC_NR(EVIOCGKEY(0))) {
 | 
				
			||||||
				return copy_to_user(p, bits, len) ? -EFAULT : len;
 | 
										int len;
 | 
				
			||||||
 | 
										len = NBITS(KEY_MAX) * sizeof(long);
 | 
				
			||||||
 | 
										if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd);
 | 
				
			||||||
 | 
										return copy_to_user(p, dev->key, len) ? -EFAULT : len;
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									if (_IOC_NR(cmd) == _IOC_NR(EVIOCGLED(0))) {
 | 
				
			||||||
 | 
										int len;
 | 
				
			||||||
 | 
										len = NBITS(LED_MAX) * sizeof(long);
 | 
				
			||||||
 | 
										if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd);
 | 
				
			||||||
 | 
										return copy_to_user(p, dev->led, len) ? -EFAULT : len;
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									if (_IOC_NR(cmd) == _IOC_NR(EVIOCGSND(0))) {
 | 
				
			||||||
 | 
										int len;
 | 
				
			||||||
 | 
										len = NBITS(SND_MAX) * sizeof(long);
 | 
				
			||||||
 | 
										if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd);
 | 
				
			||||||
 | 
										return copy_to_user(p, dev->snd, len) ? -EFAULT : len;
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									if (_IOC_NR(cmd) == _IOC_NR(EVIOCGNAME(0))) {
 | 
				
			||||||
 | 
										int len;
 | 
				
			||||||
 | 
										if (!dev->name) return -ENOENT;
 | 
				
			||||||
 | 
										len = strlen(dev->name) + 1;
 | 
				
			||||||
 | 
										if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd);
 | 
				
			||||||
 | 
										return copy_to_user(p, dev->name, len) ? -EFAULT : len;
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									if (_IOC_NR(cmd) == _IOC_NR(EVIOCGPHYS(0))) {
 | 
				
			||||||
 | 
										int len;
 | 
				
			||||||
 | 
										if (!dev->phys) return -ENOENT;
 | 
				
			||||||
 | 
										len = strlen(dev->phys) + 1;
 | 
				
			||||||
 | 
										if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd);
 | 
				
			||||||
 | 
										return copy_to_user(p, dev->phys, len) ? -EFAULT : len;
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									if (_IOC_NR(cmd) == _IOC_NR(EVIOCGUNIQ(0))) {
 | 
				
			||||||
 | 
										int len;
 | 
				
			||||||
 | 
										if (!dev->uniq) return -ENOENT;
 | 
				
			||||||
 | 
										len = strlen(dev->uniq) + 1;
 | 
				
			||||||
 | 
										if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd);
 | 
				
			||||||
 | 
										return copy_to_user(p, dev->uniq, len) ? -EFAULT : len;
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									if ((_IOC_NR(cmd) & ~ABS_MAX) == _IOC_NR(EVIOCGABS(0))) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										int t = _IOC_NR(cmd) & ABS_MAX;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										abs.value = dev->abs[t];
 | 
				
			||||||
 | 
										abs.minimum = dev->absmin[t];
 | 
				
			||||||
 | 
										abs.maximum = dev->absmax[t];
 | 
				
			||||||
 | 
										abs.fuzz = dev->absfuzz[t];
 | 
				
			||||||
 | 
										abs.flat = dev->absflat[t];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										if (copy_to_user(p, &abs, sizeof(struct input_absinfo)))
 | 
				
			||||||
 | 
											return -EFAULT;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										return 0;
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			if (_IOC_NR(cmd) == _IOC_NR(EVIOCGKEY(0))) {
 | 
								if (_IOC_DIR(cmd) == _IOC_WRITE) {
 | 
				
			||||||
				int len;
 | 
					 | 
				
			||||||
				len = NBITS(KEY_MAX) * sizeof(long);
 | 
					 | 
				
			||||||
				if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd);
 | 
					 | 
				
			||||||
				return copy_to_user(p, dev->key, len) ? -EFAULT : len;
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
			if (_IOC_NR(cmd) == _IOC_NR(EVIOCGLED(0))) {
 | 
									if ((_IOC_NR(cmd) & ~ABS_MAX) == _IOC_NR(EVIOCSABS(0))) {
 | 
				
			||||||
				int len;
 | 
					 | 
				
			||||||
				len = NBITS(LED_MAX) * sizeof(long);
 | 
					 | 
				
			||||||
				if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd);
 | 
					 | 
				
			||||||
				return copy_to_user(p, dev->led, len) ? -EFAULT : len;
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
			if (_IOC_NR(cmd) == _IOC_NR(EVIOCGSND(0))) {
 | 
										int t = _IOC_NR(cmd) & ABS_MAX;
 | 
				
			||||||
				int len;
 | 
					 | 
				
			||||||
				len = NBITS(SND_MAX) * sizeof(long);
 | 
					 | 
				
			||||||
				if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd);
 | 
					 | 
				
			||||||
				return copy_to_user(p, dev->snd, len) ? -EFAULT : len;
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
			if (_IOC_NR(cmd) == _IOC_NR(EVIOCGNAME(0))) {
 | 
										if (copy_from_user(&abs, p, sizeof(struct input_absinfo)))
 | 
				
			||||||
				int len;
 | 
											return -EFAULT;
 | 
				
			||||||
				if (!dev->name) return -ENOENT;
 | 
					 | 
				
			||||||
				len = strlen(dev->name) + 1;
 | 
					 | 
				
			||||||
				if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd);
 | 
					 | 
				
			||||||
				return copy_to_user(p, dev->name, len) ? -EFAULT : len;
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
			if (_IOC_NR(cmd) == _IOC_NR(EVIOCGPHYS(0))) {
 | 
										dev->abs[t] = abs.value;
 | 
				
			||||||
				int len;
 | 
										dev->absmin[t] = abs.minimum;
 | 
				
			||||||
				if (!dev->phys) return -ENOENT;
 | 
										dev->absmax[t] = abs.maximum;
 | 
				
			||||||
				len = strlen(dev->phys) + 1;
 | 
										dev->absfuzz[t] = abs.fuzz;
 | 
				
			||||||
				if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd);
 | 
										dev->absflat[t] = abs.flat;
 | 
				
			||||||
				return copy_to_user(p, dev->phys, len) ? -EFAULT : len;
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
			if (_IOC_NR(cmd) == _IOC_NR(EVIOCGUNIQ(0))) {
 | 
										return 0;
 | 
				
			||||||
				int len;
 | 
									}
 | 
				
			||||||
				if (!dev->uniq) return -ENOENT;
 | 
					 | 
				
			||||||
				len = strlen(dev->uniq) + 1;
 | 
					 | 
				
			||||||
				if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd);
 | 
					 | 
				
			||||||
				return copy_to_user(p, dev->uniq, len) ? -EFAULT : len;
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			if ((_IOC_NR(cmd) & ~ABS_MAX) == _IOC_NR(EVIOCGABS(0))) {
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
				int t = _IOC_NR(cmd) & ABS_MAX;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
				abs.value = dev->abs[t];
 | 
					 | 
				
			||||||
				abs.minimum = dev->absmin[t];
 | 
					 | 
				
			||||||
				abs.maximum = dev->absmax[t];
 | 
					 | 
				
			||||||
				abs.fuzz = dev->absfuzz[t];
 | 
					 | 
				
			||||||
				abs.flat = dev->absflat[t];
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
				if (copy_to_user(p, &abs, sizeof(struct input_absinfo)))
 | 
					 | 
				
			||||||
					return -EFAULT;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
				return 0;
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			if ((_IOC_NR(cmd) & ~ABS_MAX) == _IOC_NR(EVIOCSABS(0))) {
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
				int t = _IOC_NR(cmd) & ABS_MAX;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
				if (copy_from_user(&abs, p, sizeof(struct input_absinfo)))
 | 
					 | 
				
			||||||
					return -EFAULT;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
				dev->abs[t] = abs.value;
 | 
					 | 
				
			||||||
				dev->absmin[t] = abs.minimum;
 | 
					 | 
				
			||||||
				dev->absmax[t] = abs.maximum;
 | 
					 | 
				
			||||||
				dev->absfuzz[t] = abs.fuzz;
 | 
					 | 
				
			||||||
				dev->absflat[t] = abs.flat;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
				return 0;
 | 
					 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return -EINVAL;
 | 
						return -EINVAL;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef CONFIG_COMPAT
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define BITS_PER_LONG_COMPAT (sizeof(compat_long_t) * 8)
 | 
				
			||||||
 | 
					#define NBITS_COMPAT(x) ((((x)-1)/BITS_PER_LONG_COMPAT)+1)
 | 
				
			||||||
 | 
					#define OFF_COMPAT(x)  ((x)%BITS_PER_LONG_COMPAT)
 | 
				
			||||||
 | 
					#define BIT_COMPAT(x)  (1UL<<OFF_COMPAT(x))
 | 
				
			||||||
 | 
					#define LONG_COMPAT(x) ((x)/BITS_PER_LONG_COMPAT)
 | 
				
			||||||
 | 
					#define test_bit_compat(bit, array) ((array[LONG_COMPAT(bit)] >> OFF_COMPAT(bit)) & 1)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef __BIG_ENDIAN
 | 
				
			||||||
 | 
					#define bit_to_user(bit, max) \
 | 
				
			||||||
 | 
					do { \
 | 
				
			||||||
 | 
						int i; \
 | 
				
			||||||
 | 
						int len = NBITS_COMPAT((max)) * sizeof(compat_long_t); \
 | 
				
			||||||
 | 
						if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd); \
 | 
				
			||||||
 | 
						for (i = 0; i < len / sizeof(compat_long_t); i++) \
 | 
				
			||||||
 | 
							if (copy_to_user((compat_long_t*) p + i, \
 | 
				
			||||||
 | 
									 (compat_long_t*) (bit) + i + 1 - ((i % 2) << 1), \
 | 
				
			||||||
 | 
									 sizeof(compat_long_t))) \
 | 
				
			||||||
 | 
								return -EFAULT; \
 | 
				
			||||||
 | 
						return len; \
 | 
				
			||||||
 | 
					} while (0)
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
 | 
					#define bit_to_user(bit, max) \
 | 
				
			||||||
 | 
					do { \
 | 
				
			||||||
 | 
						int len = NBITS_COMPAT((max)) * sizeof(compat_long_t); \
 | 
				
			||||||
 | 
						if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd); \
 | 
				
			||||||
 | 
						return copy_to_user(p, (bit), len) ? -EFAULT : len; \
 | 
				
			||||||
 | 
					} while (0)
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static long evdev_ioctl_compat(struct file *file, unsigned int cmd, unsigned long arg)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct evdev_list *list = file->private_data;
 | 
				
			||||||
 | 
						struct evdev *evdev = list->evdev;
 | 
				
			||||||
 | 
						struct input_dev *dev = evdev->handle.dev;
 | 
				
			||||||
 | 
						struct input_absinfo abs;
 | 
				
			||||||
 | 
						void __user *p = compat_ptr(arg);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!evdev->exist) return -ENODEV;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						switch (cmd) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							case EVIOCGVERSION:
 | 
				
			||||||
 | 
							case EVIOCGID:
 | 
				
			||||||
 | 
							case EVIOCGKEYCODE:
 | 
				
			||||||
 | 
							case EVIOCSKEYCODE:
 | 
				
			||||||
 | 
							case EVIOCSFF:
 | 
				
			||||||
 | 
							case EVIOCRMFF:
 | 
				
			||||||
 | 
							case EVIOCGEFFECTS:
 | 
				
			||||||
 | 
							case EVIOCGRAB:
 | 
				
			||||||
 | 
								return evdev_ioctl(file, cmd, (unsigned long) p);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							default:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (_IOC_TYPE(cmd) != 'E')
 | 
				
			||||||
 | 
									return -EINVAL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (_IOC_DIR(cmd) == _IOC_READ) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									if ((_IOC_NR(cmd) & ~EV_MAX) == _IOC_NR(EVIOCGBIT(0,0))) {
 | 
				
			||||||
 | 
										long *bits;
 | 
				
			||||||
 | 
										int max;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										switch (_IOC_NR(cmd) & EV_MAX) {
 | 
				
			||||||
 | 
											case      0: bits = dev->evbit;  max = EV_MAX;  break;
 | 
				
			||||||
 | 
											case EV_KEY: bits = dev->keybit; max = KEY_MAX; break;
 | 
				
			||||||
 | 
											case EV_REL: bits = dev->relbit; max = REL_MAX; break;
 | 
				
			||||||
 | 
											case EV_ABS: bits = dev->absbit; max = ABS_MAX; break;
 | 
				
			||||||
 | 
											case EV_MSC: bits = dev->mscbit; max = MSC_MAX; break;
 | 
				
			||||||
 | 
											case EV_LED: bits = dev->ledbit; max = LED_MAX; break;
 | 
				
			||||||
 | 
											case EV_SND: bits = dev->sndbit; max = SND_MAX; break;
 | 
				
			||||||
 | 
											case EV_FF:  bits = dev->ffbit;  max = FF_MAX;  break;
 | 
				
			||||||
 | 
											default: return -EINVAL;
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
										bit_to_user(bits, max);
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									if (_IOC_NR(cmd) == _IOC_NR(EVIOCGKEY(0)))
 | 
				
			||||||
 | 
										bit_to_user(dev->key, KEY_MAX);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									if (_IOC_NR(cmd) == _IOC_NR(EVIOCGLED(0)))
 | 
				
			||||||
 | 
										bit_to_user(dev->led, LED_MAX);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									if (_IOC_NR(cmd) == _IOC_NR(EVIOCGSND(0)))
 | 
				
			||||||
 | 
										bit_to_user(dev->snd, SND_MAX);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									if (_IOC_NR(cmd) == _IOC_NR(EVIOCGNAME(0))) {
 | 
				
			||||||
 | 
										int len;
 | 
				
			||||||
 | 
										if (!dev->name) return -ENOENT;
 | 
				
			||||||
 | 
										len = strlen(dev->name) + 1;
 | 
				
			||||||
 | 
										if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd);
 | 
				
			||||||
 | 
										return copy_to_user(p, dev->name, len) ? -EFAULT : len;
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									if (_IOC_NR(cmd) == _IOC_NR(EVIOCGPHYS(0))) {
 | 
				
			||||||
 | 
										int len;
 | 
				
			||||||
 | 
										if (!dev->phys) return -ENOENT;
 | 
				
			||||||
 | 
										len = strlen(dev->phys) + 1;
 | 
				
			||||||
 | 
										if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd);
 | 
				
			||||||
 | 
										return copy_to_user(p, dev->phys, len) ? -EFAULT : len;
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									if (_IOC_NR(cmd) == _IOC_NR(EVIOCGUNIQ(0))) {
 | 
				
			||||||
 | 
										int len;
 | 
				
			||||||
 | 
										if (!dev->uniq) return -ENOENT;
 | 
				
			||||||
 | 
										len = strlen(dev->uniq) + 1;
 | 
				
			||||||
 | 
										if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd);
 | 
				
			||||||
 | 
										return copy_to_user(p, dev->uniq, len) ? -EFAULT : len;
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									if ((_IOC_NR(cmd) & ~ABS_MAX) == _IOC_NR(EVIOCGABS(0))) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										int t = _IOC_NR(cmd) & ABS_MAX;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										abs.value = dev->abs[t];
 | 
				
			||||||
 | 
										abs.minimum = dev->absmin[t];
 | 
				
			||||||
 | 
										abs.maximum = dev->absmax[t];
 | 
				
			||||||
 | 
										abs.fuzz = dev->absfuzz[t];
 | 
				
			||||||
 | 
										abs.flat = dev->absflat[t];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										if (copy_to_user(p, &abs, sizeof(struct input_absinfo)))
 | 
				
			||||||
 | 
											return -EFAULT;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										return 0;
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (_IOC_DIR(cmd) == _IOC_WRITE) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									if ((_IOC_NR(cmd) & ~ABS_MAX) == _IOC_NR(EVIOCSABS(0))) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										int t = _IOC_NR(cmd) & ABS_MAX;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										if (copy_from_user(&abs, p, sizeof(struct input_absinfo)))
 | 
				
			||||||
 | 
											return -EFAULT;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										dev->abs[t] = abs.value;
 | 
				
			||||||
 | 
										dev->absmin[t] = abs.minimum;
 | 
				
			||||||
 | 
										dev->absmax[t] = abs.maximum;
 | 
				
			||||||
 | 
										dev->absfuzz[t] = abs.fuzz;
 | 
				
			||||||
 | 
										dev->absflat[t] = abs.flat;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										return 0;
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return -EINVAL;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static struct file_operations evdev_fops = {
 | 
					static struct file_operations evdev_fops = {
 | 
				
			||||||
	.owner =	THIS_MODULE,
 | 
						.owner =	THIS_MODULE,
 | 
				
			||||||
	.read =		evdev_read,
 | 
						.read =		evdev_read,
 | 
				
			||||||
| 
						 | 
					@ -396,7 +640,10 @@ static struct file_operations evdev_fops = {
 | 
				
			||||||
	.poll =		evdev_poll,
 | 
						.poll =		evdev_poll,
 | 
				
			||||||
	.open =		evdev_open,
 | 
						.open =		evdev_open,
 | 
				
			||||||
	.release =	evdev_release,
 | 
						.release =	evdev_release,
 | 
				
			||||||
	.ioctl =	evdev_ioctl,
 | 
						.unlocked_ioctl = evdev_ioctl,
 | 
				
			||||||
 | 
					#ifdef CONFIG_COMPAT
 | 
				
			||||||
 | 
						.compat_ioctl =	evdev_ioctl_compat,
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
	.fasync =	evdev_fasync,
 | 
						.fasync =	evdev_fasync,
 | 
				
			||||||
	.flush =	evdev_flush
 | 
						.flush =	evdev_flush
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -49,22 +49,8 @@ config GAMEPORT_EMU10K1
 | 
				
			||||||
	  To compile this driver as a module, choose M here: the
 | 
						  To compile this driver as a module, choose M here: the
 | 
				
			||||||
	  module will be called emu10k1-gp.
 | 
						  module will be called emu10k1-gp.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
config GAMEPORT_VORTEX
 | 
					 | 
				
			||||||
	tristate "Aureal Vortex, Vortex 2 gameport support"
 | 
					 | 
				
			||||||
	depends on PCI
 | 
					 | 
				
			||||||
	help
 | 
					 | 
				
			||||||
	  Say Y here if you have an Aureal Vortex 1 or 2  card and want
 | 
					 | 
				
			||||||
	  to use its gameport.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	  To compile this driver as a module, choose M here: the
 | 
					 | 
				
			||||||
	  module will be called vortex.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
config GAMEPORT_FM801
 | 
					config GAMEPORT_FM801
 | 
				
			||||||
	tristate "ForteMedia FM801 gameport support"
 | 
						tristate "ForteMedia FM801 gameport support"
 | 
				
			||||||
	depends on PCI
 | 
						depends on PCI
 | 
				
			||||||
 | 
					
 | 
				
			||||||
config GAMEPORT_CS461X
 | 
					 | 
				
			||||||
	tristate "Crystal SoundFusion gameport support"
 | 
					 | 
				
			||||||
	depends on PCI
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
endif
 | 
					endif
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -5,9 +5,7 @@
 | 
				
			||||||
# Each configuration option enables a list of files.
 | 
					# Each configuration option enables a list of files.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
obj-$(CONFIG_GAMEPORT)		+= gameport.o
 | 
					obj-$(CONFIG_GAMEPORT)		+= gameport.o
 | 
				
			||||||
obj-$(CONFIG_GAMEPORT_CS461X)	+= cs461x.o
 | 
					 | 
				
			||||||
obj-$(CONFIG_GAMEPORT_EMU10K1)	+= emu10k1-gp.o
 | 
					obj-$(CONFIG_GAMEPORT_EMU10K1)	+= emu10k1-gp.o
 | 
				
			||||||
obj-$(CONFIG_GAMEPORT_FM801)	+= fm801-gp.o
 | 
					obj-$(CONFIG_GAMEPORT_FM801)	+= fm801-gp.o
 | 
				
			||||||
obj-$(CONFIG_GAMEPORT_L4)	+= lightning.o
 | 
					obj-$(CONFIG_GAMEPORT_L4)	+= lightning.o
 | 
				
			||||||
obj-$(CONFIG_GAMEPORT_NS558)	+= ns558.o
 | 
					obj-$(CONFIG_GAMEPORT_NS558)	+= ns558.o
 | 
				
			||||||
obj-$(CONFIG_GAMEPORT_VORTEX)	+= vortex.o
 | 
					 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,322 +0,0 @@
 | 
				
			||||||
/*
 | 
					 | 
				
			||||||
	The all defines and part of code (such as cs461x_*) are
 | 
					 | 
				
			||||||
	contributed from ALSA 0.5.8 sources.
 | 
					 | 
				
			||||||
	See http://www.alsa-project.org/ for sources
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	Tested on Linux 686 2.4.0-test9, ALSA 0.5.8a and CS4610
 | 
					 | 
				
			||||||
*/
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <asm/io.h>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <linux/module.h>
 | 
					 | 
				
			||||||
#include <linux/ioport.h>
 | 
					 | 
				
			||||||
#include <linux/config.h>
 | 
					 | 
				
			||||||
#include <linux/init.h>
 | 
					 | 
				
			||||||
#include <linux/gameport.h>
 | 
					 | 
				
			||||||
#include <linux/slab.h>
 | 
					 | 
				
			||||||
#include <linux/pci.h>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
MODULE_AUTHOR("Victor Krapivin");
 | 
					 | 
				
			||||||
MODULE_LICENSE("GPL");
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/*
 | 
					 | 
				
			||||||
	These options are experimental
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#define CS461X_FULL_MAP
 | 
					 | 
				
			||||||
*/
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#ifndef PCI_VENDOR_ID_CIRRUS
 | 
					 | 
				
			||||||
#define PCI_VENDOR_ID_CIRRUS            0x1013
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
#ifndef PCI_DEVICE_ID_CIRRUS_4610
 | 
					 | 
				
			||||||
#define PCI_DEVICE_ID_CIRRUS_4610       0x6001
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
#ifndef PCI_DEVICE_ID_CIRRUS_4612
 | 
					 | 
				
			||||||
#define PCI_DEVICE_ID_CIRRUS_4612       0x6003
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
#ifndef PCI_DEVICE_ID_CIRRUS_4615
 | 
					 | 
				
			||||||
#define PCI_DEVICE_ID_CIRRUS_4615       0x6004
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/* Registers */
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#define BA0_JSPT                                0x00000480
 | 
					 | 
				
			||||||
#define BA0_JSCTL                               0x00000484
 | 
					 | 
				
			||||||
#define BA0_JSC1                                0x00000488
 | 
					 | 
				
			||||||
#define BA0_JSC2                                0x0000048C
 | 
					 | 
				
			||||||
#define BA0_JSIO                                0x000004A0
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/* Bits for JSPT */
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#define JSPT_CAX                                0x00000001
 | 
					 | 
				
			||||||
#define JSPT_CAY                                0x00000002
 | 
					 | 
				
			||||||
#define JSPT_CBX                                0x00000004
 | 
					 | 
				
			||||||
#define JSPT_CBY                                0x00000008
 | 
					 | 
				
			||||||
#define JSPT_BA1                                0x00000010
 | 
					 | 
				
			||||||
#define JSPT_BA2                                0x00000020
 | 
					 | 
				
			||||||
#define JSPT_BB1                                0x00000040
 | 
					 | 
				
			||||||
#define JSPT_BB2                                0x00000080
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/* Bits for JSCTL */
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#define JSCTL_SP_MASK                           0x00000003
 | 
					 | 
				
			||||||
#define JSCTL_SP_SLOW                           0x00000000
 | 
					 | 
				
			||||||
#define JSCTL_SP_MEDIUM_SLOW                    0x00000001
 | 
					 | 
				
			||||||
#define JSCTL_SP_MEDIUM_FAST                    0x00000002
 | 
					 | 
				
			||||||
#define JSCTL_SP_FAST                           0x00000003
 | 
					 | 
				
			||||||
#define JSCTL_ARE                               0x00000004
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/* Data register pairs masks */
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#define JSC1_Y1V_MASK                           0x0000FFFF
 | 
					 | 
				
			||||||
#define JSC1_X1V_MASK                           0xFFFF0000
 | 
					 | 
				
			||||||
#define JSC1_Y1V_SHIFT                          0
 | 
					 | 
				
			||||||
#define JSC1_X1V_SHIFT                          16
 | 
					 | 
				
			||||||
#define JSC2_Y2V_MASK                           0x0000FFFF
 | 
					 | 
				
			||||||
#define JSC2_X2V_MASK                           0xFFFF0000
 | 
					 | 
				
			||||||
#define JSC2_Y2V_SHIFT                          0
 | 
					 | 
				
			||||||
#define JSC2_X2V_SHIFT                          16
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/* JS GPIO */
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#define JSIO_DAX                                0x00000001
 | 
					 | 
				
			||||||
#define JSIO_DAY                                0x00000002
 | 
					 | 
				
			||||||
#define JSIO_DBX                                0x00000004
 | 
					 | 
				
			||||||
#define JSIO_DBY                                0x00000008
 | 
					 | 
				
			||||||
#define JSIO_AXOE                               0x00000010
 | 
					 | 
				
			||||||
#define JSIO_AYOE                               0x00000020
 | 
					 | 
				
			||||||
#define JSIO_BXOE                               0x00000040
 | 
					 | 
				
			||||||
#define JSIO_BYOE                               0x00000080
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/*
 | 
					 | 
				
			||||||
   The card initialization code is obfuscated; the module cs461x
 | 
					 | 
				
			||||||
   need to be loaded after ALSA modules initialized and something
 | 
					 | 
				
			||||||
   played on the CS 4610 chip (see sources for details of CS4610
 | 
					 | 
				
			||||||
   initialization code from ALSA)
 | 
					 | 
				
			||||||
*/
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/* Card specific definitions */
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#define CS461X_BA0_SIZE         0x2000
 | 
					 | 
				
			||||||
#define CS461X_BA1_DATA0_SIZE   0x3000
 | 
					 | 
				
			||||||
#define CS461X_BA1_DATA1_SIZE   0x3800
 | 
					 | 
				
			||||||
#define CS461X_BA1_PRG_SIZE     0x7000
 | 
					 | 
				
			||||||
#define CS461X_BA1_REG_SIZE     0x0100
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#define BA1_SP_DMEM0                            0x00000000
 | 
					 | 
				
			||||||
#define BA1_SP_DMEM1                            0x00010000
 | 
					 | 
				
			||||||
#define BA1_SP_PMEM                             0x00020000
 | 
					 | 
				
			||||||
#define BA1_SP_REG                              0x00030000
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#define BA1_DWORD_SIZE          (13 * 1024 + 512)
 | 
					 | 
				
			||||||
#define BA1_MEMORY_COUNT        3
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/*
 | 
					 | 
				
			||||||
   Only one CS461x card is still suppoted; the code requires
 | 
					 | 
				
			||||||
   redesign to avoid this limitatuion.
 | 
					 | 
				
			||||||
*/
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static unsigned long ba0_addr;
 | 
					 | 
				
			||||||
static unsigned int __iomem *ba0;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#ifdef CS461X_FULL_MAP
 | 
					 | 
				
			||||||
static unsigned long ba1_addr;
 | 
					 | 
				
			||||||
static union ba1_t {
 | 
					 | 
				
			||||||
        struct {
 | 
					 | 
				
			||||||
                unsigned int __iomem *data0;
 | 
					 | 
				
			||||||
                unsigned int __iomem *data1;
 | 
					 | 
				
			||||||
                unsigned int __iomem *pmem;
 | 
					 | 
				
			||||||
                unsigned int __iomem *reg;
 | 
					 | 
				
			||||||
        } name;
 | 
					 | 
				
			||||||
        unsigned int __iomem *idx[4];
 | 
					 | 
				
			||||||
} ba1;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static void cs461x_poke(unsigned long reg, unsigned int val)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
        writel(val, &ba1.idx[(reg >> 16) & 3][(reg >> 2) & 0x3fff]);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static unsigned int cs461x_peek(unsigned long reg)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
        return readl(&ba1.idx[(reg >> 16) & 3][(reg >> 2) & 0x3fff]);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static void cs461x_pokeBA0(unsigned long reg, unsigned int val)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
        writel(val, &ba0[reg >> 2]);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static unsigned int cs461x_peekBA0(unsigned long reg)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
        return readl(&ba0[reg >> 2]);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static int cs461x_free(struct pci_dev *pdev)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	struct gameport *port = pci_get_drvdata(pdev);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (port)
 | 
					 | 
				
			||||||
	    gameport_unregister_port(port);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (ba0) iounmap(ba0);
 | 
					 | 
				
			||||||
#ifdef CS461X_FULL_MAP
 | 
					 | 
				
			||||||
	if (ba1.name.data0) iounmap(ba1.name.data0);
 | 
					 | 
				
			||||||
	if (ba1.name.data1) iounmap(ba1.name.data1);
 | 
					 | 
				
			||||||
	if (ba1.name.pmem)  iounmap(ba1.name.pmem);
 | 
					 | 
				
			||||||
	if (ba1.name.reg)   iounmap(ba1.name.reg);
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
	return 0;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static void cs461x_gameport_trigger(struct gameport *gameport)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	cs461x_pokeBA0(BA0_JSPT, 0xFF);  //outb(gameport->io, 0xFF);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static unsigned char cs461x_gameport_read(struct gameport *gameport)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	return cs461x_peekBA0(BA0_JSPT); //inb(gameport->io);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static int cs461x_gameport_cooked_read(struct gameport *gameport, int *axes, int *buttons)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	unsigned js1, js2, jst;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	js1 = cs461x_peekBA0(BA0_JSC1);
 | 
					 | 
				
			||||||
	js2 = cs461x_peekBA0(BA0_JSC2);
 | 
					 | 
				
			||||||
	jst = cs461x_peekBA0(BA0_JSPT);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	*buttons = (~jst >> 4) & 0x0F;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	axes[0] = ((js1 & JSC1_Y1V_MASK) >> JSC1_Y1V_SHIFT) & 0xFFFF;
 | 
					 | 
				
			||||||
	axes[1] = ((js1 & JSC1_X1V_MASK) >> JSC1_X1V_SHIFT) & 0xFFFF;
 | 
					 | 
				
			||||||
	axes[2] = ((js2 & JSC2_Y2V_MASK) >> JSC2_Y2V_SHIFT) & 0xFFFF;
 | 
					 | 
				
			||||||
	axes[3] = ((js2 & JSC2_X2V_MASK) >> JSC2_X2V_SHIFT) & 0xFFFF;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	for(jst=0;jst<4;++jst)
 | 
					 | 
				
			||||||
		if(axes[jst]==0xFFFF) axes[jst] = -1;
 | 
					 | 
				
			||||||
	return 0;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static int cs461x_gameport_open(struct gameport *gameport, int mode)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	switch (mode) {
 | 
					 | 
				
			||||||
		case GAMEPORT_MODE_COOKED:
 | 
					 | 
				
			||||||
		case GAMEPORT_MODE_RAW:
 | 
					 | 
				
			||||||
			return 0;
 | 
					 | 
				
			||||||
		default:
 | 
					 | 
				
			||||||
			return -1;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	return 0;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static struct pci_device_id cs461x_pci_tbl[] = {
 | 
					 | 
				
			||||||
	{ PCI_VENDOR_ID_CIRRUS, 0x6001, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, /* Cirrus CS4610 */
 | 
					 | 
				
			||||||
	{ PCI_VENDOR_ID_CIRRUS, 0x6003, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, /* Cirrus CS4612 */
 | 
					 | 
				
			||||||
	{ PCI_VENDOR_ID_CIRRUS, 0x6005, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, /* Cirrus CS4615 */
 | 
					 | 
				
			||||||
	{ 0, }
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
MODULE_DEVICE_TABLE(pci, cs461x_pci_tbl);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static int __devinit cs461x_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	int rc;
 | 
					 | 
				
			||||||
	struct gameport* port;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	rc = pci_enable_device(pdev);
 | 
					 | 
				
			||||||
	if (rc) {
 | 
					 | 
				
			||||||
		printk(KERN_ERR "cs461x: Cannot enable PCI gameport (bus %d, devfn %d) error=%d\n",
 | 
					 | 
				
			||||||
			pdev->bus->number, pdev->devfn, rc);
 | 
					 | 
				
			||||||
		return rc;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	ba0_addr = pci_resource_start(pdev, 0);
 | 
					 | 
				
			||||||
#ifdef CS461X_FULL_MAP
 | 
					 | 
				
			||||||
	ba1_addr = pci_resource_start(pdev, 1);
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
	if (ba0_addr == 0 || ba0_addr == ~0
 | 
					 | 
				
			||||||
#ifdef CS461X_FULL_MAP
 | 
					 | 
				
			||||||
            || ba1_addr == 0 || ba1_addr == ~0
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
	    ) {
 | 
					 | 
				
			||||||
                printk(KERN_ERR "cs461x: wrong address - ba0 = 0x%lx\n", ba0_addr);
 | 
					 | 
				
			||||||
#ifdef CS461X_FULL_MAP
 | 
					 | 
				
			||||||
                printk(KERN_ERR "cs461x: wrong address - ba1 = 0x%lx\n", ba1_addr);
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
		cs461x_free(pdev);
 | 
					 | 
				
			||||||
                return -ENOMEM;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	ba0 = ioremap(ba0_addr, CS461X_BA0_SIZE);
 | 
					 | 
				
			||||||
#ifdef CS461X_FULL_MAP
 | 
					 | 
				
			||||||
	ba1.name.data0 = ioremap(ba1_addr + BA1_SP_DMEM0, CS461X_BA1_DATA0_SIZE);
 | 
					 | 
				
			||||||
	ba1.name.data1 = ioremap(ba1_addr + BA1_SP_DMEM1, CS461X_BA1_DATA1_SIZE);
 | 
					 | 
				
			||||||
	ba1.name.pmem  = ioremap(ba1_addr + BA1_SP_PMEM, CS461X_BA1_PRG_SIZE);
 | 
					 | 
				
			||||||
	ba1.name.reg   = ioremap(ba1_addr + BA1_SP_REG, CS461X_BA1_REG_SIZE);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (ba0 == NULL || ba1.name.data0 == NULL ||
 | 
					 | 
				
			||||||
            ba1.name.data1 == NULL || ba1.name.pmem == NULL ||
 | 
					 | 
				
			||||||
            ba1.name.reg == NULL) {
 | 
					 | 
				
			||||||
		cs461x_free(pdev);
 | 
					 | 
				
			||||||
                return -ENOMEM;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
#else
 | 
					 | 
				
			||||||
	if (ba0 == NULL) {
 | 
					 | 
				
			||||||
		cs461x_free(pdev);
 | 
					 | 
				
			||||||
		return -ENOMEM;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (!(port = gameport_allocate_port())) {
 | 
					 | 
				
			||||||
		printk(KERN_ERR "cs461x: Memory allocation failed\n");
 | 
					 | 
				
			||||||
		cs461x_free(pdev);
 | 
					 | 
				
			||||||
		return -ENOMEM;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	pci_set_drvdata(pdev, port);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	port->open = cs461x_gameport_open;
 | 
					 | 
				
			||||||
	port->trigger = cs461x_gameport_trigger;
 | 
					 | 
				
			||||||
	port->read = cs461x_gameport_read;
 | 
					 | 
				
			||||||
	port->cooked_read = cs461x_gameport_cooked_read;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	gameport_set_name(port, "CS416x");
 | 
					 | 
				
			||||||
	gameport_set_phys(port, "pci%s/gameport0", pci_name(pdev));
 | 
					 | 
				
			||||||
	port->dev.parent = &pdev->dev;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	cs461x_pokeBA0(BA0_JSIO, 0xFF); // ?
 | 
					 | 
				
			||||||
	cs461x_pokeBA0(BA0_JSCTL, JSCTL_SP_MEDIUM_SLOW);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	gameport_register_port(port);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return 0;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static void __devexit cs461x_pci_remove(struct pci_dev *pdev)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	cs461x_free(pdev);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static struct pci_driver cs461x_pci_driver = {
 | 
					 | 
				
			||||||
        .name =         "CS461x_gameport",
 | 
					 | 
				
			||||||
        .id_table =     cs461x_pci_tbl,
 | 
					 | 
				
			||||||
        .probe =        cs461x_pci_probe,
 | 
					 | 
				
			||||||
        .remove =       __devexit_p(cs461x_pci_remove),
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static int __init cs461x_init(void)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
        return pci_register_driver(&cs461x_pci_driver);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static void __exit cs461x_exit(void)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
        pci_unregister_driver(&cs461x_pci_driver);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
module_init(cs461x_init);
 | 
					 | 
				
			||||||
module_exit(cs461x_exit);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
| 
						 | 
					@ -258,18 +258,18 @@ static int __init ns558_init(void)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	int i = 0;
 | 
						int i = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (pnp_register_driver(&ns558_pnp_driver) >= 0)
 | 
				
			||||||
 | 
							pnp_registered = 1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 * Probe ISA ports first so that PnP gets to choose free port addresses
 | 
					 * Probe ISA ports after PnP, so that PnP ports that are already
 | 
				
			||||||
 * not occupied by the ISA ports.
 | 
					 * enabled get detected as PnP. This may be suboptimal in multi-device
 | 
				
			||||||
 | 
					 * configurations, but saves hassle with simple setups.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	while (ns558_isa_portlist[i])
 | 
						while (ns558_isa_portlist[i])
 | 
				
			||||||
		ns558_isa_probe(ns558_isa_portlist[i++]);
 | 
							ns558_isa_probe(ns558_isa_portlist[i++]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (pnp_register_driver(&ns558_pnp_driver) >= 0)
 | 
					 | 
				
			||||||
		pnp_registered = 1;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return (list_empty(&ns558_list) && !pnp_registered) ? -ENODEV : 0;
 | 
						return (list_empty(&ns558_list) && !pnp_registered) ? -ENODEV : 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,186 +0,0 @@
 | 
				
			||||||
/*
 | 
					 | 
				
			||||||
 * $Id: vortex.c,v 1.5 2002/07/01 15:39:30 vojtech Exp $
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 *  Copyright (c) 2000-2001 Vojtech Pavlik
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 *  Based on the work of:
 | 
					 | 
				
			||||||
 *	Raymond Ingles
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/*
 | 
					 | 
				
			||||||
 * Trident 4DWave and Aureal Vortex gameport driver for Linux
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/*
 | 
					 | 
				
			||||||
 * This program is free software; you can redistribute it and/or modify
 | 
					 | 
				
			||||||
 * it under the terms of the GNU General Public License as published by
 | 
					 | 
				
			||||||
 * the Free Software Foundation; either version 2 of the License, or
 | 
					 | 
				
			||||||
 * (at your option) any later version.
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * This program is distributed in the hope that it will be useful,
 | 
					 | 
				
			||||||
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
					 | 
				
			||||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
					 | 
				
			||||||
 * GNU General Public License for more details.
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * You should have received a copy of the GNU General Public License
 | 
					 | 
				
			||||||
 * along with this program; if not, write to the Free Software
 | 
					 | 
				
			||||||
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * Should you need to contact me, the author, you can do so either by
 | 
					 | 
				
			||||||
 * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
 | 
					 | 
				
			||||||
 * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <asm/io.h>
 | 
					 | 
				
			||||||
#include <linux/delay.h>
 | 
					 | 
				
			||||||
#include <linux/errno.h>
 | 
					 | 
				
			||||||
#include <linux/ioport.h>
 | 
					 | 
				
			||||||
#include <linux/kernel.h>
 | 
					 | 
				
			||||||
#include <linux/module.h>
 | 
					 | 
				
			||||||
#include <linux/pci.h>
 | 
					 | 
				
			||||||
#include <linux/init.h>
 | 
					 | 
				
			||||||
#include <linux/slab.h>
 | 
					 | 
				
			||||||
#include <linux/delay.h>
 | 
					 | 
				
			||||||
#include <linux/gameport.h>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
 | 
					 | 
				
			||||||
MODULE_DESCRIPTION("Aureal Vortex and Vortex2 gameport driver");
 | 
					 | 
				
			||||||
MODULE_LICENSE("GPL");
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#define VORTEX_GCR		0x0c	/* Gameport control register */
 | 
					 | 
				
			||||||
#define VORTEX_LEG		0x08	/* Legacy port location */
 | 
					 | 
				
			||||||
#define VORTEX_AXD		0x10	/* Axes start */
 | 
					 | 
				
			||||||
#define VORTEX_DATA_WAIT	20	/* 20 ms */
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
struct vortex {
 | 
					 | 
				
			||||||
	struct gameport *gameport;
 | 
					 | 
				
			||||||
	struct pci_dev *dev;
 | 
					 | 
				
			||||||
	unsigned char __iomem *base;
 | 
					 | 
				
			||||||
	unsigned char __iomem *io;
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static unsigned char vortex_read(struct gameport *gameport)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	struct vortex *vortex = gameport->port_data;
 | 
					 | 
				
			||||||
	return readb(vortex->io + VORTEX_LEG);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static void vortex_trigger(struct gameport *gameport)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	struct vortex *vortex = gameport->port_data;
 | 
					 | 
				
			||||||
	writeb(0xff, vortex->io + VORTEX_LEG);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static int vortex_cooked_read(struct gameport *gameport, int *axes, int *buttons)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	struct vortex *vortex = gameport->port_data;
 | 
					 | 
				
			||||||
	int i;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	*buttons = (~readb(vortex->base + VORTEX_LEG) >> 4) & 0xf;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	for (i = 0; i < 4; i++) {
 | 
					 | 
				
			||||||
		axes[i] = readw(vortex->io + VORTEX_AXD + i * sizeof(u32));
 | 
					 | 
				
			||||||
		if (axes[i] == 0x1fff) axes[i] = -1;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        return 0;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static int vortex_open(struct gameport *gameport, int mode)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	struct vortex *vortex = gameport->port_data;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	switch (mode) {
 | 
					 | 
				
			||||||
		case GAMEPORT_MODE_COOKED:
 | 
					 | 
				
			||||||
			writeb(0x40, vortex->io + VORTEX_GCR);
 | 
					 | 
				
			||||||
			msleep(VORTEX_DATA_WAIT);
 | 
					 | 
				
			||||||
			return 0;
 | 
					 | 
				
			||||||
		case GAMEPORT_MODE_RAW:
 | 
					 | 
				
			||||||
			writeb(0x00, vortex->io + VORTEX_GCR);
 | 
					 | 
				
			||||||
			return 0;
 | 
					 | 
				
			||||||
		default:
 | 
					 | 
				
			||||||
			return -1;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return 0;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static int __devinit vortex_probe(struct pci_dev *dev, const struct pci_device_id *id)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	struct vortex *vortex;
 | 
					 | 
				
			||||||
	struct gameport *port;
 | 
					 | 
				
			||||||
	int i;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	vortex = kcalloc(1, sizeof(struct vortex), GFP_KERNEL);
 | 
					 | 
				
			||||||
	port = gameport_allocate_port();
 | 
					 | 
				
			||||||
	if (!vortex || !port) {
 | 
					 | 
				
			||||||
		printk(KERN_ERR "vortex: Memory allocation failed.\n");
 | 
					 | 
				
			||||||
		kfree(vortex);
 | 
					 | 
				
			||||||
		gameport_free_port(port);
 | 
					 | 
				
			||||||
		return -ENOMEM;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	for (i = 0; i < 6; i++)
 | 
					 | 
				
			||||||
		if (~pci_resource_flags(dev, i) & IORESOURCE_IO)
 | 
					 | 
				
			||||||
			break;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	pci_enable_device(dev);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	vortex->dev = dev;
 | 
					 | 
				
			||||||
	vortex->gameport = port;
 | 
					 | 
				
			||||||
	vortex->base = ioremap(pci_resource_start(vortex->dev, i),
 | 
					 | 
				
			||||||
				pci_resource_len(vortex->dev, i));
 | 
					 | 
				
			||||||
	vortex->io = vortex->base + id->driver_data;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	pci_set_drvdata(dev, vortex);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	port->port_data = vortex;
 | 
					 | 
				
			||||||
	port->fuzz = 64;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	gameport_set_name(port, "AU88x0");
 | 
					 | 
				
			||||||
	gameport_set_phys(port, "pci%s/gameport0", pci_name(dev));
 | 
					 | 
				
			||||||
	port->dev.parent = &dev->dev;
 | 
					 | 
				
			||||||
	port->read = vortex_read;
 | 
					 | 
				
			||||||
	port->trigger = vortex_trigger;
 | 
					 | 
				
			||||||
	port->cooked_read = vortex_cooked_read;
 | 
					 | 
				
			||||||
	port->open = vortex_open;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	gameport_register_port(port);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return 0;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static void __devexit vortex_remove(struct pci_dev *dev)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	struct vortex *vortex = pci_get_drvdata(dev);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	gameport_unregister_port(vortex->gameport);
 | 
					 | 
				
			||||||
	iounmap(vortex->base);
 | 
					 | 
				
			||||||
	kfree(vortex);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static struct pci_device_id vortex_id_table[] = {
 | 
					 | 
				
			||||||
	{ 0x12eb, 0x0001, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0x11000 },
 | 
					 | 
				
			||||||
	{ 0x12eb, 0x0002, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0x28800 },
 | 
					 | 
				
			||||||
	{ 0 }
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static struct pci_driver vortex_driver = {
 | 
					 | 
				
			||||||
	.name =		"vortex_gameport",
 | 
					 | 
				
			||||||
	.id_table =	vortex_id_table,
 | 
					 | 
				
			||||||
	.probe =	vortex_probe,
 | 
					 | 
				
			||||||
	.remove =	__devexit_p(vortex_remove),
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static int __init vortex_init(void)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	return pci_register_driver(&vortex_driver);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static void __exit vortex_exit(void)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	pci_unregister_driver(&vortex_driver);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
module_init(vortex_init);
 | 
					 | 
				
			||||||
module_exit(vortex_exit);
 | 
					 | 
				
			||||||
| 
						 | 
					@ -219,10 +219,24 @@ void input_release_device(struct input_handle *handle)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int input_open_device(struct input_handle *handle)
 | 
					int input_open_device(struct input_handle *handle)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
						struct input_dev *dev = handle->dev;
 | 
				
			||||||
 | 
						int err;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						err = down_interruptible(&dev->sem);
 | 
				
			||||||
 | 
						if (err)
 | 
				
			||||||
 | 
							return err;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	handle->open++;
 | 
						handle->open++;
 | 
				
			||||||
	if (handle->dev->open)
 | 
					
 | 
				
			||||||
		return handle->dev->open(handle->dev);
 | 
						if (!dev->users++ && dev->open)
 | 
				
			||||||
	return 0;
 | 
							err = dev->open(dev);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (err)
 | 
				
			||||||
 | 
							handle->open--;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						up(&dev->sem);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return err;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int input_flush_device(struct input_handle* handle, struct file* file)
 | 
					int input_flush_device(struct input_handle* handle, struct file* file)
 | 
				
			||||||
| 
						 | 
					@ -235,10 +249,17 @@ int input_flush_device(struct input_handle* handle, struct file* file)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void input_close_device(struct input_handle *handle)
 | 
					void input_close_device(struct input_handle *handle)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
						struct input_dev *dev = handle->dev;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	input_release_device(handle);
 | 
						input_release_device(handle);
 | 
				
			||||||
	if (handle->dev->close)
 | 
					
 | 
				
			||||||
		handle->dev->close(handle->dev);
 | 
						down(&dev->sem);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!--dev->users && dev->close)
 | 
				
			||||||
 | 
							dev->close(dev);
 | 
				
			||||||
	handle->open--;
 | 
						handle->open--;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						up(&dev->sem);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void input_link_handle(struct input_handle *handle)
 | 
					static void input_link_handle(struct input_handle *handle)
 | 
				
			||||||
| 
						 | 
					@ -415,6 +436,8 @@ void input_register_device(struct input_dev *dev)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	set_bit(EV_SYN, dev->evbit);
 | 
						set_bit(EV_SYN, dev->evbit);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						init_MUTEX(&dev->sem);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/*
 | 
						/*
 | 
				
			||||||
	 * If delay and period are pre-set by the driver, then autorepeating
 | 
						 * If delay and period are pre-set by the driver, then autorepeating
 | 
				
			||||||
	 * is handled by the driver itself and we don't do it in input.c.
 | 
						 * is handled by the driver itself and we don't do it in input.c.
 | 
				
			||||||
| 
						 | 
					@ -674,6 +697,8 @@ static int input_handlers_read(char *buf, char **start, off_t pos, int count, in
 | 
				
			||||||
	return (count > cnt) ? cnt : count;
 | 
						return (count > cnt) ? cnt : count;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static struct file_operations input_fileops;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int __init input_proc_init(void)
 | 
					static int __init input_proc_init(void)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct proc_dir_entry *entry;
 | 
						struct proc_dir_entry *entry;
 | 
				
			||||||
| 
						 | 
					@ -688,6 +713,8 @@ static int __init input_proc_init(void)
 | 
				
			||||||
		return -ENOMEM;
 | 
							return -ENOMEM;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	entry->owner = THIS_MODULE;
 | 
						entry->owner = THIS_MODULE;
 | 
				
			||||||
 | 
						input_fileops = *entry->proc_fops;
 | 
				
			||||||
 | 
						entry->proc_fops = &input_fileops;
 | 
				
			||||||
	entry->proc_fops->poll = input_devices_poll;
 | 
						entry->proc_fops->poll = input_devices_poll;
 | 
				
			||||||
	entry = create_proc_read_entry("handlers", 0, proc_bus_input_dir, input_handlers_read, NULL);
 | 
						entry = create_proc_read_entry("handlers", 0, proc_bus_input_dir, input_handlers_read, NULL);
 | 
				
			||||||
	if (entry == NULL) {
 | 
						if (entry == NULL) {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -285,48 +285,33 @@ static unsigned int joydev_poll(struct file *file, poll_table *wait)
 | 
				
			||||||
		(POLLIN | POLLRDNORM) : 0) | (list->joydev->exist ? 0 : (POLLHUP | POLLERR));
 | 
							(POLLIN | POLLRDNORM) : 0) | (list->joydev->exist ? 0 : (POLLHUP | POLLERR));
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int joydev_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
 | 
					static int joydev_ioctl_common(struct joydev *joydev, unsigned int cmd, void __user *argp)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct joydev_list *list = file->private_data;
 | 
					 | 
				
			||||||
	struct joydev *joydev = list->joydev;
 | 
					 | 
				
			||||||
	struct input_dev *dev = joydev->handle.dev;
 | 
						struct input_dev *dev = joydev->handle.dev;
 | 
				
			||||||
	void __user *argp = (void __user *)arg;
 | 
					 | 
				
			||||||
	int i, j;
 | 
						int i, j;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!joydev->exist) return -ENODEV;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	switch (cmd) {
 | 
						switch (cmd) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		case JS_SET_CAL:
 | 
							case JS_SET_CAL:
 | 
				
			||||||
			return copy_from_user(&joydev->glue.JS_CORR, argp,
 | 
								return copy_from_user(&joydev->glue.JS_CORR, argp,
 | 
				
			||||||
				sizeof(struct JS_DATA_TYPE)) ? -EFAULT : 0;
 | 
									sizeof(joydev->glue.JS_CORR)) ? -EFAULT : 0;
 | 
				
			||||||
		case JS_GET_CAL:
 | 
							case JS_GET_CAL:
 | 
				
			||||||
			return copy_to_user(argp, &joydev->glue.JS_CORR,
 | 
								return copy_to_user(argp, &joydev->glue.JS_CORR,
 | 
				
			||||||
				sizeof(struct JS_DATA_TYPE)) ? -EFAULT : 0;
 | 
									sizeof(joydev->glue.JS_CORR)) ? -EFAULT : 0;
 | 
				
			||||||
		case JS_SET_TIMEOUT:
 | 
							case JS_SET_TIMEOUT:
 | 
				
			||||||
			return get_user(joydev->glue.JS_TIMEOUT, (int __user *) arg);
 | 
								return get_user(joydev->glue.JS_TIMEOUT, (s32 __user *) argp);
 | 
				
			||||||
		case JS_GET_TIMEOUT:
 | 
							case JS_GET_TIMEOUT:
 | 
				
			||||||
			return put_user(joydev->glue.JS_TIMEOUT, (int __user *) arg);
 | 
								return put_user(joydev->glue.JS_TIMEOUT, (s32 __user *) argp);
 | 
				
			||||||
		case JS_SET_TIMELIMIT:
 | 
					 | 
				
			||||||
			return get_user(joydev->glue.JS_TIMELIMIT, (long __user *) arg);
 | 
					 | 
				
			||||||
		case JS_GET_TIMELIMIT:
 | 
					 | 
				
			||||||
			return put_user(joydev->glue.JS_TIMELIMIT, (long __user *) arg);
 | 
					 | 
				
			||||||
		case JS_SET_ALL:
 | 
					 | 
				
			||||||
			return copy_from_user(&joydev->glue, argp,
 | 
					 | 
				
			||||||
						sizeof(struct JS_DATA_SAVE_TYPE)) ? -EFAULT : 0;
 | 
					 | 
				
			||||||
		case JS_GET_ALL:
 | 
					 | 
				
			||||||
			return copy_to_user(argp, &joydev->glue,
 | 
					 | 
				
			||||||
						sizeof(struct JS_DATA_SAVE_TYPE)) ? -EFAULT : 0;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
		case JSIOCGVERSION:
 | 
							case JSIOCGVERSION:
 | 
				
			||||||
			return put_user(JS_VERSION, (__u32 __user *) arg);
 | 
								return put_user(JS_VERSION, (__u32 __user *) argp);
 | 
				
			||||||
		case JSIOCGAXES:
 | 
							case JSIOCGAXES:
 | 
				
			||||||
			return put_user(joydev->nabs, (__u8 __user *) arg);
 | 
								return put_user(joydev->nabs, (__u8 __user *) argp);
 | 
				
			||||||
		case JSIOCGBUTTONS:
 | 
							case JSIOCGBUTTONS:
 | 
				
			||||||
			return put_user(joydev->nkey, (__u8 __user *) arg);
 | 
								return put_user(joydev->nkey, (__u8 __user *) argp);
 | 
				
			||||||
		case JSIOCSCORR:
 | 
							case JSIOCSCORR:
 | 
				
			||||||
			if (copy_from_user(joydev->corr, argp,
 | 
								if (copy_from_user(joydev->corr, argp,
 | 
				
			||||||
				      sizeof(struct js_corr) * joydev->nabs))
 | 
									      sizeof(joydev->corr[0]) * joydev->nabs))
 | 
				
			||||||
			    return -EFAULT;
 | 
								    return -EFAULT;
 | 
				
			||||||
			for (i = 0; i < joydev->nabs; i++) {
 | 
								for (i = 0; i < joydev->nabs; i++) {
 | 
				
			||||||
				j = joydev->abspam[i];
 | 
									j = joydev->abspam[i];
 | 
				
			||||||
| 
						 | 
					@ -335,7 +320,7 @@ static int joydev_ioctl(struct inode *inode, struct file *file, unsigned int cmd
 | 
				
			||||||
			return 0;
 | 
								return 0;
 | 
				
			||||||
		case JSIOCGCORR:
 | 
							case JSIOCGCORR:
 | 
				
			||||||
			return copy_to_user(argp, joydev->corr,
 | 
								return copy_to_user(argp, joydev->corr,
 | 
				
			||||||
						sizeof(struct js_corr) * joydev->nabs) ? -EFAULT : 0;
 | 
											sizeof(joydev->corr[0]) * joydev->nabs) ? -EFAULT : 0;
 | 
				
			||||||
		case JSIOCSAXMAP:
 | 
							case JSIOCSAXMAP:
 | 
				
			||||||
			if (copy_from_user(joydev->abspam, argp, sizeof(__u8) * (ABS_MAX + 1)))
 | 
								if (copy_from_user(joydev->abspam, argp, sizeof(__u8) * (ABS_MAX + 1)))
 | 
				
			||||||
				return -EFAULT;
 | 
									return -EFAULT;
 | 
				
			||||||
| 
						 | 
					@ -371,6 +356,84 @@ static int joydev_ioctl(struct inode *inode, struct file *file, unsigned int cmd
 | 
				
			||||||
	return -EINVAL;
 | 
						return -EINVAL;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef CONFIG_COMPAT
 | 
				
			||||||
 | 
					static long joydev_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct joydev_list *list = file->private_data;
 | 
				
			||||||
 | 
						struct joydev *joydev = list->joydev;
 | 
				
			||||||
 | 
						void __user *argp = (void __user *)arg;
 | 
				
			||||||
 | 
						s32 tmp32;
 | 
				
			||||||
 | 
						struct JS_DATA_SAVE_TYPE_32 ds32;
 | 
				
			||||||
 | 
						int err;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!joydev->exist) return -ENODEV;
 | 
				
			||||||
 | 
						switch(cmd) {
 | 
				
			||||||
 | 
						case JS_SET_TIMELIMIT:
 | 
				
			||||||
 | 
							err = get_user(tmp32, (s32 __user *) arg);
 | 
				
			||||||
 | 
							if (err == 0)
 | 
				
			||||||
 | 
								joydev->glue.JS_TIMELIMIT = tmp32;
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						case JS_GET_TIMELIMIT:
 | 
				
			||||||
 | 
							tmp32 = joydev->glue.JS_TIMELIMIT;
 | 
				
			||||||
 | 
							err = put_user(tmp32, (s32 __user *) arg);
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						case JS_SET_ALL:
 | 
				
			||||||
 | 
							err = copy_from_user(&ds32, argp,
 | 
				
			||||||
 | 
									     sizeof(ds32)) ? -EFAULT : 0;
 | 
				
			||||||
 | 
							if (err == 0) {
 | 
				
			||||||
 | 
								joydev->glue.JS_TIMEOUT    = ds32.JS_TIMEOUT;
 | 
				
			||||||
 | 
								joydev->glue.BUSY          = ds32.BUSY;
 | 
				
			||||||
 | 
								joydev->glue.JS_EXPIRETIME = ds32.JS_EXPIRETIME;
 | 
				
			||||||
 | 
								joydev->glue.JS_TIMELIMIT  = ds32.JS_TIMELIMIT;
 | 
				
			||||||
 | 
								joydev->glue.JS_SAVE       = ds32.JS_SAVE;
 | 
				
			||||||
 | 
								joydev->glue.JS_CORR       = ds32.JS_CORR;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						case JS_GET_ALL:
 | 
				
			||||||
 | 
							ds32.JS_TIMEOUT    = joydev->glue.JS_TIMEOUT;
 | 
				
			||||||
 | 
							ds32.BUSY          = joydev->glue.BUSY;
 | 
				
			||||||
 | 
							ds32.JS_EXPIRETIME = joydev->glue.JS_EXPIRETIME;
 | 
				
			||||||
 | 
							ds32.JS_TIMELIMIT  = joydev->glue.JS_TIMELIMIT;
 | 
				
			||||||
 | 
							ds32.JS_SAVE       = joydev->glue.JS_SAVE;
 | 
				
			||||||
 | 
							ds32.JS_CORR       = joydev->glue.JS_CORR;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							err = copy_to_user(argp, &ds32,
 | 
				
			||||||
 | 
										  sizeof(ds32)) ? -EFAULT : 0;
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						default:
 | 
				
			||||||
 | 
							err = joydev_ioctl_common(joydev, cmd, argp);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return err;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					#endif /* CONFIG_COMPAT */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int joydev_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct joydev_list *list = file->private_data;
 | 
				
			||||||
 | 
						struct joydev *joydev = list->joydev;
 | 
				
			||||||
 | 
						void __user *argp = (void __user *)arg;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!joydev->exist) return -ENODEV;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						switch(cmd) {
 | 
				
			||||||
 | 
							case JS_SET_TIMELIMIT:
 | 
				
			||||||
 | 
								return get_user(joydev->glue.JS_TIMELIMIT, (long __user *) arg);
 | 
				
			||||||
 | 
							case JS_GET_TIMELIMIT:
 | 
				
			||||||
 | 
								return put_user(joydev->glue.JS_TIMELIMIT, (long __user *) arg);
 | 
				
			||||||
 | 
							case JS_SET_ALL:
 | 
				
			||||||
 | 
								return copy_from_user(&joydev->glue, argp,
 | 
				
			||||||
 | 
											sizeof(joydev->glue)) ? -EFAULT : 0;
 | 
				
			||||||
 | 
							case JS_GET_ALL:
 | 
				
			||||||
 | 
								return copy_to_user(argp, &joydev->glue,
 | 
				
			||||||
 | 
											sizeof(joydev->glue)) ? -EFAULT : 0;
 | 
				
			||||||
 | 
							default:
 | 
				
			||||||
 | 
								return joydev_ioctl_common(joydev, cmd, argp);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static struct file_operations joydev_fops = {
 | 
					static struct file_operations joydev_fops = {
 | 
				
			||||||
	.owner =	THIS_MODULE,
 | 
						.owner =	THIS_MODULE,
 | 
				
			||||||
	.read =		joydev_read,
 | 
						.read =		joydev_read,
 | 
				
			||||||
| 
						 | 
					@ -379,6 +442,9 @@ static struct file_operations joydev_fops = {
 | 
				
			||||||
	.open =		joydev_open,
 | 
						.open =		joydev_open,
 | 
				
			||||||
	.release =	joydev_release,
 | 
						.release =	joydev_release,
 | 
				
			||||||
	.ioctl =	joydev_ioctl,
 | 
						.ioctl =	joydev_ioctl,
 | 
				
			||||||
 | 
					#ifdef CONFIG_COMPAT
 | 
				
			||||||
 | 
						.compat_ioctl =	joydev_compat_ioctl,
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
	.fasync =	joydev_fasync,
 | 
						.fasync =	joydev_fasync,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -185,7 +185,7 @@ static void a3d_poll(struct gameport *gameport)
 | 
				
			||||||
	a3d->reads++;
 | 
						a3d->reads++;
 | 
				
			||||||
	if (a3d_read_packet(a3d->gameport, a3d->length, data) != a3d->length ||
 | 
						if (a3d_read_packet(a3d->gameport, a3d->length, data) != a3d->length ||
 | 
				
			||||||
	    data[0] != a3d->mode || a3d_csum(data, a3d->length))
 | 
						    data[0] != a3d->mode || a3d_csum(data, a3d->length))
 | 
				
			||||||
	 	a3d->bads++;
 | 
							a3d->bads++;
 | 
				
			||||||
	else
 | 
						else
 | 
				
			||||||
		a3d_read(a3d, data);
 | 
							a3d_read(a3d, data);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -82,7 +82,7 @@ static char adi_cm2_abs[] =	{ ABS_X, ABS_Y, ABS_Z, ABS_RX, ABS_RY, ABS_RZ };
 | 
				
			||||||
static char adi_wmf_abs[] =	{ ABS_WHEEL, ABS_GAS, ABS_BRAKE, ABS_HAT0X, ABS_HAT0Y, ABS_HAT1X, ABS_HAT1Y, ABS_HAT2X, ABS_HAT2Y };
 | 
					static char adi_wmf_abs[] =	{ ABS_WHEEL, ABS_GAS, ABS_BRAKE, ABS_HAT0X, ABS_HAT0Y, ABS_HAT1X, ABS_HAT1Y, ABS_HAT2X, ABS_HAT2Y };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static short adi_wmgpe_key[] =	{ BTN_A, BTN_B, BTN_C, BTN_X, BTN_Y, BTN_Z,  BTN_TL, BTN_TR, BTN_START, BTN_MODE, BTN_SELECT };
 | 
					static short adi_wmgpe_key[] =	{ BTN_A, BTN_B, BTN_C, BTN_X, BTN_Y, BTN_Z,  BTN_TL, BTN_TR, BTN_START, BTN_MODE, BTN_SELECT };
 | 
				
			||||||
static short adi_wmi_key[] = 	{ BTN_TRIGGER,  BTN_TOP, BTN_THUMB, BTN_TOP2, BTN_BASE, BTN_BASE2, BTN_BASE3, BTN_BASE4, BTN_EXTRA };
 | 
					static short adi_wmi_key[] =	{ BTN_TRIGGER,  BTN_TOP, BTN_THUMB, BTN_TOP2, BTN_BASE, BTN_BASE2, BTN_BASE3, BTN_BASE4, BTN_EXTRA };
 | 
				
			||||||
static short adi_wmed3d_key[] =	{ BTN_TRIGGER, BTN_THUMB, BTN_THUMB2, BTN_TOP, BTN_TOP2, BTN_BASE, BTN_BASE2 };
 | 
					static short adi_wmed3d_key[] =	{ BTN_TRIGGER, BTN_THUMB, BTN_THUMB2, BTN_TOP, BTN_TOP2, BTN_BASE, BTN_BASE2 };
 | 
				
			||||||
static short adi_cm2_key[] =	{ BTN_1, BTN_2, BTN_3, BTN_4, BTN_5, BTN_6, BTN_7, BTN_8 };
 | 
					static short adi_cm2_key[] =	{ BTN_1, BTN_2, BTN_3, BTN_4, BTN_5, BTN_6, BTN_7, BTN_8 };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -183,7 +183,7 @@ static void adi_move_bits(struct adi_port *port, int length)
 | 
				
			||||||
	int i;
 | 
						int i;
 | 
				
			||||||
	struct adi *adi = port->adi;
 | 
						struct adi *adi = port->adi;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 	adi[0].idx = adi[1].idx = 0;
 | 
						adi[0].idx = adi[1].idx = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (adi[0].ret <= 0 || adi[1].ret <= 0) return;
 | 
						if (adi[0].ret <= 0 || adi[1].ret <= 0) return;
 | 
				
			||||||
	if (adi[0].data[0] & 0x20 || ~adi[1].data[0] & 0x20) return;
 | 
						if (adi[0].data[0] & 0x20 || ~adi[1].data[0] & 0x20) return;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -51,7 +51,8 @@ MODULE_PARM_DESC(map, "Map of attached joysticks in form of <a>,<b> (default is
 | 
				
			||||||
 | 
					
 | 
				
			||||||
__obsolete_setup("amijoy=");
 | 
					__obsolete_setup("amijoy=");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int amijoy_used[2] = { 0, 0 };
 | 
					static int amijoy_used;
 | 
				
			||||||
 | 
					static DECLARE_MUTEX(amijoy_sem);
 | 
				
			||||||
static struct input_dev amijoy_dev[2];
 | 
					static struct input_dev amijoy_dev[2];
 | 
				
			||||||
static char *amijoy_phys[2] = { "amijoy/input0", "amijoy/input1" };
 | 
					static char *amijoy_phys[2] = { "amijoy/input0", "amijoy/input1" };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -84,26 +85,30 @@ static irqreturn_t amijoy_interrupt(int irq, void *dummy, struct pt_regs *fp)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int amijoy_open(struct input_dev *dev)
 | 
					static int amijoy_open(struct input_dev *dev)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	int *used = dev->private;
 | 
						int err;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if ((*used)++)
 | 
						err = down_interruptible(&amijoy_sem);
 | 
				
			||||||
		return 0;
 | 
						if (err)
 | 
				
			||||||
 | 
							return err;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (request_irq(IRQ_AMIGA_VERTB, amijoy_interrupt, 0, "amijoy", amijoy_interrupt)) {
 | 
						if (!amijoy_used && request_irq(IRQ_AMIGA_VERTB, amijoy_interrupt, 0, "amijoy", amijoy_interrupt)) {
 | 
				
			||||||
		(*used)--;
 | 
					 | 
				
			||||||
		printk(KERN_ERR "amijoy.c: Can't allocate irq %d\n", IRQ_AMIGA_VERTB);
 | 
							printk(KERN_ERR "amijoy.c: Can't allocate irq %d\n", IRQ_AMIGA_VERTB);
 | 
				
			||||||
		return -EBUSY;
 | 
							err = -EBUSY;
 | 
				
			||||||
 | 
							goto out;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return 0;
 | 
						amijoy_used++;
 | 
				
			||||||
 | 
					out:
 | 
				
			||||||
 | 
						up(&amijoy_sem);
 | 
				
			||||||
 | 
						return err;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void amijoy_close(struct input_dev *dev)
 | 
					static void amijoy_close(struct input_dev *dev)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	int *used = dev->private;
 | 
						down(&amijoysem);
 | 
				
			||||||
 | 
						if (!--amijoy_used)
 | 
				
			||||||
	if (!--(*used))
 | 
					 | 
				
			||||||
		free_irq(IRQ_AMIGA_VERTB, amijoy_interrupt);
 | 
							free_irq(IRQ_AMIGA_VERTB, amijoy_interrupt);
 | 
				
			||||||
 | 
						up(&amijoy_sem);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int __init amijoy_init(void)
 | 
					static int __init amijoy_init(void)
 | 
				
			||||||
| 
						 | 
					@ -138,8 +143,6 @@ static int __init amijoy_init(void)
 | 
				
			||||||
			amijoy_dev[i].id.product = 0x0003;
 | 
								amijoy_dev[i].id.product = 0x0003;
 | 
				
			||||||
			amijoy_dev[i].id.version = 0x0100;
 | 
								amijoy_dev[i].id.version = 0x0100;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			amijoy_dev[i].private = amijoy_used + i;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			input_register_device(amijoy_dev + i);
 | 
								input_register_device(amijoy_dev + i);
 | 
				
			||||||
			printk(KERN_INFO "input: %s at joy%ddat\n", amijoy_name, i);
 | 
								printk(KERN_INFO "input: %s at joy%ddat\n", amijoy_name, i);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -87,7 +87,7 @@ __obsolete_setup("db9_3=");
 | 
				
			||||||
#define DB9_NORMAL		0x0a
 | 
					#define DB9_NORMAL		0x0a
 | 
				
			||||||
#define DB9_NOSELECT		0x08
 | 
					#define DB9_NOSELECT		0x08
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define DB9_MAX_DEVICES 2
 | 
					#define DB9_MAX_DEVICES		2
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define DB9_GENESIS6_DELAY	14
 | 
					#define DB9_GENESIS6_DELAY	14
 | 
				
			||||||
#define DB9_REFRESH_TIME	HZ/100
 | 
					#define DB9_REFRESH_TIME	HZ/100
 | 
				
			||||||
| 
						 | 
					@ -98,6 +98,7 @@ struct db9 {
 | 
				
			||||||
	struct pardevice *pd;
 | 
						struct pardevice *pd;
 | 
				
			||||||
	int mode;
 | 
						int mode;
 | 
				
			||||||
	int used;
 | 
						int used;
 | 
				
			||||||
 | 
						struct semaphore sem;
 | 
				
			||||||
	char phys[2][32];
 | 
						char phys[2][32];
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -503,6 +504,11 @@ static int db9_open(struct input_dev *dev)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct db9 *db9 = dev->private;
 | 
						struct db9 *db9 = dev->private;
 | 
				
			||||||
	struct parport *port = db9->pd->port;
 | 
						struct parport *port = db9->pd->port;
 | 
				
			||||||
 | 
						int err;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						err = down_interruptible(&db9->sem);
 | 
				
			||||||
 | 
						if (err)
 | 
				
			||||||
 | 
							return err;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!db9->used++) {
 | 
						if (!db9->used++) {
 | 
				
			||||||
		parport_claim(db9->pd);
 | 
							parport_claim(db9->pd);
 | 
				
			||||||
| 
						 | 
					@ -514,6 +520,7 @@ static int db9_open(struct input_dev *dev)
 | 
				
			||||||
		mod_timer(&db9->timer, jiffies + DB9_REFRESH_TIME);
 | 
							mod_timer(&db9->timer, jiffies + DB9_REFRESH_TIME);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						up(&db9->sem);
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -522,12 +529,14 @@ static void db9_close(struct input_dev *dev)
 | 
				
			||||||
	struct db9 *db9 = dev->private;
 | 
						struct db9 *db9 = dev->private;
 | 
				
			||||||
	struct parport *port = db9->pd->port;
 | 
						struct parport *port = db9->pd->port;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						down(&db9->sem);
 | 
				
			||||||
	if (!--db9->used) {
 | 
						if (!--db9->used) {
 | 
				
			||||||
		del_timer(&db9->timer);
 | 
							del_timer_sync(&db9->timer);
 | 
				
			||||||
		parport_write_control(port, 0x00);
 | 
							parport_write_control(port, 0x00);
 | 
				
			||||||
		parport_data_forward(port);
 | 
							parport_data_forward(port);
 | 
				
			||||||
		parport_release(db9->pd);
 | 
							parport_release(db9->pd);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
						up(&db9->sem);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static struct db9 __init *db9_probe(int *config, int nargs)
 | 
					static struct db9 __init *db9_probe(int *config, int nargs)
 | 
				
			||||||
| 
						 | 
					@ -563,12 +572,12 @@ static struct db9 __init *db9_probe(int *config, int nargs)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!(db9 = kmalloc(sizeof(struct db9), GFP_KERNEL))) {
 | 
						if (!(db9 = kcalloc(1, sizeof(struct db9), GFP_KERNEL))) {
 | 
				
			||||||
		parport_put_port(pp);
 | 
							parport_put_port(pp);
 | 
				
			||||||
		return NULL;
 | 
							return NULL;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	memset(db9, 0, sizeof(struct db9));
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						init_MUTEX(&db9->sem);
 | 
				
			||||||
	db9->mode = config[1];
 | 
						db9->mode = config[1];
 | 
				
			||||||
	init_timer(&db9->timer);
 | 
						init_timer(&db9->timer);
 | 
				
			||||||
	db9->timer.data = (long) db9;
 | 
						db9->timer.data = (long) db9;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,12 +1,12 @@
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 * NES, SNES, N64, MultiSystem, PSX gamepad driver for Linux
 | 
					 * NES, SNES, N64, MultiSystem, PSX gamepad driver for Linux
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 *  Copyright (c) 1999-2004 	Vojtech Pavlik <vojtech@suse.cz>
 | 
					 *  Copyright (c) 1999-2004	Vojtech Pavlik <vojtech@suse.cz>
 | 
				
			||||||
 *  Copyright (c) 2004 		Peter Nelson <rufus-kernel@hackish.org>
 | 
					 *  Copyright (c) 2004		Peter Nelson <rufus-kernel@hackish.org>
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 *  Based on the work of:
 | 
					 *  Based on the work of:
 | 
				
			||||||
 *  	Andree Borrmann		John Dahlstrom
 | 
					 *	Andree Borrmann		John Dahlstrom
 | 
				
			||||||
 *  	David Kuder		Nathan Hand
 | 
					 *	David Kuder		Nathan Hand
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
| 
						 | 
					@ -81,6 +81,7 @@ struct gc {
 | 
				
			||||||
	struct timer_list timer;
 | 
						struct timer_list timer;
 | 
				
			||||||
	unsigned char pads[GC_MAX + 1];
 | 
						unsigned char pads[GC_MAX + 1];
 | 
				
			||||||
	int used;
 | 
						int used;
 | 
				
			||||||
 | 
						struct semaphore sem;
 | 
				
			||||||
	char phys[5][32];
 | 
						char phys[5][32];
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -433,7 +434,7 @@ static void gc_timer(unsigned long private)
 | 
				
			||||||
		gc_psx_read_packet(gc, data_psx, data);
 | 
							gc_psx_read_packet(gc, data_psx, data);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		for (i = 0; i < 5; i++) {
 | 
							for (i = 0; i < 5; i++) {
 | 
				
			||||||
	 		switch (data[i]) {
 | 
								switch (data[i]) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
				case GC_PSX_RUMBLE:
 | 
									case GC_PSX_RUMBLE:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -503,22 +504,33 @@ static void gc_timer(unsigned long private)
 | 
				
			||||||
static int gc_open(struct input_dev *dev)
 | 
					static int gc_open(struct input_dev *dev)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct gc *gc = dev->private;
 | 
						struct gc *gc = dev->private;
 | 
				
			||||||
 | 
						int err;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						err = down_interruptible(&gc->sem);
 | 
				
			||||||
 | 
						if (err)
 | 
				
			||||||
 | 
							return err;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!gc->used++) {
 | 
						if (!gc->used++) {
 | 
				
			||||||
		parport_claim(gc->pd);
 | 
							parport_claim(gc->pd);
 | 
				
			||||||
		parport_write_control(gc->pd->port, 0x04);
 | 
							parport_write_control(gc->pd->port, 0x04);
 | 
				
			||||||
		mod_timer(&gc->timer, jiffies + GC_REFRESH_TIME);
 | 
							mod_timer(&gc->timer, jiffies + GC_REFRESH_TIME);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						up(&gc->sem);
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void gc_close(struct input_dev *dev)
 | 
					static void gc_close(struct input_dev *dev)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct gc *gc = dev->private;
 | 
						struct gc *gc = dev->private;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						down(&gc->sem);
 | 
				
			||||||
	if (!--gc->used) {
 | 
						if (!--gc->used) {
 | 
				
			||||||
		del_timer(&gc->timer);
 | 
							del_timer_sync(&gc->timer);
 | 
				
			||||||
		parport_write_control(gc->pd->port, 0x00);
 | 
							parport_write_control(gc->pd->port, 0x00);
 | 
				
			||||||
		parport_release(gc->pd);
 | 
							parport_release(gc->pd);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
						up(&gc->sem);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static struct gc __init *gc_probe(int *config, int nargs)
 | 
					static struct gc __init *gc_probe(int *config, int nargs)
 | 
				
			||||||
| 
						 | 
					@ -542,11 +554,12 @@ static struct gc __init *gc_probe(int *config, int nargs)
 | 
				
			||||||
		return NULL;
 | 
							return NULL;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!(gc = kmalloc(sizeof(struct gc), GFP_KERNEL))) {
 | 
						if (!(gc = kcalloc(1, sizeof(struct gc), GFP_KERNEL))) {
 | 
				
			||||||
		parport_put_port(pp);
 | 
							parport_put_port(pp);
 | 
				
			||||||
		return NULL;
 | 
							return NULL;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	memset(gc, 0, sizeof(struct gc));
 | 
					
 | 
				
			||||||
 | 
						init_MUTEX(&gc->sem);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	gc->pd = parport_register_device(pp, "gamecon", NULL, NULL, NULL, PARPORT_DEV_EXCL, NULL);
 | 
						gc->pd = parport_register_device(pp, "gamecon", NULL, NULL, NULL, PARPORT_DEV_EXCL, NULL);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -329,7 +329,7 @@ static int gf2k_connect(struct gameport *gameport, struct gameport_driver *drv)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for (i = 0; i < gf2k_axes[gf2k->id]; i++) {
 | 
						for (i = 0; i < gf2k_axes[gf2k->id]; i++) {
 | 
				
			||||||
		gf2k->dev.absmax[gf2k_abs[i]] = (i < 2) ? gf2k->dev.abs[gf2k_abs[i]] * 2 - 32 :
 | 
							gf2k->dev.absmax[gf2k_abs[i]] = (i < 2) ? gf2k->dev.abs[gf2k_abs[i]] * 2 - 32 :
 | 
				
			||||||
	      		  gf2k->dev.abs[gf2k_abs[0]] + gf2k->dev.abs[gf2k_abs[1]] - 32;
 | 
								  gf2k->dev.abs[gf2k_abs[0]] + gf2k->dev.abs[gf2k_abs[1]] - 32;
 | 
				
			||||||
		gf2k->dev.absmin[gf2k_abs[i]] = 32;
 | 
							gf2k->dev.absmin[gf2k_abs[i]] = 32;
 | 
				
			||||||
		gf2k->dev.absfuzz[gf2k_abs[i]] = 8;
 | 
							gf2k->dev.absfuzz[gf2k_abs[i]] = 8;
 | 
				
			||||||
		gf2k->dev.absflat[gf2k_abs[i]] = (i < 2) ? 24 : 0;
 | 
							gf2k->dev.absflat[gf2k_abs[i]] = (i < 2) ? 24 : 0;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -171,7 +171,7 @@ static int mp_io(struct gameport* gameport, int sendflags, int sendcode, u32 *pa
 | 
				
			||||||
	*packet = 0;
 | 
						*packet = 0;
 | 
				
			||||||
	raw_data = gameport_read(gameport);
 | 
						raw_data = gameport_read(gameport);
 | 
				
			||||||
	if (raw_data & 1)
 | 
						if (raw_data & 1)
 | 
				
			||||||
 		return IO_RETRY;
 | 
							return IO_RETRY;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for (i = 0; i < 64; i++) {
 | 
						for (i = 0; i < 64; i++) {
 | 
				
			||||||
		raw_data = gameport_read(gameport);
 | 
							raw_data = gameport_read(gameport);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -78,6 +78,7 @@ static struct iforce_device iforce_device[] = {
 | 
				
			||||||
	{ 0x061c, 0xc0a4, "ACT LABS Force RS",                          btn_wheel, abs_wheel, ff_iforce }, //?
 | 
						{ 0x061c, 0xc0a4, "ACT LABS Force RS",                          btn_wheel, abs_wheel, ff_iforce }, //?
 | 
				
			||||||
	{ 0x06f8, 0x0001, "Guillemot Race Leader Force Feedback",	btn_wheel, abs_wheel, ff_iforce }, //?
 | 
						{ 0x06f8, 0x0001, "Guillemot Race Leader Force Feedback",	btn_wheel, abs_wheel, ff_iforce }, //?
 | 
				
			||||||
	{ 0x06f8, 0x0004, "Guillemot Force Feedback Racing Wheel",	btn_wheel, abs_wheel, ff_iforce }, //?
 | 
						{ 0x06f8, 0x0004, "Guillemot Force Feedback Racing Wheel",	btn_wheel, abs_wheel, ff_iforce }, //?
 | 
				
			||||||
 | 
						{ 0x06f8, 0x0004, "Gullemot Jet Leader 3D",			btn_joystick, abs_joystick, ff_iforce }, //?
 | 
				
			||||||
	{ 0x0000, 0x0000, "Unknown I-Force Device [%04x:%04x]",		btn_joystick, abs_joystick, ff_iforce }
 | 
						{ 0x0000, 0x0000, "Unknown I-Force Device [%04x:%04x]",		btn_joystick, abs_joystick, ff_iforce }
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -229,6 +229,7 @@ static struct usb_device_id iforce_usb_ids [] = {
 | 
				
			||||||
	{ USB_DEVICE(0x061c, 0xc0a4) },         /* ACT LABS Force RS */
 | 
						{ USB_DEVICE(0x061c, 0xc0a4) },         /* ACT LABS Force RS */
 | 
				
			||||||
	{ USB_DEVICE(0x06f8, 0x0001) },		/* Guillemot Race Leader Force Feedback */
 | 
						{ USB_DEVICE(0x06f8, 0x0001) },		/* Guillemot Race Leader Force Feedback */
 | 
				
			||||||
	{ USB_DEVICE(0x06f8, 0x0004) },		/* Guillemot Force Feedback Racing Wheel */
 | 
						{ USB_DEVICE(0x06f8, 0x0004) },		/* Guillemot Force Feedback Racing Wheel */
 | 
				
			||||||
 | 
						{ USB_DEVICE(0x06f8, 0xa302) },		/* Guillemot Jet Leader 3D */
 | 
				
			||||||
	{ }					/* Terminating entry */
 | 
						{ }					/* Terminating entry */
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -4,8 +4,8 @@
 | 
				
			||||||
 *  Copyright (c) 1999-2001 Vojtech Pavlik
 | 
					 *  Copyright (c) 1999-2001 Vojtech Pavlik
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 *  Based on the work of:
 | 
					 *  Based on the work of:
 | 
				
			||||||
 *  	David Thompson
 | 
					 *	David Thompson
 | 
				
			||||||
 *  	Joseph Krahn
 | 
					 *	Joseph Krahn
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -4,7 +4,7 @@
 | 
				
			||||||
 *  Copyright (c) 1999-2001 Vojtech Pavlik
 | 
					 *  Copyright (c) 1999-2001 Vojtech Pavlik
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 *  Based on the work of:
 | 
					 *  Based on the work of:
 | 
				
			||||||
 *  	David Thompson
 | 
					 *	David Thompson
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -79,7 +79,7 @@ static short tmdc_btn_pad[TMDC_BTN] =
 | 
				
			||||||
	{ BTN_A, BTN_B, BTN_C, BTN_X, BTN_Y, BTN_Z, BTN_START, BTN_SELECT, BTN_TL, BTN_TR };
 | 
						{ BTN_A, BTN_B, BTN_C, BTN_X, BTN_Y, BTN_Z, BTN_START, BTN_SELECT, BTN_TL, BTN_TR };
 | 
				
			||||||
static short tmdc_btn_joy[TMDC_BTN] =
 | 
					static short tmdc_btn_joy[TMDC_BTN] =
 | 
				
			||||||
	{ BTN_TRIGGER, BTN_THUMB, BTN_TOP, BTN_TOP2, BTN_BASE, BTN_BASE2, BTN_THUMB2, BTN_PINKIE,
 | 
						{ BTN_TRIGGER, BTN_THUMB, BTN_TOP, BTN_TOP2, BTN_BASE, BTN_BASE2, BTN_THUMB2, BTN_PINKIE,
 | 
				
			||||||
 	  BTN_BASE3, BTN_BASE4, BTN_A, BTN_B, BTN_C, BTN_X, BTN_Y, BTN_Z };
 | 
						  BTN_BASE3, BTN_BASE4, BTN_A, BTN_B, BTN_C, BTN_X, BTN_Y, BTN_Z };
 | 
				
			||||||
static short tmdc_btn_fm[TMDC_BTN] =
 | 
					static short tmdc_btn_fm[TMDC_BTN] =
 | 
				
			||||||
        { BTN_TRIGGER, BTN_C, BTN_B, BTN_A, BTN_THUMB, BTN_X, BTN_Y, BTN_Z, BTN_TOP, BTN_TOP2 };
 | 
					        { BTN_TRIGGER, BTN_C, BTN_B, BTN_A, BTN_THUMB, BTN_X, BTN_Y, BTN_Z, BTN_TOP, BTN_TOP2 };
 | 
				
			||||||
static short tmdc_btn_at[TMDC_BTN] =
 | 
					static short tmdc_btn_at[TMDC_BTN] =
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -84,6 +84,7 @@ static struct tgfx {
 | 
				
			||||||
	char phys[7][32];
 | 
						char phys[7][32];
 | 
				
			||||||
	int sticks;
 | 
						int sticks;
 | 
				
			||||||
	int used;
 | 
						int used;
 | 
				
			||||||
 | 
						struct semaphore sem;
 | 
				
			||||||
} *tgfx_base[3];
 | 
					} *tgfx_base[3];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
| 
						 | 
					@ -99,7 +100,7 @@ static void tgfx_timer(unsigned long private)
 | 
				
			||||||
	for (i = 0; i < 7; i++)
 | 
						for (i = 0; i < 7; i++)
 | 
				
			||||||
		if (tgfx->sticks & (1 << i)) {
 | 
							if (tgfx->sticks & (1 << i)) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 			dev = tgfx->dev + i;
 | 
								dev = tgfx->dev + i;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			parport_write_data(tgfx->pd->port, ~(1 << i));
 | 
								parport_write_data(tgfx->pd->port, ~(1 << i));
 | 
				
			||||||
			data1 = parport_read_status(tgfx->pd->port) ^ 0x7f;
 | 
								data1 = parport_read_status(tgfx->pd->port) ^ 0x7f;
 | 
				
			||||||
| 
						 | 
					@ -122,23 +123,34 @@ static void tgfx_timer(unsigned long private)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int tgfx_open(struct input_dev *dev)
 | 
					static int tgfx_open(struct input_dev *dev)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
        struct tgfx *tgfx = dev->private;
 | 
						struct tgfx *tgfx = dev->private;
 | 
				
			||||||
        if (!tgfx->used++) {
 | 
						int err;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						err = down_interruptible(&tgfx->sem);
 | 
				
			||||||
 | 
						if (err)
 | 
				
			||||||
 | 
							return err;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!tgfx->used++) {
 | 
				
			||||||
		parport_claim(tgfx->pd);
 | 
							parport_claim(tgfx->pd);
 | 
				
			||||||
		parport_write_control(tgfx->pd->port, 0x04);
 | 
							parport_write_control(tgfx->pd->port, 0x04);
 | 
				
			||||||
                mod_timer(&tgfx->timer, jiffies + TGFX_REFRESH_TIME);
 | 
							mod_timer(&tgfx->timer, jiffies + TGFX_REFRESH_TIME);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
        return 0;
 | 
					
 | 
				
			||||||
 | 
						up(&tgfx->sem);
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void tgfx_close(struct input_dev *dev)
 | 
					static void tgfx_close(struct input_dev *dev)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
        struct tgfx *tgfx = dev->private;
 | 
						struct tgfx *tgfx = dev->private;
 | 
				
			||||||
        if (!--tgfx->used) {
 | 
					
 | 
				
			||||||
                del_timer(&tgfx->timer);
 | 
						down(&tgfx->sem);
 | 
				
			||||||
 | 
						if (!--tgfx->used) {
 | 
				
			||||||
 | 
							del_timer_sync(&tgfx->timer);
 | 
				
			||||||
		parport_write_control(tgfx->pd->port, 0x00);
 | 
							parport_write_control(tgfx->pd->port, 0x00);
 | 
				
			||||||
        	parport_release(tgfx->pd);
 | 
							parport_release(tgfx->pd);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
						up(&tgfx->sem);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
| 
						 | 
					@ -166,11 +178,12 @@ static struct tgfx __init *tgfx_probe(int *config, int nargs)
 | 
				
			||||||
		return NULL;
 | 
							return NULL;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!(tgfx = kmalloc(sizeof(struct tgfx), GFP_KERNEL))) {
 | 
						if (!(tgfx = kcalloc(1, sizeof(struct tgfx), GFP_KERNEL))) {
 | 
				
			||||||
		parport_put_port(pp);
 | 
							parport_put_port(pp);
 | 
				
			||||||
		return NULL;
 | 
							return NULL;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	memset(tgfx, 0, sizeof(struct tgfx));
 | 
					
 | 
				
			||||||
 | 
						init_MUTEX(&tgfx->sem);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	tgfx->pd = parport_register_device(pp, "turbografx", NULL, NULL, NULL, PARPORT_DEV_EXCL, NULL);
 | 
						tgfx->pd = parport_register_device(pp, "turbografx", NULL, NULL, NULL, PARPORT_DEV_EXCL, NULL);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -227,7 +227,7 @@ static ssize_t atkbd_do_set_##_name(struct device *d, struct device_attribute *a
 | 
				
			||||||
{										\
 | 
					{										\
 | 
				
			||||||
	return atkbd_attr_set_helper(d, b, s, atkbd_set_##_name);		\
 | 
						return atkbd_attr_set_helper(d, b, s, atkbd_set_##_name);		\
 | 
				
			||||||
}										\
 | 
					}										\
 | 
				
			||||||
static struct device_attribute atkbd_attr_##_name = 				\
 | 
					static struct device_attribute atkbd_attr_##_name =				\
 | 
				
			||||||
	__ATTR(_name, S_IWUSR | S_IRUGO, atkbd_do_show_##_name, atkbd_do_set_##_name);
 | 
						__ATTR(_name, S_IWUSR | S_IRUGO, atkbd_do_show_##_name, atkbd_do_set_##_name);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
ATKBD_DEFINE_ATTR(extra);
 | 
					ATKBD_DEFINE_ATTR(extra);
 | 
				
			||||||
| 
						 | 
					@ -388,7 +388,7 @@ static irqreturn_t atkbd_interrupt(struct serio *serio, unsigned char data,
 | 
				
			||||||
			value = atkbd->release ? 0 :
 | 
								value = atkbd->release ? 0 :
 | 
				
			||||||
				(1 + (!atkbd->softrepeat && test_bit(atkbd->keycode[code], atkbd->dev.key)));
 | 
									(1 + (!atkbd->softrepeat && test_bit(atkbd->keycode[code], atkbd->dev.key)));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			switch (value) { 	/* Workaround Toshiba laptop multiple keypress */
 | 
								switch (value) {	/* Workaround Toshiba laptop multiple keypress */
 | 
				
			||||||
				case 0:
 | 
									case 0:
 | 
				
			||||||
					atkbd->last = 0;
 | 
										atkbd->last = 0;
 | 
				
			||||||
					break;
 | 
										break;
 | 
				
			||||||
| 
						 | 
					@ -894,7 +894,7 @@ static int atkbd_reconnect(struct serio *serio)
 | 
				
			||||||
	if (atkbd->write) {
 | 
						if (atkbd->write) {
 | 
				
			||||||
		param[0] = (test_bit(LED_SCROLLL, atkbd->dev.led) ? 1 : 0)
 | 
							param[0] = (test_bit(LED_SCROLLL, atkbd->dev.led) ? 1 : 0)
 | 
				
			||||||
		         | (test_bit(LED_NUML,    atkbd->dev.led) ? 2 : 0)
 | 
							         | (test_bit(LED_NUML,    atkbd->dev.led) ? 2 : 0)
 | 
				
			||||||
 		         | (test_bit(LED_CAPSL,   atkbd->dev.led) ? 4 : 0);
 | 
							         | (test_bit(LED_CAPSL,   atkbd->dev.led) ? 4 : 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (atkbd_probe(atkbd))
 | 
							if (atkbd_probe(atkbd))
 | 
				
			||||||
			return -1;
 | 
								return -1;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -39,6 +39,7 @@
 | 
				
			||||||
#define CORGI_KEY_CALENDER	KEY_F1
 | 
					#define CORGI_KEY_CALENDER	KEY_F1
 | 
				
			||||||
#define CORGI_KEY_ADDRESS	KEY_F2
 | 
					#define CORGI_KEY_ADDRESS	KEY_F2
 | 
				
			||||||
#define CORGI_KEY_FN		KEY_F3
 | 
					#define CORGI_KEY_FN		KEY_F3
 | 
				
			||||||
 | 
					#define CORGI_KEY_CANCEL	KEY_F4
 | 
				
			||||||
#define CORGI_KEY_OFF		KEY_SUSPEND
 | 
					#define CORGI_KEY_OFF		KEY_SUSPEND
 | 
				
			||||||
#define CORGI_KEY_EXOK		KEY_F5
 | 
					#define CORGI_KEY_EXOK		KEY_F5
 | 
				
			||||||
#define CORGI_KEY_EXCANCEL	KEY_F6
 | 
					#define CORGI_KEY_EXCANCEL	KEY_F6
 | 
				
			||||||
| 
						 | 
					@ -46,6 +47,7 @@
 | 
				
			||||||
#define CORGI_KEY_EXJOGUP	KEY_F8
 | 
					#define CORGI_KEY_EXJOGUP	KEY_F8
 | 
				
			||||||
#define CORGI_KEY_JAP1		KEY_LEFTCTRL
 | 
					#define CORGI_KEY_JAP1		KEY_LEFTCTRL
 | 
				
			||||||
#define CORGI_KEY_JAP2		KEY_LEFTALT
 | 
					#define CORGI_KEY_JAP2		KEY_LEFTALT
 | 
				
			||||||
 | 
					#define CORGI_KEY_MAIL		KEY_F10
 | 
				
			||||||
#define CORGI_KEY_OK		KEY_F11
 | 
					#define CORGI_KEY_OK		KEY_F11
 | 
				
			||||||
#define CORGI_KEY_MENU		KEY_F12
 | 
					#define CORGI_KEY_MENU		KEY_F12
 | 
				
			||||||
#define CORGI_HINGE_0		KEY_KP0
 | 
					#define CORGI_HINGE_0		KEY_KP0
 | 
				
			||||||
| 
						 | 
					@ -59,8 +61,8 @@ static unsigned char corgikbd_keycode[NR_SCANCODES] = {
 | 
				
			||||||
	KEY_TAB, KEY_Q, KEY_E, KEY_T, KEY_G, KEY_U, KEY_J, KEY_K, 0, 0, 0, 0, 0, 0, 0, 0,                                 /* 33-48 */
 | 
						KEY_TAB, KEY_Q, KEY_E, KEY_T, KEY_G, KEY_U, KEY_J, KEY_K, 0, 0, 0, 0, 0, 0, 0, 0,                                 /* 33-48 */
 | 
				
			||||||
	CORGI_KEY_CALENDER, KEY_W, KEY_S, KEY_F, KEY_V, KEY_H, KEY_M, KEY_L, 0, KEY_RIGHTSHIFT, 0, 0, 0, 0, 0, 0,         /* 49-64 */
 | 
						CORGI_KEY_CALENDER, KEY_W, KEY_S, KEY_F, KEY_V, KEY_H, KEY_M, KEY_L, 0, KEY_RIGHTSHIFT, 0, 0, 0, 0, 0, 0,         /* 49-64 */
 | 
				
			||||||
	CORGI_KEY_ADDRESS, KEY_A, KEY_D, KEY_C, KEY_B, KEY_N, KEY_DOT, 0, KEY_ENTER, 0, KEY_LEFTSHIFT, 0, 0, 0, 0, 0, 	  /* 65-80 */
 | 
						CORGI_KEY_ADDRESS, KEY_A, KEY_D, KEY_C, KEY_B, KEY_N, KEY_DOT, 0, KEY_ENTER, 0, KEY_LEFTSHIFT, 0, 0, 0, 0, 0, 	  /* 65-80 */
 | 
				
			||||||
	KEY_MAIL, KEY_Z, KEY_X, KEY_MINUS, KEY_SPACE, KEY_COMMA, 0, KEY_UP, 0, 0, 0, CORGI_KEY_FN, 0, 0, 0, 0,            /* 81-96 */
 | 
						CORGI_KEY_MAIL, KEY_Z, KEY_X, KEY_MINUS, KEY_SPACE, KEY_COMMA, 0, KEY_UP, 0, 0, 0, CORGI_KEY_FN, 0, 0, 0, 0,            /* 81-96 */
 | 
				
			||||||
	KEY_SYSRQ, CORGI_KEY_JAP1, CORGI_KEY_JAP2, KEY_CANCEL, CORGI_KEY_OK, CORGI_KEY_MENU, KEY_LEFT, KEY_DOWN, KEY_RIGHT, 0, 0, 0, 0, 0, 0, 0,  /* 97-112 */
 | 
						KEY_SYSRQ, CORGI_KEY_JAP1, CORGI_KEY_JAP2, CORGI_KEY_CANCEL, CORGI_KEY_OK, CORGI_KEY_MENU, KEY_LEFT, KEY_DOWN, KEY_RIGHT, 0, 0, 0, 0, 0, 0, 0,  /* 97-112 */
 | 
				
			||||||
	CORGI_KEY_OFF, CORGI_KEY_EXOK, CORGI_KEY_EXCANCEL, CORGI_KEY_EXJOGDOWN, CORGI_KEY_EXJOGUP, 0, 0, 0, 0, 0, 0, 0,   /* 113-124 */
 | 
						CORGI_KEY_OFF, CORGI_KEY_EXOK, CORGI_KEY_EXCANCEL, CORGI_KEY_EXJOGDOWN, CORGI_KEY_EXJOGUP, 0, 0, 0, 0, 0, 0, 0,   /* 113-124 */
 | 
				
			||||||
	CORGI_HINGE_0, CORGI_HINGE_1, CORGI_HINGE_2	  /* 125-127 */
 | 
						CORGI_HINGE_0, CORGI_HINGE_1, CORGI_HINGE_2	  /* 125-127 */
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -15,10 +15,10 @@
 | 
				
			||||||
 * information given below, I will _not_ be liable!
 | 
					 * information given below, I will _not_ be liable!
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * RJ10 pinout:		To DE9:		Or DB25:
 | 
					 * RJ10 pinout:		To DE9:		Or DB25:
 | 
				
			||||||
 * 	1 - RxD <---->	Pin 3 (TxD) <->	Pin 2 (TxD)
 | 
					 *	1 - RxD <---->	Pin 3 (TxD) <->	Pin 2 (TxD)
 | 
				
			||||||
 * 	2 - GND <---->	Pin 5 (GND) <->	Pin 7 (GND)
 | 
					 *	2 - GND <---->	Pin 5 (GND) <->	Pin 7 (GND)
 | 
				
			||||||
 * 	4 - TxD <---->	Pin 2 (RxD) <->	Pin 3 (RxD)
 | 
					 *	4 - TxD <---->	Pin 2 (RxD) <->	Pin 3 (RxD)
 | 
				
			||||||
 * 	3 - +12V (from HDD drive connector), DON'T connect to DE9 or DB25!!!
 | 
					 *	3 - +12V (from HDD drive connector), DON'T connect to DE9 or DB25!!!
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * Pin numbers for DE9 and DB25 are noted on the plug (quite small:). For
 | 
					 * Pin numbers for DE9 and DB25 are noted on the plug (quite small:). For
 | 
				
			||||||
 * RJ10, it's like this:
 | 
					 * RJ10, it's like this:
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -42,7 +42,7 @@ MODULE_AUTHOR("John Lenz <lenz@cs.wisc.edu>");
 | 
				
			||||||
MODULE_DESCRIPTION("LoCoMo keyboard driver");
 | 
					MODULE_DESCRIPTION("LoCoMo keyboard driver");
 | 
				
			||||||
MODULE_LICENSE("GPL");
 | 
					MODULE_LICENSE("GPL");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define LOCOMOKBD_NUMKEYS 	128
 | 
					#define LOCOMOKBD_NUMKEYS	128
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define KEY_ACTIVITY		KEY_F16
 | 
					#define KEY_ACTIVITY		KEY_F16
 | 
				
			||||||
#define KEY_CONTACT		KEY_F18
 | 
					#define KEY_CONTACT		KEY_F18
 | 
				
			||||||
| 
						 | 
					@ -61,7 +61,7 @@ static unsigned char locomokbd_keycode[LOCOMOKBD_NUMKEYS] = {
 | 
				
			||||||
	KEY_G, KEY_F, KEY_X, KEY_S, 0, 0, 0, 0, 0, 0,				/* 90 - 99 */
 | 
						KEY_G, KEY_F, KEY_X, KEY_S, 0, 0, 0, 0, 0, 0,				/* 90 - 99 */
 | 
				
			||||||
	0, 0, KEY_DOT, 0, KEY_COMMA, KEY_N, KEY_B, KEY_C, KEY_Z, KEY_A,		/* 100 - 109 */
 | 
						0, 0, KEY_DOT, 0, KEY_COMMA, KEY_N, KEY_B, KEY_C, KEY_Z, KEY_A,		/* 100 - 109 */
 | 
				
			||||||
	KEY_LEFTSHIFT, KEY_TAB, KEY_LEFTCTRL, 0, 0, 0, 0, 0, 0, 0,		/* 110 - 119 */
 | 
						KEY_LEFTSHIFT, KEY_TAB, KEY_LEFTCTRL, 0, 0, 0, 0, 0, 0, 0,		/* 110 - 119 */
 | 
				
			||||||
	KEY_M, KEY_SPACE, KEY_V, KEY_APOSTROPHE, KEY_SLASH, 0, 0, 0 		/* 120 - 128 */
 | 
						KEY_M, KEY_SPACE, KEY_V, KEY_APOSTROPHE, KEY_SLASH, 0, 0, 0		/* 120 - 128 */
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define KB_ROWS			16
 | 
					#define KB_ROWS			16
 | 
				
			||||||
| 
						 | 
					@ -148,7 +148,7 @@ static void locomokbd_scankeyboard(struct locomokbd *locomokbd, struct pt_regs *
 | 
				
			||||||
		udelay(KB_DELAY);
 | 
							udelay(KB_DELAY);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		rowd = ~locomo_readl(membase + LOCOMO_KIB);
 | 
							rowd = ~locomo_readl(membase + LOCOMO_KIB);
 | 
				
			||||||
		for (row = 0; row < KB_ROWS; row++ ) {
 | 
							for (row = 0; row < KB_ROWS; row++) {
 | 
				
			||||||
			scancode = SCANCODE(col, row);
 | 
								scancode = SCANCODE(col, row);
 | 
				
			||||||
			if (rowd & KB_ROWMASK(row)) {
 | 
								if (rowd & KB_ROWMASK(row)) {
 | 
				
			||||||
				num_pressed += 1;
 | 
									num_pressed += 1;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,6 +1,6 @@
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 *	$Id: maple_keyb.c,v 1.4 2004/03/22 01:18:15 lethal Exp $
 | 
					 *	$Id: maple_keyb.c,v 1.4 2004/03/22 01:18:15 lethal Exp $
 | 
				
			||||||
 * 	SEGA Dreamcast keyboard driver
 | 
					 *	SEGA Dreamcast keyboard driver
 | 
				
			||||||
 *	Based on drivers/usb/usbkbd.c
 | 
					 *	Based on drivers/usb/usbkbd.c
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -40,7 +40,6 @@ struct dc_kbd {
 | 
				
			||||||
	struct input_dev dev;
 | 
						struct input_dev dev;
 | 
				
			||||||
	unsigned char new[8];
 | 
						unsigned char new[8];
 | 
				
			||||||
	unsigned char old[8];
 | 
						unsigned char old[8];
 | 
				
			||||||
	int open;
 | 
					 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -95,22 +94,6 @@ static void dc_kbd_callback(struct mapleq *mq)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
static int dc_kbd_open(struct input_dev *dev)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	struct dc_kbd *kbd = dev->private;
 | 
					 | 
				
			||||||
	kbd->open++;
 | 
					 | 
				
			||||||
	return 0;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static void dc_kbd_close(struct input_dev *dev)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	struct dc_kbd *kbd = dev->private;
 | 
					 | 
				
			||||||
	kbd->open--;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static int dc_kbd_connect(struct maple_device *dev)
 | 
					static int dc_kbd_connect(struct maple_device *dev)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	int i;
 | 
						int i;
 | 
				
			||||||
| 
						 | 
					@ -133,9 +116,6 @@ static int dc_kbd_connect(struct maple_device *dev)
 | 
				
			||||||
	clear_bit(0, kbd->dev.keybit);
 | 
						clear_bit(0, kbd->dev.keybit);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	kbd->dev.private = kbd;
 | 
						kbd->dev.private = kbd;
 | 
				
			||||||
	kbd->dev.open = dc_kbd_open;
 | 
					 | 
				
			||||||
	kbd->dev.close = dc_kbd_close;
 | 
					 | 
				
			||||||
	kbd->dev.event = NULL;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	kbd->dev.name = dev->product_name;
 | 
						kbd->dev.name = dev->product_name;
 | 
				
			||||||
	kbd->dev.id.bustype = BUS_MAPLE;
 | 
						kbd->dev.id.bustype = BUS_MAPLE;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -298,9 +298,11 @@ static int uinput_alloc_device(struct file *file, const char __user *buffer, siz
 | 
				
			||||||
	/* check if absmin/absmax/absfuzz/absflat are filled as
 | 
						/* check if absmin/absmax/absfuzz/absflat are filled as
 | 
				
			||||||
	 * told in Documentation/input/input-programming.txt */
 | 
						 * told in Documentation/input/input-programming.txt */
 | 
				
			||||||
	if (test_bit(EV_ABS, dev->evbit)) {
 | 
						if (test_bit(EV_ABS, dev->evbit)) {
 | 
				
			||||||
		retval = uinput_validate_absbits(dev);
 | 
							int err = uinput_validate_absbits(dev);
 | 
				
			||||||
		if (retval < 0)
 | 
							if (err < 0) {
 | 
				
			||||||
 | 
								retval = err;
 | 
				
			||||||
			kfree(dev->name);
 | 
								kfree(dev->name);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
exit:
 | 
					exit:
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -15,4 +15,4 @@ obj-$(CONFIG_MOUSE_SERIAL)	+= sermouse.o
 | 
				
			||||||
obj-$(CONFIG_MOUSE_HIL)		+= hil_ptr.o
 | 
					obj-$(CONFIG_MOUSE_HIL)		+= hil_ptr.o
 | 
				
			||||||
obj-$(CONFIG_MOUSE_VSXXXAA)	+= vsxxxaa.o
 | 
					obj-$(CONFIG_MOUSE_VSXXXAA)	+= vsxxxaa.o
 | 
				
			||||||
 | 
					
 | 
				
			||||||
psmouse-objs  := psmouse-base.o alps.o logips2pp.o synaptics.o
 | 
					psmouse-objs  := psmouse-base.o alps.o logips2pp.o synaptics.o lifebook.o
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -30,10 +30,11 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define ALPS_DUALPOINT	0x01
 | 
					#define ALPS_DUALPOINT	0x01
 | 
				
			||||||
#define ALPS_WHEEL	0x02
 | 
					#define ALPS_WHEEL	0x02
 | 
				
			||||||
#define ALPS_FW_BK	0x04
 | 
					#define ALPS_FW_BK_1	0x04
 | 
				
			||||||
#define ALPS_4BTN	0x08
 | 
					#define ALPS_4BTN	0x08
 | 
				
			||||||
#define ALPS_OLDPROTO	0x10
 | 
					#define ALPS_OLDPROTO	0x10
 | 
				
			||||||
#define ALPS_PASS	0x20
 | 
					#define ALPS_PASS	0x20
 | 
				
			||||||
 | 
					#define ALPS_FW_BK_2	0x40
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static struct alps_model_info alps_model_data[] = {
 | 
					static struct alps_model_info alps_model_data[] = {
 | 
				
			||||||
	{ { 0x33, 0x02, 0x0a },	0x88, 0xf8, ALPS_OLDPROTO },		/* UMAX-530T */
 | 
						{ { 0x33, 0x02, 0x0a },	0x88, 0xf8, ALPS_OLDPROTO },		/* UMAX-530T */
 | 
				
			||||||
| 
						 | 
					@ -43,11 +44,11 @@ static struct alps_model_info alps_model_data[] = {
 | 
				
			||||||
	{ { 0x63, 0x02, 0x14 },	0xf8, 0xf8, 0 },
 | 
						{ { 0x63, 0x02, 0x14 },	0xf8, 0xf8, 0 },
 | 
				
			||||||
	{ { 0x63, 0x02, 0x28 },	0xf8, 0xf8, 0 },
 | 
						{ { 0x63, 0x02, 0x28 },	0xf8, 0xf8, 0 },
 | 
				
			||||||
	{ { 0x63, 0x02, 0x3c },	0x8f, 0x8f, ALPS_WHEEL },		/* Toshiba Satellite S2400-103 */
 | 
						{ { 0x63, 0x02, 0x3c },	0x8f, 0x8f, ALPS_WHEEL },		/* Toshiba Satellite S2400-103 */
 | 
				
			||||||
	{ { 0x63, 0x02, 0x50 },	0xef, 0xef, ALPS_FW_BK },		/* NEC Versa L320 */
 | 
						{ { 0x63, 0x02, 0x50 },	0xef, 0xef, ALPS_FW_BK_1 },		/* NEC Versa L320 */
 | 
				
			||||||
	{ { 0x63, 0x02, 0x64 },	0xf8, 0xf8, 0 },
 | 
						{ { 0x63, 0x02, 0x64 },	0xf8, 0xf8, 0 },
 | 
				
			||||||
	{ { 0x63, 0x03, 0xc8 }, 0xf8, 0xf8, ALPS_PASS },		/* Dell Latitude D800 */
 | 
						{ { 0x63, 0x03, 0xc8 }, 0xf8, 0xf8, ALPS_PASS },		/* Dell Latitude D800 */
 | 
				
			||||||
	{ { 0x73, 0x02, 0x0a },	0xf8, 0xf8, 0 },
 | 
						{ { 0x73, 0x02, 0x0a },	0xf8, 0xf8, 0 },
 | 
				
			||||||
	{ { 0x73, 0x02, 0x14 },	0xf8, 0xf8, 0 },
 | 
						{ { 0x73, 0x02, 0x14 },	0xf8, 0xf8, ALPS_FW_BK_2 },		/* Ahtec Laptop */
 | 
				
			||||||
	{ { 0x20, 0x02, 0x0e },	0xf8, 0xf8, ALPS_PASS | ALPS_DUALPOINT }, /* XXX */
 | 
						{ { 0x20, 0x02, 0x0e },	0xf8, 0xf8, ALPS_PASS | ALPS_DUALPOINT }, /* XXX */
 | 
				
			||||||
	{ { 0x22, 0x02, 0x0a },	0xf8, 0xf8, ALPS_PASS | ALPS_DUALPOINT },
 | 
						{ { 0x22, 0x02, 0x0a },	0xf8, 0xf8, ALPS_PASS | ALPS_DUALPOINT },
 | 
				
			||||||
	{ { 0x22, 0x02, 0x14 }, 0xff, 0xff, ALPS_PASS | ALPS_DUALPOINT }, /* Dell Latitude D600 */
 | 
						{ { 0x22, 0x02, 0x14 }, 0xff, 0xff, ALPS_PASS | ALPS_DUALPOINT }, /* Dell Latitude D600 */
 | 
				
			||||||
| 
						 | 
					@ -81,6 +82,7 @@ static void alps_process_packet(struct psmouse *psmouse, struct pt_regs *regs)
 | 
				
			||||||
	struct input_dev *dev = &psmouse->dev;
 | 
						struct input_dev *dev = &psmouse->dev;
 | 
				
			||||||
	struct input_dev *dev2 = &priv->dev2;
 | 
						struct input_dev *dev2 = &priv->dev2;
 | 
				
			||||||
	int x, y, z, ges, fin, left, right, middle;
 | 
						int x, y, z, ges, fin, left, right, middle;
 | 
				
			||||||
 | 
						int back = 0, forward = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	input_regs(dev, regs);
 | 
						input_regs(dev, regs);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -112,6 +114,18 @@ static void alps_process_packet(struct psmouse *psmouse, struct pt_regs *regs)
 | 
				
			||||||
		z = packet[5];
 | 
							z = packet[5];
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (priv->i->flags & ALPS_FW_BK_1) {
 | 
				
			||||||
 | 
							back = packet[2] & 4;
 | 
				
			||||||
 | 
							forward = packet[0] & 0x10;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (priv->i->flags & ALPS_FW_BK_2) {
 | 
				
			||||||
 | 
							back = packet[3] & 4;
 | 
				
			||||||
 | 
							forward = packet[2] & 4;
 | 
				
			||||||
 | 
							if ((middle = forward && back))
 | 
				
			||||||
 | 
								forward = back = 0;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	ges = packet[2] & 1;
 | 
						ges = packet[2] & 1;
 | 
				
			||||||
	fin = packet[2] & 2;
 | 
						fin = packet[2] & 2;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -155,13 +169,12 @@ static void alps_process_packet(struct psmouse *psmouse, struct pt_regs *regs)
 | 
				
			||||||
	input_report_abs(dev, ABS_PRESSURE, z);
 | 
						input_report_abs(dev, ABS_PRESSURE, z);
 | 
				
			||||||
	input_report_key(dev, BTN_TOOL_FINGER, z > 0);
 | 
						input_report_key(dev, BTN_TOOL_FINGER, z > 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (priv->i->flags & ALPS_WHEEL)
 | 
						if (priv->i->flags & ALPS_WHEEL)
 | 
				
			||||||
		input_report_rel(dev, REL_WHEEL, ((packet[0] >> 4) & 0x07) | ((packet[2] >> 2) & 0x08));
 | 
							input_report_rel(dev, REL_WHEEL, ((packet[0] >> 4) & 0x07) | ((packet[2] >> 2) & 0x08));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (priv->i->flags & ALPS_FW_BK) {
 | 
						if (priv->i->flags & (ALPS_FW_BK_1 | ALPS_FW_BK_2)) {
 | 
				
			||||||
		input_report_key(dev, BTN_FORWARD, packet[0] & 0x10);
 | 
							input_report_key(dev, BTN_FORWARD, forward);
 | 
				
			||||||
		input_report_key(dev, BTN_BACK, packet[2] & 0x04);
 | 
							input_report_key(dev, BTN_BACK, back);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	input_sync(dev);
 | 
						input_sync(dev);
 | 
				
			||||||
| 
						 | 
					@ -257,7 +270,6 @@ static struct alps_model_info *alps_get_model(struct psmouse *psmouse, int *vers
 | 
				
			||||||
static int alps_passthrough_mode(struct psmouse *psmouse, int enable)
 | 
					static int alps_passthrough_mode(struct psmouse *psmouse, int enable)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct ps2dev *ps2dev = &psmouse->ps2dev;
 | 
						struct ps2dev *ps2dev = &psmouse->ps2dev;
 | 
				
			||||||
	unsigned char param[3];
 | 
					 | 
				
			||||||
	int cmd = enable ? PSMOUSE_CMD_SETSCALE21 : PSMOUSE_CMD_SETSCALE11;
 | 
						int cmd = enable ? PSMOUSE_CMD_SETSCALE21 : PSMOUSE_CMD_SETSCALE11;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (ps2_command(ps2dev, NULL, cmd) ||
 | 
						if (ps2_command(ps2dev, NULL, cmd) ||
 | 
				
			||||||
| 
						 | 
					@ -267,7 +279,7 @@ static int alps_passthrough_mode(struct psmouse *psmouse, int enable)
 | 
				
			||||||
		return -1;
 | 
							return -1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* we may get 3 more bytes, just ignore them */
 | 
						/* we may get 3 more bytes, just ignore them */
 | 
				
			||||||
	ps2_command(ps2dev, param, 0x0300);
 | 
						ps2_drain(ps2dev, 3, 100);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -425,7 +437,7 @@ int alps_init(struct psmouse *psmouse)
 | 
				
			||||||
		psmouse->dev.relbit[LONG(REL_WHEEL)] |= BIT(REL_WHEEL);
 | 
							psmouse->dev.relbit[LONG(REL_WHEEL)] |= BIT(REL_WHEEL);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (priv->i->flags & ALPS_FW_BK) {
 | 
						if (priv->i->flags & (ALPS_FW_BK_1 | ALPS_FW_BK_2)) {
 | 
				
			||||||
		psmouse->dev.keybit[LONG(BTN_FORWARD)] |= BIT(BTN_FORWARD);
 | 
							psmouse->dev.keybit[LONG(BTN_FORWARD)] |= BIT(BTN_FORWARD);
 | 
				
			||||||
		psmouse->dev.keybit[LONG(BTN_BACK)] |= BIT(BTN_BACK);
 | 
							psmouse->dev.keybit[LONG(BTN_BACK)] |= BIT(BTN_BACK);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					@ -468,10 +480,8 @@ int alps_detect(struct psmouse *psmouse, int set_properties)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (set_properties) {
 | 
						if (set_properties) {
 | 
				
			||||||
		psmouse->vendor = "ALPS";
 | 
							psmouse->vendor = "ALPS";
 | 
				
			||||||
		if (model->flags & ALPS_DUALPOINT) 
 | 
							psmouse->name = model->flags & ALPS_DUALPOINT ?
 | 
				
			||||||
			psmouse->name = "DualPoint TouchPad";
 | 
									"DualPoint TouchPad" : "GlidePoint";
 | 
				
			||||||
		else
 | 
					 | 
				
			||||||
			psmouse->name = "GlidePoint";
 | 
					 | 
				
			||||||
		psmouse->model = version;
 | 
							psmouse->model = version;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -33,7 +33,6 @@ MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
 | 
				
			||||||
MODULE_DESCRIPTION("Amiga mouse driver");
 | 
					MODULE_DESCRIPTION("Amiga mouse driver");
 | 
				
			||||||
MODULE_LICENSE("GPL");
 | 
					MODULE_LICENSE("GPL");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int amimouse_used = 0;
 | 
					 | 
				
			||||||
static int amimouse_lastx, amimouse_lasty;
 | 
					static int amimouse_lastx, amimouse_lasty;
 | 
				
			||||||
static struct input_dev amimouse_dev;
 | 
					static struct input_dev amimouse_dev;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -81,16 +80,12 @@ static int amimouse_open(struct input_dev *dev)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	unsigned short joy0dat;
 | 
						unsigned short joy0dat;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (amimouse_used++)
 | 
					 | 
				
			||||||
                return 0;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	joy0dat = custom.joy0dat;
 | 
						joy0dat = custom.joy0dat;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	amimouse_lastx = joy0dat & 0xff;
 | 
						amimouse_lastx = joy0dat & 0xff;
 | 
				
			||||||
	amimouse_lasty = joy0dat >> 8;
 | 
						amimouse_lasty = joy0dat >> 8;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (request_irq(IRQ_AMIGA_VERTB, amimouse_interrupt, 0, "amimouse", amimouse_interrupt)) {
 | 
						if (request_irq(IRQ_AMIGA_VERTB, amimouse_interrupt, 0, "amimouse", amimouse_interrupt)) {
 | 
				
			||||||
                amimouse_used--;
 | 
					 | 
				
			||||||
                printk(KERN_ERR "amimouse.c: Can't allocate irq %d\n", IRQ_AMIGA_VERTB);
 | 
					                printk(KERN_ERR "amimouse.c: Can't allocate irq %d\n", IRQ_AMIGA_VERTB);
 | 
				
			||||||
                return -EBUSY;
 | 
					                return -EBUSY;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
| 
						 | 
					@ -100,8 +95,7 @@ static int amimouse_open(struct input_dev *dev)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void amimouse_close(struct input_dev *dev)
 | 
					static void amimouse_close(struct input_dev *dev)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
        if (!--amimouse_used)
 | 
						free_irq(IRQ_AMIGA_VERTB, amimouse_interrupt);
 | 
				
			||||||
		free_irq(IRQ_AMIGA_VERTB, amimouse_interrupt);
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int __init amimouse_init(void)
 | 
					static int __init amimouse_init(void)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -87,29 +87,23 @@ MODULE_PARM_DESC(irq, "IRQ number (5=default)");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
__obsolete_setup("inport_irq=");
 | 
					__obsolete_setup("inport_irq=");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int inport_used;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static irqreturn_t inport_interrupt(int irq, void *dev_id, struct pt_regs *regs);
 | 
					static irqreturn_t inport_interrupt(int irq, void *dev_id, struct pt_regs *regs);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int inport_open(struct input_dev *dev)
 | 
					static int inport_open(struct input_dev *dev)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	if (!inport_used++) {
 | 
						if (request_irq(inport_irq, inport_interrupt, 0, "inport", NULL))
 | 
				
			||||||
		if (request_irq(inport_irq, inport_interrupt, 0, "inport", NULL))
 | 
							return -EBUSY;
 | 
				
			||||||
			return -EBUSY;
 | 
						outb(INPORT_REG_MODE, INPORT_CONTROL_PORT);
 | 
				
			||||||
		outb(INPORT_REG_MODE, INPORT_CONTROL_PORT);
 | 
						outb(INPORT_MODE_IRQ | INPORT_MODE_BASE, INPORT_DATA_PORT);
 | 
				
			||||||
		outb(INPORT_MODE_IRQ | INPORT_MODE_BASE, INPORT_DATA_PORT);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void inport_close(struct input_dev *dev)
 | 
					static void inport_close(struct input_dev *dev)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	if (!--inport_used) {
 | 
						outb(INPORT_REG_MODE, INPORT_CONTROL_PORT);
 | 
				
			||||||
		outb(INPORT_REG_MODE, INPORT_CONTROL_PORT);
 | 
						outb(INPORT_MODE_BASE, INPORT_DATA_PORT);
 | 
				
			||||||
		outb(INPORT_MODE_BASE, INPORT_DATA_PORT);
 | 
						free_irq(inport_irq, NULL);
 | 
				
			||||||
		free_irq(inport_irq, NULL);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static struct input_dev inport_dev = {
 | 
					static struct input_dev inport_dev = {
 | 
				
			||||||
| 
						 | 
					@ -121,10 +115,10 @@ static struct input_dev inport_dev = {
 | 
				
			||||||
	.name	= INPORT_NAME,
 | 
						.name	= INPORT_NAME,
 | 
				
			||||||
	.phys	= "isa023c/input0",
 | 
						.phys	= "isa023c/input0",
 | 
				
			||||||
	.id = {
 | 
						.id = {
 | 
				
			||||||
 		.bustype = BUS_ISA,
 | 
							.bustype = BUS_ISA,
 | 
				
			||||||
        	.vendor  = INPORT_VENDOR,
 | 
							.vendor  = INPORT_VENDOR,
 | 
				
			||||||
        	.product = 0x0001,
 | 
							.product = 0x0001,
 | 
				
			||||||
        	.version = 0x0100,
 | 
							.version = 0x0100,
 | 
				
			||||||
	},
 | 
						},
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										134
									
								
								drivers/input/mouse/lifebook.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										134
									
								
								drivers/input/mouse/lifebook.c
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,134 @@
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Fujitsu B-series Lifebook PS/2 TouchScreen driver
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Copyright (c) 2005 Vojtech Pavlik <vojtech@suse.cz>
 | 
				
			||||||
 | 
					 * Copyright (c) 2005 Kenan Esau <kenan.esau@conan.de>
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * TouchScreen detection, absolute mode setting and packet layout is taken from
 | 
				
			||||||
 | 
					 * Harald Hoyer's description of the device.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * 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/input.h>
 | 
				
			||||||
 | 
					#include <linux/serio.h>
 | 
				
			||||||
 | 
					#include <linux/libps2.h>
 | 
				
			||||||
 | 
					#include <linux/dmi.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "psmouse.h"
 | 
				
			||||||
 | 
					#include "lifebook.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static struct dmi_system_id lifebook_dmi_table[] = {
 | 
				
			||||||
 | 
					       {
 | 
				
			||||||
 | 
					               .ident = "Lifebook B",
 | 
				
			||||||
 | 
					               .matches = {
 | 
				
			||||||
 | 
					                       DMI_MATCH(DMI_PRODUCT_NAME, "LIFEBOOK B Series"),
 | 
				
			||||||
 | 
					               },
 | 
				
			||||||
 | 
					       },
 | 
				
			||||||
 | 
					       { }
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static psmouse_ret_t lifebook_process_byte(struct psmouse *psmouse, struct pt_regs *regs)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						unsigned char *packet = psmouse->packet;
 | 
				
			||||||
 | 
						struct input_dev *dev = &psmouse->dev;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (psmouse->pktcnt != 3)
 | 
				
			||||||
 | 
							return PSMOUSE_GOOD_DATA;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						input_regs(dev, regs);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* calculate X and Y */
 | 
				
			||||||
 | 
						if ((packet[0] & 0x08) == 0x00) {
 | 
				
			||||||
 | 
							input_report_abs(dev, ABS_X,
 | 
				
			||||||
 | 
									 (packet[1] | ((packet[0] & 0x30) << 4)));
 | 
				
			||||||
 | 
							input_report_abs(dev, ABS_Y,
 | 
				
			||||||
 | 
									 1024 - (packet[2] | ((packet[0] & 0xC0) << 2)));
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							input_report_rel(dev, REL_X,
 | 
				
			||||||
 | 
									((packet[0] & 0x10) ? packet[1] - 256 : packet[1]));
 | 
				
			||||||
 | 
							input_report_rel(dev, REL_Y,
 | 
				
			||||||
 | 
									 -(int)((packet[0] & 0x20) ? packet[2] - 256 : packet[2]));
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						input_report_key(dev, BTN_LEFT, packet[0] & 0x01);
 | 
				
			||||||
 | 
						input_report_key(dev, BTN_RIGHT, packet[0] & 0x02);
 | 
				
			||||||
 | 
						input_report_key(dev, BTN_TOUCH, packet[0] & 0x04);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						input_sync(dev);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return PSMOUSE_FULL_PACKET;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int lifebook_absolute_mode(struct psmouse *psmouse)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct ps2dev *ps2dev = &psmouse->ps2dev;
 | 
				
			||||||
 | 
						unsigned char param;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (psmouse_reset(psmouse))
 | 
				
			||||||
 | 
							return -1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/*
 | 
				
			||||||
 | 
						   Enable absolute output -- ps2_command fails always but if
 | 
				
			||||||
 | 
						   you leave this call out the touchsreen will never send
 | 
				
			||||||
 | 
						   absolute coordinates
 | 
				
			||||||
 | 
						*/
 | 
				
			||||||
 | 
						param = 0x07;
 | 
				
			||||||
 | 
						ps2_command(ps2dev, ¶m, PSMOUSE_CMD_SETRES);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void lifebook_set_resolution(struct psmouse *psmouse, unsigned int resolution)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						unsigned char params[] = { 0, 1, 2, 2, 3 };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (resolution == 0 || resolution > 400)
 | 
				
			||||||
 | 
							resolution = 400;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ps2_command(&psmouse->ps2dev, ¶ms[resolution / 100], PSMOUSE_CMD_SETRES);
 | 
				
			||||||
 | 
						psmouse->resolution = 50 << params[resolution / 100];
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void lifebook_disconnect(struct psmouse *psmouse)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						psmouse_reset(psmouse);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int lifebook_detect(struct psmouse *psmouse, int set_properties)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					        if (!dmi_check_system(lifebook_dmi_table))
 | 
				
			||||||
 | 
					                return -1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (set_properties) {
 | 
				
			||||||
 | 
							psmouse->vendor = "Fujitsu";
 | 
				
			||||||
 | 
							psmouse->name = "Lifebook TouchScreen";
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int lifebook_init(struct psmouse *psmouse)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						if (lifebook_absolute_mode(psmouse))
 | 
				
			||||||
 | 
							return -1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						psmouse->dev.evbit[0] = BIT(EV_ABS) | BIT(EV_KEY) | BIT(EV_REL);
 | 
				
			||||||
 | 
						psmouse->dev.keybit[LONG(BTN_LEFT)] = BIT(BTN_LEFT) | BIT(BTN_MIDDLE) | BIT(BTN_RIGHT);
 | 
				
			||||||
 | 
						psmouse->dev.keybit[LONG(BTN_TOUCH)] = BIT(BTN_TOUCH);
 | 
				
			||||||
 | 
						psmouse->dev.relbit[0] = BIT(REL_X) | BIT(REL_Y);
 | 
				
			||||||
 | 
						input_set_abs_params(&psmouse->dev, ABS_X, 0, 1024, 0, 0);
 | 
				
			||||||
 | 
						input_set_abs_params(&psmouse->dev, ABS_Y, 0, 1024, 0, 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						psmouse->protocol_handler = lifebook_process_byte;
 | 
				
			||||||
 | 
						psmouse->set_resolution = lifebook_set_resolution;
 | 
				
			||||||
 | 
						psmouse->disconnect = lifebook_disconnect;
 | 
				
			||||||
 | 
						psmouse->reconnect  = lifebook_absolute_mode;
 | 
				
			||||||
 | 
						psmouse->pktsize = 3;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										17
									
								
								drivers/input/mouse/lifebook.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								drivers/input/mouse/lifebook.h
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,17 @@
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Fujitsu B-series Lifebook PS/2 TouchScreen driver
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Copyright (c) 2005 Vojtech Pavlik
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * This program is free software; you can redistribute it and/or modify it
 | 
				
			||||||
 | 
					 * under the terms of the GNU General Public License version 2 as published by
 | 
				
			||||||
 | 
					 * the Free Software Foundation.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifndef _LIFEBOOK_H
 | 
				
			||||||
 | 
					#define _LIFEBOOK_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int lifebook_detect(struct psmouse *psmouse, int set_properties);
 | 
				
			||||||
 | 
					int lifebook_init(struct psmouse *psmouse);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
| 
						 | 
					@ -77,16 +77,11 @@ MODULE_PARM_DESC(irq, "IRQ number (5=default)");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
__obsolete_setup("logibm_irq=");
 | 
					__obsolete_setup("logibm_irq=");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int logibm_used = 0;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static irqreturn_t logibm_interrupt(int irq, void *dev_id, struct pt_regs *regs);
 | 
					static irqreturn_t logibm_interrupt(int irq, void *dev_id, struct pt_regs *regs);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int logibm_open(struct input_dev *dev)
 | 
					static int logibm_open(struct input_dev *dev)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	if (logibm_used++)
 | 
					 | 
				
			||||||
		return 0;
 | 
					 | 
				
			||||||
	if (request_irq(logibm_irq, logibm_interrupt, 0, "logibm", NULL)) {
 | 
						if (request_irq(logibm_irq, logibm_interrupt, 0, "logibm", NULL)) {
 | 
				
			||||||
		logibm_used--;
 | 
					 | 
				
			||||||
		printk(KERN_ERR "logibm.c: Can't allocate irq %d\n", logibm_irq);
 | 
							printk(KERN_ERR "logibm.c: Can't allocate irq %d\n", logibm_irq);
 | 
				
			||||||
		return -EBUSY;
 | 
							return -EBUSY;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					@ -96,8 +91,6 @@ static int logibm_open(struct input_dev *dev)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void logibm_close(struct input_dev *dev)
 | 
					static void logibm_close(struct input_dev *dev)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	if (--logibm_used)
 | 
					 | 
				
			||||||
		return;
 | 
					 | 
				
			||||||
	outb(LOGIBM_DISABLE_IRQ, LOGIBM_CONTROL_PORT);
 | 
						outb(LOGIBM_DISABLE_IRQ, LOGIBM_CONTROL_PORT);
 | 
				
			||||||
	free_irq(logibm_irq, NULL);
 | 
						free_irq(logibm_irq, NULL);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,6 +1,6 @@
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 *	$Id: maplemouse.c,v 1.2 2004/03/22 01:18:15 lethal Exp $
 | 
					 *	$Id: maplemouse.c,v 1.2 2004/03/22 01:18:15 lethal Exp $
 | 
				
			||||||
 * 	SEGA Dreamcast mouse driver
 | 
					 *	SEGA Dreamcast mouse driver
 | 
				
			||||||
 *	Based on drivers/usb/usbmouse.c
 | 
					 *	Based on drivers/usb/usbmouse.c
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -15,80 +15,51 @@
 | 
				
			||||||
MODULE_AUTHOR("YAEGASHI Takeshi <t@keshi.org>");
 | 
					MODULE_AUTHOR("YAEGASHI Takeshi <t@keshi.org>");
 | 
				
			||||||
MODULE_DESCRIPTION("SEGA Dreamcast mouse driver");
 | 
					MODULE_DESCRIPTION("SEGA Dreamcast mouse driver");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct dc_mouse {
 | 
					 | 
				
			||||||
	struct input_dev dev;
 | 
					 | 
				
			||||||
	int open;
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static void dc_mouse_callback(struct mapleq *mq)
 | 
					static void dc_mouse_callback(struct mapleq *mq)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	int buttons, relx, rely, relz;
 | 
						int buttons, relx, rely, relz;
 | 
				
			||||||
	struct maple_device *mapledev = mq->dev;
 | 
						struct maple_device *mapledev = mq->dev;
 | 
				
			||||||
	struct dc_mouse *mouse = mapledev->private_data;
 | 
						struct input_dev *dev = mapledev->private_data;
 | 
				
			||||||
	struct input_dev *dev = &mouse->dev;
 | 
					 | 
				
			||||||
	unsigned char *res = mq->recvbuf;
 | 
						unsigned char *res = mq->recvbuf;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	buttons = ~res[8];
 | 
						buttons = ~res[8];
 | 
				
			||||||
	relx=*(unsigned short *)(res+12)-512;
 | 
						relx = *(unsigned short *)(res + 12) - 512;
 | 
				
			||||||
	rely=*(unsigned short *)(res+14)-512;
 | 
						rely = *(unsigned short *)(res + 14) - 512;
 | 
				
			||||||
	relz=*(unsigned short *)(res+16)-512;
 | 
						relz = *(unsigned short *)(res + 16) - 512;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	input_report_key(dev, BTN_LEFT,   buttons&4);
 | 
						input_report_key(dev, BTN_LEFT,   buttons & 4);
 | 
				
			||||||
	input_report_key(dev, BTN_MIDDLE, buttons&9);
 | 
						input_report_key(dev, BTN_MIDDLE, buttons & 9);
 | 
				
			||||||
	input_report_key(dev, BTN_RIGHT,  buttons&2);
 | 
						input_report_key(dev, BTN_RIGHT,  buttons & 2);
 | 
				
			||||||
	input_report_rel(dev, REL_X,      relx);
 | 
						input_report_rel(dev, REL_X,      relx);
 | 
				
			||||||
	input_report_rel(dev, REL_Y,      rely);
 | 
						input_report_rel(dev, REL_Y,      rely);
 | 
				
			||||||
	input_report_rel(dev, REL_WHEEL,  relz);
 | 
						input_report_rel(dev, REL_WHEEL,  relz);
 | 
				
			||||||
	input_sync(dev);
 | 
						input_sync(dev);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
static int dc_mouse_open(struct input_dev *dev)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	struct dc_mouse *mouse = dev->private;
 | 
					 | 
				
			||||||
	mouse->open++;
 | 
					 | 
				
			||||||
	return 0;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static void dc_mouse_close(struct input_dev *dev)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	struct dc_mouse *mouse = dev->private;
 | 
					 | 
				
			||||||
	mouse->open--;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static int dc_mouse_connect(struct maple_device *dev)
 | 
					static int dc_mouse_connect(struct maple_device *dev)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	unsigned long data = be32_to_cpu(dev->devinfo.function_data[0]);
 | 
						unsigned long data = be32_to_cpu(dev->devinfo.function_data[0]);
 | 
				
			||||||
	struct dc_mouse *mouse;
 | 
						struct input_dev *input_dev;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!(mouse = kmalloc(sizeof(struct dc_mouse), GFP_KERNEL)))
 | 
						if (!(input_dev = kmalloc(sizeof(struct input_dev), GFP_KERNEL)))
 | 
				
			||||||
		return -1;
 | 
							return -1;
 | 
				
			||||||
	memset(mouse, 0, sizeof(struct dc_mouse));
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	dev->private_data = mouse;
 | 
						dev->private_data = input_dev;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	mouse->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_REL);
 | 
						memset(input_dev, 0, sizeof(struct dc_mouse));
 | 
				
			||||||
	mouse->dev.keybit[LONG(BTN_MOUSE)] = BIT(BTN_LEFT) | BIT(BTN_RIGHT) | BIT(BTN_MIDDLE);
 | 
						init_input_dev(input_dev);
 | 
				
			||||||
	mouse->dev.relbit[0] = BIT(REL_X) | BIT(REL_Y) | BIT(REL_WHEEL);
 | 
						input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REL);
 | 
				
			||||||
 | 
						input_dev->keybit[LONG(BTN_MOUSE)] = BIT(BTN_LEFT) | BIT(BTN_RIGHT) | BIT(BTN_MIDDLE);
 | 
				
			||||||
 | 
						input_dev->relbit[0] = BIT(REL_X) | BIT(REL_Y) | BIT(REL_WHEEL);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	init_input_dev(&mouse->dev);
 | 
						input_dev->name = dev->product_name;
 | 
				
			||||||
 | 
						input_dev->id.bustype = BUS_MAPLE;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	mouse->dev.private = mouse;
 | 
						input_register_device(input_dev);
 | 
				
			||||||
	mouse->dev.open = dc_mouse_open;
 | 
					 | 
				
			||||||
	mouse->dev.close = dc_mouse_close;
 | 
					 | 
				
			||||||
	mouse->dev.event = NULL;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	mouse->dev.name = dev->product_name;
 | 
					 | 
				
			||||||
	mouse->dev.id.bustype = BUS_MAPLE;
 | 
					 | 
				
			||||||
	
 | 
					 | 
				
			||||||
	input_register_device(&mouse->dev);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	maple_getcond_callback(dev, dc_mouse_callback, 1, MAPLE_FUNC_MOUSE);
 | 
						maple_getcond_callback(dev, dc_mouse_callback, 1, MAPLE_FUNC_MOUSE);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	printk(KERN_INFO "input: mouse(0x%lx): %s\n", data, mouse->dev.name);
 | 
						printk(KERN_INFO "input: mouse(0x%lx): %s\n", data, input_dev->name);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -96,10 +67,10 @@ static int dc_mouse_connect(struct maple_device *dev)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void dc_mouse_disconnect(struct maple_device *dev)
 | 
					static void dc_mouse_disconnect(struct maple_device *dev)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct dc_mouse *mouse = dev->private_data;
 | 
						struct input_dev *input_dev = dev->private_data;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	input_unregister_device(&mouse->dev);
 | 
						input_unregister_device(input_dev);
 | 
				
			||||||
	kfree(mouse);
 | 
						kfree(input_dev);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -56,7 +56,6 @@ static int pc110pad_io = 0x15e0;
 | 
				
			||||||
static struct input_dev pc110pad_dev;
 | 
					static struct input_dev pc110pad_dev;
 | 
				
			||||||
static int pc110pad_data[3];
 | 
					static int pc110pad_data[3];
 | 
				
			||||||
static int pc110pad_count;
 | 
					static int pc110pad_count;
 | 
				
			||||||
static int pc110pad_used;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
static char *pc110pad_name = "IBM PC110 TouchPad";
 | 
					static char *pc110pad_name = "IBM PC110 TouchPad";
 | 
				
			||||||
static char *pc110pad_phys = "isa15e0/input0";
 | 
					static char *pc110pad_phys = "isa15e0/input0";
 | 
				
			||||||
| 
						 | 
					@ -90,15 +89,11 @@ static irqreturn_t pc110pad_interrupt(int irq, void *ptr, struct pt_regs *regs)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void pc110pad_close(struct input_dev *dev)
 | 
					static void pc110pad_close(struct input_dev *dev)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	if (!--pc110pad_used)
 | 
						outb(PC110PAD_OFF, pc110pad_io + 2);
 | 
				
			||||||
		outb(PC110PAD_OFF, pc110pad_io + 2);
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int pc110pad_open(struct input_dev *dev)
 | 
					static int pc110pad_open(struct input_dev *dev)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	if (pc110pad_used++)
 | 
					 | 
				
			||||||
		return 0;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	pc110pad_interrupt(0,NULL,NULL);
 | 
						pc110pad_interrupt(0,NULL,NULL);
 | 
				
			||||||
	pc110pad_interrupt(0,NULL,NULL);
 | 
						pc110pad_interrupt(0,NULL,NULL);
 | 
				
			||||||
	pc110pad_interrupt(0,NULL,NULL);
 | 
						pc110pad_interrupt(0,NULL,NULL);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -24,6 +24,7 @@
 | 
				
			||||||
#include "synaptics.h"
 | 
					#include "synaptics.h"
 | 
				
			||||||
#include "logips2pp.h"
 | 
					#include "logips2pp.h"
 | 
				
			||||||
#include "alps.h"
 | 
					#include "alps.h"
 | 
				
			||||||
 | 
					#include "lifebook.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define DRIVER_DESC	"PS/2 mouse driver"
 | 
					#define DRIVER_DESC	"PS/2 mouse driver"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -31,10 +32,9 @@ MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>");
 | 
				
			||||||
MODULE_DESCRIPTION(DRIVER_DESC);
 | 
					MODULE_DESCRIPTION(DRIVER_DESC);
 | 
				
			||||||
MODULE_LICENSE("GPL");
 | 
					MODULE_LICENSE("GPL");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static unsigned int psmouse_max_proto = -1U;
 | 
					static unsigned int psmouse_max_proto = PSMOUSE_AUTO;
 | 
				
			||||||
static int psmouse_set_maxproto(const char *val, struct kernel_param *kp);
 | 
					static int psmouse_set_maxproto(const char *val, struct kernel_param *kp);
 | 
				
			||||||
static int psmouse_get_maxproto(char *buffer, struct kernel_param *kp);
 | 
					static int psmouse_get_maxproto(char *buffer, struct kernel_param *kp);
 | 
				
			||||||
static char *psmouse_proto_abbrev[] = { NULL, "bare", NULL, NULL, NULL, "imps", "exps", NULL, NULL, NULL };
 | 
					 | 
				
			||||||
#define param_check_proto_abbrev(name, p)	__param_check(name, p, unsigned int)
 | 
					#define param_check_proto_abbrev(name, p)	__param_check(name, p, unsigned int)
 | 
				
			||||||
#define param_set_proto_abbrev			psmouse_set_maxproto
 | 
					#define param_set_proto_abbrev			psmouse_set_maxproto
 | 
				
			||||||
#define param_get_proto_abbrev			psmouse_get_maxproto
 | 
					#define param_get_proto_abbrev			psmouse_get_maxproto
 | 
				
			||||||
| 
						 | 
					@ -57,6 +57,7 @@ static unsigned int psmouse_resetafter;
 | 
				
			||||||
module_param_named(resetafter, psmouse_resetafter, uint, 0644);
 | 
					module_param_named(resetafter, psmouse_resetafter, uint, 0644);
 | 
				
			||||||
MODULE_PARM_DESC(resetafter, "Reset device after so many bad packets (0 = never).");
 | 
					MODULE_PARM_DESC(resetafter, "Reset device after so many bad packets (0 = never).");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					PSMOUSE_DEFINE_ATTR(protocol);
 | 
				
			||||||
PSMOUSE_DEFINE_ATTR(rate);
 | 
					PSMOUSE_DEFINE_ATTR(rate);
 | 
				
			||||||
PSMOUSE_DEFINE_ATTR(resolution);
 | 
					PSMOUSE_DEFINE_ATTR(resolution);
 | 
				
			||||||
PSMOUSE_DEFINE_ATTR(resetafter);
 | 
					PSMOUSE_DEFINE_ATTR(resetafter);
 | 
				
			||||||
| 
						 | 
					@ -67,7 +68,23 @@ __obsolete_setup("psmouse_smartscroll=");
 | 
				
			||||||
__obsolete_setup("psmouse_resetafter=");
 | 
					__obsolete_setup("psmouse_resetafter=");
 | 
				
			||||||
__obsolete_setup("psmouse_rate=");
 | 
					__obsolete_setup("psmouse_rate=");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static char *psmouse_protocols[] = { "None", "PS/2", "PS2++", "ThinkPS/2", "GenPS/2", "ImPS/2", "ImExPS/2", "SynPS/2", "AlpsPS/2" };
 | 
					/*
 | 
				
			||||||
 | 
					 * psmouse_sem protects all operations changing state of mouse
 | 
				
			||||||
 | 
					 * (connecting, disconnecting, changing rate or resolution via
 | 
				
			||||||
 | 
					 * sysfs). We could use a per-device semaphore but since there
 | 
				
			||||||
 | 
					 * rarely more than one PS/2 mouse connected and since semaphore
 | 
				
			||||||
 | 
					 * is taken in "slow" paths it is not worth it.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					static DECLARE_MUTEX(psmouse_sem);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct psmouse_protocol {
 | 
				
			||||||
 | 
						enum psmouse_type type;
 | 
				
			||||||
 | 
						char *name;
 | 
				
			||||||
 | 
						char *alias;
 | 
				
			||||||
 | 
						int maxproto;
 | 
				
			||||||
 | 
						int (*detect)(struct psmouse *, int);
 | 
				
			||||||
 | 
						int (*init)(struct psmouse *);
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 * psmouse_process_byte() analyzes the PS/2 data stream and reports
 | 
					 * psmouse_process_byte() analyzes the PS/2 data stream and reports
 | 
				
			||||||
| 
						 | 
					@ -407,12 +424,15 @@ static int thinking_detect(struct psmouse *psmouse, int set_properties)
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
static int ps2bare_detect(struct psmouse *psmouse, int set_properties)
 | 
					static int ps2bare_detect(struct psmouse *psmouse, int set_properties)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	if (!psmouse->vendor) psmouse->vendor = "Generic";
 | 
						if (set_properties) {
 | 
				
			||||||
	if (!psmouse->name) psmouse->name = "Mouse";
 | 
							if (!psmouse->vendor) psmouse->vendor = "Generic";
 | 
				
			||||||
 | 
							if (!psmouse->name) psmouse->name = "Mouse";
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 * psmouse_extensions() probes for any extensions to the basic PS/2 protocol
 | 
					 * psmouse_extensions() probes for any extensions to the basic PS/2 protocol
 | 
				
			||||||
 * the mouse may have.
 | 
					 * the mouse may have.
 | 
				
			||||||
| 
						 | 
					@ -423,6 +443,17 @@ static int psmouse_extensions(struct psmouse *psmouse,
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	int synaptics_hardware = 0;
 | 
						int synaptics_hardware = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * We always check for lifebook because it does not disturb mouse
 | 
				
			||||||
 | 
					 * (it only checks DMI information).
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
						if (lifebook_detect(psmouse, set_properties) == 0) {
 | 
				
			||||||
 | 
							if (max_proto > PSMOUSE_IMEX) {
 | 
				
			||||||
 | 
								if (!set_properties || lifebook_init(psmouse) == 0)
 | 
				
			||||||
 | 
									return PSMOUSE_LIFEBOOK;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 * Try Kensington ThinkingMouse (we try first, because synaptics probe
 | 
					 * Try Kensington ThinkingMouse (we try first, because synaptics probe
 | 
				
			||||||
 * upsets the thinkingmouse).
 | 
					 * upsets the thinkingmouse).
 | 
				
			||||||
| 
						 | 
					@ -506,6 +537,103 @@ static int psmouse_extensions(struct psmouse *psmouse,
 | 
				
			||||||
	return PSMOUSE_PS2;
 | 
						return PSMOUSE_PS2;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static struct psmouse_protocol psmouse_protocols[] = {
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							.type		= PSMOUSE_PS2,
 | 
				
			||||||
 | 
							.name		= "PS/2",
 | 
				
			||||||
 | 
							.alias		= "bare",
 | 
				
			||||||
 | 
							.maxproto	= 1,
 | 
				
			||||||
 | 
							.detect		= ps2bare_detect,
 | 
				
			||||||
 | 
						},
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							.type		= PSMOUSE_PS2PP,
 | 
				
			||||||
 | 
							.name		= "PS2++",
 | 
				
			||||||
 | 
							.alias		= "logitech",
 | 
				
			||||||
 | 
							.detect		= ps2pp_init,
 | 
				
			||||||
 | 
						},
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							.type		= PSMOUSE_THINKPS,
 | 
				
			||||||
 | 
							.name		= "ThinkPS/2",
 | 
				
			||||||
 | 
							.alias		= "thinkps",
 | 
				
			||||||
 | 
							.detect		= thinking_detect,
 | 
				
			||||||
 | 
						},
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							.type		= PSMOUSE_GENPS,
 | 
				
			||||||
 | 
							.name		= "GenPS/2",
 | 
				
			||||||
 | 
							.alias		= "genius",
 | 
				
			||||||
 | 
							.detect		= genius_detect,
 | 
				
			||||||
 | 
						},
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							.type		= PSMOUSE_IMPS,
 | 
				
			||||||
 | 
							.name		= "ImPS/2",
 | 
				
			||||||
 | 
							.alias		= "imps",
 | 
				
			||||||
 | 
							.maxproto	= 1,
 | 
				
			||||||
 | 
							.detect		= intellimouse_detect,
 | 
				
			||||||
 | 
						},
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							.type		= PSMOUSE_IMEX,
 | 
				
			||||||
 | 
							.name		= "ImExPS/2",
 | 
				
			||||||
 | 
							.alias		= "exps",
 | 
				
			||||||
 | 
							.maxproto	= 1,
 | 
				
			||||||
 | 
							.detect		= im_explorer_detect,
 | 
				
			||||||
 | 
						},
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							.type		= PSMOUSE_SYNAPTICS,
 | 
				
			||||||
 | 
							.name		= "SynPS/2",
 | 
				
			||||||
 | 
							.alias		= "synaptics",
 | 
				
			||||||
 | 
							.detect		= synaptics_detect,
 | 
				
			||||||
 | 
							.init		= synaptics_init,
 | 
				
			||||||
 | 
						},
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							.type		= PSMOUSE_ALPS,
 | 
				
			||||||
 | 
							.name		= "AlpsPS/2",
 | 
				
			||||||
 | 
							.alias		= "alps",
 | 
				
			||||||
 | 
							.detect		= alps_detect,
 | 
				
			||||||
 | 
							.init		= alps_init,
 | 
				
			||||||
 | 
						},
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							.type		= PSMOUSE_LIFEBOOK,
 | 
				
			||||||
 | 
							.name		= "LBPS/2",
 | 
				
			||||||
 | 
							.alias		= "lifebook",
 | 
				
			||||||
 | 
							.init		= lifebook_init,
 | 
				
			||||||
 | 
						},
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							.type		= PSMOUSE_AUTO,
 | 
				
			||||||
 | 
							.name		= "auto",
 | 
				
			||||||
 | 
							.alias		= "any",
 | 
				
			||||||
 | 
							.maxproto	= 1,
 | 
				
			||||||
 | 
						},
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static struct psmouse_protocol *psmouse_protocol_by_type(enum psmouse_type type)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						int i;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for (i = 0; i < ARRAY_SIZE(psmouse_protocols); i++)
 | 
				
			||||||
 | 
							if (psmouse_protocols[i].type == type)
 | 
				
			||||||
 | 
								return &psmouse_protocols[i];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						WARN_ON(1);
 | 
				
			||||||
 | 
						return &psmouse_protocols[0];
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static struct psmouse_protocol *psmouse_protocol_by_name(const char *name, size_t len)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct psmouse_protocol *p;
 | 
				
			||||||
 | 
						int i;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for (i = 0; i < ARRAY_SIZE(psmouse_protocols); i++) {
 | 
				
			||||||
 | 
							p = &psmouse_protocols[i];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if ((strlen(p->name) == len && !strncmp(p->name, name, len)) ||
 | 
				
			||||||
 | 
							    (strlen(p->alias) == len && !strncmp(p->alias, name, len)))
 | 
				
			||||||
 | 
								return &psmouse_protocols[i];
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return NULL;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 * psmouse_probe() probes for a PS/2 mouse.
 | 
					 * psmouse_probe() probes for a PS/2 mouse.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
| 
						 | 
					@ -653,30 +781,84 @@ static void psmouse_cleanup(struct serio *serio)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void psmouse_disconnect(struct serio *serio)
 | 
					static void psmouse_disconnect(struct serio *serio)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct psmouse *psmouse, *parent;
 | 
						struct psmouse *psmouse, *parent = NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						psmouse = serio_get_drvdata(serio);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						device_remove_file(&serio->dev, &psmouse_attr_protocol);
 | 
				
			||||||
	device_remove_file(&serio->dev, &psmouse_attr_rate);
 | 
						device_remove_file(&serio->dev, &psmouse_attr_rate);
 | 
				
			||||||
	device_remove_file(&serio->dev, &psmouse_attr_resolution);
 | 
						device_remove_file(&serio->dev, &psmouse_attr_resolution);
 | 
				
			||||||
	device_remove_file(&serio->dev, &psmouse_attr_resetafter);
 | 
						device_remove_file(&serio->dev, &psmouse_attr_resetafter);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	psmouse = serio_get_drvdata(serio);
 | 
						down(&psmouse_sem);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	psmouse_set_state(psmouse, PSMOUSE_CMD_MODE);
 | 
						psmouse_set_state(psmouse, PSMOUSE_CMD_MODE);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (serio->parent && serio->id.type == SERIO_PS_PSTHRU) {
 | 
						if (serio->parent && serio->id.type == SERIO_PS_PSTHRU) {
 | 
				
			||||||
		parent = serio_get_drvdata(serio->parent);
 | 
							parent = serio_get_drvdata(serio->parent);
 | 
				
			||||||
		if (parent->pt_deactivate)
 | 
							psmouse_deactivate(parent);
 | 
				
			||||||
			parent->pt_deactivate(parent);
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (psmouse->disconnect)
 | 
						if (psmouse->disconnect)
 | 
				
			||||||
		psmouse->disconnect(psmouse);
 | 
							psmouse->disconnect(psmouse);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (parent && parent->pt_deactivate)
 | 
				
			||||||
 | 
							parent->pt_deactivate(parent);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	psmouse_set_state(psmouse, PSMOUSE_IGNORE);
 | 
						psmouse_set_state(psmouse, PSMOUSE_IGNORE);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	input_unregister_device(&psmouse->dev);
 | 
						input_unregister_device(&psmouse->dev);
 | 
				
			||||||
	serio_close(serio);
 | 
						serio_close(serio);
 | 
				
			||||||
	serio_set_drvdata(serio, NULL);
 | 
						serio_set_drvdata(serio, NULL);
 | 
				
			||||||
	kfree(psmouse);
 | 
						kfree(psmouse);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (parent)
 | 
				
			||||||
 | 
							psmouse_activate(parent);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						up(&psmouse_sem);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int psmouse_switch_protocol(struct psmouse *psmouse, struct psmouse_protocol *proto)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						memset(&psmouse->dev, 0, sizeof(struct input_dev));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						init_input_dev(&psmouse->dev);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						psmouse->dev.private = psmouse;
 | 
				
			||||||
 | 
						psmouse->dev.dev = &psmouse->ps2dev.serio->dev;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						psmouse->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_REL);
 | 
				
			||||||
 | 
						psmouse->dev.keybit[LONG(BTN_MOUSE)] = BIT(BTN_LEFT) | BIT(BTN_MIDDLE) | BIT(BTN_RIGHT);
 | 
				
			||||||
 | 
						psmouse->dev.relbit[0] = BIT(REL_X) | BIT(REL_Y);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						psmouse->set_rate = psmouse_set_rate;
 | 
				
			||||||
 | 
						psmouse->set_resolution = psmouse_set_resolution;
 | 
				
			||||||
 | 
						psmouse->protocol_handler = psmouse_process_byte;
 | 
				
			||||||
 | 
						psmouse->pktsize = 3;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (proto && (proto->detect || proto->init)) {
 | 
				
			||||||
 | 
							if (proto->detect && proto->detect(psmouse, 1) < 0)
 | 
				
			||||||
 | 
								return -1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (proto->init && proto->init(psmouse) < 0)
 | 
				
			||||||
 | 
								return -1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							psmouse->type = proto->type;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						else
 | 
				
			||||||
 | 
							psmouse->type = psmouse_extensions(psmouse, psmouse_max_proto, 1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						sprintf(psmouse->devname, "%s %s %s",
 | 
				
			||||||
 | 
							psmouse_protocol_by_type(psmouse->type)->name, psmouse->vendor, psmouse->name);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						psmouse->dev.name = psmouse->devname;
 | 
				
			||||||
 | 
						psmouse->dev.phys = psmouse->phys;
 | 
				
			||||||
 | 
						psmouse->dev.id.bustype = BUS_I8042;
 | 
				
			||||||
 | 
						psmouse->dev.id.vendor = 0x0002;
 | 
				
			||||||
 | 
						psmouse->dev.id.product = psmouse->type;
 | 
				
			||||||
 | 
						psmouse->dev.id.version = psmouse->model;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
| 
						 | 
					@ -688,6 +870,8 @@ static int psmouse_connect(struct serio *serio, struct serio_driver *drv)
 | 
				
			||||||
	struct psmouse *psmouse, *parent = NULL;
 | 
						struct psmouse *psmouse, *parent = NULL;
 | 
				
			||||||
	int retval;
 | 
						int retval;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						down(&psmouse_sem);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/*
 | 
						/*
 | 
				
			||||||
	 * If this is a pass-through port deactivate parent so the device
 | 
						 * If this is a pass-through port deactivate parent so the device
 | 
				
			||||||
	 * connected to this port can be successfully identified
 | 
						 * connected to this port can be successfully identified
 | 
				
			||||||
| 
						 | 
					@ -697,20 +881,14 @@ static int psmouse_connect(struct serio *serio, struct serio_driver *drv)
 | 
				
			||||||
		psmouse_deactivate(parent);
 | 
							psmouse_deactivate(parent);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!(psmouse = kmalloc(sizeof(struct psmouse), GFP_KERNEL))) {
 | 
						if (!(psmouse = kcalloc(1, sizeof(struct psmouse), GFP_KERNEL))) {
 | 
				
			||||||
		retval = -ENOMEM;
 | 
							retval = -ENOMEM;
 | 
				
			||||||
		goto out;
 | 
							goto out;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	memset(psmouse, 0, sizeof(struct psmouse));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	ps2_init(&psmouse->ps2dev, serio);
 | 
						ps2_init(&psmouse->ps2dev, serio);
 | 
				
			||||||
	sprintf(psmouse->phys, "%s/input0", serio->phys);
 | 
						sprintf(psmouse->phys, "%s/input0", serio->phys);
 | 
				
			||||||
	psmouse->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_REL);
 | 
					
 | 
				
			||||||
	psmouse->dev.keybit[LONG(BTN_MOUSE)] = BIT(BTN_LEFT) | BIT(BTN_MIDDLE) | BIT(BTN_RIGHT);
 | 
					 | 
				
			||||||
	psmouse->dev.relbit[0] = BIT(REL_X) | BIT(REL_Y);
 | 
					 | 
				
			||||||
	psmouse->dev.private = psmouse;
 | 
					 | 
				
			||||||
	psmouse->dev.dev = &serio->dev;
 | 
					 | 
				
			||||||
	psmouse_set_state(psmouse, PSMOUSE_INITIALIZING);
 | 
						psmouse_set_state(psmouse, PSMOUSE_INITIALIZING);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	serio_set_drvdata(serio, psmouse);
 | 
						serio_set_drvdata(serio, psmouse);
 | 
				
			||||||
| 
						 | 
					@ -734,25 +912,10 @@ static int psmouse_connect(struct serio *serio, struct serio_driver *drv)
 | 
				
			||||||
	psmouse->resolution = psmouse_resolution;
 | 
						psmouse->resolution = psmouse_resolution;
 | 
				
			||||||
	psmouse->resetafter = psmouse_resetafter;
 | 
						psmouse->resetafter = psmouse_resetafter;
 | 
				
			||||||
	psmouse->smartscroll = psmouse_smartscroll;
 | 
						psmouse->smartscroll = psmouse_smartscroll;
 | 
				
			||||||
	psmouse->set_rate = psmouse_set_rate;
 | 
					 | 
				
			||||||
	psmouse->set_resolution = psmouse_set_resolution;
 | 
					 | 
				
			||||||
	psmouse->protocol_handler = psmouse_process_byte;
 | 
					 | 
				
			||||||
	psmouse->pktsize = 3;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	psmouse->type = psmouse_extensions(psmouse, psmouse_max_proto, 1);
 | 
						psmouse_switch_protocol(psmouse, NULL);
 | 
				
			||||||
 | 
					 | 
				
			||||||
	sprintf(psmouse->devname, "%s %s %s",
 | 
					 | 
				
			||||||
		psmouse_protocols[psmouse->type], psmouse->vendor, psmouse->name);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	psmouse->dev.name = psmouse->devname;
 | 
					 | 
				
			||||||
	psmouse->dev.phys = psmouse->phys;
 | 
					 | 
				
			||||||
	psmouse->dev.id.bustype = BUS_I8042;
 | 
					 | 
				
			||||||
	psmouse->dev.id.vendor = 0x0002;
 | 
					 | 
				
			||||||
	psmouse->dev.id.product = psmouse->type;
 | 
					 | 
				
			||||||
	psmouse->dev.id.version = psmouse->model;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	input_register_device(&psmouse->dev);
 | 
						input_register_device(&psmouse->dev);
 | 
				
			||||||
 | 
					 | 
				
			||||||
	printk(KERN_INFO "input: %s on %s\n", psmouse->devname, serio->phys);
 | 
						printk(KERN_INFO "input: %s on %s\n", psmouse->devname, serio->phys);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	psmouse_set_state(psmouse, PSMOUSE_CMD_MODE);
 | 
						psmouse_set_state(psmouse, PSMOUSE_CMD_MODE);
 | 
				
			||||||
| 
						 | 
					@ -762,6 +925,7 @@ static int psmouse_connect(struct serio *serio, struct serio_driver *drv)
 | 
				
			||||||
	if (parent && parent->pt_activate)
 | 
						if (parent && parent->pt_activate)
 | 
				
			||||||
		parent->pt_activate(parent);
 | 
							parent->pt_activate(parent);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						device_create_file(&serio->dev, &psmouse_attr_protocol);
 | 
				
			||||||
	device_create_file(&serio->dev, &psmouse_attr_rate);
 | 
						device_create_file(&serio->dev, &psmouse_attr_rate);
 | 
				
			||||||
	device_create_file(&serio->dev, &psmouse_attr_resolution);
 | 
						device_create_file(&serio->dev, &psmouse_attr_resolution);
 | 
				
			||||||
	device_create_file(&serio->dev, &psmouse_attr_resetafter);
 | 
						device_create_file(&serio->dev, &psmouse_attr_resetafter);
 | 
				
			||||||
| 
						 | 
					@ -771,10 +935,11 @@ static int psmouse_connect(struct serio *serio, struct serio_driver *drv)
 | 
				
			||||||
	retval = 0;
 | 
						retval = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
out:
 | 
					out:
 | 
				
			||||||
	/* If this is a pass-through port the parent awaits to be activated */
 | 
						/* If this is a pass-through port the parent needs to be re-activated */
 | 
				
			||||||
	if (parent)
 | 
						if (parent)
 | 
				
			||||||
		psmouse_activate(parent);
 | 
							psmouse_activate(parent);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						up(&psmouse_sem);
 | 
				
			||||||
	return retval;
 | 
						return retval;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -791,6 +956,8 @@ static int psmouse_reconnect(struct serio *serio)
 | 
				
			||||||
		return -1;
 | 
							return -1;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						down(&psmouse_sem);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (serio->parent && serio->id.type == SERIO_PS_PSTHRU) {
 | 
						if (serio->parent && serio->id.type == SERIO_PS_PSTHRU) {
 | 
				
			||||||
		parent = serio_get_drvdata(serio->parent);
 | 
							parent = serio_get_drvdata(serio->parent);
 | 
				
			||||||
		psmouse_deactivate(parent);
 | 
							psmouse_deactivate(parent);
 | 
				
			||||||
| 
						 | 
					@ -823,6 +990,7 @@ out:
 | 
				
			||||||
	if (parent)
 | 
						if (parent)
 | 
				
			||||||
		psmouse_activate(parent);
 | 
							psmouse_activate(parent);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						up(&psmouse_sem);
 | 
				
			||||||
	return rc;
 | 
						return rc;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -893,26 +1061,109 @@ ssize_t psmouse_attr_set_helper(struct device *dev, const char *buf, size_t coun
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (serio->drv != &psmouse_drv) {
 | 
						if (serio->drv != &psmouse_drv) {
 | 
				
			||||||
		retval = -ENODEV;
 | 
							retval = -ENODEV;
 | 
				
			||||||
		goto out;
 | 
							goto out_unpin;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						retval = down_interruptible(&psmouse_sem);
 | 
				
			||||||
 | 
						if (retval)
 | 
				
			||||||
 | 
							goto out_unpin;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (psmouse->state == PSMOUSE_IGNORE) {
 | 
				
			||||||
 | 
							retval = -ENODEV;
 | 
				
			||||||
 | 
							goto out_up;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (serio->parent && serio->id.type == SERIO_PS_PSTHRU) {
 | 
						if (serio->parent && serio->id.type == SERIO_PS_PSTHRU) {
 | 
				
			||||||
		parent = serio_get_drvdata(serio->parent);
 | 
							parent = serio_get_drvdata(serio->parent);
 | 
				
			||||||
		psmouse_deactivate(parent);
 | 
							psmouse_deactivate(parent);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	psmouse_deactivate(psmouse);
 | 
						psmouse_deactivate(psmouse);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	retval = handler(psmouse, buf, count);
 | 
						retval = handler(psmouse, buf, count);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	psmouse_activate(psmouse);
 | 
						if (retval != -ENODEV)
 | 
				
			||||||
 | 
							psmouse_activate(psmouse);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (parent)
 | 
						if (parent)
 | 
				
			||||||
		psmouse_activate(parent);
 | 
							psmouse_activate(parent);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
out:
 | 
					 out_up:
 | 
				
			||||||
 | 
						up(&psmouse_sem);
 | 
				
			||||||
 | 
					 out_unpin:
 | 
				
			||||||
	serio_unpin_driver(serio);
 | 
						serio_unpin_driver(serio);
 | 
				
			||||||
	return retval;
 | 
						return retval;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static ssize_t psmouse_attr_show_protocol(struct psmouse *psmouse, char *buf)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						return sprintf(buf, "%s\n", psmouse_protocol_by_type(psmouse->type)->name);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static ssize_t psmouse_attr_set_protocol(struct psmouse *psmouse, const char *buf, size_t count)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct serio *serio = psmouse->ps2dev.serio;
 | 
				
			||||||
 | 
						struct psmouse *parent = NULL;
 | 
				
			||||||
 | 
						struct psmouse_protocol *proto;
 | 
				
			||||||
 | 
						int retry = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!(proto = psmouse_protocol_by_name(buf, count)))
 | 
				
			||||||
 | 
							return -EINVAL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (psmouse->type == proto->type)
 | 
				
			||||||
 | 
							return count;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						while (serio->child) {
 | 
				
			||||||
 | 
							if (++retry > 3) {
 | 
				
			||||||
 | 
								printk(KERN_WARNING "psmouse: failed to destroy child port, protocol change aborted.\n");
 | 
				
			||||||
 | 
								return -EIO;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							up(&psmouse_sem);
 | 
				
			||||||
 | 
							serio_unpin_driver(serio);
 | 
				
			||||||
 | 
							serio_unregister_child_port(serio);
 | 
				
			||||||
 | 
							serio_pin_driver_uninterruptible(serio);
 | 
				
			||||||
 | 
							down(&psmouse_sem);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (serio->drv != &psmouse_drv)
 | 
				
			||||||
 | 
								return -ENODEV;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (psmouse->type == proto->type)
 | 
				
			||||||
 | 
								return count; /* switched by other thread */
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (serio->parent && serio->id.type == SERIO_PS_PSTHRU) {
 | 
				
			||||||
 | 
							parent = serio_get_drvdata(serio->parent);
 | 
				
			||||||
 | 
							if (parent->pt_deactivate)
 | 
				
			||||||
 | 
								parent->pt_deactivate(parent);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (psmouse->disconnect)
 | 
				
			||||||
 | 
							psmouse->disconnect(psmouse);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						psmouse_set_state(psmouse, PSMOUSE_IGNORE);
 | 
				
			||||||
 | 
						input_unregister_device(&psmouse->dev);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						psmouse_set_state(psmouse, PSMOUSE_INITIALIZING);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (psmouse_switch_protocol(psmouse, proto) < 0) {
 | 
				
			||||||
 | 
							psmouse_reset(psmouse);
 | 
				
			||||||
 | 
							/* default to PSMOUSE_PS2 */
 | 
				
			||||||
 | 
							psmouse_switch_protocol(psmouse, &psmouse_protocols[0]);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						psmouse_initialize(psmouse);
 | 
				
			||||||
 | 
						psmouse_set_state(psmouse, PSMOUSE_CMD_MODE);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						input_register_device(&psmouse->dev);
 | 
				
			||||||
 | 
						printk(KERN_INFO "input: %s on %s\n", psmouse->devname, serio->phys);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (parent && parent->pt_activate)
 | 
				
			||||||
 | 
							parent->pt_activate(parent);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return count;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static ssize_t psmouse_attr_show_rate(struct psmouse *psmouse, char *buf)
 | 
					static ssize_t psmouse_attr_show_rate(struct psmouse *psmouse, char *buf)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	return sprintf(buf, "%d\n", psmouse->rate);
 | 
						return sprintf(buf, "%d\n", psmouse->rate);
 | 
				
			||||||
| 
						 | 
					@ -969,34 +1220,26 @@ static ssize_t psmouse_attr_set_resetafter(struct psmouse *psmouse, const char *
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int psmouse_set_maxproto(const char *val, struct kernel_param *kp)
 | 
					static int psmouse_set_maxproto(const char *val, struct kernel_param *kp)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	int i;
 | 
						struct psmouse_protocol *proto;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!val)
 | 
						if (!val)
 | 
				
			||||||
		return -EINVAL;
 | 
							return -EINVAL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!strncmp(val, "any", 3)) {
 | 
						proto = psmouse_protocol_by_name(val, strlen(val));
 | 
				
			||||||
		*((unsigned int *)kp->arg) = -1U;
 | 
					 | 
				
			||||||
		return 0;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for (i = 0; i < ARRAY_SIZE(psmouse_proto_abbrev); i++) {
 | 
						if (!proto || !proto->maxproto)
 | 
				
			||||||
		if (!psmouse_proto_abbrev[i])
 | 
							return -EINVAL;
 | 
				
			||||||
			continue;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (!strncmp(val, psmouse_proto_abbrev[i], strlen(psmouse_proto_abbrev[i]))) {
 | 
						*((unsigned int *)kp->arg) = proto->type;
 | 
				
			||||||
			*((unsigned int *)kp->arg) = i;
 | 
					 | 
				
			||||||
			return 0;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return -EINVAL;					\
 | 
						return 0;					\
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int psmouse_get_maxproto(char *buffer, struct kernel_param *kp)
 | 
					static int psmouse_get_maxproto(char *buffer, struct kernel_param *kp)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	return sprintf(buffer, "%s\n",
 | 
						int type = *((unsigned int *)kp->arg);
 | 
				
			||||||
			psmouse_max_proto < ARRAY_SIZE(psmouse_proto_abbrev) ?
 | 
					
 | 
				
			||||||
				psmouse_proto_abbrev[psmouse_max_proto] : "any");
 | 
						return sprintf(buffer, "%s\n", psmouse_protocol_by_type(type)->name);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int __init psmouse_init(void)
 | 
					static int __init psmouse_init(void)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -77,6 +77,8 @@ enum psmouse_type {
 | 
				
			||||||
	PSMOUSE_IMEX,
 | 
						PSMOUSE_IMEX,
 | 
				
			||||||
	PSMOUSE_SYNAPTICS,
 | 
						PSMOUSE_SYNAPTICS,
 | 
				
			||||||
	PSMOUSE_ALPS,
 | 
						PSMOUSE_ALPS,
 | 
				
			||||||
 | 
						PSMOUSE_LIFEBOOK,
 | 
				
			||||||
 | 
						PSMOUSE_AUTO		/* This one should always be last */
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int psmouse_sliced_command(struct psmouse *psmouse, unsigned char command);
 | 
					int psmouse_sliced_command(struct psmouse *psmouse, unsigned char command);
 | 
				
			||||||
| 
						 | 
					@ -99,7 +101,7 @@ static ssize_t psmouse_do_set_##_name(struct device *d, struct device_attribute
 | 
				
			||||||
{										\
 | 
					{										\
 | 
				
			||||||
	return psmouse_attr_set_helper(d, b, s, psmouse_attr_set_##_name);	\
 | 
						return psmouse_attr_set_helper(d, b, s, psmouse_attr_set_##_name);	\
 | 
				
			||||||
}										\
 | 
					}										\
 | 
				
			||||||
static struct device_attribute psmouse_attr_##_name = 				\
 | 
					static struct device_attribute psmouse_attr_##_name =				\
 | 
				
			||||||
	__ATTR(_name, S_IWUSR | S_IRUGO,					\
 | 
						__ATTR(_name, S_IWUSR | S_IRUGO,					\
 | 
				
			||||||
		psmouse_do_show_##_name, psmouse_do_set_##_name);
 | 
							psmouse_do_show_##_name, psmouse_do_set_##_name);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,7 +1,7 @@
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 * Driver for	DEC VSXXX-AA mouse (hockey-puck mouse, ball or two rollers)
 | 
					 * Driver for	DEC VSXXX-AA mouse (hockey-puck mouse, ball or two rollers)
 | 
				
			||||||
 * 		DEC VSXXX-GA mouse (rectangular mouse, with ball)
 | 
					 *		DEC VSXXX-GA mouse (rectangular mouse, with ball)
 | 
				
			||||||
 * 		DEC VSXXX-AB tablet (digitizer with hair cross or stylus)
 | 
					 *		DEC VSXXX-AB tablet (digitizer with hair cross or stylus)
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * Copyright (C) 2003-2004 by Jan-Benedict Glaw <jbglaw@lug-owl.de>
 | 
					 * Copyright (C) 2003-2004 by Jan-Benedict Glaw <jbglaw@lug-owl.de>
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -220,6 +220,7 @@ static void mousedev_notify_readers(struct mousedev *mousedev, struct mousedev_h
 | 
				
			||||||
	struct mousedev_list *list;
 | 
						struct mousedev_list *list;
 | 
				
			||||||
	struct mousedev_motion *p;
 | 
						struct mousedev_motion *p;
 | 
				
			||||||
	unsigned long flags;
 | 
						unsigned long flags;
 | 
				
			||||||
 | 
						int wake_readers = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	list_for_each_entry(list, &mousedev->list, node) {
 | 
						list_for_each_entry(list, &mousedev->list, node) {
 | 
				
			||||||
		spin_lock_irqsave(&list->packet_lock, flags);
 | 
							spin_lock_irqsave(&list->packet_lock, flags);
 | 
				
			||||||
| 
						 | 
					@ -255,11 +256,14 @@ static void mousedev_notify_readers(struct mousedev *mousedev, struct mousedev_h
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		spin_unlock_irqrestore(&list->packet_lock, flags);
 | 
							spin_unlock_irqrestore(&list->packet_lock, flags);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (list->ready)
 | 
							if (list->ready) {
 | 
				
			||||||
			kill_fasync(&list->fasync, SIGIO, POLL_IN);
 | 
								kill_fasync(&list->fasync, SIGIO, POLL_IN);
 | 
				
			||||||
 | 
								wake_readers = 1;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	wake_up_interruptible(&mousedev->wait);
 | 
						if (wake_readers)
 | 
				
			||||||
 | 
							wake_up_interruptible(&mousedev->wait);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void mousedev_touchpad_touch(struct mousedev *mousedev, int value)
 | 
					static void mousedev_touchpad_touch(struct mousedev *mousedev, int value)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -29,6 +29,7 @@ MODULE_LICENSE("GPL");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
EXPORT_SYMBOL(ps2_init);
 | 
					EXPORT_SYMBOL(ps2_init);
 | 
				
			||||||
EXPORT_SYMBOL(ps2_sendbyte);
 | 
					EXPORT_SYMBOL(ps2_sendbyte);
 | 
				
			||||||
 | 
					EXPORT_SYMBOL(ps2_drain);
 | 
				
			||||||
EXPORT_SYMBOL(ps2_command);
 | 
					EXPORT_SYMBOL(ps2_command);
 | 
				
			||||||
EXPORT_SYMBOL(ps2_schedule_command);
 | 
					EXPORT_SYMBOL(ps2_schedule_command);
 | 
				
			||||||
EXPORT_SYMBOL(ps2_handle_ack);
 | 
					EXPORT_SYMBOL(ps2_handle_ack);
 | 
				
			||||||
| 
						 | 
					@ -45,11 +46,11 @@ struct ps2work {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 * ps2_sendbyte() sends a byte to the mouse, and waits for acknowledge.
 | 
					 * ps2_sendbyte() sends a byte to the device and waits for acknowledge.
 | 
				
			||||||
 * It doesn't handle retransmission, though it could - because when there would
 | 
					 * It doesn't handle retransmission, though it could - because if there
 | 
				
			||||||
 * be need for retransmissions, the mouse has to be replaced anyway.
 | 
					 * is a need for retransmissions device has to be replaced anyway.
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * ps2_sendbyte() can only be called from a process context
 | 
					 * ps2_sendbyte() can only be called from a process context.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int ps2_sendbyte(struct ps2dev *ps2dev, unsigned char byte, int timeout)
 | 
					int ps2_sendbyte(struct ps2dev *ps2dev, unsigned char byte, int timeout)
 | 
				
			||||||
| 
						 | 
					@ -71,6 +72,91 @@ int ps2_sendbyte(struct ps2dev *ps2dev, unsigned char byte, int timeout)
 | 
				
			||||||
	return -ps2dev->nak;
 | 
						return -ps2dev->nak;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * ps2_drain() waits for device to transmit requested number of bytes
 | 
				
			||||||
 | 
					 * and discards them.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void ps2_drain(struct ps2dev *ps2dev, int maxbytes, int timeout)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						if (maxbytes > sizeof(ps2dev->cmdbuf)) {
 | 
				
			||||||
 | 
							WARN_ON(1);
 | 
				
			||||||
 | 
							maxbytes = sizeof(ps2dev->cmdbuf);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						down(&ps2dev->cmd_sem);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						serio_pause_rx(ps2dev->serio);
 | 
				
			||||||
 | 
						ps2dev->flags = PS2_FLAG_CMD;
 | 
				
			||||||
 | 
						ps2dev->cmdcnt = maxbytes;
 | 
				
			||||||
 | 
						serio_continue_rx(ps2dev->serio);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						wait_event_timeout(ps2dev->wait,
 | 
				
			||||||
 | 
								   !(ps2dev->flags & PS2_FLAG_CMD),
 | 
				
			||||||
 | 
								   msecs_to_jiffies(timeout));
 | 
				
			||||||
 | 
						up(&ps2dev->cmd_sem);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * ps2_is_keyboard_id() checks received ID byte against the list of
 | 
				
			||||||
 | 
					 * known keyboard IDs.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static inline int ps2_is_keyboard_id(char id_byte)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						static char keyboard_ids[] = {
 | 
				
			||||||
 | 
							0xab,	/* Regular keyboards		*/
 | 
				
			||||||
 | 
							0xac,	/* NCD Sun keyboard		*/
 | 
				
			||||||
 | 
							0x2b,	/* Trust keyboard, translated	*/
 | 
				
			||||||
 | 
							0x5d,	/* Trust keyboard		*/
 | 
				
			||||||
 | 
							0x60,	/* NMB SGI keyboard, translated */
 | 
				
			||||||
 | 
							0x47,	/* NMB SGI keyboard		*/
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return memchr(keyboard_ids, id_byte, sizeof(keyboard_ids)) != NULL;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * ps2_adjust_timeout() is called after receiving 1st byte of command
 | 
				
			||||||
 | 
					 * response and tries to reduce remaining timeout to speed up command
 | 
				
			||||||
 | 
					 * completion.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int ps2_adjust_timeout(struct ps2dev *ps2dev, int command, int timeout)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						switch (command) {
 | 
				
			||||||
 | 
							case PS2_CMD_RESET_BAT:
 | 
				
			||||||
 | 
								/*
 | 
				
			||||||
 | 
								 * Device has sent the first response byte after
 | 
				
			||||||
 | 
								 * reset command, reset is thus done, so we can
 | 
				
			||||||
 | 
								 * shorten the timeout.
 | 
				
			||||||
 | 
								 * The next byte will come soon (keyboard) or not
 | 
				
			||||||
 | 
								 * at all (mouse).
 | 
				
			||||||
 | 
								 */
 | 
				
			||||||
 | 
								if (timeout > msecs_to_jiffies(100))
 | 
				
			||||||
 | 
									timeout = msecs_to_jiffies(100);
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							case PS2_CMD_GETID:
 | 
				
			||||||
 | 
								/*
 | 
				
			||||||
 | 
								 * If device behind the port is not a keyboard there
 | 
				
			||||||
 | 
								 * won't be 2nd byte of ID response.
 | 
				
			||||||
 | 
								 */
 | 
				
			||||||
 | 
								if (!ps2_is_keyboard_id(ps2dev->cmdbuf[1])) {
 | 
				
			||||||
 | 
									serio_pause_rx(ps2dev->serio);
 | 
				
			||||||
 | 
									ps2dev->flags = ps2dev->cmdcnt = 0;
 | 
				
			||||||
 | 
									serio_continue_rx(ps2dev->serio);
 | 
				
			||||||
 | 
									timeout = 0;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							default:
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return timeout;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 * ps2_command() sends a command and its parameters to the mouse,
 | 
					 * ps2_command() sends a command and its parameters to the mouse,
 | 
				
			||||||
 * then waits for the response and puts it in the param array.
 | 
					 * then waits for the response and puts it in the param array.
 | 
				
			||||||
| 
						 | 
					@ -86,6 +172,11 @@ int ps2_command(struct ps2dev *ps2dev, unsigned char *param, int command)
 | 
				
			||||||
	int rc = -1;
 | 
						int rc = -1;
 | 
				
			||||||
	int i;
 | 
						int i;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (receive > sizeof(ps2dev->cmdbuf)) {
 | 
				
			||||||
 | 
							WARN_ON(1);
 | 
				
			||||||
 | 
							return -1;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	down(&ps2dev->cmd_sem);
 | 
						down(&ps2dev->cmd_sem);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	serio_pause_rx(ps2dev->serio);
 | 
						serio_pause_rx(ps2dev->serio);
 | 
				
			||||||
| 
						 | 
					@ -101,10 +192,9 @@ int ps2_command(struct ps2dev *ps2dev, unsigned char *param, int command)
 | 
				
			||||||
	 * ACKing the reset command, and so it can take a long
 | 
						 * ACKing the reset command, and so it can take a long
 | 
				
			||||||
	 * time before the ACK arrrives.
 | 
						 * time before the ACK arrrives.
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
	if (command & 0xff)
 | 
						if (ps2_sendbyte(ps2dev, command & 0xff,
 | 
				
			||||||
		if (ps2_sendbyte(ps2dev, command & 0xff,
 | 
								 command == PS2_CMD_RESET_BAT ? 1000 : 200))
 | 
				
			||||||
			command == PS2_CMD_RESET_BAT ? 1000 : 200))
 | 
							goto out;
 | 
				
			||||||
			goto out;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for (i = 0; i < send; i++)
 | 
						for (i = 0; i < send; i++)
 | 
				
			||||||
		if (ps2_sendbyte(ps2dev, param[i], 200))
 | 
							if (ps2_sendbyte(ps2dev, param[i], 200))
 | 
				
			||||||
| 
						 | 
					@ -120,33 +210,7 @@ int ps2_command(struct ps2dev *ps2dev, unsigned char *param, int command)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (ps2dev->cmdcnt && timeout > 0) {
 | 
						if (ps2dev->cmdcnt && timeout > 0) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (command == PS2_CMD_RESET_BAT && timeout > msecs_to_jiffies(100)) {
 | 
							timeout = ps2_adjust_timeout(ps2dev, command, timeout);
 | 
				
			||||||
			/*
 | 
					 | 
				
			||||||
			 * Device has sent the first response byte
 | 
					 | 
				
			||||||
			 * after a reset command, reset is thus done,
 | 
					 | 
				
			||||||
			 * shorten the timeout. The next byte will come
 | 
					 | 
				
			||||||
			 * soon (keyboard) or not at all (mouse).
 | 
					 | 
				
			||||||
			 */
 | 
					 | 
				
			||||||
			timeout = msecs_to_jiffies(100);
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		if (command == PS2_CMD_GETID &&
 | 
					 | 
				
			||||||
		    ps2dev->cmdbuf[receive - 1] != 0xab && /* Regular keyboards */
 | 
					 | 
				
			||||||
		    ps2dev->cmdbuf[receive - 1] != 0xac && /* NCD Sun keyboard */
 | 
					 | 
				
			||||||
		    ps2dev->cmdbuf[receive - 1] != 0x2b && /* Trust keyboard, translated */
 | 
					 | 
				
			||||||
		    ps2dev->cmdbuf[receive - 1] != 0x5d && /* Trust keyboard */
 | 
					 | 
				
			||||||
		    ps2dev->cmdbuf[receive - 1] != 0x60 && /* NMB SGI keyboard, translated */
 | 
					 | 
				
			||||||
		    ps2dev->cmdbuf[receive - 1] != 0x47) { /* NMB SGI keyboard */
 | 
					 | 
				
			||||||
			/*
 | 
					 | 
				
			||||||
			 * Device behind the port is not a keyboard
 | 
					 | 
				
			||||||
			 * so we don't need to wait for the 2nd byte
 | 
					 | 
				
			||||||
			 * of ID response.
 | 
					 | 
				
			||||||
			 */
 | 
					 | 
				
			||||||
			serio_pause_rx(ps2dev->serio);
 | 
					 | 
				
			||||||
			ps2dev->flags = ps2dev->cmdcnt = 0;
 | 
					 | 
				
			||||||
			serio_continue_rx(ps2dev->serio);
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		wait_event_timeout(ps2dev->wait,
 | 
							wait_event_timeout(ps2dev->wait,
 | 
				
			||||||
				   !(ps2dev->flags & PS2_FLAG_CMD), timeout);
 | 
									   !(ps2dev->flags & PS2_FLAG_CMD), timeout);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					@ -160,7 +224,7 @@ int ps2_command(struct ps2dev *ps2dev, unsigned char *param, int command)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	rc = 0;
 | 
						rc = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
out:
 | 
					 out:
 | 
				
			||||||
	serio_pause_rx(ps2dev->serio);
 | 
						serio_pause_rx(ps2dev->serio);
 | 
				
			||||||
	ps2dev->flags = 0;
 | 
						ps2dev->flags = 0;
 | 
				
			||||||
	serio_continue_rx(ps2dev->serio);
 | 
						serio_continue_rx(ps2dev->serio);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -89,9 +89,9 @@ MODULE_LICENSE("GPL");
 | 
				
			||||||
#define H3600_SCANCODE_Q	4	 /* 4 -> Q button */
 | 
					#define H3600_SCANCODE_Q	4	 /* 4 -> Q button */
 | 
				
			||||||
#define	H3600_SCANCODE_START	5	 /* 5 -> start menu */
 | 
					#define	H3600_SCANCODE_START	5	 /* 5 -> start menu */
 | 
				
			||||||
#define	H3600_SCANCODE_UP	6	 /* 6 -> up */
 | 
					#define	H3600_SCANCODE_UP	6	 /* 6 -> up */
 | 
				
			||||||
#define H3600_SCANCODE_RIGHT	7 	 /* 7 -> right */
 | 
					#define H3600_SCANCODE_RIGHT	7	 /* 7 -> right */
 | 
				
			||||||
#define H3600_SCANCODE_LEFT 	8	 /* 8 -> left */
 | 
					#define H3600_SCANCODE_LEFT	8	 /* 8 -> left */
 | 
				
			||||||
#define H3600_SCANCODE_DOWN 	9	 /* 9 -> down */
 | 
					#define H3600_SCANCODE_DOWN	9	 /* 9 -> down */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static char *h3600_name = "H3600 TouchScreen";
 | 
					static char *h3600_name = "H3600 TouchScreen";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -113,7 +113,7 @@ struct h3600_dev {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static irqreturn_t action_button_handler(int irq, void *dev_id, struct pt_regs *regs)
 | 
					static irqreturn_t action_button_handler(int irq, void *dev_id, struct pt_regs *regs)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
        int down = (GPLR & GPIO_BITSY_ACTION_BUTTON) ? 0 : 1;
 | 
						int down = (GPLR & GPIO_BITSY_ACTION_BUTTON) ? 0 : 1;
 | 
				
			||||||
	struct input_dev *dev = (struct input_dev *) dev_id;
 | 
						struct input_dev *dev = (struct input_dev *) dev_id;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	input_regs(dev, regs);
 | 
						input_regs(dev, regs);
 | 
				
			||||||
| 
						 | 
					@ -125,7 +125,7 @@ static irqreturn_t action_button_handler(int irq, void *dev_id, struct pt_regs *
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static irqreturn_t npower_button_handler(int irq, void *dev_id, struct pt_regs *regs)
 | 
					static irqreturn_t npower_button_handler(int irq, void *dev_id, struct pt_regs *regs)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
        int down = (GPLR & GPIO_BITSY_NPOWER_BUTTON) ? 0 : 1;
 | 
						int down = (GPLR & GPIO_BITSY_NPOWER_BUTTON) ? 0 : 1;
 | 
				
			||||||
	struct input_dev *dev = (struct input_dev *) dev_id;
 | 
						struct input_dev *dev = (struct input_dev *) dev_id;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/*
 | 
						/*
 | 
				
			||||||
| 
						 | 
					@ -145,8 +145,8 @@ static irqreturn_t npower_button_handler(int irq, void *dev_id, struct pt_regs *
 | 
				
			||||||
static int flite_brightness = 25;
 | 
					static int flite_brightness = 25;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
enum flite_pwr {
 | 
					enum flite_pwr {
 | 
				
			||||||
        FLITE_PWR_OFF = 0,
 | 
						FLITE_PWR_OFF = 0,
 | 
				
			||||||
        FLITE_PWR_ON = 1
 | 
						FLITE_PWR_ON = 1
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
| 
						 | 
					@ -157,9 +157,9 @@ unsigned int h3600_flite_power(struct input_dev *dev, enum flite_pwr pwr)
 | 
				
			||||||
	struct h3600_dev *ts = dev->private;
 | 
						struct h3600_dev *ts = dev->private;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Must be in this order */
 | 
						/* Must be in this order */
 | 
				
			||||||
       	ts->serio->write(ts->serio, 1);
 | 
						ts->serio->write(ts->serio, 1);
 | 
				
			||||||
	ts->serio->write(ts->serio, pwr);
 | 
						ts->serio->write(ts->serio, pwr);
 | 
				
			||||||
      	ts->serio->write(ts->serio, brightness);
 | 
						ts->serio->write(ts->serio, brightness);
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -169,26 +169,26 @@ static int h3600ts_pm_callback(struct pm_dev *pm_dev, pm_request_t req,
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct input_dev *dev = (struct input_dev *) data;
 | 
						struct input_dev *dev = (struct input_dev *) data;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        switch (req) {
 | 
						switch (req) {
 | 
				
			||||||
        case PM_SUSPEND: /* enter D1-D3 */
 | 
						case PM_SUSPEND: /* enter D1-D3 */
 | 
				
			||||||
                suspended = 1;
 | 
							suspended = 1;
 | 
				
			||||||
                h3600_flite_power(dev, FLITE_PWR_OFF);
 | 
							h3600_flite_power(dev, FLITE_PWR_OFF);
 | 
				
			||||||
                break;
 | 
							break;
 | 
				
			||||||
        case PM_BLANK:
 | 
						case PM_BLANK:
 | 
				
			||||||
                if (!suspended)
 | 
							if (!suspended)
 | 
				
			||||||
                        h3600_flite_power(dev, FLITE_PWR_OFF);
 | 
								h3600_flite_power(dev, FLITE_PWR_OFF);
 | 
				
			||||||
                break;
 | 
							break;
 | 
				
			||||||
        case PM_RESUME:  /* enter D0 */
 | 
						case PM_RESUME:  /* enter D0 */
 | 
				
			||||||
                /* same as unblank */
 | 
							/* same as unblank */
 | 
				
			||||||
        case PM_UNBLANK:
 | 
						case PM_UNBLANK:
 | 
				
			||||||
                if (suspended) {
 | 
							if (suspended) {
 | 
				
			||||||
                        //initSerial();
 | 
								//initSerial();
 | 
				
			||||||
                        suspended = 0;
 | 
								suspended = 0;
 | 
				
			||||||
                }
 | 
							}
 | 
				
			||||||
                h3600_flite_power(dev, FLITE_PWR_ON);
 | 
							h3600_flite_power(dev, FLITE_PWR_ON);
 | 
				
			||||||
                break;
 | 
							break;
 | 
				
			||||||
        }
 | 
						}
 | 
				
			||||||
        return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -199,25 +199,25 @@ static int h3600ts_pm_callback(struct pm_dev *pm_dev, pm_request_t req,
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
static void h3600ts_process_packet(struct h3600_dev *ts, struct pt_regs *regs)
 | 
					static void h3600ts_process_packet(struct h3600_dev *ts, struct pt_regs *regs)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
        struct input_dev *dev = &ts->dev;
 | 
						struct input_dev *dev = &ts->dev;
 | 
				
			||||||
	static int touched = 0;
 | 
						static int touched = 0;
 | 
				
			||||||
	int key, down = 0;
 | 
						int key, down = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	input_regs(dev, regs);
 | 
						input_regs(dev, regs);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        switch (ts->event) {
 | 
						switch (ts->event) {
 | 
				
			||||||
                /*
 | 
							/*
 | 
				
			||||||
                   Buttons - returned as a single byte
 | 
							   Buttons - returned as a single byte
 | 
				
			||||||
                        7 6 5 4 3 2 1 0
 | 
								7 6 5 4 3 2 1 0
 | 
				
			||||||
                        S x x x N N N N
 | 
								S x x x N N N N
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                   S       switch state ( 0=pressed 1=released)
 | 
							   S       switch state ( 0=pressed 1=released)
 | 
				
			||||||
                   x       Unused.
 | 
							   x       Unused.
 | 
				
			||||||
                   NNNN    switch number 0-15
 | 
							   NNNN    switch number 0-15
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                Note: This is true for non interrupt generated key events.
 | 
							   Note: This is true for non interrupt generated key events.
 | 
				
			||||||
                */
 | 
							*/
 | 
				
			||||||
                case KEYBD_ID:
 | 
							case KEYBD_ID:
 | 
				
			||||||
			down = (ts->buf[0] & 0x80) ? 0 : 1;
 | 
								down = (ts->buf[0] & 0x80) ? 0 : 1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			switch (ts->buf[0] & 0x7f) {
 | 
								switch (ts->buf[0] & 0x7f) {
 | 
				
			||||||
| 
						 | 
					@ -229,40 +229,40 @@ static void h3600ts_process_packet(struct h3600_dev *ts, struct pt_regs *regs)
 | 
				
			||||||
                                        break;
 | 
					                                        break;
 | 
				
			||||||
				case H3600_SCANCODE_CONTACTS:
 | 
									case H3600_SCANCODE_CONTACTS:
 | 
				
			||||||
					key = KEY_PROG2;
 | 
										key = KEY_PROG2;
 | 
				
			||||||
                                        break;
 | 
										break;
 | 
				
			||||||
				case H3600_SCANCODE_Q:
 | 
									case H3600_SCANCODE_Q:
 | 
				
			||||||
					key = KEY_Q;
 | 
										key = KEY_Q;
 | 
				
			||||||
                                        break;
 | 
										break;
 | 
				
			||||||
				case H3600_SCANCODE_START:
 | 
									case H3600_SCANCODE_START:
 | 
				
			||||||
					key = KEY_PROG3;
 | 
										key = KEY_PROG3;
 | 
				
			||||||
                                        break;
 | 
										break;
 | 
				
			||||||
				case H3600_SCANCODE_UP:
 | 
									case H3600_SCANCODE_UP:
 | 
				
			||||||
					key = KEY_UP;
 | 
										key = KEY_UP;
 | 
				
			||||||
                                        break;
 | 
										break;
 | 
				
			||||||
				case H3600_SCANCODE_RIGHT:
 | 
									case H3600_SCANCODE_RIGHT:
 | 
				
			||||||
					key = KEY_RIGHT;
 | 
										key = KEY_RIGHT;
 | 
				
			||||||
                                        break;
 | 
										break;
 | 
				
			||||||
				case H3600_SCANCODE_LEFT:
 | 
									case H3600_SCANCODE_LEFT:
 | 
				
			||||||
					key = KEY_LEFT;
 | 
										key = KEY_LEFT;
 | 
				
			||||||
                                        break;
 | 
										break;
 | 
				
			||||||
				case H3600_SCANCODE_DOWN:
 | 
									case H3600_SCANCODE_DOWN:
 | 
				
			||||||
					key = KEY_DOWN;
 | 
										key = KEY_DOWN;
 | 
				
			||||||
                                        break;
 | 
										break;
 | 
				
			||||||
				default:
 | 
									default:
 | 
				
			||||||
					key = 0;
 | 
										key = 0;
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
                        if (key)
 | 
								if (key)
 | 
				
			||||||
                        	input_report_key(dev, key, down);
 | 
									input_report_key(dev, key, down);
 | 
				
			||||||
                        break;
 | 
								break;
 | 
				
			||||||
                /*
 | 
							/*
 | 
				
			||||||
                 * Native touchscreen event data is formatted as shown below:-
 | 
							 * Native touchscreen event data is formatted as shown below:-
 | 
				
			||||||
                 *
 | 
							 *
 | 
				
			||||||
                 *      +-------+-------+-------+-------+
 | 
							 *      +-------+-------+-------+-------+
 | 
				
			||||||
                 *      | Xmsb  | Xlsb  | Ymsb  | Ylsb  |
 | 
							 *      | Xmsb  | Xlsb  | Ymsb  | Ylsb  |
 | 
				
			||||||
                 *      +-------+-------+-------+-------+
 | 
							 *      +-------+-------+-------+-------+
 | 
				
			||||||
                 *       byte 0    1       2       3
 | 
							 *       byte 0    1       2       3
 | 
				
			||||||
                 */
 | 
							 */
 | 
				
			||||||
                case TOUCHS_ID:
 | 
							case TOUCHS_ID:
 | 
				
			||||||
			if (!touched) {
 | 
								if (!touched) {
 | 
				
			||||||
				input_report_key(dev, BTN_TOUCH, 1);
 | 
									input_report_key(dev, BTN_TOUCH, 1);
 | 
				
			||||||
				touched = 1;
 | 
									touched = 1;
 | 
				
			||||||
| 
						 | 
					@ -272,19 +272,19 @@ static void h3600ts_process_packet(struct h3600_dev *ts, struct pt_regs *regs)
 | 
				
			||||||
				unsigned short x, y;
 | 
									unsigned short x, y;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
				x = ts->buf[0]; x <<= 8; x += ts->buf[1];
 | 
									x = ts->buf[0]; x <<= 8; x += ts->buf[1];
 | 
				
			||||||
                                y = ts->buf[2]; y <<= 8; y += ts->buf[3];
 | 
									y = ts->buf[2]; y <<= 8; y += ts->buf[3];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                       		input_report_abs(dev, ABS_X, x);
 | 
									input_report_abs(dev, ABS_X, x);
 | 
				
			||||||
                       		input_report_abs(dev, ABS_Y, y);
 | 
									input_report_abs(dev, ABS_Y, y);
 | 
				
			||||||
			} else {
 | 
								} else {
 | 
				
			||||||
		               	input_report_key(dev, BTN_TOUCH, 0);
 | 
									input_report_key(dev, BTN_TOUCH, 0);
 | 
				
			||||||
				touched = 0;
 | 
									touched = 0;
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
                        break;
 | 
								break;
 | 
				
			||||||
		default:
 | 
							default:
 | 
				
			||||||
			/* Send a non input event elsewhere */
 | 
								/* Send a non input event elsewhere */
 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
        }
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	input_sync(dev);
 | 
						input_sync(dev);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -293,7 +293,7 @@ static void h3600ts_process_packet(struct h3600_dev *ts, struct pt_regs *regs)
 | 
				
			||||||
 * h3600ts_event() handles events from the input module.
 | 
					 * h3600ts_event() handles events from the input module.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
static int h3600ts_event(struct input_dev *dev, unsigned int type,
 | 
					static int h3600ts_event(struct input_dev *dev, unsigned int type,
 | 
				
			||||||
		 	 unsigned int code, int value)
 | 
								 unsigned int code, int value)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct h3600_dev *ts = dev->private;
 | 
						struct h3600_dev *ts = dev->private;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -332,41 +332,41 @@ static int state;
 | 
				
			||||||
static irqreturn_t h3600ts_interrupt(struct serio *serio, unsigned char data,
 | 
					static irqreturn_t h3600ts_interrupt(struct serio *serio, unsigned char data,
 | 
				
			||||||
                                     unsigned int flags, struct pt_regs *regs)
 | 
					                                     unsigned int flags, struct pt_regs *regs)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
        struct h3600_dev *ts = serio_get_drvdata(serio);
 | 
						struct h3600_dev *ts = serio_get_drvdata(serio);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/*
 | 
						/*
 | 
				
			||||||
         * We have a new frame coming in.
 | 
						 * We have a new frame coming in.
 | 
				
			||||||
         */
 | 
						 */
 | 
				
			||||||
	switch (state) {
 | 
						switch (state) {
 | 
				
			||||||
		case STATE_SOF:
 | 
							case STATE_SOF:
 | 
				
			||||||
        		if (data == CHAR_SOF)
 | 
								if (data == CHAR_SOF)
 | 
				
			||||||
                		state = STATE_ID;
 | 
									state = STATE_ID;
 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
        	case STATE_ID:
 | 
							case STATE_ID:
 | 
				
			||||||
			ts->event = (data & 0xf0) >> 4;
 | 
								ts->event = (data & 0xf0) >> 4;
 | 
				
			||||||
			ts->len = (data & 0xf);
 | 
								ts->len = (data & 0xf);
 | 
				
			||||||
			ts->idx = 0;
 | 
								ts->idx = 0;
 | 
				
			||||||
			if (ts->event >= MAX_ID) {
 | 
								if (ts->event >= MAX_ID) {
 | 
				
			||||||
				state = STATE_SOF;
 | 
									state = STATE_SOF;
 | 
				
			||||||
                        	break;
 | 
									break;
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			ts->chksum = data;
 | 
								ts->chksum = data;
 | 
				
			||||||
                	state = (ts->len > 0) ? STATE_DATA : STATE_EOF;
 | 
								state = (ts->len > 0) ? STATE_DATA : STATE_EOF;
 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
		case STATE_DATA:
 | 
							case STATE_DATA:
 | 
				
			||||||
			ts->chksum += data;
 | 
								ts->chksum += data;
 | 
				
			||||||
			ts->buf[ts->idx]= data;
 | 
								ts->buf[ts->idx]= data;
 | 
				
			||||||
			if(++ts->idx == ts->len)
 | 
								if (++ts->idx == ts->len)
 | 
				
			||||||
                        	state = STATE_EOF;
 | 
									state = STATE_EOF;
 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
		case STATE_EOF:
 | 
							case STATE_EOF:
 | 
				
			||||||
                	state = STATE_SOF;
 | 
								state = STATE_SOF;
 | 
				
			||||||
                	if (data == CHAR_EOF || data == ts->chksum)
 | 
								if (data == CHAR_EOF || data == ts->chksum)
 | 
				
			||||||
				h3600ts_process_packet(ts, regs);
 | 
									h3600ts_process_packet(ts, regs);
 | 
				
			||||||
                	break;
 | 
								break;
 | 
				
			||||||
        	default:
 | 
							default:
 | 
				
			||||||
                	printk("Error3\n");
 | 
								printk("Error3\n");
 | 
				
			||||||
                	break;
 | 
								break;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return IRQ_HANDLED;
 | 
						return IRQ_HANDLED;
 | 
				
			||||||
| 
						 | 
					@ -390,10 +390,10 @@ static int h3600ts_connect(struct serio *serio, struct serio_driver *drv)
 | 
				
			||||||
	init_input_dev(&ts->dev);
 | 
						init_input_dev(&ts->dev);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Device specific stuff */
 | 
						/* Device specific stuff */
 | 
				
			||||||
        set_GPIO_IRQ_edge(GPIO_BITSY_ACTION_BUTTON, GPIO_BOTH_EDGES);
 | 
						set_GPIO_IRQ_edge(GPIO_BITSY_ACTION_BUTTON, GPIO_BOTH_EDGES);
 | 
				
			||||||
        set_GPIO_IRQ_edge(GPIO_BITSY_NPOWER_BUTTON, GPIO_RISING_EDGE);
 | 
						set_GPIO_IRQ_edge(GPIO_BITSY_NPOWER_BUTTON, GPIO_RISING_EDGE);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (request_irq(IRQ_GPIO_BITSY_ACTION_BUTTON, action_button_handler,
 | 
						if (request_irq(IRQ_GPIO_BITSY_ACTION_BUTTON, action_button_handler,
 | 
				
			||||||
			SA_SHIRQ | SA_INTERRUPT | SA_SAMPLE_RANDOM,
 | 
								SA_SHIRQ | SA_INTERRUPT | SA_SAMPLE_RANDOM,
 | 
				
			||||||
			"h3600_action", &ts->dev)) {
 | 
								"h3600_action", &ts->dev)) {
 | 
				
			||||||
		printk(KERN_ERR "h3600ts.c: Could not allocate Action Button IRQ!\n");
 | 
							printk(KERN_ERR "h3600ts.c: Could not allocate Action Button IRQ!\n");
 | 
				
			||||||
| 
						 | 
					@ -401,7 +401,7 @@ static int h3600ts_connect(struct serio *serio, struct serio_driver *drv)
 | 
				
			||||||
		return -EBUSY;
 | 
							return -EBUSY;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (request_irq(IRQ_GPIO_BITSY_NPOWER_BUTTON, npower_button_handler,
 | 
						if (request_irq(IRQ_GPIO_BITSY_NPOWER_BUTTON, npower_button_handler,
 | 
				
			||||||
			SA_SHIRQ | SA_INTERRUPT | SA_SAMPLE_RANDOM,
 | 
								SA_SHIRQ | SA_INTERRUPT | SA_SAMPLE_RANDOM,
 | 
				
			||||||
			"h3600_suspend", &ts->dev)) {
 | 
								"h3600_suspend", &ts->dev)) {
 | 
				
			||||||
		free_irq(IRQ_GPIO_BITSY_ACTION_BUTTON, &ts->dev);
 | 
							free_irq(IRQ_GPIO_BITSY_ACTION_BUTTON, &ts->dev);
 | 
				
			||||||
| 
						 | 
					@ -433,7 +433,7 @@ static int h3600ts_connect(struct serio *serio, struct serio_driver *drv)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	sprintf(ts->phys, "%s/input0", serio->phys);
 | 
						sprintf(ts->phys, "%s/input0", serio->phys);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
       	ts->dev.event = h3600ts_event;
 | 
						ts->dev.event = h3600ts_event;
 | 
				
			||||||
	ts->dev.private = ts;
 | 
						ts->dev.private = ts;
 | 
				
			||||||
	ts->dev.name = h3600_name;
 | 
						ts->dev.name = h3600_name;
 | 
				
			||||||
	ts->dev.phys = ts->phys;
 | 
						ts->dev.phys = ts->phys;
 | 
				
			||||||
| 
						 | 
					@ -446,8 +446,8 @@ static int h3600ts_connect(struct serio *serio, struct serio_driver *drv)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	err = serio_open(serio, drv);
 | 
						err = serio_open(serio, drv);
 | 
				
			||||||
	if (err) {
 | 
						if (err) {
 | 
				
			||||||
        	free_irq(IRQ_GPIO_BITSY_ACTION_BUTTON, ts);
 | 
							free_irq(IRQ_GPIO_BITSY_ACTION_BUTTON, ts);
 | 
				
			||||||
        	free_irq(IRQ_GPIO_BITSY_NPOWER_BUTTON, ts);
 | 
							free_irq(IRQ_GPIO_BITSY_NPOWER_BUTTON, ts);
 | 
				
			||||||
		serio_set_drvdata(serio, NULL);
 | 
							serio_set_drvdata(serio, NULL);
 | 
				
			||||||
		kfree(ts);
 | 
							kfree(ts);
 | 
				
			||||||
		return err;
 | 
							return err;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
Some files were not shown because too many files have changed in this diff Show more
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue