diff options
171 files changed, 6253 insertions, 2121 deletions
diff --git a/Documentation/input/input.txt b/Documentation/input/input.txt index 686ee9932dff..b93c08442e3c 100644 --- a/Documentation/input/input.txt +++ b/Documentation/input/input.txt @@ -278,7 +278,7 @@ struct input_event { }; 'time' is the timestamp, it returns the time at which the event happened. -Type is for example EV_REL for relative moment, REL_KEY for a keypress or +Type is for example EV_REL for relative moment, EV_KEY for a keypress or release. More types are defined in include/linux/input.h. 'code' is event code, for example REL_X or KEY_BACKSPACE, again a complete diff --git a/Documentation/input/rotary-encoder.txt b/Documentation/input/rotary-encoder.txt index 435102a26d96..3a6aec40c0b0 100644 --- a/Documentation/input/rotary-encoder.txt +++ b/Documentation/input/rotary-encoder.txt @@ -67,7 +67,12 @@ data with it. struct rotary_encoder_platform_data is declared in include/linux/rotary-encoder.h and needs to be filled with the number of steps the encoder has and can carry information about externally inverted -signals (because of used invertig buffer or other reasons). +signals (because of an inverting buffer or other reasons). The encoder +can be set up to deliver input information as either an absolute or relative +axes. For relative axes the input event returns +/-1 for each step. For +absolute axes the position of the encoder can either roll over between zero +and the number of steps or will clamp at the maximum and zero depending on +the configuration. Because GPIO to IRQ mapping is platform specific, this information must be given in seperately to the driver. See the example below. @@ -85,6 +90,8 @@ be given in seperately to the driver. See the example below. static struct rotary_encoder_platform_data my_rotary_encoder_info = { .steps = 24, .axis = ABS_X, + .relative_axis = false, + .rollover = false, .gpio_a = GPIO_ROTARY_A, .gpio_b = GPIO_ROTARY_B, .inverted_a = 0, diff --git a/arch/arm/mach-ep93xx/include/mach/ep93xx_keypad.h b/arch/arm/mach-ep93xx/include/mach/ep93xx_keypad.h new file mode 100644 index 000000000000..83f31cd0a274 --- /dev/null +++ b/arch/arm/mach-ep93xx/include/mach/ep93xx_keypad.h @@ -0,0 +1,42 @@ +/* + * arch/arm/mach-ep93xx/include/mach/ep93xx_keypad.h + */ + +#ifndef __ASM_ARCH_EP93XX_KEYPAD_H +#define __ASM_ARCH_EP93XX_KEYPAD_H + +#define MAX_MATRIX_KEY_ROWS (8) +#define MAX_MATRIX_KEY_COLS (8) + +/* flags for the ep93xx_keypad driver */ +#define EP93XX_KEYPAD_DISABLE_3_KEY (1<<0) /* disable 3-key reset */ +#define EP93XX_KEYPAD_DIAG_MODE (1<<1) /* diagnostic mode */ +#define EP93XX_KEYPAD_BACK_DRIVE (1<<2) /* back driving mode */ +#define EP93XX_KEYPAD_TEST_MODE (1<<3) /* scan only column 0 */ +#define EP93XX_KEYPAD_KDIV (1<<4) /* 1/4 clock or 1/16 clock */ +#define EP93XX_KEYPAD_AUTOREPEAT (1<<5) /* enable key autorepeat */ + +/** + * struct ep93xx_keypad_platform_data - platform specific device structure + * @matrix_key_rows: number of rows in the keypad matrix + * @matrix_key_cols: number of columns in the keypad matrix + * @matrix_key_map: array of keycodes defining the keypad matrix + * @matrix_key_map_size: ARRAY_SIZE(matrix_key_map) + * @debounce: debounce start count; terminal count is 0xff + * @prescale: row/column counter pre-scaler load value + * @flags: see above + */ +struct ep93xx_keypad_platform_data { + unsigned int matrix_key_rows; + unsigned int matrix_key_cols; + unsigned int *matrix_key_map; + int matrix_key_map_size; + unsigned int debounce; + unsigned int prescale; + unsigned int flags; +}; + +/* macro for creating the matrix_key_map table */ +#define KEY(row, col, val) (((row) << 28) | ((col) << 24) | (val)) + +#endif /* __ASM_ARCH_EP93XX_KEYPAD_H */ diff --git a/arch/x86/mm/gup.c b/arch/x86/mm/gup.c index 6340cef6798a..f97480941269 100644 --- a/arch/x86/mm/gup.c +++ b/arch/x86/mm/gup.c @@ -247,10 +247,15 @@ int get_user_pages_fast(unsigned long start, int nr_pages, int write, start &= PAGE_MASK; addr = start; len = (unsigned long) nr_pages << PAGE_SHIFT; + end = start + len; - if (unlikely(!access_ok(write ? VERIFY_WRITE : VERIFY_READ, - (void __user *)start, len))) + if (end < start) + goto slow_irqon; + +#ifdef CONFIG_X86_64 + if (end >> __VIRTUAL_MASK_SHIFT) goto slow_irqon; +#endif /* * XXX: batch / limit 'nr', to avoid large irq off latency diff --git a/drivers/char/agp/agp.h b/drivers/char/agp/agp.h index 46f507531177..178e2e9e9f09 100644 --- a/drivers/char/agp/agp.h +++ b/drivers/char/agp/agp.h @@ -107,7 +107,7 @@ struct agp_bridge_driver { void (*agp_enable)(struct agp_bridge_data *, u32); void (*cleanup)(void); void (*tlb_flush)(struct agp_memory *); - unsigned long (*mask_memory)(struct agp_bridge_data *, unsigned long, int); + unsigned long (*mask_memory)(struct agp_bridge_data *, struct page *, int); void (*cache_flush)(void); int (*create_gatt_table)(struct agp_bridge_data *); int (*free_gatt_table)(struct agp_bridge_data *); @@ -115,9 +115,9 @@ struct agp_bridge_driver { int (*remove_memory)(struct agp_memory *, off_t, int); struct agp_memory *(*alloc_by_type) (size_t, int); void (*free_by_type)(struct agp_memory *); - void *(*agp_alloc_page)(struct agp_bridge_data *); + struct page *(*agp_alloc_page)(struct agp_bridge_data *); int (*agp_alloc_pages)(struct agp_bridge_data *, struct agp_memory *, size_t); - void (*agp_destroy_page)(void *, int flags); + void (*agp_destroy_page)(struct page *, int flags); void (*agp_destroy_pages)(struct agp_memory *); int (*agp_type_to_mask_type) (struct agp_bridge_data *, int); void (*chipset_flush)(struct agp_bridge_data *); @@ -278,10 +278,10 @@ int agp_generic_insert_memory(struct agp_memory *mem, off_t pg_start, int type); int agp_generic_remove_memory(struct agp_memory *mem, off_t pg_start, int type); struct agp_memory *agp_generic_alloc_by_type(size_t page_count, int type); void agp_generic_free_by_type(struct agp_memory *curr); -void *agp_generic_alloc_page(struct agp_bridge_data *bridge); +struct page *agp_generic_alloc_page(struct agp_bridge_data *bridge); int agp_generic_alloc_pages(struct agp_bridge_data *agp_bridge, struct agp_memory *memory, size_t page_count); -void agp_generic_destroy_page(void *addr, int flags); +void agp_generic_destroy_page(struct page *page, int flags); void agp_generic_destroy_pages(struct agp_memory *memory); void agp_free_key(int key); int agp_num_entries(void); @@ -291,7 +291,7 @@ int agp_3_5_enable(struct agp_bridge_data *bridge); void global_cache_flush(void); void get_agp_version(struct agp_bridge_data *bridge); unsigned long agp_generic_mask_memory(struct agp_bridge_data *bridge, - unsigned long addr, int type); + struct page *page, int type); int agp_generic_type_to_mask_type(struct agp_bridge_data *bridge, int type); struct agp_bridge_data *agp_generic_find_bridge(struct pci_dev *pdev); diff --git a/drivers/char/agp/ali-agp.c b/drivers/char/agp/ali-agp.c index dc8d1a90971f..201ef3ffd484 100644 --- a/drivers/char/agp/ali-agp.c +++ b/drivers/char/agp/ali-agp.c @@ -141,37 +141,37 @@ static void m1541_cache_flush(void) } } -static void *m1541_alloc_page(struct agp_bridge_data *bridge) +static struct page *m1541_alloc_page(struct agp_bridge_data *bridge) { - void *addr = agp_generic_alloc_page(agp_bridge); + struct page *page = agp_generic_alloc_page(agp_bridge); u32 temp; - if (!addr) + if (!page) return NULL; pci_read_config_dword(agp_bridge->dev, ALI_CACHE_FLUSH_CTRL, &temp); pci_write_config_dword(agp_bridge->dev, ALI_CACHE_FLUSH_CTRL, (((temp & ALI_CACHE_FLUSH_ADDR_MASK) | - virt_to_gart(addr)) | ALI_CACHE_FLUSH_EN )); - return addr; + phys_to_gart(page_to_phys(page))) | ALI_CACHE_FLUSH_EN )); + return page; } -static void ali_destroy_page(void * addr, int flags) +static void ali_destroy_page(struct page *page, int flags) { - if (addr) { + if (page) { if (flags & AGP_PAGE_DESTROY_UNMAP) { global_cache_flush(); /* is this really needed? --hch */ - agp_generic_destroy_page(addr, flags); + agp_generic_destroy_page(page, flags); } else - agp_generic_destroy_page(addr, flags); + agp_generic_destroy_page(page, flags); } } -static void m1541_destroy_page(void * addr, int flags) +static void m1541_destroy_page(struct page *page, int flags) { u32 temp; - if (addr == NULL) + if (page == NULL) return; if (flags & AGP_PAGE_DESTROY_UNMAP) { @@ -180,9 +180,9 @@ static void m1541_destroy_page(void * addr, int flags) pci_read_config_dword(agp_bridge->dev, ALI_CACHE_FLUSH_CTRL, &temp); pci_write_config_dword(agp_bridge->dev, ALI_CACHE_FLUSH_CTRL, (((temp & ALI_CACHE_FLUSH_ADDR_MASK) | - virt_to_gart(addr)) | ALI_CACHE_FLUSH_EN)); + phys_to_gart(page_to_phys(page))) | ALI_CACHE_FLUSH_EN)); } - agp_generic_destroy_page(addr, flags); + agp_generic_destroy_page(page, flags); } @@ -346,7 +346,7 @@ found: devs[j].chipset_name = "M1641"; break; case 0x43: - devs[j].chipset_name = "M????"; + devs[j].chipset_name = "M1621"; break; case 0x47: devs[j].chipset_name = "M1647"; diff --git a/drivers/char/agp/amd-k7-agp.c b/drivers/char/agp/amd-k7-agp.c index 3f98254b911f..ba9bde71eaaf 100644 --- a/drivers/char/agp/amd-k7-agp.c +++ b/drivers/char/agp/amd-k7-agp.c @@ -325,7 +325,7 @@ static int amd_insert_memory(struct agp_memory *mem, off_t pg_start, int type) addr = (j * PAGE_SIZE) + agp_bridge->gart_bus_addr; cur_gatt = GET_GATT(addr); writel(agp_generic_mask_memory(agp_bridge, - mem->memory[i], mem->type), cur_gatt+GET_GATT_OFF(addr)); + mem->pages[i], mem->type), cur_gatt+GET_GATT_OFF(addr)); readl(cur_gatt+GET_GATT_OFF(addr)); /* PCI Posting. */ } amd_irongate_tlbflush(mem); diff --git a/drivers/char/agp/amd64-agp.c b/drivers/char/agp/amd64-agp.c index d765afda9c2a..3bf5dda90f4a 100644 --- a/drivers/char/agp/amd64-agp.c +++ b/drivers/char/agp/amd64-agp.c @@ -79,7 +79,7 @@ static int amd64_insert_memory(struct agp_memory *mem, off_t pg_start, int type) for (i = 0, j = pg_start; i < mem->page_count; i++, j++) { tmp = agp_bridge->driver->mask_memory(agp_bridge, - mem->memory[i], mask_type); + mem->pages[i], mask_type); BUG_ON(tmp & 0xffffff0000000ffcULL); pte = (tmp & 0x000000ff00000000ULL) >> 28; diff --git a/drivers/char/agp/ati-agp.c b/drivers/char/agp/ati-agp.c index f1537eece07f..33656e144cc5 100644 --- a/drivers/char/agp/ati-agp.c +++ b/drivers/char/agp/ati-agp.c @@ -269,12 +269,17 @@ static int ati_insert_memory(struct agp_memory * mem, int i, j, num_entries; unsigned long __iomem *cur_gatt; unsigned long addr; + int mask_type; num_entries = A_SIZE_LVL2(agp_bridge->current_size)->num_entries; - if (type != 0 || mem->type != 0) + mask_type = agp_generic_type_to_mask_type(mem->bridge, type); + if (mask_type != 0 || type != mem->type) return -EINVAL; + if (mem->page_count == 0) + return 0; + if ((pg_start + mem->page_count) > num_entries) return -EINVAL; @@ -296,10 +301,11 @@ static int ati_insert_memory(struct agp_memory * mem, for (i = 0, j = pg_start; i < mem->page_count; i++, j++) { addr = (j * PAGE_SIZE) + agp_bridge->gart_bus_addr; cur_gatt = GET_GATT(addr); - writel(agp_bridge->driver->mask_memory(agp_bridge, - mem->memory[i], mem->type), cur_gatt+GET_GATT_OFF(addr)); - readl(cur_gatt+GET_GATT_OFF(addr)); /* PCI Posting. */ + writel(agp_bridge->driver->mask_memory(agp_bridge, + mem->pages[i], mem->type), + cur_gatt+GET_GATT_OFF(addr)); } + readl(GET_GATT(agp_bridge->gart_bus_addr)); /* PCI posting */ agp_bridge->driver->tlb_flush(mem); return 0; } @@ -310,17 +316,22 @@ static int ati_remove_memory(struct agp_memory * mem, off_t pg_start, int i; unsigned long __iomem *cur_gatt; unsigned long addr; + int mask_type; - if (type != 0 || mem->type != 0) + mask_type = agp_generic_type_to_mask_type(mem->bridge, type); + if (mask_type != 0 || type != mem->type) return -EINVAL; + if (mem->page_count == 0) + return 0; + for (i = pg_start; i < (mem->page_count + pg_start); i++) { addr = (i * PAGE_SIZE) + agp_bridge->gart_bus_addr; cur_gatt = GET_GATT(addr); writel(agp_bridge->scratch_page, cur_gatt+GET_GATT_OFF(addr)); - readl(cur_gatt+GET_GATT_OFF(addr)); /* PCI Posting. */ } + readl(GET_GATT(agp_bridge->gart_bus_addr)); /* PCI posting */ agp_bridge->driver->tlb_flush(mem); return 0; } diff --git a/drivers/char/agp/backend.c b/drivers/char/agp/backend.c index 8c617ad7497f..cfa5a649dfe7 100644 --- a/drivers/char/agp/backend.c +++ b/drivers/char/agp/backend.c @@ -141,17 +141,17 @@ static int agp_backend_initialize(struct agp_bridge_data *bridge) bridge->version = &agp_current_version; if (bridge->driver->needs_scratch_page) { - void *addr = bridge->driver->agp_alloc_page(bridge); + struct page *page = bridge->driver->agp_alloc_page(bridge); - if (!addr) { + if (!page) { dev_err(&bridge->dev->dev, "can't get memory for scratch page\n"); return -ENOMEM; } - bridge->scratch_page_real = virt_to_gart(addr); + bridge->scratch_page_real = phys_to_gart(page_to_phys(page)); bridge->scratch_page = - bridge->driver->mask_memory(bridge, bridge->scratch_page_real, 0); + bridge->driver->mask_memory(bridge, page, 0); } size_value = bridge->driver->fetch_size(); diff --git a/drivers/char/agp/efficeon-agp.c b/drivers/char/agp/efficeon-agp.c index 453543a1f293..35d50f2861b6 100644 --- a/drivers/char/agp/efficeon-agp.c +++ b/drivers/char/agp/efficeon-agp.c @@ -65,8 +65,9 @@ static const struct gatt_mask efficeon_generic_masks[] = }; /* This function does the same thing as mask_memory() for this chipset... */ -static inline unsigned long efficeon_mask_memory(unsigned long addr) +static inline unsigned long efficeon_mask_memory(struct page *page) { + unsigned long addr = phys_to_gart(page_to_phys(page)); return addr | 0x00000001; } @@ -257,7 +258,7 @@ static int efficeon_insert_memory(struct agp_memory * mem, off_t pg_start, int t last_page = NULL; for (i = 0; i < count; i++) { int index = pg_start + i; - unsigned long insert = efficeon_mask_memory(mem->memory[i]); + unsigned long insert = efficeon_mask_memory(mem->pages[i]); page = (unsigned int *) efficeon_private.l1_table[index >> 10]; diff --git a/drivers/char/agp/generic.c b/drivers/char/agp/generic.c index 2224b762b7fb..1e8b461b91f1 100644 --- a/drivers/char/agp/generic.c +++ b/drivers/char/agp/generic.c @@ -95,13 +95,13 @@ EXPORT_SYMBOL(agp_flush_chipset); void agp_alloc_page_array(size_t size, struct agp_memory *mem) { - mem->memory = NULL; + mem->pages = NULL; mem->vmalloc_flag = false; if (size <= 2*PAGE_SIZE) - mem->memory = kmalloc(size, GFP_KERNEL | __GFP_NORETRY); - if (mem->memory == NULL) { - mem->memory = vmalloc(size); + mem->pages = kmalloc(size, GFP_KERNEL | __GFP_NORETRY); + if (mem->pages == NULL) { + mem->pages = vmalloc(size); mem->vmalloc_flag = true; } } @@ -110,9 +110,9 @@ EXPORT_SYMBOL(agp_alloc_page_array); void agp_free_page_array(struct agp_memory *mem) { if (mem->vmalloc_flag) { - vfree(mem->memory); + vfree(mem->pages); } else { - kfree(mem->memory); + kfree(mem->pages); } } EXPORT_SYMBOL(agp_free_page_array); @@ -136,7 +136,7 @@ static struct agp_memory *agp_create_user_memory(unsigned long num_agp_pages) agp_alloc_page_array(alloc_size, new); - if (new->memory == NULL) { + if (new->pages == NULL) { agp_free_key(new->key); kfree(new); return NULL; @@ -162,7 +162,7 @@ struct agp_memory *agp_create_memory(int scratch_pages) agp_alloc_page_array(PAGE_SIZE * scratch_pages, new); - if (new->memory == NULL) { + if (new->pages == NULL) { agp_free_key(new->key); kfree(new); return NULL; @@ -206,15 +206,13 @@ void agp_free_memory(struct agp_memory *curr) } else { for (i = 0; i < curr->page_count; i++) { - curr->memory[i] = (unsigned long)gart_to_virt( - curr->memory[i]); curr->bridge->driver->agp_destroy_page( - (void *)curr->memory[i], + curr->pages[i], AGP_PAGE_DESTROY_UNMAP); } for (i = 0; i < curr->page_count; i++) { curr->bridge->driver->agp_destroy_page( - (void *)curr->memory[i], + curr->pages[i], AGP_PAGE_DESTROY_FREE); } } @@ -282,13 +280,13 @@ struct agp_memory *agp_allocate_memory(struct agp_bridge_data *bridge, } for (i = 0; i < page_count; i++) { - void *addr = bridge->driver->agp_alloc_page(bridge); + struct page *page = bridge->driver->agp_alloc_page(bridge); - if (addr == NULL) { + if (page == NULL) { agp_free_memory(new); return NULL; } - new->memory[i] = virt_to_gart(addr); + new->pages[i] = page; new->page_count++; } new->bridge = bridge; @@ -1134,7 +1132,7 @@ int agp_generic_insert_memory(struct agp_memory * mem, off_t pg_start, int type) } for (i = 0, j = pg_start; i < mem->page_count; i++, j++) { - writel(bridge->driver->mask_memory(bridge, mem->memory[i], mask_type), + writel(bridge->driver->mask_memory(bridge, mem->pages[i], mask_type), bridge->gatt_table+j); } readl(bridge->gatt_table+j-1); /* PCI Posting. */ @@ -1204,7 +1202,7 @@ struct agp_memory *agp_generic_alloc_user(size_t page_count, int type) return NULL; for (i = 0; i < page_count; i++) - new->memory[i] = 0; + new->pages[i] = 0; new->page_count = 0; new->type = type; new->num_scratch_pages = pages; @@ -1237,23 +1235,20 @@ int agp_generic_alloc_pages(struct agp_bridge_data *bridge, struct agp_memory *m get_page(page); atomic_inc(&agp_bridge->current_memory_agp); - /* set_memory_array_uc() needs virtual address */ - mem->memory[i] = (unsigned long)page_address(page); + mem->pages[i] = page; mem->page_count++; } #ifdef CONFIG_X86 - set_memory_array_uc(mem->memory, num_pages); + set_pages_array_uc(mem->pages, num_pages); #endif ret = 0; out: - for (i = 0; i < mem->page_count; i++) - mem->memory[i] = virt_to_gart((void *)mem->memory[i]); return ret; } EXPORT_SYMBOL(agp_generic_alloc_pages); -void *agp_generic_alloc_page(struct agp_bridge_data *bridge) +struct page *agp_generic_alloc_page(struct agp_bridge_data *bridge) { struct page * page; @@ -1265,56 +1260,47 @@ void *agp_generic_alloc_page(struct agp_bridge_data *bridge) get_page(page); atomic_inc(&agp_bridge->current_memory_agp); - return page_address(page); + return page; } EXPORT_SYMBOL(agp_generic_alloc_page); void agp_generic_destroy_pages(struct agp_memory *mem) { int i; - void *addr; struct page *page; if (!mem) return; - for (i = 0; i < mem->page_count; i++) - mem->memory[i] = (unsigned long)gart_to_virt(mem->memory[i]); - #ifdef CONFIG_X86 - set_memory_array_wb(mem->memory, mem->page_count); + set_pages_array_wb(mem->pages, mem->page_count); #endif for (i = 0; i < mem->page_count; i++) { - addr = (void *)mem->memory[i]; - page = virt_to_page(addr); + page = mem->pages[i]; #ifndef CONFIG_X86 unmap_page_from_agp(page); #endif - put_page(page); - free_page((unsigned long)addr); + __free_page(page); atomic_dec(&agp_bridge->current_memory_agp); - mem->memory[i] = 0; + mem->pages[i] = NULL; } } EXPORT_SYMBOL(agp_generic_destroy_pages); -void agp_generic_destroy_page(void *addr, int flags) +void agp_generic_destroy_page(struct page *page, int flags) { - struct page *page; - - if (addr == NULL) + if (page == NULL) return; - page = virt_to_page(addr); if (flags & AGP_PAGE_DESTROY_UNMAP) unmap_page_from_agp(page); if (flags & AGP_PAGE_DESTROY_FREE) { put_page(page); - free_page((unsigned long)addr); + __free_page(page); atomic_dec(&agp_bridge->current_memory_agp); } } @@ -1361,8 +1347,9 @@ void global_cache_flush(void) EXPORT_SYMBOL(global_cache_flush); unsigned long agp_generic_mask_memory(struct agp_bridge_data *bridge, - unsigned long addr, int type) + struct page *page, int type) { + unsigned long addr = phys_to_gart(page_to_phys(page)); /* memory type is ignored in the generic routine */ if (bridge->driver->masks) return addr | bridge->driver->masks[0].mask; diff --git a/drivers/char/agp/hp-agp.c b/drivers/char/agp/hp-agp.c index 9c7e2343c399..8f3d4c184914 100644 --- a/drivers/char/agp/hp-agp.c +++ b/drivers/char/agp/hp-agp.c @@ -361,13 +361,11 @@ hp_zx1_insert_memory (struct agp_memory *mem, off_t pg_start, int type) for (i = 0, j = io_pg_start; i < mem->page_count; i++) { unsigned long paddr; - paddr = mem->memory[i]; + paddr = page_to_phys(mem->pages[i]); for (k = 0; k < hp->io_pages_per_kpage; k++, j++, paddr += hp->io_page_size) { - hp->gatt[j] = - agp_bridge->driver->mask_memory(agp_bridge, - paddr, type); + hp->gatt[j] = HP_ZX1_PDIR_VALID_BIT | paddr; } } @@ -397,8 +395,9 @@ hp_zx1_remove_memory (struct agp_memory *mem, off_t pg_start, int type) static unsigned long hp_zx1_mask_memory (struct agp_bridge_data *bridge, - unsigned long addr, int type) + struct page *page, int type) { + unsigned long addr = phys_to_gart(page_to_phys(page)); return HP_ZX1_PDIR_VALID_BIT | addr; } diff --git a/drivers/char/agp/i460-agp.c b/drivers/char/agp/i460-agp.c index 10da687d131a..60cc35bb5db7 100644 --- a/drivers/char/agp/i460-agp.c +++ b/drivers/char/agp/i460-agp.c @@ -60,6 +60,9 @@ */ #define WR_FLUSH_GATT(index) RD_GATT(index) +static unsigned long i460_mask_memory (struct agp_bridge_data *bridge, + unsigned long addr, int type); + static struct { void *gatt; /* ioremap'd GATT area */ @@ -74,6 +77,7 @@ static struct { unsigned long *alloced_map; /* bitmap of kernel-pages in use */ int refcount; /* number of kernel pages using the large page */ u64 paddr; /* physical address of large page */ + struct page *page; /* page pointer */ } *lp_desc; } i460; @@ -294,7 +298,7 @@ static int i460_insert_memory_small_io_page (struct agp_memory *mem, void *temp; pr_debug("i460_insert_memory_small_io_page(mem=%p, pg_start=%ld, type=%d, paddr0=0x%lx)\n", - mem, pg_start, type, mem->memory[0]); + mem, pg_start, type, page_to_phys(mem->pages[0])); if (type >= AGP_USER_TYPES || mem->type >= AGP_USER_TYPES) return -EINVAL; @@ -321,10 +325,9 @@ static int i460_insert_memory_small_io_page (struct agp_memory *mem, io_page_size = 1UL << I460_IO_PAGE_SHIFT; for (i = 0, j = io_pg_start; i < mem->page_count; i++) { - paddr = mem->memory[i]; + paddr = phys_to_gart(page_to_phys(mem->pages[i])); for (k = 0; k < I460_IOPAGES_PER_KPAGE; k++, j++, paddr += io_page_size) - WR_GATT(j, agp_bridge->driver->mask_memory(agp_bridge, - paddr, mem->type)); + WR_GATT(j, i460_mask_memory(agp_bridge, paddr, mem->type)); } WR_FLUSH_GATT(j - 1); return 0; @@ -364,10 +367,9 @@ static int i460_alloc_large_page (struct lp_desc *lp) { unsigned long order = I460_IO_PAGE_SHIFT - PAGE_SHIFT; size_t map_size; - void *lpage; - lpage = (void *) __get_free_pages(GFP_KERNEL, order); - if (!lpage) { + lp->page = alloc_pages(GFP_KERNEL, order); + if (!lp->page) { printk(KERN_ERR PFX "Couldn't alloc 4M GART page...\n"); return -ENOMEM; } @@ -375,12 +377,12 @@ static int i460_alloc_large_page (struct lp_desc *lp) map_size = ((I460_KPAGES_PER_IOPAGE + BITS_PER_LONG - 1) & -BITS_PER_LONG)/8; lp->alloced_map = kzalloc(map_size, GFP_KERNEL); if (!lp->alloced_map) { - free_pages((unsigned long) lpage, order); + __free_pages(lp->page, order); printk(KERN_ERR PFX "Out of memory, we're in trouble...\n"); return -ENOMEM; } - lp->paddr = virt_to_gart(lpage); + lp->paddr = phys_to_gart(page_to_phys(lp->page)); lp->refcount = 0; atomic_add(I460_KPAGES_PER_IOPAGE, &agp_bridge->current_memory_agp); return 0; @@ -391,7 +393,7 @@ static void i460_free_large_page (struct lp_desc *lp) kfree(lp->alloced_map); lp->alloced_map = NULL; - free_pages((unsigned long) gart_to_virt(lp->paddr), I460_IO_PAGE_SHIFT - PAGE_SHIFT); + __free_pages(lp->page, I460_IO_PAGE_SHIFT - PAGE_SHIFT); atomic_sub(I460_KPAGES_PER_IOPAGE, &agp_bridge->current_memory_agp); } @@ -439,8 +441,8 @@ static int i460_insert_memory_large_io_page (struct agp_memory *mem, if (i460_alloc_large_page(lp) < 0) return -ENOMEM; pg = lp - i460.lp_desc; - WR_GATT(pg, agp_bridge->driver->mask_memory(agp_bridge, - lp->paddr, 0)); + WR_GATT(pg, i460_mask_memory(agp_bridge, + lp->paddr, 0)); WR_FLUSH_GATT(pg); } @@ -448,7 +450,7 @@ static int i460_insert_memory_large_io_page (struct agp_memory *mem, idx < ((lp == end) ? (end_offset + 1) : I460_KPAGES_PER_IOPAGE); idx++, i++) { - mem->memory[i] = lp->paddr + idx*PAGE_SIZE; + mem->pages[i] = lp->page; __set_bit(idx, lp->alloced_map); ++lp->refcount; } @@ -463,7 +465,7 @@ static int i460_remove_memory_large_io_page (struct agp_memory *mem, struct lp_desc *start, *end, *lp; void *temp; - temp = agp_bridge->driver->current_size; + temp = agp_bridge->current_size; num_entries = A_SIZE_8(temp)->num_entries; /* Figure out what pg_start means in terms of our large GART pages */ @@ -477,7 +479,7 @@ static int i460_remove_memory_large_io_page (struct agp_memory *mem, idx < ((lp == end) ? (end_offset + 1) : I460_KPAGES_PER_IOPAGE); idx++, i++) { - mem->memory[i] = 0; + mem->pages[i] = NULL; __clear_bit(idx, lp->alloced_map); --lp->refcount; } @@ -521,7 +523,7 @@ static int i460_remove_memory (struct agp_memory *mem, * Let's just hope nobody counts on the allocated AGP memory being there before bind time * (I don't think current drivers do)... */ -static void *i460_alloc_page (struct agp_bridge_data *bridge) +static struct page *i460_alloc_page (struct agp_bridge_data *bridge) { void *page; @@ -534,7 +536,7 @@ static void *i460_alloc_page (struct agp_bridge_data *bridge) return page; } -static void i460_destroy_page (void *page, int flags) +static void i460_destroy_page (struct page *page, int flags) { if (I460_IO_PAGE_SHIFT <= PAGE_SHIFT) { agp_generic_destroy_page(page, flags); @@ -544,13 +546,20 @@ static void i460_destroy_page (void *page, int flags) #endif /* I460_LARGE_IO_PAGES */ static unsigned long i460_mask_memory (struct agp_bridge_data *bridge, - unsigned long addr, int type) + unsigned long addr, int type) { /* Make sure the returned address is a valid GATT entry */ return bridge->driver->masks[0].mask | (((addr & ~((1 << I460_IO_PAGE_SHIFT) - 1)) & 0xfffff000) >> 12); } +static unsigned long i460_page_mask_memory(struct agp_bridge_data *bridge, + struct page *page, int type) +{ + unsigned long addr = phys_to_gart(page_to_phys(page)); + return i460_mask_memory(bridge, addr, type); +} + const struct agp_bridge_driver intel_i460_driver = { .owner = THIS_MODULE, .aperture_sizes = i460_sizes, @@ -560,7 +569,7 @@ const struct agp_bridge_driver intel_i460_driver = { .fetch_size = i460_fetch_size, .cleanup = i460_cleanup, .tlb_flush = i460_tlb_flush, - .mask_memory = i460_mask_memory, + .mask_memory = i460_page_mask_memory, .masks = i460_masks, .agp_enable = agp_generic_enable, .cache_flush = global_cache_flush, diff --git a/drivers/char/agp/intel-agp.c b/drivers/char/agp/intel-agp.c index 7a748fa0dfce..8c9d50db5c3a 100644 --- a/drivers/char/agp/intel-agp.c +++ b/drivers/char/agp/intel-agp.c @@ -257,7 +257,7 @@ static void intel_i810_agp_enable(struct agp_bridge_data *bridge, u32 mode) } /* Exists to support ARGB cursors */ -static void *i8xx_alloc_pages(void) +static struct page *i8xx_alloc_pages(void) { struct page *page; @@ -272,17 +272,14 @@ static void *i8xx_alloc_pages(void) } get_page(page); atomic_inc(&agp_bridge->current_memory_agp); - return page_address(page); + return page; } -static void i8xx_destroy_pages(void *addr) +static void i8xx_destroy_pages(struct page *page) { - struct page *page; - - if (addr == NULL) + if (page == NULL) return; - page = virt_to_page(addr); set_pages_wb(page, 4); put_page(page); __free_pages(page, 2); @@ -346,7 +343,7 @@ static int intel_i810_insert_entries(struct agp_memory *mem, off_t pg_start, global_cache_flush(); for (i = 0, j = pg_start; i < mem->page_count; i++, j++) { writel(agp_bridge->driver->mask_memory(agp_bridge, - mem->memory[i], + mem->pages[i], mask_type), intel_private.registers+I810_PTE_BASE+(j*4)); } @@ -389,37 +386,37 @@ static int intel_i810_remove_entries(struct agp_memory *mem, off_t pg_start, static struct agp_memory *alloc_agpphysmem_i8xx(size_t pg_count, int type) { struct agp_memory *new; - void *addr; + struct page *page; switch (pg_count) { - case 1: addr = agp_bridge->driver->agp_alloc_page(agp_bridge); + case 1: page = agp_bridge->driver->agp_alloc_page(agp_bridge); break; case 4: /* kludge to get 4 physical pages for ARGB cursor */ - addr = i8xx_alloc_pages(); + page = i8xx_alloc_pages(); break; default: return NULL; } - if (addr == NULL) + if (page == NULL) return NULL; new = agp_create_memory(pg_count); if (new == NULL) return NULL; - new->memory[0] = virt_to_gart(addr); + new->pages[0] = page; if (pg_count == 4) { /* kludge to get 4 physical pages for ARGB cursor */ - new->memory[1] = new->memory[0] + PAGE_SIZE; - new->memory[2] = new->memory[1] + PAGE_SIZE; - new->memory[3] = new->memory[2] + PAGE_SIZE; + new->pages[1] = new->pages[0] + 1; + new->pages[2] = new->pages[1] + 1; + new->pages[3] = new->pages[2] + 1; } new->page_count = pg_count; new->num_scratch_pages = pg_count; new->type = AGP_PHYS_MEMORY; - new->physical = new->memory[0]; + new->physical = page_to_phys(new->pages[0]); return new; } @@ -451,13 +448,11 @@ static void intel_i810_free_by_type(struct agp_memory *curr) agp_free_key(curr->key); if (curr->type == AGP_PHYS_MEMORY) { if (curr->page_count == 4) - i8xx_destroy_pages(gart_to_virt(curr->memory[0])); + i8xx_destroy_pages(curr->pages[0]); else { - void *va = gart_to_virt(curr->memory[0]); - - agp_bridge->driver->agp_destroy_page(va, + agp_bridge->driver->agp_destroy_page(curr->pages[0], AGP_PAGE_DESTROY_UNMAP); - agp_bridge->driver->agp_destroy_page(va, + agp_bridge->driver->agp_destroy_page(curr->pages[0], AGP_PAGE_DESTROY_FREE); } agp_free_page_array(curr); @@ -466,8 +461,9 @@ static void intel_i810_free_by_type(struct agp_memory *curr) } static unsigned long intel_i810_mask_memory(struct agp_bridge_data *bridge, - unsigned long addr, int type) + struct page *page, int type) { + unsigned long addr = phys_to_gart(page_to_phys(page)); /* Type checking must be done elsewhere */ return addr | bridge->driver->masks[type].mask; } @@ -855,7 +851,7 @@ static int intel_i830_insert_entries(struct agp_memory *mem, off_t pg_start, for (i = 0, j = pg_start; i < mem->page_count; i++, j++) { writel(agp_bridge->driver->mask_memory(agp_bridge, - mem->memory[i], mask_type), + mem->pages[i], mask_type), intel_private.registers+I810_PTE_BASE+(j*4)); } readl(intel_private.registers+I810_PTE_BASE+((j-1)*4)); @@ -1085,7 +1081,7 @@ static int intel_i915_insert_entries(struct agp_memory *mem, off_t pg_start, for (i = 0, j = pg_start; i < mem->page_count; i++, j++) { writel(agp_bridge->driver->mask_memory(agp_bridge, - mem->memory[i], mask_type), intel_private.gtt+j); + mem->pages[i], mask_type), intel_private.gtt+j); } readl(intel_private.gtt+j-1); @@ -1200,8 +1196,9 @@ static int intel_i915_create_gatt_table(struct agp_bridge_data *bridge) * this conditional. */ static unsigned long intel_i965_mask_memory(struct agp_bridge_data *bridge, - unsigned long addr, int type) + struct page *page, int type) { + dma_addr_t addr = phys_to_gart(page_to_phys(page)); /* Shift high bits down */ addr |= (addr >> 28) & 0xf0; diff --git a/drivers/char/agp/nvidia-agp.c b/drivers/char/agp/nvidia-agp.c index 16acee2de117..263d71dd441c 100644 --- a/drivers/char/agp/nvidia-agp.c +++ b/drivers/char/agp/nvidia-agp.c @@ -225,7 +225,7 @@ static int nvidia_insert_memory(struct agp_memory *mem, off_t pg_start, int type } for (i = 0, j = pg_start; i < mem->page_count; i++, j++) { writel(agp_bridge->driver->mask_memory(agp_bridge, - mem->memory[i], mask_type), + mem->pages[i], mask_type), agp_bridge->gatt_table+nvidia_private.pg_offset+j); } diff --git a/drivers/char/agp/parisc-agp.c b/drivers/char/agp/parisc-agp.c index 699e3422ad93..f4bb43fb8016 100644 --- a/drivers/char/agp/parisc-agp.c +++ b/drivers/char/agp/parisc-agp.c @@ -31,6 +31,10 @@ #define AGP8X_MODE_BIT 3 #define AGP8X_MODE (1 << AGP8X_MODE_BIT) +static unsigned long +parisc_agp_mask_memory(struct agp_bridge_data *bridge, unsigned long addr, + int type); + static struct _parisc_agp_info { void __iomem *ioc_regs; void __iomem *lba_regs; @@ -149,12 +153,12 @@ parisc_agp_insert_memory(struct agp_memory *mem, off_t pg_start, int type) for (i = 0, j = io_pg_start; i < mem->page_count; i++) { unsigned long paddr; - paddr = mem->memory[i]; + paddr = page_to_phys(mem->pages[i]); for (k = 0; k < info->io_pages_per_kpage; k++, j++, paddr += info->io_page_size) { info->gatt[j] = - agp_bridge->driver->mask_memory(agp_bridge, + parisc_agp_mask_memory(agp_bridge, paddr, type); } } @@ -185,9 +189,17 @@ parisc_agp_remove_memory(struct agp_memory *mem, off_t pg_start, int type) } static unsigned long -parisc_agp_mask_memory(struct agp_bridge_data *bridge, - unsigned long addr, int type) +parisc_agp_mask_memory(struct agp_bridge_data *bridge, unsigned long addr, + int type) +{ + return SBA_PDIR_VALID_BIT | addr; +} + +static unsigned long +parisc_agp_page_mask_memory(struct agp_bridge_data *bridge, struct page *page, + int type) { + unsigned long addr = phys_to_gart(page_to_phys(page)); return SBA_PDIR_VALID_BIT | addr; } diff --git a/drivers/char/agp/sgi-agp.c b/drivers/char/agp/sgi-agp.c index b972d83bb1b2..d3ea2e4226b5 100644 --- a/drivers/char/agp/sgi-agp.c +++ b/drivers/char/agp/sgi-agp.c @@ -38,7 +38,7 @@ static struct aper_size_info_fixed sgi_tioca_sizes[] = { {0, 0, 0}, }; -static void *sgi_tioca_alloc_page(struct agp_bridge_data *bridge) +static struct page *sgi_tioca_alloc_page(struct agp_bridge_data *bridge) { struct page *page; int nid; @@ -52,7 +52,7 @@ static void *sgi_tioca_alloc_page(struct agp_bridge_data *bridge) get_page(page); atomic_inc(&agp_bridge->current_memory_agp); - return page_address(page); + return page; } /* @@ -71,8 +71,9 @@ static void sgi_tioca_tlbflush(struct agp_memory *mem) */ static unsigned long sgi_tioca_mask_memory(struct agp_bridge_data *bridge, - unsigned long addr, int type) + struct page *page, int type) { + unsigned long addr = phys_to_gart(page_to_phys(page)); return tioca_physpage_to_gart(addr); } @@ -189,7 +190,7 @@ static int sgi_tioca_insert_memory(struct agp_memory *mem, off_t pg_start, for (i = 0, j = pg_start; i < mem->page_count; i++, j++) { table[j] = - bridge->driver->mask_memory(bridge, mem->memory[i], + bridge->driver->mask_memory(bridge, mem->pages[i], mem->type); } diff --git a/drivers/char/agp/sworks-agp.c b/drivers/char/agp/sworks-agp.c index 6224df8b7f0a..b964a2199329 100644 --- a/drivers/char/agp/sworks-agp.c +++ b/drivers/char/agp/sworks-agp.c @@ -349,7 +349,7 @@ static int serverworks_insert_memory(struct agp_memory *mem, for (i = 0, j = pg_start; i < mem->page_count; i++, j++) { addr = (j * PAGE_SIZE) + agp_bridge->gart_bus_addr; cur_gatt = SVRWRKS_GET_GATT(addr); - writel(agp_bridge->driver->mask_memory(agp_bridge, mem->memory[i], mem->type), cur_gatt+GET_GATT_OFF(addr)); + writel(agp_bridge->driver->mask_memory(agp_bridge, mem->pages[i], mem->type), cur_gatt+GET_GATT_OFF(addr)); } serverworks_tlbflush(mem); return 0; diff --git a/drivers/char/agp/uninorth-agp.c b/drivers/char/agp/uninorth-agp.c index 03f95ec08f59..f192c3b9ad41 100644 --- a/drivers/char/agp/uninorth-agp.c +++ b/drivers/char/agp/uninorth-agp.c @@ -146,13 +146,20 @@ static int uninorth_insert_memory(struct agp_memory *mem, off_t pg_start, { int i, j, num_entries; void *temp; + int mask_type; temp = agp_bridge->current_size; num_entries = A_SIZE_32(temp)->num_entries; - if (type != 0 || mem->type != 0) + if (type != mem->type) + return -EINVAL; + + mask_type = agp_bridge->driver->agp_type_to_mask_type(agp_bridge, type); + if (mask_type != 0) { /* We know nothing of memory types */ return -EINVAL; + } + if ((pg_start + mem->page_count) > num_entries) return -EINVAL; @@ -166,9 +173,9 @@ static int uninorth_insert_memory(struct agp_memory *mem, off_t pg_start, for (i = 0, j = pg_start; i < mem->page_count; i++, j++) { agp_bridge->gatt_table[j] = - cpu_to_le32((mem->memory[i] & 0xFFFFF000UL) | 0x1UL); - flush_dcache_range((unsigned long)__va(mem->memory[i]), - (unsigned long)__va(mem->memory[i])+0x1000); + cpu_to_le32((page_to_phys(mem->pages[i]) & 0xFFFFF000UL) | 0x1UL); + flush_dcache_range((unsigned long)__va(page_to_phys(mem->pages[i])), + (unsigned long)__va(page_to_phys(mem->pages[i]))+0x1000); } (void)in_le32((volatile u32*)&agp_bridge->gatt_table[pg_start]); mb(); @@ -184,13 +191,20 @@ static int u3_insert_memory(struct agp_memory *mem, off_t pg_start, int type) int i, num_entries; void *temp; u32 *gp; + int mask_type; temp = agp_bridge->current_size; num_entries = A_SIZE_32(temp)->num_entries; - if (type != 0 || mem->type != 0) + if (type != mem->type) + return -EINVAL; + + mask_type = agp_bridge->driver->agp_type_to_mask_type(agp_bridge, type); + if (mask_type != 0) { /* We know nothing of memory types */ return -EINVAL; + } + if ((pg_start + mem->page_count) > num_entries) return -EINVAL; @@ -205,9 +219,9 @@ static int u3_insert_memory(struct agp_memory *mem, off_t pg_start, int type) } for (i = 0; i < mem->page_count; i++) { - gp[i] = (mem->memory[i] >> PAGE_SHIFT) | 0x80000000UL; - flush_dcache_range((unsigned long)__va(mem->memory[i]), - (unsigned long)__va(mem->memory[i])+0x1000); + gp[i] = (page_to_phys(mem->pages[i]) >> PAGE_SHIFT) | 0x80000000UL; + flush_dcache_range((unsigned long)__va(page_to_phys(mem->pages[i])), + (unsigned long)__va(page_to_phys(mem->pages[i]))+0x1000); } mb(); flush_dcache_range((unsigned long)gp, (unsigned long) &gp[i]); diff --git a/drivers/char/keyboard.c b/drivers/char/keyboard.c index de26a978fbdd..737be953cc58 100644 --- a/drivers/char/keyboard.c +++ b/drivers/char/keyboard.c @@ -1123,8 +1123,6 @@ static int emulate_raw(struct vc_data *vc, unsigned int keycode, #define HW_RAW(dev) 0 -#warning "Cannot generate rawmode keyboard for your architecture yet." - static int emulate_raw(struct vc_data *vc, unsigned int keycode, unsigned char up_flag) { if (keycode > 127) diff --git a/drivers/gpu/drm/drm_agpsupport.c b/drivers/gpu/drm/drm_agpsupport.c index 14796594e5d9..d68888fe3df9 100644 --- a/drivers/gpu/drm/drm_agpsupport.c +++ b/drivers/gpu/drm/drm_agpsupport.c @@ -203,7 +203,7 @@ int drm_agp_alloc(struct drm_device *dev, struct drm_agp_buffer *request) if (!dev->agp || !dev->agp->acquired) return -EINVAL; - if (!(entry = drm_alloc(sizeof(*entry), DRM_MEM_AGPLISTS))) + if (!(entry = kmalloc(sizeof(*entry), GFP_KERNEL))) return -ENOMEM; memset(entry, 0, sizeof(*entry)); @@ -211,7 +211,7 @@ int drm_agp_alloc(struct drm_device *dev, struct drm_agp_buffer *request) pages = (request->size + PAGE_SIZE - 1) / PAGE_SIZE; type = (u32) request->type; if (!(memory = drm_alloc_agp(dev, pages, type))) { - drm_free(entry, sizeof(*entry), DRM_MEM_AGPLISTS); + kfree(entry); return -ENOMEM; } @@ -369,7 +369,7 @@ int drm_agp_free(struct drm_device *dev, struct drm_agp_buffer *request) list_del(&entry->head); drm_free_agp(entry->memory, entry->pages); - drm_free(entry, sizeof(*entry), DRM_MEM_AGPLISTS); + kfree(entry); return 0; } EXPORT_SYMBOL(drm_agp_free); @@ -397,13 +397,13 @@ struct drm_agp_head *drm_agp_init(struct drm_device *dev) { struct drm_agp_head *head = NULL; - if (!(head = drm_alloc(sizeof(*head), DRM_MEM_AGPLISTS))) + if (!(head = kmalloc(sizeof(*head), GFP_KERNEL))) return NULL; memset((void *)head, 0, sizeof(*head)); head->bridge = agp_find_bridge(dev->pdev); if (!head->bridge) { if (!(head->bridge = agp_backend_acquire(dev->pdev))) { - drm_free(head, sizeof(*head), DRM_MEM_AGPLISTS); + kfree(head); return NULL; } agp_copy_info(head->bridge, &head->agp_info); @@ -412,7 +412,7 @@ struct drm_agp_head *drm_agp_init(struct drm_device *dev) agp_copy_info(head->bridge, &head->agp_info); } if (head->agp_info.chipset == NOT_SUPPORTED) { - drm_free(head, sizeof(*head), DRM_MEM_AGPLISTS); + kfree(head); return NULL; } INIT_LIST_HEAD(&head->memory); @@ -482,7 +482,7 @@ drm_agp_bind_pages(struct drm_device *dev, } for (i = 0; i < num_pages; i++) - mem->memory[i] = phys_to_gart(page_to_phys(pages[i])); + mem->pages[i] = pages[i]; mem->page_count = num_pages; mem->is_flushed = true; diff --git a/drivers/gpu/drm/drm_auth.c b/drivers/gpu/drm/drm_auth.c index ca7a9ef5007b..932b5aa96a67 100644 --- a/drivers/gpu/drm/drm_auth.c +++ b/drivers/gpu/drm/drm_auth.c @@ -79,7 +79,7 @@ static int drm_add_magic(struct drm_master *master, struct drm_file *priv, struct drm_device *dev = master->minor->dev; DRM_DEBUG("%d\n", magic); - entry = drm_alloc(sizeof(*entry), DRM_MEM_MAGIC); + entry = kmalloc(sizeof(*entry), GFP_KERNEL); if (!entry) return -ENOMEM; memset(entry, 0, sizeof(*entry)); @@ -120,7 +120,7 @@ static int drm_remove_magic(struct drm_master *master, drm_magic_t magic) list_del(&pt->head); mutex_unlock(&dev->struct_mutex); - drm_free(pt, sizeof(*pt), DRM_MEM_MAGIC); + kfree(pt); return 0; } diff --git a/drivers/gpu/drm/drm_bufs.c b/drivers/gpu/drm/drm_bufs.c index 80a257554b30..6246e3f3dad7 100644 --- a/drivers/gpu/drm/drm_bufs.c +++ b/drivers/gpu/drm/drm_bufs.c @@ -151,7 +151,7 @@ static int drm_addmap_core(struct drm_device * dev, resource_size_t offset, unsigned long user_token; int ret; - map = drm_alloc(sizeof(*map), DRM_MEM_MAPS); + map = kmalloc(sizeof(*map), GFP_KERNEL); if (!map) return -ENOMEM; @@ -165,7 +165,7 @@ static int drm_addmap_core(struct drm_device * dev, resource_size_t offset, * when processes fork. */ if ((map->flags & _DRM_REMOVABLE) && map->type != _DRM_SHM) { - drm_free(map, sizeof(*map), DRM_MEM_MAPS); + kfree(map); return -EINVAL; } DRM_DEBUG("offset = 0x%08llx, size = 0x%08lx, type = %d\n", @@ -179,7 +179,7 @@ static int drm_addmap_core(struct drm_device * dev, resource_size_t offset, map->size = PAGE_ALIGN(map->size); if ((map->offset & (~(resource_size_t)PAGE_MASK)) || (map->size & (~PAGE_MASK))) { - drm_free(map, sizeof(*map), DRM_MEM_MAPS); + kfree(map); return -EINVAL; } map->mtrr = -1; @@ -191,7 +191,7 @@ static int drm_addmap_core(struct drm_device * dev, resource_size_t offset, #if !defined(__sparc__) && !defined(__alpha__) && !defined(__ia64__) && !defined(__powerpc64__) && !defined(__x86_64__) if (map->offset + (map->size-1) < map->offset || map->offset < virt_to_phys(high_memory)) { - drm_free(map, sizeof(*map), DRM_MEM_MAPS); + kfree(map); return -EINVAL; } #endif @@ -212,7 +212,7 @@ static int drm_addmap_core(struct drm_device * dev, resource_size_t offset, list->map->size = map->size; } - drm_free(map, sizeof(*map), DRM_MEM_MAPS); + kfree(map); *maplist = list; return 0; } @@ -227,7 +227,7 @@ static int drm_addmap_core(struct drm_device * dev, resource_size_t offset, if (map->type == _DRM_REGISTERS) { map->handle = ioremap(map->offset, map->size); if (!map->handle) { - drm_free(map, sizeof(*map), DRM_MEM_MAPS); + kfree(map); return -ENOMEM; } } @@ -243,7 +243,7 @@ static int drm_addmap_core(struct drm_device * dev, resource_size_t offset, list->map->size = map->size; } - drm_free(map, sizeof(*map), DRM_MEM_MAPS); + kfree(map); *maplist = list; return 0; } @@ -251,7 +251,7 @@ static int drm_addmap_core(struct drm_device * dev, resource_size_t offset, DRM_DEBUG("%lu %d %p\n", map->size, drm_order(map->size), map->handle); if (!map->handle) { - drm_free(map, sizeof(*map), DRM_MEM_MAPS); + kfree(map); return -ENOMEM; } map->offset = (unsigned long)map->handle; @@ -259,7 +259,7 @@ static int drm_addmap_core(struct drm_device * dev, resource_size_t offset, /* Prevent a 2nd X Server from creating a 2nd lock */ if (dev->primary->master->lock.hw_lock != NULL) { vfree(map->handle); - drm_free(map, sizeof(*map), DRM_MEM_MAPS); + kfree(map); return -EBUSY; } dev->sigdata.lock = dev->primary->master->lock.hw_lock = map->handle; /* Pointer to lock */ @@ -270,7 +270,7 @@ static int drm_addmap_core(struct drm_device * dev, resource_size_t offset, int valid = 0; if (!drm_core_has_AGP(dev)) { - drm_free(map, sizeof(*map), DRM_MEM_MAPS); + kfree(map); return -EINVAL; } #ifdef __alpha__ @@ -303,7 +303,7 @@ static int drm_addmap_core(struct drm_device * dev, resource_size_t offset, } } if (!list_empty(&dev->agp->memory) && !valid) { - drm_free(map, sizeof(*map), DRM_MEM_MAPS); + kfree(map); return -EPERM; } DRM_DEBUG("AGP offset = 0x%08llx, size = 0x%08lx\n", @@ -316,7 +316,7 @@ static int drm_addmap_core(struct drm_device * dev, resource_size_t offset, } case _DRM_SCATTER_GATHER: if (!dev->sg) { - drm_free(map, sizeof(*map), DRM_MEM_MAPS); + kfree(map); return -EINVAL; } map->offset += (unsigned long)dev->sg->virtual; @@ -328,7 +328,7 @@ static int drm_addmap_core(struct drm_device * dev, resource_size_t offset, * need to point to a 64bit variable first. */ dmah = drm_pci_alloc(dev, map->size, map->size, 0xffffffffUL); if (!dmah) { - drm_free(map, sizeof(*map), DRM_MEM_MAPS); + kfree(map); return -ENOMEM; } map->handle = dmah->vaddr; @@ -336,15 +336,15 @@ static int drm_addmap_core(struct drm_device * dev, resource_size_t offset, kfree(dmah); break; default: - drm_free(map, sizeof(*map), DRM_MEM_MAPS); + kfree(map); return -EINVAL; } - list = drm_alloc(sizeof(*list), DRM_MEM_MAPS); + list = kmalloc(sizeof(*list), GFP_KERNEL); if (!list) { if (map->type == _DRM_REGISTERS) iounmap(map->handle); - drm_free(map, sizeof(*map), DRM_MEM_MAPS); + kfree(map); return -EINVAL; } memset(list, 0, sizeof(*list)); @@ -362,8 +362,8 @@ static int drm_addmap_core(struct drm_device * dev, resource_size_t offset, if (ret) { if (map->type == _DRM_REGISTERS) iounmap(map->handle); - drm_free(map, sizeof(*map), DRM_MEM_MAPS); - drm_free(list, sizeof(*list), DRM_MEM_MAPS); + kfree(map); + kfree(list); mutex_unlock(&dev->struct_mutex); return ret; } @@ -448,7 +448,7 @@ int drm_rmmap_locked(struct drm_device *dev, struct drm_local_map *map) list_del(&r_list->head); drm_ht_remove_key(&dev->map_hash, r_list->user_token >> PAGE_SHIFT); - drm_free(r_list, sizeof(*r_list), DRM_MEM_MAPS); + kfree(r_list); found = 1; break; } @@ -491,7 +491,7 @@ int drm_rmmap_locked(struct drm_device *dev, struct drm_local_map *map) DRM_ERROR("tried to rmmap GEM object\n"); break; } - drm_free(map, sizeof(*map), DRM_MEM_MAPS); + kfree(map); return 0; } @@ -582,24 +582,16 @@ static void drm_cleanup_buf_error(struct drm_device * dev, drm_pci_free(dev, entry->seglist[i]); } } - drm_free(entry->seglist, - entry->seg_count * - sizeof(*entry->seglist), DRM_MEM_SEGS); + kfree(entry->seglist); entry->seg_count = 0; } if (entry->buf_count) { for (i = 0; i < entry->buf_count; i++) { - if (entry->buflist[i].dev_private) { - drm_free(entry->buflist[i].dev_private, - entry->buflist[i].dev_priv_size, - DRM_MEM_BUFS); - } + kfree(entry->buflist[i].dev_private); } - drm_free(entry->buflist, - entry->buf_count * - sizeof(*entry->buflist), DRM_MEM_BUFS); + kfree(entry->buflist); entry->buf_count = 0; } @@ -698,8 +690,7 @@ int drm_addbufs_agp(struct drm_device * dev, struct drm_buf_desc * request) return -EINVAL; } - entry->buflist = drm_alloc(count * sizeof(*entry->buflist), - DRM_MEM_BUFS); + entry->buflist = kmalloc(count * sizeof(*entry->buflist), GFP_KERNEL); if (!entry->buflist) { mutex_unlock(&dev->struct_mutex); atomic_dec(&dev->buf_alloc); @@ -729,7 +720,7 @@ int drm_addbufs_agp(struct drm_device * dev, struct drm_buf_desc * request) buf->file_priv = NULL; buf->dev_priv_size = dev->driver->dev_priv_size; - buf->dev_private = drm_alloc(buf->dev_priv_size, DRM_MEM_BUFS); + buf->dev_private = kmalloc(buf->dev_priv_size, GFP_KERNEL); if (!buf->dev_private) { /* Set count correctly so we free the proper amount. */ entry->buf_count = count; @@ -749,10 +740,9 @@ int drm_addbufs_agp(struct drm_device * dev, struct drm_buf_desc * request) DRM_DEBUG("byte_count: %d\n", byte_count); - temp_buflist = drm_realloc(dma->buflist, - dma->buf_count * sizeof(*dma->buflist), - (dma->buf_count + entry->buf_count) - * sizeof(*dma->buflist), DRM_MEM_BUFS); + temp_buflist = krealloc(dma->buflist, + (dma->buf_count + entry->buf_count) * + sizeof(*dma->buflist), GFP_KERNEL); if (!temp_buflist) { /* Free the entry because it isn't valid */ drm_cleanup_buf_error(dev, entry); @@ -854,8 +844,7 @@ int drm_addbufs_pci(struct drm_device * dev, struct drm_buf_desc * request) return -EINVAL; } - entry->buflist = drm_alloc(count * sizeof(*entry->buflist), - DRM_MEM_BUFS); + entry->buflist = kmalloc(count * sizeof(*entry->buflist), GFP_KERNEL); if (!entry->buflist) { mutex_unlock(&dev->struct_mutex); atomic_dec(&dev->buf_alloc); @@ -863,11 +852,9 @@ int drm_addbufs_pci(struct drm_device * dev, struct drm_buf_desc * request) } memset(entry->buflist, 0, count * sizeof(*entry->buflist)); - entry->seglist = drm_alloc(count * sizeof(*entry->seglist), - DRM_MEM_SEGS); + entry->seglist = kmalloc(count * sizeof(*entry->seglist), GFP_KERNEL); if (!entry->seglist) { - drm_free(entry->buflist, - count * sizeof(*entry->buflist), DRM_MEM_BUFS); + kfree(entry->buflist); mutex_unlock(&dev->struct_mutex); atomic_dec(&dev->buf_alloc); return -ENOMEM; @@ -877,13 +864,11 @@ int drm_addbufs_pci(struct drm_device * dev, struct drm_buf_desc * request) /* Keep the original pagelist until we know all the allocations * have succeeded */ - temp_pagelist = drm_alloc((dma->page_count + (count << page_order)) - * sizeof(*dma->pagelist), DRM_MEM_PAGES); + temp_pagelist = kmalloc((dma->page_count + (count << page_order)) * + sizeof(*dma->pagelist), GFP_KERNEL); if (!temp_pagelist) { - drm_free(entry->buflist, - count * sizeof(*entry->buflist), DRM_MEM_BUFS); - drm_free(entry->seglist, - count * sizeof(*entry->seglist), DRM_MEM_SEGS); + kfree(entry->buflist); + kfree(entry->seglist); mutex_unlock(&dev->struct_mutex); atomic_dec(&dev->buf_alloc); return -ENOMEM; @@ -907,9 +892,7 @@ int drm_addbufs_pci(struct drm_device * dev, struct drm_buf_desc * request) entry->buf_count = count; entry->seg_count = count; drm_cleanup_buf_error(dev, entry); - drm_free(temp_pagelist, - (dma->page_count + (count << page_order)) - * sizeof(*dma->pagelist), DRM_MEM_PAGES); + kfree(temp_pagelist); mutex_unlock(&dev->struct_mutex); atomic_dec(&dev->buf_alloc); return -ENOMEM; @@ -940,18 +923,14 @@ int drm_addbufs_pci(struct drm_device * dev, struct drm_buf_desc * request) buf->file_priv = NULL; buf->dev_priv_size = dev->driver->dev_priv_size; - buf->dev_private = drm_alloc(buf->dev_priv_size, - DRM_MEM_BUFS); + buf->dev_private = kmalloc(buf->dev_priv_size, + GFP_KERNEL); if (!buf->dev_private) { /* Set count correctly so we free the proper amount. */ entry->buf_count = count; entry->seg_count = count; drm_cleanup_buf_error(dev, entry); - drm_free(temp_pagelist, - (dma->page_count + - (count << page_order)) - * sizeof(*dma->pagelist), - DRM_MEM_PAGES); + kfree(temp_pagelist); mutex_unlock(&dev->struct_mutex); atomic_dec(&dev->buf_alloc); return -ENOMEM; @@ -964,16 +943,13 @@ int drm_addbufs_pci(struct drm_device * dev, struct drm_buf_desc * request) byte_count += PAGE_SIZE << page_order; } - temp_buflist = drm_realloc(dma->buflist, - dma->buf_count * sizeof(*dma->buflist), - (dma->buf_count + entry->buf_count) - * sizeof(*dma->buflist), DRM_MEM_BUFS); + temp_buflist = krealloc(dma->buflist, + (dma->buf_count + entry->buf_count) * + sizeof(*dma->buflist), GFP_KERNEL); if (!temp_buflist) { /* Free the entry because it isn't valid */ drm_cleanup_buf_error(dev, entry); - drm_free(temp_pagelist, - (dma->page_count + (count << page_order)) - * sizeof(*dma->pagelist), DRM_MEM_PAGES); + kfree(temp_pagelist); mutex_unlock(&dev->struct_mutex); atomic_dec(&dev->buf_alloc); return -ENOMEM; @@ -988,9 +964,7 @@ int drm_addbufs_pci(struct drm_device * dev, struct drm_buf_desc * request) * with the new one. */ if (dma->page_count) { - drm_free(dma->pagelist, - dma->page_count * sizeof(*dma->pagelist), - DRM_MEM_PAGES); + kfree(dma->pagelist); } dma->pagelist = temp_pagelist; @@ -1086,8 +1060,8 @@ static int drm_addbufs_sg(struct drm_device * dev, struct drm_buf_desc * request return -EINVAL; } - entry->buflist = drm_alloc(count * sizeof(*entry->buflist), - DRM_MEM_BUFS); + entry->buflist = kmalloc(count * sizeof(*entry->buflist), + GFP_KERNEL); if (!entry->buflist) { mutex_unlock(&dev->struct_mutex); atomic_dec(&dev->buf_alloc); @@ -1118,7 +1092,7 @@ static int drm_addbufs_sg(struct drm_device * dev, struct drm_buf_desc * request buf->file_priv = NULL; buf->dev_priv_size = dev->driver->dev_priv_size; - buf->dev_private = drm_alloc(buf->dev_priv_size, DRM_MEM_BUFS); + buf->dev_private = kmalloc(buf->dev_priv_size, GFP_KERNEL); if (!buf->dev_private) { /* Set count correctly so we free the proper amount. */ entry->buf_count = count; @@ -1139,10 +1113,9 @@ static int drm_addbufs_sg(struct drm_device * dev, struct drm_buf_desc * request DRM_DEBUG("byte_count: %d\n", byte_count); - temp_buflist = drm_realloc(dma->buflist, - dma->buf_count * sizeof(*dma->buflist), - (dma->buf_count + entry->buf_count) - * sizeof(*dma->buflist), DRM_MEM_BUFS); + temp_buflist = krealloc(dma->buflist, + (dma->buf_count + entry->buf_count) * + sizeof(*dma->buflist), GFP_KERNEL); if (!temp_buflist) { /* Free the entry because it isn't valid */ drm_cleanup_buf_error(dev, entry); @@ -1248,8 +1221,8 @@ static int drm_addbufs_fb(struct drm_device * dev, struct drm_buf_desc * request return -EINVAL; } - entry->buflist = drm_alloc(count * sizeof(*entry->buflist), - DRM_MEM_BUFS); + entry->buflist = kmalloc(count * sizeof(*entry->buflist), + GFP_KERNEL); if (!entry->buflist) { mutex_unlock(&dev->struct_mutex); atomic_dec(&dev->buf_alloc); @@ -1279,7 +1252,7 @@ static int drm_addbufs_fb(struct drm_device * dev, struct drm_buf_desc * request buf->file_priv = NULL; buf->dev_priv_size = dev->driver->dev_priv_size; - buf->dev_private = drm_alloc(buf->dev_priv_size, DRM_MEM_BUFS); + buf->dev_private = kmalloc(buf->dev_priv_size, GFP_KERNEL); if (!buf->dev_private) { /* Set count correctly so we free the proper amount. */ entry->buf_count = count; @@ -1299,10 +1272,9 @@ static int drm_addbufs_fb(struct drm_device * dev, struct drm_buf_desc * request DRM_DEBUG("byte_count: %d\n", byte_count); - temp_buflist = drm_realloc(dma->buflist, - dma->buf_count * sizeof(*dma->buflist), - (dma->buf_count + entry->buf_count) - * sizeof(*dma->buflist), DRM_MEM_BUFS); + temp_buflist = krealloc(dma->buflist, + (dma->buf_count + entry->buf_count) * + sizeof(*dma->buflist), GFP_KERNEL); if (!temp_buflist) { /* Free the entry because it isn't valid */ drm_cleanup_buf_error(dev, entry); diff --git a/drivers/gpu/drm/drm_context.c b/drivers/gpu/drm/drm_context.c index 7d1e53c10d4b..2607753a320b 100644 --- a/drivers/gpu/drm/drm_context.c +++ b/drivers/gpu/drm/drm_context.c @@ -341,7 +341,7 @@ int drm_addctx(struct drm_device *dev, void *data, } } - ctx_entry = drm_alloc(sizeof(*ctx_entry), DRM_MEM_CTXLIST); + ctx_entry = kmalloc(sizeof(*ctx_entry), GFP_KERNEL); if (!ctx_entry) { DRM_DEBUG("out of memory\n"); return -ENOMEM; @@ -456,7 +456,7 @@ int drm_rmctx(struct drm_device *dev, void *data, list_for_each_entry_safe(pos, n, &dev->ctxlist, head) { if (pos->handle == ctx->handle) { list_del(&pos->head); - drm_free(pos, sizeof(*pos), DRM_MEM_CTXLIST); + kfree(pos); --dev->ctx_count; } } diff --git a/drivers/gpu/drm/drm_debugfs.c b/drivers/gpu/drm/drm_debugfs.c index 6ce0e2667a85..2960b6d73456 100644 --- a/drivers/gpu/drm/drm_debugfs.c +++ b/drivers/gpu/drm/drm_debugfs.c @@ -100,15 +100,13 @@ int drm_debugfs_create_files(struct drm_info_list *files, int count, (dev->driver->driver_features & features) != features) continue; - tmp = drm_alloc(sizeof(struct drm_info_node), - _DRM_DRIVER); + tmp = kmalloc(sizeof(struct drm_info_node), GFP_KERNEL); ent = debugfs_create_file(files[i].name, S_IFREG | S_IRUGO, root, tmp, &drm_debugfs_fops); if (!ent) { DRM_ERROR("Cannot create /sys/kernel/debug/dri/%s/%s\n", name, files[i].name); - drm_free(tmp, sizeof(struct drm_info_node), - _DRM_DRIVER); + kfree(tmp); ret = -1; goto fail; } @@ -196,8 +194,7 @@ int drm_debugfs_remove_files(struct drm_info_list *files, int count, if (tmp->info_ent == &files[i]) { debugfs_remove(tmp->dent); list_del(pos); - drm_free(tmp, sizeof(struct drm_info_node), - _DRM_DRIVER); + kfree(tmp); } } } diff --git a/drivers/gpu/drm/drm_dma.c b/drivers/gpu/drm/drm_dma.c index 7a8e2fba4678..13f1537413fb 100644 --- a/drivers/gpu/drm/drm_dma.c +++ b/drivers/gpu/drm/drm_dma.c @@ -47,7 +47,7 @@ int drm_dma_setup(struct drm_device *dev) { int i; - dev->dma = drm_alloc(sizeof(*dev->dma), DRM_MEM_DRIVER); + dev->dma = kmalloc(sizeof(*dev->dma), GFP_KERNEL); if (!dev->dma) return -ENOMEM; @@ -88,36 +88,19 @@ void drm_dma_takedown(struct drm_device *dev) drm_pci_free(dev, dma->bufs[i].seglist[j]); } } - drm_free(dma->bufs[i].seglist, - dma->bufs[i].seg_count - * sizeof(*dma->bufs[0].seglist), DRM_MEM_SEGS); + kfree(dma->bufs[i].seglist); } if (dma->bufs[i].buf_count) { for (j = 0; j < dma->bufs[i].buf_count; j++) { - if (dma->bufs[i].buflist[j].dev_private) { - drm_free(dma->bufs[i].buflist[j]. - dev_private, - dma->bufs[i].buflist[j]. - dev_priv_size, DRM_MEM_BUFS); - } + kfree(dma->bufs[i].buflist[j].dev_private); } - drm_free(dma->bufs[i].buflist, - dma->bufs[i].buf_count * - sizeof(*dma->bufs[0].buflist), DRM_MEM_BUFS); + kfree(dma->bufs[i].buflist); } } - if (dma->buflist) { - drm_free(dma->buflist, - dma->buf_count * sizeof(*dma->buflist), DRM_MEM_BUFS); - } - - if (dma->pagelist) { - drm_free(dma->pagelist, - dma->page_count * sizeof(*dma->pagelist), - DRM_MEM_PAGES); - } - drm_free(dev->dma, sizeof(*dev->dma), DRM_MEM_DRIVER); + kfree(dma->buflist); + kfree(dma->pagelist); + kfree(dev->dma); dev->dma = NULL; } diff --git a/drivers/gpu/drm/drm_drawable.c b/drivers/gpu/drm/drm_drawable.c index 80be1cab62af..c53c9768cc11 100644 --- a/drivers/gpu/drm/drm_drawable.c +++ b/drivers/gpu/drm/drm_drawable.c @@ -85,9 +85,8 @@ int drm_rmdraw(struct drm_device *dev, void *data, struct drm_file *file_priv) spin_unlock_irqrestore(&dev->drw_lock, irqflags); return -EINVAL; } - drm_free(info->rects, info->num_rects * sizeof(struct drm_clip_rect), - DRM_MEM_BUFS); - drm_free(info, sizeof(struct drm_drawable_info), DRM_MEM_BUFS); + kfree(info->rects); + kfree(info); idr_remove(&dev->drw_idr, draw->handle); @@ -106,12 +105,12 @@ int drm_update_drawable_info(struct drm_device *dev, void *data, struct drm_file info = idr_find(&dev->drw_idr, update->handle); if (!info) { - info = drm_calloc(1, sizeof(*info), DRM_MEM_BUFS); + info = kzalloc(sizeof(*info), GFP_KERNEL); if (!info) return -ENOMEM; if (IS_ERR(idr_replace(&dev->drw_idr, info, update->handle))) { DRM_ERROR("No such drawable %d\n", update->handle); - drm_free(info, sizeof(*info), DRM_MEM_BUFS); + kfree(info); return -EINVAL; } } @@ -121,8 +120,9 @@ int drm_update_drawable_info(struct drm_device *dev, void *data, struct drm_file if (update->num == 0) rects = NULL; else if (update->num != info->num_rects) { - rects = drm_alloc(update->num * sizeof(struct drm_clip_rect), - DRM_MEM_BUFS); + rects = kmalloc(update->num * + sizeof(struct drm_clip_rect), + GFP_KERNEL); } else rects = info->rects; @@ -145,8 +145,7 @@ int drm_update_drawable_info(struct drm_device *dev, void *data, struct drm_file spin_lock_irqsave(&dev->drw_lock, irqflags); if (rects != info->rects) { - drm_free(info->rects, info->num_rects * - sizeof(struct drm_clip_rect), DRM_MEM_BUFS); + kfree(info->rects); } info->rects = rects; @@ -166,8 +165,7 @@ int drm_update_drawable_info(struct drm_device *dev, void *data, struct drm_file error: if (rects != info->rects) - drm_free(rects, update->num * sizeof(struct drm_clip_rect), - DRM_MEM_BUFS); + kfree(rects); return err; } @@ -186,9 +184,8 @@ static int drm_drawable_free(int idr, void *p, void *data) struct drm_drawable_info *info = p; if (info) { - drm_free(info->rects, info->num_rects * - sizeof(struct drm_clip_rect), DRM_MEM_BUFS); - drm_free(info, sizeof(*info), DRM_MEM_BUFS); + kfree(info->rects); + kfree(info); } return 0; diff --git a/drivers/gpu/drm/drm_drv.c b/drivers/gpu/drm/drm_drv.c index 1bf7efd8d334..b39d7bfc0c9c 100644 --- a/drivers/gpu/drm/drm_drv.c +++ b/drivers/gpu/drm/drm_drv.c @@ -189,7 +189,7 @@ int drm_lastclose(struct drm_device * dev) if (entry->bound) drm_unbind_agp(entry->memory); drm_free_agp(entry->memory, entry->pages); - drm_free(entry, sizeof(*entry), DRM_MEM_AGPLISTS); + kfree(entry); } INIT_LIST_HEAD(&dev->agp->memory); @@ -208,21 +208,15 @@ int drm_lastclose(struct drm_device * dev) /* Clear vma list (only built for debugging) */ list_for_each_entry_safe(vma, vma_temp, &dev->vmalist, head) { list_del(&vma->head); - drm_free(vma, sizeof(*vma), DRM_MEM_VMAS); + kfree(vma); } if (drm_core_check_feature(dev, DRIVER_DMA_QUEUE) && dev->queuelist) { for (i = 0; i < dev->queue_count; i++) { - if (dev->queuelist[i]) { - drm_free(dev->queuelist[i], - sizeof(*dev->queuelist[0]), - DRM_MEM_QUEUES); - dev->queuelist[i] = NULL; - } + kfree(dev->queuelist[i]); + dev->queuelist[i] = NULL; } - drm_free(dev->queuelist, - dev->queue_slots * sizeof(*dev->queuelist), - DRM_MEM_QUEUES); + kfree(dev->queuelist); dev->queuelist = NULL; } dev->queue_count = 0; @@ -344,8 +338,6 @@ static int __init drm_core_init(void) goto err_p3; } - drm_mem_init(); - DRM_INFO("Initialized %s %d.%d.%d %s\n", CORE_NAME, CORE_MAJOR, CORE_MINOR, CORE_PATCHLEVEL, CORE_DATE); return 0; diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index 801a0d0e0810..7d0835226f6e 100644 --- a/drivers/gpu/drm/drm_edid.c +++ b/drivers/gpu/drm/drm_edid.c @@ -252,16 +252,18 @@ struct drm_display_mode *drm_mode_std(struct drm_device *dev, { struct drm_display_mode *mode; int hsize = t->hsize * 8 + 248, vsize; + unsigned aspect_ratio = (t->vfreq_aspect & EDID_TIMING_ASPECT_MASK) + >> EDID_TIMING_ASPECT_SHIFT; mode = drm_mode_create(dev); if (!mode) return NULL; - if (t->aspect_ratio == 0) + if (aspect_ratio == 0) vsize = (hsize * 10) / 16; - else if (t->aspect_ratio == 1) + else if (aspect_ratio == 1) vsize = (hsize * 3) / 4; - else if (t->aspect_ratio == 2) + else if (aspect_ratio == 2) vsize = (hsize * 4) / 5; else vsize = (hsize * 9) / 16; @@ -288,17 +290,24 @@ static struct drm_display_mode *drm_mode_detailed(struct drm_device *dev, { struct drm_display_mode *mode; struct detailed_pixel_timing *pt = &timing->data.pixel_data; + unsigned hactive = (pt->hactive_hblank_hi & 0xf0) << 4 | pt->hactive_lo; + unsigned vactive = (pt->vactive_vblank_hi & 0xf0) << 4 | pt->vactive_lo; + unsigned hblank = (pt->hactive_hblank_hi & 0xf) << 8 | pt->hblank_lo; + unsigned vblank = (pt->vactive_vblank_hi & 0xf) << 8 | pt->vblank_lo; + unsigned hsync_offset = (pt->hsync_vsync_offset_pulse_width_hi & 0x3) << 8 | pt->hsync_offset_lo; + unsigned hsync_pulse_width = (pt->hsync_vsync_offset_pulse_width_hi & 0xc) << 6 | pt->hsync_pulse_width_lo; + unsigned vsync_offset = (pt->hsync_vsync_offset_pulse_width_hi & 0x30) | (pt->vsync_offset_pulse_width_lo & 0xf); + unsigned vsync_pulse_width = (pt->hsync_vsync_offset_pulse_width_hi & 0xc0) >> 2 | pt->vsync_offset_pulse_width_lo >> 4; /* ignore tiny modes */ - if (((pt->hactive_hi << 8) | pt->hactive_lo) < 64 || - ((pt->vactive_hi << 8) | pt->hactive_lo) < 64) + if (hactive < 64 || vactive < 64) return NULL; - if (pt->stereo) { + if (pt->misc & DRM_EDID_PT_STEREO) { printk(KERN_WARNING "stereo mode not supported\n"); return NULL; } - if (!pt->separate_sync) { + if (!(pt->misc & DRM_EDID_PT_SEPARATE_SYNC)) { printk(KERN_WARNING "integrated sync not supported\n"); return NULL; } @@ -310,41 +319,36 @@ static struct drm_display_mode *drm_mode_detailed(struct drm_device *dev, mode->type = DRM_MODE_TYPE_DRIVER; if (quirks & EDID_QUIRK_135_CLOCK_TOO_HIGH) - timing->pixel_clock = 1088; - - mode->clock = timing->pixel_clock * 10; - - mode->hdisplay = (pt->hactive_hi << 8) | pt->hactive_lo; - mode->hsync_start = mode->hdisplay + ((pt->hsync_offset_hi << 8) | - pt->hsync_offset_lo); - mode->hsync_end = mode->hsync_start + - ((pt->hsync_pulse_width_hi << 8) | - pt->hsync_pulse_width_lo); - mode->htotal = mode->hdisplay + ((pt->hblank_hi << 8) | pt->hblank_lo); - - mode->vdisplay = (pt->vactive_hi << 8) | pt->vactive_lo; - mode->vsync_start = mode->vdisplay + ((pt->vsync_offset_hi << 4) | - pt->vsync_offset_lo); - mode->vsync_end = mode->vsync_start + - ((pt->vsync_pulse_width_hi << 4) | - pt->vsync_pulse_width_lo); - mode->vtotal = mode->vdisplay + ((pt->vblank_hi << 8) | pt->vblank_lo); + timing->pixel_clock = cpu_to_le16(1088); + + mode->clock = le16_to_cpu(timing->pixel_clock) * 10; + + mode->hdisplay = hactive; + mode->hsync_start = mode->hdisplay + hsync_offset; + mode->hsync_end = mode->hsync_start + hsync_pulse_width; + mode->htotal = mode->hdisplay + hblank; + + mode->vdisplay = vactive; + mode->vsync_start = mode->vdisplay + vsync_offset; + mode->vsync_end = mode->vsync_start + vsync_pulse_width; + mode->vtotal = mode->vdisplay + vblank; drm_mode_set_name(mode); - if (pt->interlaced) + if (pt->misc & DRM_EDID_PT_INTERLACED) mode->flags |= DRM_MODE_FLAG_INTERLACE; if (quirks & EDID_QUIRK_DETAILED_SYNC_PP) { - pt->hsync_positive = 1; - pt->vsync_positive = 1; + pt->misc |= DRM_EDID_PT_HSYNC_POSITIVE | DRM_EDID_PT_VSYNC_POSITIVE; } - mode->flags |= pt->hsync_positive ? DRM_MODE_FLAG_PHSYNC : DRM_MODE_FLAG_NHSYNC; - mode->flags |= pt->vsync_positive ? DRM_MODE_FLAG_PVSYNC : DRM_MODE_FLAG_NVSYNC; + mode->flags |= (pt->misc & DRM_EDID_PT_HSYNC_POSITIVE) ? + DRM_MODE_FLAG_PHSYNC : DRM_MODE_FLAG_NHSYNC; + mode->flags |= (pt->misc & DRM_EDID_PT_VSYNC_POSITIVE) ? + DRM_MODE_FLAG_PVSYNC : DRM_MODE_FLAG_NVSYNC; - mode->width_mm = pt->width_mm_lo | (pt->width_mm_hi << 8); - mode->height_mm = pt->height_mm_lo | (pt->height_mm_hi << 8); + mode->width_mm = pt->width_mm_lo | (pt->width_height_mm_hi & 0xf) << 8; + mode->height_mm = pt->height_mm_lo | (pt->width_height_mm_hi & 0xf0) << 4; if (quirks & EDID_QUIRK_DETAILED_IN_CM) { mode->width_mm *= 10; @@ -465,7 +469,7 @@ static int add_standard_modes(struct drm_connector *connector, struct edid *edid struct drm_display_mode *newmode; /* If std timings bytes are 1, 1 it's empty */ - if (t->hsize == 1 && (t->aspect_ratio | t->vfreq) == 1) + if (t->hsize == 1 && t->vfreq_aspect == 1) continue; newmode = drm_mode_std(dev, &edid->standard_timings[i]); @@ -509,7 +513,7 @@ static int add_detailed_info(struct drm_connector *connector, continue; /* First detailed mode is preferred */ - if (i == 0 && edid->preferred_timing) + if (i == 0 && (edid->features & DRM_EDID_FEATURE_PREFERRED_TIMING)) newmode->type |= DRM_MODE_TYPE_PREFERRED; drm_mode_probed_add(connector, newmode); @@ -767,22 +771,22 @@ int drm_add_edid_modes(struct drm_connector *connector, struct edid *edid) if (quirks & (EDID_QUIRK_PREFER_LARGE_60 | EDID_QUIRK_PREFER_LARGE_75)) edid_fixup_preferred(connector, quirks); - connector->display_info.serration_vsync = edid->serration_vsync; - connector->display_info.sync_on_green = edid->sync_on_green; - connector->display_info.composite_sync = edid->composite_sync; - connector->display_info.separate_syncs = edid->separate_syncs; - connector->display_info.blank_to_black = edid->blank_to_black; - connector->display_info.video_level = edid->video_level; - connector->display_info.digital = edid->digital; + connector->display_info.serration_vsync = (edid->input & DRM_EDID_INPUT_SERRATION_VSYNC) ? 1 : 0; + connector->display_info.sync_on_green = (edid->input & DRM_EDID_INPUT_SYNC_ON_GREEN) ? 1 : 0; + connector->display_info.composite_sync = (edid->input & DRM_EDID_INPUT_COMPOSITE_SYNC) ? 1 : 0; + connector->display_info.separate_syncs = (edid->input & DRM_EDID_INPUT_SEPARATE_SYNCS) ? 1 : 0; + connector->display_info.blank_to_black = (edid->input & DRM_EDID_INPUT_BLANK_TO_BLACK) ? 1 : 0; + connector->display_info.video_level = (edid->input & DRM_EDID_INPUT_VIDEO_LEVEL) >> 5; + connector->display_info.digital = (edid->input & DRM_EDID_INPUT_DIGITAL) ? 1 : 0; connector->display_info.width_mm = edid->width_cm * 10; connector->display_info.height_mm = edid->height_cm * 10; connector->display_info.gamma = edid->gamma; - connector->display_info.gtf_supported = edid->default_gtf; - connector->display_info.standard_color = edid->standard_color; - connector->display_info.display_type = edid->display_type; - connector->display_info.active_off_supported = edid->pm_active_off; - connector->display_info.suspend_supported = edid->pm_suspend; - connector->display_info.standby_supported = edid->pm_standby; + connector->display_info.gtf_supported = (edid->features & DRM_EDID_FEATURE_DEFAULT_GTF) ? 1 : 0; + connector->display_info.standard_color = (edid->features & DRM_EDID_FEATURE_STANDARD_COLOR) ? 1 : 0; + connector->display_info.display_type = (edid->features & DRM_EDID_FEATURE_DISPLAY_TYPE) >> 3; + connector->display_info.active_off_supported = (edid->features & DRM_EDID_FEATURE_PM_ACTIVE_OFF) ? 1 : 0; + connector->display_info.suspend_supported = (edid->features & DRM_EDID_FEATURE_PM_SUSPEND) ? 1 : 0; + connector->display_info.standby_supported = (edid->features & DRM_EDID_FEATURE_PM_STANDBY) ? 1 : 0; connector->display_info.gamma = edid->gamma; return num_modes; diff --git a/drivers/gpu/drm/drm_fops.c b/drivers/gpu/drm/drm_fops.c index 09a3571c9908..251bc0e3b5ec 100644 --- a/drivers/gpu/drm/drm_fops.c +++ b/drivers/gpu/drm/drm_fops.c @@ -240,7 +240,7 @@ static int drm_open_helper(struct inode *inode, struct file *filp, DRM_DEBUG("pid = %d, minor = %d\n", task_pid_nr(current), minor_id); - priv = drm_alloc(sizeof(*priv), DRM_MEM_FILES); + priv = kmalloc(sizeof(*priv), GFP_KERNEL); if (!priv) return -ENOMEM; @@ -328,7 +328,7 @@ static int drm_open_helper(struct inode *inode, struct file *filp, return 0; out_free: - drm_free(priv, sizeof(*priv), DRM_MEM_FILES); + kfree(priv); filp->private_data = NULL; return ret; } @@ -471,7 +471,7 @@ int drm_release(struct inode *inode, struct file *filp) drm_ctxbitmap_free(dev, pos->handle); list_del(&pos->head); - drm_free(pos, sizeof(*pos), DRM_MEM_CTXLIST); + kfree(pos); --dev->ctx_count; } } @@ -516,7 +516,7 @@ int drm_release(struct inode *inode, struct file *filp) if (dev->driver->postclose) dev->driver->postclose(dev, file_priv); - drm_free(file_priv, sizeof(*file_priv), DRM_MEM_FILES); + kfree(file_priv); /* ======================================================== * End inline drm_release diff --git a/drivers/gpu/drm/drm_gem.c b/drivers/gpu/drm/drm_gem.c index ec43005100d9..8104ecaea26f 100644 --- a/drivers/gpu/drm/drm_gem.c +++ b/drivers/gpu/drm/drm_gem.c @@ -89,7 +89,7 @@ drm_gem_init(struct drm_device *dev) atomic_set(&dev->gtt_count, 0); atomic_set(&dev->gtt_memory, 0); - mm = drm_calloc(1, sizeof(struct drm_gem_mm), DRM_MEM_MM); + mm = kzalloc(sizeof(struct drm_gem_mm), GFP_KERNEL); if (!mm) { DRM_ERROR("out of memory\n"); return -ENOMEM; @@ -98,14 +98,14 @@ drm_gem_init(struct drm_device *dev) dev->mm_private = mm; if (drm_ht_create(&mm->offset_hash, 19)) { - drm_free(mm, sizeof(struct drm_gem_mm), DRM_MEM_MM); + kfree(mm); return -ENOMEM; } if (drm_mm_init(&mm->offset_manager, DRM_FILE_PAGE_OFFSET_START, DRM_FILE_PAGE_OFFSET_SIZE)) { drm_ht_remove(&mm->offset_hash); - drm_free(mm, sizeof(struct drm_gem_mm), DRM_MEM_MM); + kfree(mm); return -ENOMEM; } @@ -119,7 +119,7 @@ drm_gem_destroy(struct drm_device *dev) drm_mm_takedown(&mm->offset_manager); drm_ht_remove(&mm->offset_hash); - drm_free(mm, sizeof(struct drm_gem_mm), DRM_MEM_MM); + kfree(mm); dev->mm_private = NULL; } diff --git a/drivers/gpu/drm/drm_hashtab.c b/drivers/gpu/drm/drm_hashtab.c index ac35145c3e20..f36b21c5b2e1 100644 --- a/drivers/gpu/drm/drm_hashtab.c +++ b/drivers/gpu/drm/drm_hashtab.c @@ -46,8 +46,7 @@ int drm_ht_create(struct drm_open_hash *ht, unsigned int order) ht->table = NULL; ht->use_vmalloc = ((ht->size * sizeof(*ht->table)) > PAGE_SIZE); if (!ht->use_vmalloc) { - ht->table = drm_calloc(ht->size, sizeof(*ht->table), - DRM_MEM_HASHTAB); + ht->table = kcalloc(ht->size, sizeof(*ht->table), GFP_KERNEL); } if (!ht->table) { ht->use_vmalloc = 1; @@ -200,8 +199,7 @@ void drm_ht_remove(struct drm_open_hash *ht) if (ht->use_vmalloc) vfree(ht->table); else - drm_free(ht->table, ht->size * sizeof(*ht->table), - DRM_MEM_HASHTAB); + kfree(ht->table); ht->table = NULL; } } diff --git a/drivers/gpu/drm/drm_ioctl.c b/drivers/gpu/drm/drm_ioctl.c index 1fad76289e66..9b9ff46c2378 100644 --- a/drivers/gpu/drm/drm_ioctl.c +++ b/drivers/gpu/drm/drm_ioctl.c @@ -93,7 +93,7 @@ int drm_setunique(struct drm_device *dev, void *data, master->unique_len = u->unique_len; master->unique_size = u->unique_len + 1; - master->unique = drm_alloc(master->unique_size, DRM_MEM_DRIVER); + master->unique = kmalloc(master->unique_size, GFP_KERNEL); if (!master->unique) return -ENOMEM; if (copy_from_user(master->unique, u->unique, master->unique_len)) @@ -101,9 +101,8 @@ int drm_setunique(struct drm_device *dev, void *data, master->unique[master->unique_len] = '\0'; - dev->devname = - drm_alloc(strlen(dev->driver->pci_driver.name) + - strlen(master->unique) + 2, DRM_MEM_DRIVER); + dev->devname = kmalloc(strlen(dev->driver->pci_driver.name) + + strlen(master->unique) + 2, GFP_KERNEL); if (!dev->devname) return -ENOMEM; @@ -138,7 +137,7 @@ static int drm_set_busid(struct drm_device *dev, struct drm_file *file_priv) master->unique_len = 40; master->unique_size = master->unique_len; - master->unique = drm_alloc(master->unique_size, DRM_MEM_DRIVER); + master->unique = kmalloc(master->unique_size, GFP_KERNEL); if (master->unique == NULL) return -ENOMEM; @@ -152,9 +151,8 @@ static int drm_set_busid(struct drm_device *dev, struct drm_file *file_priv) else master->unique_len = len; - dev->devname = - drm_alloc(strlen(dev->driver->pci_driver.name) + master->unique_len + - 2, DRM_MEM_DRIVER); + dev->devname = kmalloc(strlen(dev->driver->pci_driver.name) + + master->unique_len + 2, GFP_KERNEL); if (dev->devname == NULL) return -ENOMEM; diff --git a/drivers/gpu/drm/drm_irq.c b/drivers/gpu/drm/drm_irq.c index fc8e5acd9d9a..b4a3dbcebe9b 100644 --- a/drivers/gpu/drm/drm_irq.c +++ b/drivers/gpu/drm/drm_irq.c @@ -104,21 +104,13 @@ void drm_vblank_cleanup(struct drm_device *dev) vblank_disable_fn((unsigned long)dev); - drm_free(dev->vbl_queue, sizeof(*dev->vbl_queue) * dev->num_crtcs, - DRM_MEM_DRIVER); - drm_free(dev->_vblank_count, sizeof(*dev->_vblank_count) * - dev->num_crtcs, DRM_MEM_DRIVER); - drm_free(dev->vblank_refcount, sizeof(*dev->vblank_refcount) * - dev->num_crtcs, DRM_MEM_DRIVER); - drm_free(dev->vblank_enabled, sizeof(*dev->vblank_enabled) * - dev->num_crtcs, DRM_MEM_DRIVER); - drm_free(dev->last_vblank, sizeof(*dev->last_vblank) * dev->num_crtcs, - DRM_MEM_DRIVER); - drm_free(dev->last_vblank_wait, - sizeof(*dev->last_vblank_wait) * dev->num_crtcs, - DRM_MEM_DRIVER); - drm_free(dev->vblank_inmodeset, sizeof(*dev->vblank_inmodeset) * - dev->num_crtcs, DRM_MEM_DRIVER); + kfree(dev->vbl_queue); + kfree(dev->_vblank_count); + kfree(dev->vblank_refcount); + kfree(dev->vblank_enabled); + kfree(dev->last_vblank); + kfree(dev->last_vblank_wait); + kfree(dev->vblank_inmodeset); dev->num_crtcs = 0; } @@ -132,37 +124,33 @@ int drm_vblank_init(struct drm_device *dev, int num_crtcs) spin_lock_init(&dev->vbl_lock); dev->num_crtcs = num_crtcs; - dev->vbl_queue = drm_alloc(sizeof(wait_queue_head_t) * num_crtcs, - DRM_MEM_DRIVER); + dev->vbl_queue = kmalloc(sizeof(wait_queue_head_t) * num_crtcs, + GFP_KERNEL); if (!dev->vbl_queue) goto err; - dev->_vblank_count = drm_alloc(sizeof(atomic_t) * num_crtcs, - DRM_MEM_DRIVER); + dev->_vblank_count = kmalloc(sizeof(atomic_t) * num_crtcs, GFP_KERNEL); if (!dev->_vblank_count) goto err; - dev->vblank_refcount = drm_alloc(sizeof(atomic_t) * num_crtcs, - DRM_MEM_DRIVER); + dev->vblank_refcount = kmalloc(sizeof(atomic_t) * num_crtcs, + GFP_KERNEL); if (!dev->vblank_refcount) goto err; - dev->vblank_enabled = drm_calloc(num_crtcs, sizeof(int), - DRM_MEM_DRIVER); + dev->vblank_enabled = kcalloc(num_crtcs, sizeof(int), GFP_KERNEL); if (!dev->vblank_enabled) goto err; - dev->last_vblank = drm_calloc(num_crtcs, sizeof(u32), DRM_MEM_DRIVER); + dev->last_vblank = kcalloc(num_crtcs, sizeof(u32), GFP_KERNEL); if (!dev->last_vblank) goto err; - dev->last_vblank_wait = drm_calloc(num_crtcs, sizeof(u32), - DRM_MEM_DRIVER); + dev->last_vblank_wait = kcalloc(num_crtcs, sizeof(u32), GFP_KERNEL); if (!dev->last_vblank_wait) goto err; - dev->vblank_inmodeset = drm_calloc(num_crtcs, sizeof(int), - DRM_MEM_DRIVER); + dev->vblank_inmodeset = kcalloc(num_crtcs, sizeof(int), GFP_KERNEL); if (!dev->vblank_inmodeset) goto err; diff --git a/drivers/gpu/drm/drm_memory.c b/drivers/gpu/drm/drm_memory.c index 0c707f533eab..e4865f99989c 100644 --- a/drivers/gpu/drm/drm_memory.c +++ b/drivers/gpu/drm/drm_memory.c @@ -36,15 +36,6 @@ #include <linux/highmem.h> #include "drmP.h" -#ifdef DEBUG_MEMORY -#include "drm_memory_debug.h" -#else - -/** No-op. */ -void drm_mem_init(void) -{ -} - /** * Called when "/proc/dri/%dev%/mem" is read. * @@ -64,28 +55,15 @@ int drm_mem_info(char *buf, char **start, off_t offset, return 0; } -/** Wrapper around kmalloc() and kfree() */ -void *drm_realloc(void *oldpt, size_t oldsize, size_t size, int area) -{ - void *pt; - - if (!(pt = kmalloc(size, GFP_KERNEL))) - return NULL; - if (oldpt && oldsize) { - memcpy(pt, oldpt, oldsize); - kfree(oldpt); - } - return pt; -} - #if __OS_HAS_AGP static void *agp_remap(unsigned long offset, unsigned long size, struct drm_device * dev) { - unsigned long *phys_addr_map, i, num_pages = + unsigned long i, num_pages = PAGE_ALIGN(size) / PAGE_SIZE; struct drm_agp_mem *agpmem; struct page **page_map; + struct page **phys_page_map; void *addr; size = PAGE_ALIGN(size); @@ -112,10 +90,9 @@ static void *agp_remap(unsigned long offset, unsigned long size, if (!page_map) return NULL; - phys_addr_map = - agpmem->memory->memory + (offset - agpmem->bound) / PAGE_SIZE; + phys_page_map = (agpmem->memory->pages + (offset - agpmem->bound) / PAGE_SIZE); for (i = 0; i < num_pages; ++i) - page_map[i] = pfn_to_page(phys_addr_map[i] >> PAGE_SHIFT); + page_map[i] = phys_page_map[i]; addr = vmap(page_map, num_pages, VM_IOREMAP, PAGE_AGP); vfree(page_map); @@ -157,8 +134,6 @@ static inline void *agp_remap(unsigned long offset, unsigned long size, #endif /* agp */ -#endif /* debug_memory */ - void drm_core_ioremap(struct drm_local_map *map, struct drm_device *dev) { if (drm_core_has_AGP(dev) && diff --git a/drivers/gpu/drm/drm_mm.c b/drivers/gpu/drm/drm_mm.c index a912a0ff11cc..3e47869d6dae 100644 --- a/drivers/gpu/drm/drm_mm.c +++ b/drivers/gpu/drm/drm_mm.c @@ -187,9 +187,10 @@ static struct drm_mm_node *drm_mm_split_at_start(struct drm_mm_node *parent, } - -struct drm_mm_node *drm_mm_get_block(struct drm_mm_node *node, - unsigned long size, unsigned alignment) +struct drm_mm_node *drm_mm_get_block_generic(struct drm_mm_node *node, + unsigned long size, + unsigned alignment, + int atomic) { struct drm_mm_node *align_splitoff = NULL; @@ -200,7 +201,7 @@ struct drm_mm_node *drm_mm_get_block(struct drm_mm_node *node, if (tmp) { align_splitoff = - drm_mm_split_at_start(node, alignment - tmp, 0); + drm_mm_split_at_start(node, alignment - tmp, atomic); if (unlikely(align_splitoff == NULL)) return NULL; } @@ -209,7 +210,7 @@ struct drm_mm_node *drm_mm_get_block(struct drm_mm_node *node, list_del_init(&node->fl_entry); node->free = 0; } else { - node = drm_mm_split_at_start(node, size, 0); + node = drm_mm_split_at_start(node, size, atomic); } if (align_splitoff) @@ -217,42 +218,7 @@ struct drm_mm_node *drm_mm_get_block(struct drm_mm_node *node, return node; } - -EXPORT_SYMBOL(drm_mm_get_block); - -struct drm_mm_node *drm_mm_get_block_atomic(struct drm_mm_node *parent, - unsigned long size, - unsigned alignment) -{ - - struct drm_mm_node *align_splitoff = NULL; - struct drm_mm_node *child; - unsigned tmp = 0; - - if (alignment) - tmp = parent->start % alignment; - - if (tmp) { - align_splitoff = - drm_mm_split_at_start(parent, alignment - tmp, 1); - if (unlikely(align_splitoff == NULL)) - return NULL; - } - - if (parent->size == size) { - list_del_init(&parent->fl_entry); - parent->free = 0; - return parent; - } else { - child = drm_mm_split_at_start(parent, size, 1); - } - - if (align_splitoff) - drm_mm_put_block(align_splitoff); - - return child; -} -EXPORT_SYMBOL(drm_mm_get_block_atomic); +EXPORT_SYMBOL(drm_mm_get_block_generic); /* * Put a block. Merge with the previous and / or next block if they are free. diff --git a/drivers/gpu/drm/drm_pci.c b/drivers/gpu/drm/drm_pci.c index b55d5bc6ea61..577094fb1995 100644 --- a/drivers/gpu/drm/drm_pci.c +++ b/drivers/gpu/drm/drm_pci.c @@ -55,17 +55,6 @@ drm_dma_handle_t *drm_pci_alloc(struct drm_device * dev, size_t size, size_t ali unsigned long addr; size_t sz; #endif -#ifdef DRM_DEBUG_MEMORY - int area = DRM_MEM_DMA; - - spin_lock(&drm_mem_lock); - if ((drm_ram_used >> PAGE_SHIFT) - > (DRM_RAM_PERCENT * drm_ram_available) / 100) { - spin_unlock(&drm_mem_lock); - return 0; - } - spin_unlock(&drm_mem_lock); -#endif /* pci_alloc_consistent only guarantees alignment to the smallest * PAGE_SIZE order which is greater than or equal to the requested size. @@ -86,26 +75,10 @@ drm_dma_handle_t *drm_pci_alloc(struct drm_device * dev, size_t size, size_t ali dmah->size = size; dmah->vaddr = dma_alloc_coherent(&dev->pdev->dev, size, &dmah->busaddr, GFP_KERNEL | __GFP_COMP); -#ifdef DRM_DEBUG_MEMORY - if (dmah->vaddr == NULL) { - spin_lock(&drm_mem_lock); - ++drm_mem_stats[area].fail_count; - spin_unlock(&drm_mem_lock); - kfree(dmah); - return NULL; - } - - spin_lock(&drm_mem_lock); - ++drm_mem_stats[area].succeed_count; - drm_mem_stats[area].bytes_allocated += size; - drm_ram_used += size; - spin_unlock(&drm_mem_lock); -#else if (dmah->vaddr == NULL) { kfree(dmah); return NULL; } -#endif memset(dmah->vaddr, 0, size); @@ -132,17 +105,8 @@ void __drm_pci_free(struct drm_device * dev, drm_dma_handle_t * dmah) unsigned long addr; size_t sz; #endif -#ifdef DRM_DEBUG_MEMORY - int area = DRM_MEM_DMA; - int alloc_count; - int free_count; -#endif - if (!dmah->vaddr) { -#ifdef DRM_DEBUG_MEMORY - DRM_MEM_ERROR(area, "Attempt to free address 0\n"); -#endif - } else { + if (dmah->vaddr) { /* XXX - Is virt_to_page() legal for consistent mem? */ /* Unreserve */ for (addr = (unsigned long)dmah->vaddr, sz = dmah->size; @@ -152,21 +116,6 @@ void __drm_pci_free(struct drm_device * dev, drm_dma_handle_t * dmah) dma_free_coherent(&dev->pdev->dev, dmah->size, dmah->vaddr, dmah->busaddr); } - -#ifdef DRM_DEBUG_MEMORY - spin_lock(&drm_mem_lock); - free_count = ++drm_mem_stats[area].free_count; - alloc_count = drm_mem_stats[area].succeed_count; - drm_mem_stats[area].bytes_freed += size; - drm_ram_used -= size; - spin_unlock(&drm_mem_lock); - if (free_count > alloc_count) { - DRM_MEM_ERROR(area, - "Excess frees: %d frees, %d allocs\n", - free_count, alloc_count); - } -#endif - } /** diff --git a/drivers/gpu/drm/drm_proc.c b/drivers/gpu/drm/drm_proc.c index bae5391165ac..bbd4b3d1074a 100644 --- a/drivers/gpu/drm/drm_proc.c +++ b/drivers/gpu/drm/drm_proc.c @@ -105,13 +105,12 @@ int drm_proc_create_files(struct drm_info_list *files, int count, (dev->driver->driver_features & features) != features) continue; - tmp = drm_alloc(sizeof(struct drm_info_node), _DRM_DRIVER); + tmp = kmalloc(sizeof(struct drm_info_node), GFP_KERNEL); ent = create_proc_entry(files[i].name, S_IFREG | S_IRUGO, root); if (!ent) { DRM_ERROR("Cannot create /proc/dri/%s/%s\n", name, files[i].name); - drm_free(tmp, sizeof(struct drm_info_node), - _DRM_DRIVER); + kfree(tmp); ret = -1; goto fail; } @@ -192,8 +191,7 @@ int drm_proc_remove_files(struct drm_info_list *files, int count, remove_proc_entry(files[i].name, minor->proc_root); list_del(pos); - drm_free(tmp, sizeof(struct drm_info_node), - _DRM_DRIVER); + kfree(tmp); } } } diff --git a/drivers/gpu/drm/drm_scatter.c b/drivers/gpu/drm/drm_scatter.c index b2b0f3d41714..c7823c863d4f 100644 --- a/drivers/gpu/drm/drm_scatter.c +++ b/drivers/gpu/drm/drm_scatter.c @@ -58,11 +58,9 @@ void drm_sg_cleanup(struct drm_sg_mem * entry) vfree(entry->virtual); - drm_free(entry->busaddr, - entry->pages * sizeof(*entry->busaddr), DRM_MEM_PAGES); - drm_free(entry->pagelist, - entry->pages * sizeof(*entry->pagelist), DRM_MEM_PAGES); - drm_free(entry, sizeof(*entry), DRM_MEM_SGLISTS); + kfree(entry->busaddr); + kfree(entry->pagelist); + kfree(entry); } #ifdef _LP64 @@ -84,7 +82,7 @@ int drm_sg_alloc(struct drm_device *dev, struct drm_scatter_gather * request) if (dev->sg) return -EINVAL; - entry = drm_alloc(sizeof(*entry), DRM_MEM_SGLISTS); + entry = kmalloc(sizeof(*entry), GFP_KERNEL); if (!entry) return -ENOMEM; @@ -93,34 +91,27 @@ int drm_sg_alloc(struct drm_device *dev, struct drm_scatter_gather * request) DRM_DEBUG("size=%ld pages=%ld\n", request->size, pages); entry->pages = pages; - entry->pagelist = drm_alloc(pages * sizeof(*entry->pagelist), - DRM_MEM_PAGES); + entry->pagelist = kmalloc(pages * sizeof(*entry->pagelist), GFP_KERNEL); if (!entry->pagelist) { - drm_free(entry, sizeof(*entry), DRM_MEM_SGLISTS); + kfree(entry); return -ENOMEM; } memset(entry->pagelist, 0, pages * sizeof(*entry->pagelist)); - entry->busaddr = drm_alloc(pages * sizeof(*entry->busaddr), - DRM_MEM_PAGES); + entry->busaddr = kmalloc(pages * sizeof(*entry->busaddr), GFP_KERNEL); if (!entry->busaddr) { - drm_free(entry->pagelist, - entry->pages * sizeof(*entry->pagelist), - DRM_MEM_PAGES); - drm_free(entry, sizeof(*entry), DRM_MEM_SGLISTS); + kfree(entry->pagelist); + kfree(entry); return -ENOMEM; } memset((void *)entry->busaddr, 0, pages * sizeof(*entry->busaddr)); entry->virtual = drm_vmalloc_dma(pages << PAGE_SHIFT); if (!entry->virtual) { - drm_free(entry->busaddr, - entry->pages * sizeof(*entry->busaddr), DRM_MEM_PAGES); - drm_free(entry->pagelist, - entry->pages * sizeof(*entry->pagelist), - DRM_MEM_PAGES); - drm_free(entry, sizeof(*entry), DRM_MEM_SGLISTS); + kfree(entry->busaddr); + kfree(entry->pagelist); + kfree(entry); return -ENOMEM; } diff --git a/drivers/gpu/drm/drm_sman.c b/drivers/gpu/drm/drm_sman.c index 926f146390ce..463aed9403db 100644 --- a/drivers/gpu/drm/drm_sman.c +++ b/drivers/gpu/drm/drm_sman.c @@ -48,9 +48,7 @@ void drm_sman_takedown(struct drm_sman * sman) { drm_ht_remove(&sman->user_hash_tab); drm_ht_remove(&sman->owner_hash_tab); - if (sman->mm) - drm_free(sman->mm, sman->num_managers * sizeof(*sman->mm), - DRM_MEM_MM); + kfree(sman->mm); } EXPORT_SYMBOL(drm_sman_takedown); @@ -61,8 +59,9 @@ drm_sman_init(struct drm_sman * sman, unsigned int num_managers, { int ret = 0; - sman->mm = (struct drm_sman_mm *) drm_calloc(num_managers, sizeof(*sman->mm), - DRM_MEM_MM); + sman->mm = (struct drm_sman_mm *) kcalloc(num_managers, + sizeof(*sman->mm), + GFP_KERNEL); if (!sman->mm) { ret = -ENOMEM; goto out; @@ -78,7 +77,7 @@ drm_sman_init(struct drm_sman * sman, unsigned int num_managers, drm_ht_remove(&sman->owner_hash_tab); out1: - drm_free(sman->mm, num_managers * sizeof(*sman->mm), DRM_MEM_MM); + kfree(sman->mm); out: return ret; } @@ -110,7 +109,7 @@ static void drm_sman_mm_destroy(void *private) { struct drm_mm *mm = (struct drm_mm *) private; drm_mm_takedown(mm); - drm_free(mm, sizeof(*mm), DRM_MEM_MM); + kfree(mm); } static unsigned long drm_sman_mm_offset(void *private, void *ref) @@ -130,7 +129,7 @@ drm_sman_set_range(struct drm_sman * sman, unsigned int manager, BUG_ON(manager >= sman->num_managers); sman_mm = &sman->mm[manager]; - mm = drm_calloc(1, sizeof(*mm), DRM_MEM_MM); + mm = kzalloc(sizeof(*mm), GFP_KERNEL); if (!mm) { return -ENOMEM; } @@ -138,7 +137,7 @@ drm_sman_set_range(struct drm_sman * sman, unsigned int manager, ret = drm_mm_init(mm, start, size); if (ret) { - drm_free(mm, sizeof(*mm), DRM_MEM_MM); + kfree(mm); return ret; } @@ -176,7 +175,7 @@ static struct drm_owner_item *drm_sman_get_owner_item(struct drm_sman * sman, owner_hash); } - owner_item = drm_calloc(1, sizeof(*owner_item), DRM_MEM_MM); + owner_item = kzalloc(sizeof(*owner_item), GFP_KERNEL); if (!owner_item) goto out; @@ -189,7 +188,7 @@ static struct drm_owner_item *drm_sman_get_owner_item(struct drm_sman * sman, return owner_item; out1: - drm_free(owner_item, sizeof(*owner_item), DRM_MEM_MM); + kfree(owner_item); out: return NULL; } @@ -212,7 +211,7 @@ struct drm_memblock_item *drm_sman_alloc(struct drm_sman *sman, unsigned int man return NULL; } - memblock = drm_calloc(1, sizeof(*memblock), DRM_MEM_MM); + memblock = kzalloc(sizeof(*memblock), GFP_KERNEL); if (!memblock) goto out; @@ -237,7 +236,7 @@ struct drm_memblock_item *drm_sman_alloc(struct drm_sman *sman, unsigned int man out2: drm_ht_remove_item(&sman->user_hash_tab, &memblock->user_hash); out1: - drm_free(memblock, sizeof(*memblock), DRM_MEM_MM); + kfree(memblock); out: sman_mm->free(sman_mm->private, tmp); @@ -253,7 +252,7 @@ static void drm_sman_free(struct drm_memblock_item *item) list_del(&item->owner_list); drm_ht_remove_item(&sman->user_hash_tab, &item->user_hash); item->mm->free(item->mm->private, item->mm_info); - drm_free(item, sizeof(*item), DRM_MEM_MM); + kfree(item); } int drm_sman_free_key(struct drm_sman *sman, unsigned int key) @@ -277,7 +276,7 @@ static void drm_sman_remove_owner(struct drm_sman *sman, { list_del(&owner_item->sman_list); drm_ht_remove_item(&sman->owner_hash_tab, &owner_item->owner_hash); - drm_free(owner_item, sizeof(*owner_item), DRM_MEM_MM); + kfree(owner_item); } int drm_sman_owner_clean(struct drm_sman *sman, unsigned long owner) diff --git a/drivers/gpu/drm/drm_stub.c b/drivers/gpu/drm/drm_stub.c index 387a8de1bc7e..155a5bbce680 100644 --- a/drivers/gpu/drm/drm_stub.c +++ b/drivers/gpu/drm/drm_stub.c @@ -107,7 +107,7 @@ struct drm_master *drm_master_create(struct drm_minor *minor) { struct drm_master *master; - master = drm_calloc(1, sizeof(*master), DRM_MEM_DRIVER); + master = kzalloc(sizeof(*master), GFP_KERNEL); if (!master) return NULL; @@ -149,7 +149,7 @@ static void drm_master_destroy(struct kref *kref) } if (master->unique) { - drm_free(master->unique, master->unique_size, DRM_MEM_DRIVER); + kfree(master->unique); master->unique = NULL; master->unique_len = 0; } @@ -157,12 +157,12 @@ static void drm_master_destroy(struct kref *kref) list_for_each_entry_safe(pt, next, &master->magicfree, head) { list_del(&pt->head); drm_ht_remove_item(&master->magiclist, &pt->hash_item); - drm_free(pt, sizeof(*pt), DRM_MEM_MAGIC); + kfree(pt); } drm_ht_remove(&master->magiclist); - drm_free(master, sizeof(*master), DRM_MEM_DRIVER); + kfree(master); } void drm_master_put(struct drm_master **master) @@ -390,7 +390,7 @@ int drm_get_dev(struct pci_dev *pdev, const struct pci_device_id *ent, DRM_DEBUG("\n"); - dev = drm_calloc(1, sizeof(*dev), DRM_MEM_STUB); + dev = kzalloc(sizeof(*dev), GFP_KERNEL); if (!dev) return -ENOMEM; @@ -443,7 +443,7 @@ err_g3: err_g2: pci_disable_device(pdev); err_g1: - drm_free(dev, sizeof(*dev), DRM_MEM_STUB); + kfree(dev); return ret; } EXPORT_SYMBOL(drm_get_dev); @@ -516,7 +516,7 @@ void drm_put_dev(struct drm_device *dev) dev->driver->unload(dev); if (drm_core_has_AGP(dev) && dev->agp) { - drm_free(dev->agp, sizeof(*dev->agp), DRM_MEM_AGPLISTS); + kfree(dev->agp); dev->agp = NULL; } @@ -535,10 +535,9 @@ void drm_put_dev(struct drm_device *dev) drm_put_minor(&dev->primary); if (dev->devname) { - drm_free(dev->devname, strlen(dev->devname) + 1, - DRM_MEM_DRIVER); + kfree(dev->devname); dev->devname = NULL; } - drm_free(dev, sizeof(*dev), DRM_MEM_STUB); + kfree(dev); } EXPORT_SYMBOL(drm_put_dev); diff --git a/drivers/gpu/drm/drm_vm.c b/drivers/gpu/drm/drm_vm.c index 22f76567ac7d..7e1fbe5d4779 100644 --- a/drivers/gpu/drm/drm_vm.c +++ b/drivers/gpu/drm/drm_vm.c @@ -144,14 +144,14 @@ static int drm_do_vm_fault(struct vm_area_struct *vma, struct vm_fault *vmf) * Get the page, inc the use count, and return it */ offset = (baddr - agpmem->bound) >> PAGE_SHIFT; - page = virt_to_page(__va(agpmem->memory->memory[offset])); + page = agpmem->memory->pages[offset]; get_page(page); vmf->page = page; DRM_DEBUG ("baddr = 0x%llx page = 0x%p, offset = 0x%llx, count=%d\n", (unsigned long long)baddr, - __va(agpmem->memory->memory[offset]), + agpmem->memory->pages[offset], (unsigned long long)offset, page_count(page)); return 0; @@ -227,7 +227,7 @@ static void drm_vm_shm_close(struct vm_area_struct *vma) found_maps++; if (pt->vma == vma) { list_del(&pt->head); - drm_free(pt, sizeof(*pt), DRM_MEM_VMAS); + kfree(pt); } } @@ -273,7 +273,7 @@ static void drm_vm_shm_close(struct vm_area_struct *vma) DRM_ERROR("tried to rmmap GEM object\n"); break; } - drm_free(map, sizeof(*map), DRM_MEM_MAPS); + kfree(map); } } mutex_unlock(&dev->struct_mutex); @@ -414,7 +414,7 @@ void drm_vm_open_locked(struct vm_area_struct *vma) vma->vm_start, vma->vm_end - vma->vm_start); atomic_inc(&dev->vma_count); - vma_entry = drm_alloc(sizeof(*vma_entry), DRM_MEM_VMAS); + vma_entry = kmalloc(sizeof(*vma_entry), GFP_KERNEL); if (vma_entry) { vma_entry->vma = vma; vma_entry->pid = current->pid; @@ -454,7 +454,7 @@ static void drm_vm_close(struct vm_area_struct *vma) list_for_each_entry_safe(pt, temp, &dev->vmalist, head) { if (pt->vma == vma) { list_del(&pt->head); - drm_free(pt, sizeof(*pt), DRM_MEM_VMAS); + kfree(pt); break; } } diff --git a/drivers/gpu/drm/i810/i810_dma.c b/drivers/gpu/drm/i810/i810_dma.c index e5de8ea41544..7d1d88cdf2dc 100644 --- a/drivers/gpu/drm/i810/i810_dma.c +++ b/drivers/gpu/drm/i810/i810_dma.c @@ -227,8 +227,7 @@ static int i810_dma_cleanup(struct drm_device * dev) /* Need to rewrite hardware status page */ I810_WRITE(0x02080, 0x1ffff000); } - drm_free(dev->dev_private, sizeof(drm_i810_private_t), - DRM_MEM_DRIVER); + kfree(dev->dev_private); dev->dev_private = NULL; for (i = 0; i < dma->buf_count; i++) { @@ -439,8 +438,7 @@ static int i810_dma_init(struct drm_device *dev, void *data, switch (init->func) { case I810_INIT_DMA_1_4: DRM_INFO("Using v1.4 init.\n"); - dev_priv = drm_alloc(sizeof(drm_i810_private_t), - DRM_MEM_DRIVER); + dev_priv = kmalloc(sizeof(drm_i810_private_t), GFP_KERNEL); if (dev_priv == NULL) return -ENOMEM; retcode = i810_dma_initialize(dev, dev_priv, init); diff --git a/drivers/gpu/drm/i830/i830_dma.c b/drivers/gpu/drm/i830/i830_dma.c index a86ab30b4620..877bf6cb14a4 100644 --- a/drivers/gpu/drm/i830/i830_dma.c +++ b/drivers/gpu/drm/i830/i830_dma.c @@ -232,8 +232,7 @@ static int i830_dma_cleanup(struct drm_device * dev) I830_WRITE(0x02080, 0x1ffff000); } - drm_free(dev->dev_private, sizeof(drm_i830_private_t), - DRM_MEM_DRIVER); + kfree(dev->dev_private); dev->dev_private = NULL; for (i = 0; i < dma->buf_count; i++) { @@ -459,8 +458,7 @@ static int i830_dma_init(struct drm_device *dev, void *data, switch (init->func) { case I830_INIT_DMA: - dev_priv = drm_alloc(sizeof(drm_i830_private_t), - DRM_MEM_DRIVER); + dev_priv = kmalloc(sizeof(drm_i830_private_t), GFP_KERNEL); if (dev_priv == NULL) return -ENOMEM; retcode = i830_dma_initialize(dev, dev_priv, init); diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c index 1a60626f6803..f112c769d533 100644 --- a/drivers/gpu/drm/i915/i915_dma.c +++ b/drivers/gpu/drm/i915/i915_dma.c @@ -643,9 +643,9 @@ static int i915_batchbuffer(struct drm_device *dev, void *data, return -EINVAL; if (batch->num_cliprects) { - cliprects = drm_calloc(batch->num_cliprects, - sizeof(struct drm_clip_rect), - DRM_MEM_DRIVER); + cliprects = kcalloc(batch->num_cliprects, + sizeof(struct drm_clip_rect), + GFP_KERNEL); if (cliprects == NULL) return -ENOMEM; @@ -664,9 +664,7 @@ static int i915_batchbuffer(struct drm_device *dev, void *data, sarea_priv->last_dispatch = READ_BREADCRUMB(dev_priv); fail_free: - drm_free(cliprects, - batch->num_cliprects * sizeof(struct drm_clip_rect), - DRM_MEM_DRIVER); + kfree(cliprects); return ret; } @@ -692,7 +690,7 @@ static int i915_cmdbuffer(struct drm_device *dev, void *data, if (cmdbuf->num_cliprects < 0) return -EINVAL; - batch_data = drm_alloc(cmdbuf->sz, DRM_MEM_DRIVER); + batch_data = kmalloc(cmdbuf->sz, GFP_KERNEL); if (batch_data == NULL) return -ENOMEM; @@ -701,9 +699,8 @@ static int i915_cmdbuffer(struct drm_device *dev, void *data, goto fail_batch_free; if (cmdbuf->num_cliprects) { - cliprects = drm_calloc(cmdbuf->num_cliprects, - sizeof(struct drm_clip_rect), - DRM_MEM_DRIVER); + cliprects = kcalloc(cmdbuf->num_cliprects, + sizeof(struct drm_clip_rect), GFP_KERNEL); if (cliprects == NULL) goto fail_batch_free; @@ -726,11 +723,9 @@ static int i915_cmdbuffer(struct drm_device *dev, void *data, sarea_priv->last_dispatch = READ_BREADCRUMB(dev_priv); fail_clip_free: - drm_free(cliprects, - cmdbuf->num_cliprects * sizeof(struct drm_clip_rect), - DRM_MEM_DRIVER); + kfree(cliprects); fail_batch_free: - drm_free(batch_data, cmdbuf->sz, DRM_MEM_DRIVER); + kfree(batch_data); return ret; } @@ -1067,7 +1062,7 @@ int i915_master_create(struct drm_device *dev, struct drm_master *master) { struct drm_i915_master_private *master_priv; - master_priv = drm_calloc(1, sizeof(*master_priv), DRM_MEM_DRIVER); + master_priv = kzalloc(sizeof(*master_priv), GFP_KERNEL); if (!master_priv) return -ENOMEM; @@ -1082,7 +1077,7 @@ void i915_master_destroy(struct drm_device *dev, struct drm_master *master) if (!master_priv) return; - drm_free(master_priv, sizeof(*master_priv), DRM_MEM_DRIVER); + kfree(master_priv); master->driver_priv = NULL; } @@ -1111,12 +1106,10 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags) dev->types[8] = _DRM_STAT_SECONDARY; dev->types[9] = _DRM_STAT_DMA; - dev_priv = drm_alloc(sizeof(drm_i915_private_t), DRM_MEM_DRIVER); + dev_priv = kzalloc(sizeof(drm_i915_private_t), GFP_KERNEL); if (dev_priv == NULL) return -ENOMEM; - memset(dev_priv, 0, sizeof(drm_i915_private_t)); - dev->dev_private = (void *)dev_priv; dev_priv->dev = dev; @@ -1153,13 +1146,8 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags) "performance may suffer.\n"); } -#ifdef CONFIG_HIGHMEM64G - /* don't enable GEM on PAE - needs agp + set_memory_* interface fixes */ - dev_priv->has_gem = 0; -#else /* enable GEM by default */ dev_priv->has_gem = 1; -#endif dev->driver->get_vblank_counter = i915_get_vblank_counter; dev->max_vblank_count = 0xffffff; /* only 24 bits of frame count */ @@ -1221,7 +1209,7 @@ out_iomapfree: out_rmmap: iounmap(dev_priv->regs); free_priv: - drm_free(dev_priv, sizeof(struct drm_i915_private), DRM_MEM_DRIVER); + kfree(dev_priv); return ret; } @@ -1261,8 +1249,7 @@ int i915_driver_unload(struct drm_device *dev) i915_gem_lastclose(dev); } - drm_free(dev->dev_private, sizeof(drm_i915_private_t), - DRM_MEM_DRIVER); + kfree(dev->dev_private); return 0; } @@ -1273,7 +1260,7 @@ int i915_driver_open(struct drm_device *dev, struct drm_file *file_priv) DRM_DEBUG_DRIVER(I915_DRV, "\n"); i915_file_priv = (struct drm_i915_file_private *) - drm_alloc(sizeof(*i915_file_priv), DRM_MEM_FILES); + kmalloc(sizeof(*i915_file_priv), GFP_KERNEL); if (!i915_file_priv) return -ENOMEM; @@ -1326,7 +1313,7 @@ void i915_driver_postclose(struct drm_device *dev, struct drm_file *file_priv) { struct drm_i915_file_private *i915_file_priv = file_priv->driver_priv; - drm_free(i915_file_priv, sizeof(*i915_file_priv), DRM_MEM_FILES); + kfree(i915_file_priv); } struct drm_ioctl_desc i915_ioctls[] = { diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 8ef6bcec211b..7a84f04e8439 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -646,6 +646,8 @@ void i915_gem_object_unpin(struct drm_gem_object *obj); int i915_gem_object_unbind(struct drm_gem_object *obj); void i915_gem_lastclose(struct drm_device *dev); uint32_t i915_get_gem_seqno(struct drm_device *dev); +int i915_gem_object_get_fence_reg(struct drm_gem_object *obj); +int i915_gem_object_put_fence_reg(struct drm_gem_object *obj); void i915_gem_retire_requests(struct drm_device *dev); void i915_gem_retire_work_handler(struct work_struct *work); void i915_gem_clflush_object(struct drm_gem_object *obj); diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index c0ae6bbbd9b5..fd2b8bdffe3f 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -46,7 +46,6 @@ static void i915_gem_object_set_to_full_cpu_read_domain(struct drm_gem_object *o static int i915_gem_object_wait_rendering(struct drm_gem_object *obj); static int i915_gem_object_bind_to_gtt(struct drm_gem_object *obj, unsigned alignment); -static int i915_gem_object_get_fence_reg(struct drm_gem_object *obj, bool write); static void i915_gem_clear_fence_reg(struct drm_gem_object *obj); static int i915_gem_evict_something(struct drm_device *dev); static int i915_gem_phys_pwrite(struct drm_device *dev, struct drm_gem_object *obj, @@ -1158,7 +1157,7 @@ int i915_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf) /* Need a new fence register? */ if (obj_priv->fence_reg == I915_FENCE_REG_NONE && obj_priv->tiling_mode != I915_TILING_NONE) { - ret = i915_gem_object_get_fence_reg(obj, write); + ret = i915_gem_object_get_fence_reg(obj); if (ret) { mutex_unlock(&dev->struct_mutex); return VM_FAULT_SIGBUS; @@ -1208,8 +1207,7 @@ i915_gem_create_mmap_offset(struct drm_gem_object *obj) /* Set the object up for mmap'ing */ list = &obj->map_list; - list->map = drm_calloc(1, sizeof(struct drm_map_list), - DRM_MEM_DRIVER); + list->map = kzalloc(sizeof(struct drm_map_list), GFP_KERNEL); if (!list->map) return -ENOMEM; @@ -1249,7 +1247,7 @@ i915_gem_create_mmap_offset(struct drm_gem_object *obj) out_free_mm: drm_mm_put_block(list->file_offset_node); out_free_list: - drm_free(list->map, sizeof(struct drm_map_list), DRM_MEM_DRIVER); + kfree(list->map); return ret; } @@ -1271,7 +1269,7 @@ i915_gem_free_mmap_offset(struct drm_gem_object *obj) } if (list->map) { - drm_free(list->map, sizeof(struct drm_map), DRM_MEM_DRIVER); + kfree(list->map); list->map = NULL; } @@ -1494,7 +1492,7 @@ i915_add_request(struct drm_device *dev, struct drm_file *file_priv, if (file_priv != NULL) i915_file_priv = file_priv->driver_priv; - request = drm_calloc(1, sizeof(*request), DRM_MEM_DRIVER); + request = kzalloc(sizeof(*request), GFP_KERNEL); if (request == NULL) return 0; @@ -1676,7 +1674,7 @@ i915_gem_retire_requests(struct drm_device *dev) list_del(&request->list); list_del(&request->client_list); - drm_free(request, sizeof(*request), DRM_MEM_DRIVER); + kfree(request); } else break; } @@ -2163,13 +2161,11 @@ static void i830_write_fence_reg(struct drm_i915_fence_reg *reg) val |= I830_FENCE_REG_VALID; I915_WRITE(FENCE_REG_830_0 + (regnum * 4), val); - } /** * i915_gem_object_get_fence_reg - set up a fence reg for an object * @obj: object to map through a fence reg - * @write: object is about to be written * * When mapping objects through the GTT, userspace wants to be able to write * to them without having to worry about swizzling if the object is tiled. @@ -2180,8 +2176,8 @@ static void i830_write_fence_reg(struct drm_i915_fence_reg *reg) * It then sets up the reg based on the object's properties: address, pitch * and tiling format. */ -static int -i915_gem_object_get_fence_reg(struct drm_gem_object *obj, bool write) +int +i915_gem_object_get_fence_reg(struct drm_gem_object *obj) { struct drm_device *dev = obj->dev; struct drm_i915_private *dev_priv = dev->dev_private; @@ -2331,6 +2327,42 @@ i915_gem_clear_fence_reg(struct drm_gem_object *obj) } /** + * i915_gem_object_put_fence_reg - waits on outstanding fenced access + * to the buffer to finish, and then resets the fence register. + * @obj: tiled object holding a fence register. + * + * Zeroes out the fence register itself and clears out the associated + * data structures in dev_priv and obj_priv. + */ +int +i915_gem_object_put_fence_reg(struct drm_gem_object *obj) +{ + struct drm_device *dev = obj->dev; + struct drm_i915_gem_object *obj_priv = obj->driver_private; + + if (obj_priv->fence_reg == I915_FENCE_REG_NONE) + return 0; + + /* On the i915, GPU access to tiled buffers is via a fence, + * therefore we must wait for any outstanding access to complete + * before clearing the fence. + */ + if (!IS_I965G(dev)) { + int ret; + + i915_gem_object_flush_gpu_write_domain(obj); + i915_gem_object_flush_gtt_write_domain(obj); + ret = i915_gem_object_wait_rendering(obj); + if (ret != 0) + return ret; + } + + i915_gem_clear_fence_reg (obj); + + return 0; +} + +/** * Finds free space in the GTT aperture and binds the object there. */ static int @@ -2800,8 +2832,7 @@ i915_gem_object_set_to_full_cpu_read_domain(struct drm_gem_object *obj) /* Free the page_cpu_valid mappings which are now stale, whether * or not we've got I915_GEM_DOMAIN_CPU. */ - drm_free(obj_priv->page_cpu_valid, obj->size / PAGE_SIZE, - DRM_MEM_DRIVER); + kfree(obj_priv->page_cpu_valid); obj_priv->page_cpu_valid = NULL; } @@ -2843,8 +2874,8 @@ i915_gem_object_set_cpu_read_domain_range(struct drm_gem_object *obj, * newly adding I915_GEM_DOMAIN_CPU */ if (obj_priv->page_cpu_valid == NULL) { - obj_priv->page_cpu_valid = drm_calloc(1, obj->size / PAGE_SIZE, - DRM_MEM_DRIVER); + obj_priv->page_cpu_valid = kzalloc(obj->size / PAGE_SIZE, + GFP_KERNEL); if (obj_priv->page_cpu_valid == NULL) return -ENOMEM; } else if ((obj->read_domains & I915_GEM_DOMAIN_CPU) == 0) @@ -3267,8 +3298,8 @@ i915_gem_execbuffer(struct drm_device *dev, void *data, } if (args->num_cliprects != 0) { - cliprects = drm_calloc(args->num_cliprects, sizeof(*cliprects), - DRM_MEM_DRIVER); + cliprects = kcalloc(args->num_cliprects, sizeof(*cliprects), + GFP_KERNEL); if (cliprects == NULL) goto pre_mutex_err; @@ -3521,8 +3552,7 @@ err: pre_mutex_err: drm_free_large(object_list); drm_free_large(exec_list); - drm_free(cliprects, sizeof(*cliprects) * args->num_cliprects, - DRM_MEM_DRIVER); + kfree(cliprects); return ret; } @@ -3550,7 +3580,7 @@ i915_gem_object_pin(struct drm_gem_object *obj, uint32_t alignment) if (!IS_I965G(dev) && obj_priv->fence_reg == I915_FENCE_REG_NONE && obj_priv->tiling_mode != I915_TILING_NONE) { - ret = i915_gem_object_get_fence_reg(obj, true); + ret = i915_gem_object_get_fence_reg(obj); if (ret != 0) { if (ret != -EBUSY && ret != -ERESTARTSYS) DRM_ERROR("Failure to install fence: %d\n", @@ -3739,7 +3769,7 @@ int i915_gem_init_object(struct drm_gem_object *obj) { struct drm_i915_gem_object *obj_priv; - obj_priv = drm_calloc(1, sizeof(*obj_priv), DRM_MEM_DRIVER); + obj_priv = kzalloc(sizeof(*obj_priv), GFP_KERNEL); if (obj_priv == NULL) return -ENOMEM; @@ -3777,9 +3807,9 @@ void i915_gem_free_object(struct drm_gem_object *obj) i915_gem_free_mmap_offset(obj); - drm_free(obj_priv->page_cpu_valid, 1, DRM_MEM_DRIVER); + kfree(obj_priv->page_cpu_valid); kfree(obj_priv->bit_17); - drm_free(obj->driver_private, 1, DRM_MEM_DRIVER); + kfree(obj->driver_private); } /** Unbinds all objects that are on the given buffer list. */ @@ -4233,7 +4263,7 @@ int i915_gem_init_phys_object(struct drm_device *dev, if (dev_priv->mm.phys_objs[id - 1] || !size) return 0; - phys_obj = drm_calloc(1, sizeof(struct drm_i915_gem_phys_object), DRM_MEM_DRIVER); + phys_obj = kzalloc(sizeof(struct drm_i915_gem_phys_object), GFP_KERNEL); if (!phys_obj) return -ENOMEM; @@ -4252,7 +4282,7 @@ int i915_gem_init_phys_object(struct drm_device *dev, return 0; kfree_obj: - drm_free(phys_obj, sizeof(struct drm_i915_gem_phys_object), DRM_MEM_DRIVER); + kfree(phys_obj); return ret; } @@ -4312,6 +4342,8 @@ void i915_gem_detach_phys_object(struct drm_device *dev, } drm_clflush_pages(obj_priv->pages, page_count); drm_agp_chipset_flush(dev); + + i915_gem_object_put_pages(obj); out: obj_priv->phys_obj->cur_obj = NULL; obj_priv->phys_obj = NULL; @@ -4369,6 +4401,8 @@ i915_gem_attach_phys_object(struct drm_device *dev, kunmap_atomic(src, KM_USER0); } + i915_gem_object_put_pages(obj); + return 0; out: return ret; diff --git a/drivers/gpu/drm/i915/i915_gem_debugfs.c b/drivers/gpu/drm/i915/i915_gem_debugfs.c index 986f1082c596..28146e405e87 100644 --- a/drivers/gpu/drm/i915/i915_gem_debugfs.c +++ b/drivers/gpu/drm/i915/i915_gem_debugfs.c @@ -104,7 +104,7 @@ static int i915_gem_object_list_info(struct seq_file *m, void *data) if (obj->name) seq_printf(m, " (name: %d)", obj->name); if (obj_priv->fence_reg != I915_FENCE_REG_NONE) - seq_printf(m, " (fence: %d\n", obj_priv->fence_reg); + seq_printf(m, " (fence: %d)\n", obj_priv->fence_reg); seq_printf(m, "\n"); } @@ -318,7 +318,7 @@ static int i915_ringbuffer_info(struct seq_file *m, void *data) seq_printf(m, "RingTail : %08x\n", tail); seq_printf(m, "RingMask : %08x\n", mask); seq_printf(m, "RingSize : %08lx\n", dev_priv->ring.Size); - seq_printf(m, "Acthd : %08x\n", I915_READ(IS_I965G(dev) ? ACTHD_I965 : ACTHD)); + seq_printf(m, "Acthd : %08x\n", I915_READ(IS_I965G(dev) ? ACTHD_I965 : ACTHD)); return 0; } diff --git a/drivers/gpu/drm/i915/i915_gem_tiling.c b/drivers/gpu/drm/i915/i915_gem_tiling.c index 9a05cadaa4ad..5c1ceec49f5b 100644 --- a/drivers/gpu/drm/i915/i915_gem_tiling.c +++ b/drivers/gpu/drm/i915/i915_gem_tiling.c @@ -408,7 +408,7 @@ i915_tiling_ok(struct drm_device *dev, int stride, int size, int tiling_mode) if (stride & (stride - 1)) return false; - /* We don't handle the aperture area covered by the fence being bigger + /* We don't 0handle the aperture area covered by the fence being bigger * than the object size. */ if (i915_get_fence_size(dev, size) != size) @@ -417,6 +417,33 @@ i915_tiling_ok(struct drm_device *dev, int stride, int size, int tiling_mode) return true; } +static bool +i915_gem_object_fence_offset_ok(struct drm_gem_object *obj, int tiling_mode) +{ + struct drm_device *dev = obj->dev; + struct drm_i915_gem_object *obj_priv = obj->driver_private; + + if (obj_priv->gtt_space == NULL) + return true; + + if (tiling_mode == I915_TILING_NONE) + return true; + + if (!IS_I965G(dev)) { + if (obj_priv->gtt_offset & (obj->size - 1)) + return false; + if (IS_I9XX(dev)) { + if (obj_priv->gtt_offset & ~I915_FENCE_START_MASK) + return false; + } else { + if (obj_priv->gtt_offset & ~I830_FENCE_START_MASK) + return false; + } + } + + return true; +} + /** * Sets the tiling mode of an object, returning the required swizzling of * bit 6 of addresses in the object. @@ -429,6 +456,7 @@ i915_gem_set_tiling(struct drm_device *dev, void *data, drm_i915_private_t *dev_priv = dev->dev_private; struct drm_gem_object *obj; struct drm_i915_gem_object *obj_priv; + int ret = 0; obj = drm_gem_object_lookup(dev, file_priv, args->handle); if (obj == NULL) @@ -436,14 +464,15 @@ i915_gem_set_tiling(struct drm_device *dev, void *data, obj_priv = obj->driver_private; if (!i915_tiling_ok(dev, args->stride, obj->size, args->tiling_mode)) { + mutex_lock(&dev->struct_mutex); drm_gem_object_unreference(obj); + mutex_unlock(&dev->struct_mutex); return -EINVAL; } - mutex_lock(&dev->struct_mutex); - if (args->tiling_mode == I915_TILING_NONE) { args->swizzle_mode = I915_BIT_6_SWIZZLE_NONE; + args->stride = 0; } else { if (args->tiling_mode == I915_TILING_X) args->swizzle_mode = dev_priv->mm.bit_6_swizzle_x; @@ -466,32 +495,38 @@ i915_gem_set_tiling(struct drm_device *dev, void *data, if (args->swizzle_mode == I915_BIT_6_SWIZZLE_UNKNOWN) { args->tiling_mode = I915_TILING_NONE; args->swizzle_mode = I915_BIT_6_SWIZZLE_NONE; + args->stride = 0; } } - if (args->tiling_mode != obj_priv->tiling_mode) { - int ret; - /* Unbind the object, as switching tiling means we're - * switching the cache organization due to fencing, probably. + mutex_lock(&dev->struct_mutex); + if (args->tiling_mode != obj_priv->tiling_mode || + args->stride != obj_priv->stride) { + /* We need to rebind the object if its current allocation + * no longer meets the alignment restrictions for its new + * tiling mode. Otherwise we can just leave it alone, but + * need to ensure that any fence register is cleared. */ - ret = i915_gem_object_unbind(obj); + if (!i915_gem_object_fence_offset_ok(obj, args->tiling_mode)) + ret = i915_gem_object_unbind(obj); + else + ret = i915_gem_object_put_fence_reg(obj); if (ret != 0) { WARN(ret != -ERESTARTSYS, - "failed to unbind object for tiling switch"); + "failed to reset object for tiling switch"); args->tiling_mode = obj_priv->tiling_mode; - mutex_unlock(&dev->struct_mutex); - drm_gem_object_unreference(obj); - - return ret; + args->stride = obj_priv->stride; + goto err; } + obj_priv->tiling_mode = args->tiling_mode; + obj_priv->stride = args->stride; } - obj_priv->stride = args->stride; - +err: drm_gem_object_unreference(obj); mutex_unlock(&dev->struct_mutex); - return 0; + return ret; } /** diff --git a/drivers/gpu/drm/i915/i915_mem.c b/drivers/gpu/drm/i915/i915_mem.c index 96e271986d2a..83b7b81bb2b8 100644 --- a/drivers/gpu/drm/i915/i915_mem.c +++ b/drivers/gpu/drm/i915/i915_mem.c @@ -94,8 +94,8 @@ static struct mem_block *split_block(struct mem_block *p, int start, int size, { /* Maybe cut off the start of an existing block */ if (start > p->start) { - struct mem_block *newblock = - drm_alloc(sizeof(*newblock), DRM_MEM_BUFLISTS); + struct mem_block *newblock = kmalloc(sizeof(*newblock), + GFP_KERNEL); if (!newblock) goto out; newblock->start = start; @@ -111,8 +111,8 @@ static struct mem_block *split_block(struct mem_block *p, int start, int size, /* Maybe cut off the end of an existing block */ if (size < p->size) { - struct mem_block *newblock = - drm_alloc(sizeof(*newblock), DRM_MEM_BUFLISTS); + struct mem_block *newblock = kmalloc(sizeof(*newblock), + GFP_KERNEL); if (!newblock) goto out; newblock->start = start + size; @@ -169,7 +169,7 @@ static void free_block(struct mem_block *p) p->size += q->size; p->next = q->next; p->next->prev = p; - drm_free(q, sizeof(*q), DRM_MEM_BUFLISTS); + kfree(q); } if (p->prev->file_priv == NULL) { @@ -177,7 +177,7 @@ static void free_block(struct mem_block *p) q->size += p->size; q->next = p->next; q->next->prev = q; - drm_free(p, sizeof(*q), DRM_MEM_BUFLISTS); + kfree(p); } } @@ -185,14 +185,14 @@ static void free_block(struct mem_block *p) */ static int init_heap(struct mem_block **heap, int start, int size) { - struct mem_block *blocks = drm_alloc(sizeof(*blocks), DRM_MEM_BUFLISTS); + struct mem_block *blocks = kmalloc(sizeof(*blocks), GFP_KERNEL); if (!blocks) return -ENOMEM; - *heap = drm_alloc(sizeof(**heap), DRM_MEM_BUFLISTS); + *heap = kmalloc(sizeof(**heap), GFP_KERNEL); if (!*heap) { - drm_free(blocks, sizeof(*blocks), DRM_MEM_BUFLISTS); + kfree(blocks); return -ENOMEM; } @@ -233,7 +233,7 @@ void i915_mem_release(struct drm_device * dev, struct drm_file *file_priv, p->size += q->size; p->next = q->next; p->next->prev = p; - drm_free(q, sizeof(*q), DRM_MEM_BUFLISTS); + kfree(q); } } } @@ -250,10 +250,10 @@ void i915_mem_takedown(struct mem_block **heap) for (p = (*heap)->next; p != *heap;) { struct mem_block *q = p; p = p->next; - drm_free(q, sizeof(*q), DRM_MEM_BUFLISTS); + kfree(q); } - drm_free(*heap, sizeof(**heap), DRM_MEM_BUFLISTS); + kfree(*heap); *heap = NULL; } diff --git a/drivers/gpu/drm/i915/intel_bios.c b/drivers/gpu/drm/i915/intel_bios.c index 754dd22fdd77..cdd126d068a7 100644 --- a/drivers/gpu/drm/i915/intel_bios.c +++ b/drivers/gpu/drm/i915/intel_bios.c @@ -124,8 +124,7 @@ parse_lfp_panel_data(struct drm_i915_private *dev_priv, entry = &lvds_lfp_data->data[lvds_options->panel_type]; dvo_timing = &entry->dvo_timing; - panel_fixed_mode = drm_calloc(1, sizeof(*panel_fixed_mode), - DRM_MEM_DRIVER); + panel_fixed_mode = kzalloc(sizeof(*panel_fixed_mode), GFP_KERNEL); fill_detail_timing_data(panel_fixed_mode, dvo_timing); @@ -156,8 +155,7 @@ parse_sdvo_panel_data(struct drm_i915_private *dev_priv, if (!dvo_timing) return; - panel_fixed_mode = drm_calloc(1, sizeof(*panel_fixed_mode), - DRM_MEM_DRIVER); + panel_fixed_mode = kzalloc(sizeof(*panel_fixed_mode), GFP_KERNEL); if (!panel_fixed_mode) return; diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 028f5b66e3d8..3e1c78162119 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -828,19 +828,31 @@ intel_pipe_set_base(struct drm_crtc *crtc, int x, int y, } mutex_lock(&dev->struct_mutex); - ret = i915_gem_object_pin(intel_fb->obj, alignment); + ret = i915_gem_object_pin(obj, alignment); if (ret != 0) { mutex_unlock(&dev->struct_mutex); return ret; } - ret = i915_gem_object_set_to_gtt_domain(intel_fb->obj, 1); + ret = i915_gem_object_set_to_gtt_domain(obj, 1); if (ret != 0) { - i915_gem_object_unpin(intel_fb->obj); + i915_gem_object_unpin(obj); mutex_unlock(&dev->struct_mutex); return ret; } + /* Pre-i965 needs to install a fence for tiled scan-out */ + if (!IS_I965G(dev) && + obj_priv->fence_reg == I915_FENCE_REG_NONE && + obj_priv->tiling_mode != I915_TILING_NONE) { + ret = i915_gem_object_get_fence_reg(obj); + if (ret != 0) { + i915_gem_object_unpin(obj); + mutex_unlock(&dev->struct_mutex); + return ret; + } + } + dspcntr = I915_READ(dspcntr_reg); /* Mask out pixel format bits in case we change it */ dspcntr &= ~DISPPLANE_PIXFORMAT_MASK; @@ -860,7 +872,7 @@ intel_pipe_set_base(struct drm_crtc *crtc, int x, int y, break; default: DRM_ERROR("Unknown color depth\n"); - i915_gem_object_unpin(intel_fb->obj); + i915_gem_object_unpin(obj); mutex_unlock(&dev->struct_mutex); return -EINVAL; } diff --git a/drivers/gpu/drm/i915/intel_fb.c b/drivers/gpu/drm/i915/intel_fb.c index 8e28e5993df5..1af7d68e3807 100644 --- a/drivers/gpu/drm/i915/intel_fb.c +++ b/drivers/gpu/drm/i915/intel_fb.c @@ -870,7 +870,11 @@ static int intelfb_single_fb_probe(struct drm_device *dev) */ void intelfb_restore(void) { - drm_crtc_helper_set_config(&kernelfb_mode); + int ret; + if ((ret = drm_crtc_helper_set_config(&kernelfb_mode)) != 0) { + printk(KERN_ERR "Failed to restore crtc configuration: %d\n", + ret); + } } static void intelfb_restore_work_fn(struct work_struct *ignored) diff --git a/drivers/gpu/drm/i915/intel_tv.c b/drivers/gpu/drm/i915/intel_tv.c index 50d7ed70b338..ea68992e4416 100644 --- a/drivers/gpu/drm/i915/intel_tv.c +++ b/drivers/gpu/drm/i915/intel_tv.c @@ -1561,8 +1561,7 @@ intel_tv_destroy (struct drm_connector *connector) drm_sysfs_connector_remove(connector); drm_connector_cleanup(connector); - drm_free(intel_output, sizeof(struct intel_output) + sizeof(struct intel_tv_priv), - DRM_MEM_DRIVER); + kfree(intel_output); } @@ -1695,8 +1694,8 @@ intel_tv_init(struct drm_device *dev) (tv_dac_off & TVDAC_STATE_CHG_EN) != 0) return; - intel_output = drm_calloc(1, sizeof(struct intel_output) + - sizeof(struct intel_tv_priv), DRM_MEM_DRIVER); + intel_output = kzalloc(sizeof(struct intel_output) + + sizeof(struct intel_tv_priv), GFP_KERNEL); if (!intel_output) { return; } @@ -1730,8 +1729,8 @@ intel_tv_init(struct drm_device *dev) connector->doublescan_allowed = false; /* Create TV properties then attach current values */ - tv_format_names = drm_alloc(sizeof(char *) * NUM_TV_MODES, - DRM_MEM_DRIVER); + tv_format_names = kmalloc(sizeof(char *) * NUM_TV_MODES, + GFP_KERNEL); if (!tv_format_names) goto out; for (i = 0; i < NUM_TV_MODES; i++) diff --git a/drivers/gpu/drm/mga/mga_dma.c b/drivers/gpu/drm/mga/mga_dma.c index 7a6bf9ffc5a3..6c67a02910c8 100644 --- a/drivers/gpu/drm/mga/mga_dma.c +++ b/drivers/gpu/drm/mga/mga_dma.c @@ -254,23 +254,20 @@ static int mga_freelist_init(struct drm_device * dev, drm_mga_private_t * dev_pr int i; DRM_DEBUG("count=%d\n", dma->buf_count); - dev_priv->head = drm_alloc(sizeof(drm_mga_freelist_t), DRM_MEM_DRIVER); + dev_priv->head = kzalloc(sizeof(drm_mga_freelist_t), GFP_KERNEL); if (dev_priv->head == NULL) return -ENOMEM; - memset(dev_priv->head, 0, sizeof(drm_mga_freelist_t)); SET_AGE(&dev_priv->head->age, MGA_BUFFER_USED, 0); for (i = 0; i < dma->buf_count; i++) { buf = dma->buflist[i]; buf_priv = buf->dev_private; - entry = drm_alloc(sizeof(drm_mga_freelist_t), DRM_MEM_DRIVER); + entry = kzalloc(sizeof(drm_mga_freelist_t), GFP_KERNEL); if (entry == NULL) return -ENOMEM; - memset(entry, 0, sizeof(drm_mga_freelist_t)); - entry->next = dev_priv->head->next; entry->prev = dev_priv->head; SET_AGE(&entry->age, MGA_BUFFER_FREE, 0); @@ -301,7 +298,7 @@ static void mga_freelist_cleanup(struct drm_device * dev) entry = dev_priv->head; while (entry) { next = entry->next; - drm_free(entry, sizeof(drm_mga_freelist_t), DRM_MEM_DRIVER); + kfree(entry); entry = next; } @@ -399,12 +396,11 @@ int mga_driver_load(struct drm_device * dev, unsigned long flags) drm_mga_private_t *dev_priv; int ret; - dev_priv = drm_alloc(sizeof(drm_mga_private_t), DRM_MEM_DRIVER); + dev_priv = kzalloc(sizeof(drm_mga_private_t), GFP_KERNEL); if (!dev_priv) return -ENOMEM; dev->dev_private = (void *)dev_priv; - memset(dev_priv, 0, sizeof(drm_mga_private_t)); dev_priv->usec_timeout = MGA_DEFAULT_USEC_TIMEOUT; dev_priv->chipset = flags; @@ -1150,7 +1146,7 @@ int mga_dma_buffers(struct drm_device *dev, void *data, */ int mga_driver_unload(struct drm_device * dev) { - drm_free(dev->dev_private, sizeof(drm_mga_private_t), DRM_MEM_DRIVER); + kfree(dev->dev_private); dev->dev_private = NULL; return 0; diff --git a/drivers/gpu/drm/r128/r128_cce.c b/drivers/gpu/drm/r128/r128_cce.c index 077c0455a6b9..c75fd3564040 100644 --- a/drivers/gpu/drm/r128/r128_cce.c +++ b/drivers/gpu/drm/r128/r128_cce.c @@ -353,12 +353,10 @@ static int r128_do_init_cce(struct drm_device * dev, drm_r128_init_t * init) DRM_DEBUG("\n"); - dev_priv = drm_alloc(sizeof(drm_r128_private_t), DRM_MEM_DRIVER); + dev_priv = kzalloc(sizeof(drm_r128_private_t), GFP_KERNEL); if (dev_priv == NULL) return -ENOMEM; - memset(dev_priv, 0, sizeof(drm_r128_private_t)); - dev_priv->is_pci = init->is_pci; if (dev_priv->is_pci && !dev->sg) { @@ -619,8 +617,7 @@ int r128_do_cleanup_cce(struct drm_device * dev) ("failed to cleanup PCI GART!\n"); } - drm_free(dev->dev_private, sizeof(drm_r128_private_t), - DRM_MEM_DRIVER); + kfree(dev->dev_private); dev->dev_private = NULL; } @@ -768,18 +765,17 @@ static int r128_freelist_init(struct drm_device * dev) drm_r128_freelist_t *entry; int i; - dev_priv->head = drm_alloc(sizeof(drm_r128_freelist_t), DRM_MEM_DRIVER); + dev_priv->head = kzalloc(sizeof(drm_r128_freelist_t), GFP_KERNEL); if (dev_priv->head == NULL) return -ENOMEM; - memset(dev_priv->head, 0, sizeof(drm_r128_freelist_t)); dev_priv->head->age = R128_BUFFER_USED; for (i = 0; i < dma->buf_count; i++) { buf = dma->buflist[i]; buf_priv = buf->dev_private; - entry = drm_alloc(sizeof(drm_r128_freelist_t), DRM_MEM_DRIVER); + entry = kmalloc(sizeof(drm_r128_freelist_t), GFP_KERNEL); if (!entry) return -ENOMEM; diff --git a/drivers/gpu/drm/r128/r128_state.c b/drivers/gpu/drm/r128/r128_state.c index f7a5b5740764..026a48c95c8f 100644 --- a/drivers/gpu/drm/r128/r128_state.c +++ b/drivers/gpu/drm/r128/r128_state.c @@ -910,24 +910,24 @@ static int r128_cce_dispatch_write_span(struct drm_device * dev, } buffer_size = depth->n * sizeof(u32); - buffer = drm_alloc(buffer_size, DRM_MEM_BUFS); + buffer = kmalloc(buffer_size, GFP_KERNEL); if (buffer == NULL) return -ENOMEM; if (DRM_COPY_FROM_USER(buffer, depth->buffer, buffer_size)) { - drm_free(buffer, buffer_size, DRM_MEM_BUFS); + kfree(buffer); return -EFAULT; } mask_size = depth->n * sizeof(u8); if (depth->mask) { - mask = drm_alloc(mask_size, DRM_MEM_BUFS); + mask = kmalloc(mask_size, GFP_KERNEL); if (mask == NULL) { - drm_free(buffer, buffer_size, DRM_MEM_BUFS); + kfree(buffer); return -ENOMEM; } if (DRM_COPY_FROM_USER(mask, depth->mask, mask_size)) { - drm_free(buffer, buffer_size, DRM_MEM_BUFS); - drm_free(mask, mask_size, DRM_MEM_BUFS); + kfree(buffer); + kfree(mask); return -EFAULT; } @@ -954,7 +954,7 @@ static int r128_cce_dispatch_write_span(struct drm_device * dev, } } - drm_free(mask, mask_size, DRM_MEM_BUFS); + kfree(mask); } else { for (i = 0; i < count; i++, x++) { BEGIN_RING(6); @@ -978,7 +978,7 @@ static int r128_cce_dispatch_write_span(struct drm_device * dev, } } - drm_free(buffer, buffer_size, DRM_MEM_BUFS); + kfree(buffer); return 0; } @@ -1000,54 +1000,54 @@ static int r128_cce_dispatch_write_pixels(struct drm_device * dev, xbuf_size = count * sizeof(*x); ybuf_size = count * sizeof(*y); - x = drm_alloc(xbuf_size, DRM_MEM_BUFS); + x = kmalloc(xbuf_size, GFP_KERNEL); if (x == NULL) { return -ENOMEM; } - y = drm_alloc(ybuf_size, DRM_MEM_BUFS); + y = kmalloc(ybuf_size, GFP_KERNEL); if (y == NULL) { - drm_free(x, xbuf_size, DRM_MEM_BUFS); + kfree(x); return -ENOMEM; } if (DRM_COPY_FROM_USER(x, depth->x, xbuf_size)) { - drm_free(x, xbuf_size, DRM_MEM_BUFS); - drm_free(y, ybuf_size, DRM_MEM_BUFS); + kfree(x); + kfree(y); return -EFAULT; } if (DRM_COPY_FROM_USER(y, depth->y, xbuf_size)) { - drm_free(x, xbuf_size, DRM_MEM_BUFS); - drm_free(y, ybuf_size, DRM_MEM_BUFS); + kfree(x); + kfree(y); return -EFAULT; } buffer_size = depth->n * sizeof(u32); - buffer = drm_alloc(buffer_size, DRM_MEM_BUFS); + buffer = kmalloc(buffer_size, GFP_KERNEL); if (buffer == NULL) { - drm_free(x, xbuf_size, DRM_MEM_BUFS); - drm_free(y, ybuf_size, DRM_MEM_BUFS); + kfree(x); + kfree(y); return -ENOMEM; } if (DRM_COPY_FROM_USER(buffer, depth->buffer, buffer_size)) { - drm_free(x, xbuf_size, DRM_MEM_BUFS); - drm_free(y, ybuf_size, DRM_MEM_BUFS); - drm_free(buffer, buffer_size, DRM_MEM_BUFS); + kfree(x); + kfree(y); + kfree(buffer); return -EFAULT; } if (depth->mask) { mask_size = depth->n * sizeof(u8); - mask = drm_alloc(mask_size, DRM_MEM_BUFS); + mask = kmalloc(mask_size, GFP_KERNEL); if (mask == NULL) { - drm_free(x, xbuf_size, DRM_MEM_BUFS); - drm_free(y, ybuf_size, DRM_MEM_BUFS); - drm_free(buffer, buffer_size, DRM_MEM_BUFS); + kfree(x); + kfree(y); + kfree(buffer); return -ENOMEM; } if (DRM_COPY_FROM_USER(mask, depth->mask, mask_size)) { - drm_free(x, xbuf_size, DRM_MEM_BUFS); - drm_free(y, ybuf_size, DRM_MEM_BUFS); - drm_free(buffer, buffer_size, DRM_MEM_BUFS); - drm_free(mask, mask_size, DRM_MEM_BUFS); + kfree(x); + kfree(y); + kfree(buffer); + kfree(mask); return -EFAULT; } @@ -1074,7 +1074,7 @@ static int r128_cce_dispatch_write_pixels(struct drm_device * dev, } } - drm_free(mask, mask_size, DRM_MEM_BUFS); + kfree(mask); } else { for (i = 0; i < count; i++) { BEGIN_RING(6); @@ -1098,9 +1098,9 @@ static int r128_cce_dispatch_write_pixels(struct drm_device * dev, } } - drm_free(x, xbuf_size, DRM_MEM_BUFS); - drm_free(y, ybuf_size, DRM_MEM_BUFS); - drm_free(buffer, buffer_size, DRM_MEM_BUFS); + kfree(x); + kfree(y); + kfree(buffer); return 0; } @@ -1167,23 +1167,23 @@ static int r128_cce_dispatch_read_pixels(struct drm_device * dev, xbuf_size = count * sizeof(*x); ybuf_size = count * sizeof(*y); - x = drm_alloc(xbuf_size, DRM_MEM_BUFS); + x = kmalloc(xbuf_size, GFP_KERNEL); if (x == NULL) { return -ENOMEM; } - y = drm_alloc(ybuf_size, DRM_MEM_BUFS); + y = kmalloc(ybuf_size, GFP_KERNEL); if (y == NULL) { - drm_free(x, xbuf_size, DRM_MEM_BUFS); + kfree(x); return -ENOMEM; } if (DRM_COPY_FROM_USER(x, depth->x, xbuf_size)) { - drm_free(x, xbuf_size, DRM_MEM_BUFS); - drm_free(y, ybuf_size, DRM_MEM_BUFS); + kfree(x); + kfree(y); return -EFAULT; } if (DRM_COPY_FROM_USER(y, depth->y, ybuf_size)) { - drm_free(x, xbuf_size, DRM_MEM_BUFS); - drm_free(y, ybuf_size, DRM_MEM_BUFS); + kfree(x); + kfree(y); return -EFAULT; } @@ -1210,8 +1210,8 @@ static int r128_cce_dispatch_read_pixels(struct drm_device * dev, ADVANCE_RING(); } - drm_free(x, xbuf_size, DRM_MEM_BUFS); - drm_free(y, ybuf_size, DRM_MEM_BUFS); + kfree(x); + kfree(y); return 0; } diff --git a/drivers/gpu/drm/radeon/r100.c b/drivers/gpu/drm/radeon/r100.c index 5225f5be7ea7..c550932a108f 100644 --- a/drivers/gpu/drm/radeon/r100.c +++ b/drivers/gpu/drm/radeon/r100.c @@ -551,6 +551,9 @@ int r100_cp_init(struct radeon_device *rdev, unsigned ring_size) /* cp setup */ WREG32(0x718, pre_write_timer | (pre_write_limit << 28)); WREG32(RADEON_CP_RB_CNTL, +#ifdef __BIG_ENDIAN + RADEON_BUF_SWAP_32BIT | +#endif REG_SET(RADEON_RB_BUFSZ, rb_bufsz) | REG_SET(RADEON_RB_BLKSZ, rb_blksz) | REG_SET(RADEON_MAX_FETCH, max_fetch) | @@ -644,7 +647,7 @@ int r100_cp_reset(struct radeon_device *rdev) */ int r100_cs_parse_packet0(struct radeon_cs_parser *p, struct radeon_cs_packet *pkt, - unsigned *auth, unsigned n, + const unsigned *auth, unsigned n, radeon_packet0_check_t check) { unsigned reg; @@ -654,6 +657,10 @@ int r100_cs_parse_packet0(struct radeon_cs_parser *p, idx = pkt->idx + 1; reg = pkt->reg; + /* Check that register fall into register range + * determined by the number of entry (n) in the + * safe register bitmap. + */ if (pkt->one_reg_wr) { if ((reg >> 7) > n) { return -EINVAL; @@ -683,24 +690,6 @@ int r100_cs_parse_packet0(struct radeon_cs_parser *p, return 0; } -int r100_cs_parse_packet3(struct radeon_cs_parser *p, - struct radeon_cs_packet *pkt, - unsigned *auth, unsigned n, - radeon_packet3_check_t check) -{ - unsigned i, m; - - if ((pkt->opcode >> 5) > n) { - return -EINVAL; - } - i = pkt->opcode >> 5; - m = 1 << (pkt->opcode & 31); - if (auth[i] & m) { - return check(p, pkt); - } - return 0; -} - void r100_cs_dump_packet(struct radeon_cs_parser *p, struct radeon_cs_packet *pkt) { @@ -901,6 +890,25 @@ static int r100_packet0_check(struct radeon_cs_parser *p, return 0; } +int r100_cs_track_check_pkt3_indx_buffer(struct radeon_cs_parser *p, + struct radeon_cs_packet *pkt, + struct radeon_object *robj) +{ + struct radeon_cs_chunk *ib_chunk; + unsigned idx; + + ib_chunk = &p->chunks[p->chunk_ib_idx]; + idx = pkt->idx + 1; + if ((ib_chunk->kdata[idx+2] + 1) > radeon_object_size(robj)) { + DRM_ERROR("[drm] Buffer too small for PACKET3 INDX_BUFFER " + "(need %u have %lu) !\n", + ib_chunk->kdata[idx+2] + 1, + radeon_object_size(robj)); + return -EINVAL; + } + return 0; +} + static int r100_packet3_check(struct radeon_cs_parser *p, struct radeon_cs_packet *pkt) { @@ -954,6 +962,10 @@ static int r100_packet3_check(struct radeon_cs_parser *p, return r; } ib[idx+1] = ib_chunk->kdata[idx+1] + ((u32)reloc->lobj.gpu_offset); + r = r100_cs_track_check_pkt3_indx_buffer(p, pkt, reloc->robj); + if (r) { + return r; + } break; case 0x23: /* FIXME: cleanup */ @@ -999,18 +1011,18 @@ int r100_cs_parse(struct radeon_cs_parser *p) } p->idx += pkt.count + 2; switch (pkt.type) { - case PACKET_TYPE0: - r = r100_packet0_check(p, &pkt); - break; - case PACKET_TYPE2: - break; - case PACKET_TYPE3: - r = r100_packet3_check(p, &pkt); - break; - default: - DRM_ERROR("Unknown packet type %d !\n", - pkt.type); - return -EINVAL; + case PACKET_TYPE0: + r = r100_packet0_check(p, &pkt); + break; + case PACKET_TYPE2: + break; + case PACKET_TYPE3: + r = r100_packet3_check(p, &pkt); + break; + default: + DRM_ERROR("Unknown packet type %d !\n", + pkt.type); + return -EINVAL; } if (r) { return r; @@ -1267,12 +1279,6 @@ void r100_vram_info(struct radeon_device *rdev) rdev->mc.aper_base = drm_get_resource_start(rdev->ddev, 0); rdev->mc.aper_size = drm_get_resource_len(rdev->ddev, 0); - if (rdev->mc.aper_size > rdev->mc.vram_size) { - /* Why does some hw doesn't have CONFIG_MEMSIZE properly - * setup ? */ - rdev->mc.vram_size = rdev->mc.aper_size; - WREG32(RADEON_CONFIG_MEMSIZE, rdev->mc.vram_size); - } } @@ -1352,6 +1358,11 @@ void r100_mm_wreg(struct radeon_device *rdev, uint32_t reg, uint32_t v) } } +int r100_init(struct radeon_device *rdev) +{ + return 0; +} + /* * Debugfs info */ diff --git a/drivers/gpu/drm/radeon/r300.c b/drivers/gpu/drm/radeon/r300.c index f5870a099d4f..e2ed5bc08170 100644 --- a/drivers/gpu/drm/radeon/r300.c +++ b/drivers/gpu/drm/radeon/r300.c @@ -48,14 +48,13 @@ int r100_cs_packet_next_reloc(struct radeon_cs_parser *p, struct radeon_cs_reloc **cs_reloc); int r100_cs_parse_packet0(struct radeon_cs_parser *p, struct radeon_cs_packet *pkt, - unsigned *auth, unsigned n, + const unsigned *auth, unsigned n, radeon_packet0_check_t check); -int r100_cs_parse_packet3(struct radeon_cs_parser *p, - struct radeon_cs_packet *pkt, - unsigned *auth, unsigned n, - radeon_packet3_check_t check); void r100_cs_dump_packet(struct radeon_cs_parser *p, struct radeon_cs_packet *pkt); +int r100_cs_track_check_pkt3_indx_buffer(struct radeon_cs_parser *p, + struct radeon_cs_packet *pkt, + struct radeon_object *robj); /* This files gather functions specifics to: * r300,r350,rv350,rv370,rv380 @@ -288,7 +287,7 @@ int r300_copy_dma(struct radeon_device *rdev, return r; } /* Must wait for 2D idle & clean before DMA or hangs might happen */ - radeon_ring_write(rdev, PACKET0(RADEON_WAIT_UNTIL, 0)); + radeon_ring_write(rdev, PACKET0(RADEON_WAIT_UNTIL, 0 )); radeon_ring_write(rdev, (1 << 16)); for (i = 0; i < num_loops; i++) { cur_size = size; @@ -319,7 +318,7 @@ void r300_ring_start(struct radeon_device *rdev) /* Sub pixel 1/12 so we can have 4K rendering according to doc */ gb_tile_config = (R300_ENABLE_TILING | R300_TILE_SIZE_16); - switch (rdev->num_gb_pipes) { + switch(rdev->num_gb_pipes) { case 2: gb_tile_config |= R300_PIPE_COUNT_R300; break; @@ -452,8 +451,8 @@ void r300_gpu_init(struct radeon_device *rdev) case 4: gb_tile_config |= R300_PIPE_COUNT_R420; break; - case 1: default: + case 1: gb_tile_config |= R300_PIPE_COUNT_RV350; break; } @@ -725,18 +724,120 @@ struct r300_cs_track_cb { unsigned offset; }; +struct r300_cs_track_array { + struct radeon_object *robj; + unsigned esize; +}; + +struct r300_cs_track_texture { + struct radeon_object *robj; + unsigned pitch; + unsigned width; + unsigned height; + unsigned num_levels; + unsigned cpp; + unsigned tex_coord_type; + unsigned txdepth; + unsigned width_11; + unsigned height_11; + bool use_pitch; + bool enabled; + bool roundup_w; + bool roundup_h; +}; + struct r300_cs_track { - unsigned num_cb; - unsigned maxy; - struct r300_cs_track_cb cb[4]; - struct r300_cs_track_cb zb; - bool z_enabled; + unsigned num_cb; + unsigned maxy; + unsigned vtx_size; + unsigned vap_vf_cntl; + unsigned immd_dwords; + unsigned num_arrays; + unsigned max_indx; + struct r300_cs_track_array arrays[11]; + struct r300_cs_track_cb cb[4]; + struct r300_cs_track_cb zb; + struct r300_cs_track_texture textures[16]; + bool z_enabled; }; +static inline void r300_cs_track_texture_print(struct r300_cs_track_texture *t) +{ + DRM_ERROR("pitch %d\n", t->pitch); + DRM_ERROR("width %d\n", t->width); + DRM_ERROR("height %d\n", t->height); + DRM_ERROR("num levels %d\n", t->num_levels); + DRM_ERROR("depth %d\n", t->txdepth); + DRM_ERROR("bpp %d\n", t->cpp); + DRM_ERROR("coordinate type %d\n", t->tex_coord_type); + DRM_ERROR("width round to power of 2 %d\n", t->roundup_w); + DRM_ERROR("height round to power of 2 %d\n", t->roundup_h); +} + +static inline int r300_cs_track_texture_check(struct radeon_device *rdev, + struct r300_cs_track *track) +{ + struct radeon_object *robj; + unsigned long size; + unsigned u, i, w, h; + + for (u = 0; u < 16; u++) { + if (!track->textures[u].enabled) + continue; + robj = track->textures[u].robj; + if (robj == NULL) { + DRM_ERROR("No texture bound to unit %u\n", u); + return -EINVAL; + } + size = 0; + for (i = 0; i <= track->textures[u].num_levels; i++) { + if (track->textures[u].use_pitch) { + w = track->textures[u].pitch / (1 << i); + } else { + w = track->textures[u].width / (1 << i); + if (rdev->family >= CHIP_RV515) + w |= track->textures[u].width_11; + if (track->textures[u].roundup_w) + w = roundup_pow_of_two(w); + } + h = track->textures[u].height / (1 << i); + if (rdev->family >= CHIP_RV515) + h |= track->textures[u].height_11; + if (track->textures[u].roundup_h) + h = roundup_pow_of_two(h); + size += w * h; + } + size *= track->textures[u].cpp; + switch (track->textures[u].tex_coord_type) { + case 0: + break; + case 1: + size *= (1 << track->textures[u].txdepth); + break; + case 2: + size *= 6; + break; + default: + DRM_ERROR("Invalid texture coordinate type %u for unit " + "%u\n", track->textures[u].tex_coord_type, u); + return -EINVAL; + } + if (size > radeon_object_size(robj)) { + DRM_ERROR("Texture of unit %u needs %lu bytes but is " + "%lu\n", u, size, radeon_object_size(robj)); + r300_cs_track_texture_print(&track->textures[u]); + return -EINVAL; + } + } + return 0; +} + int r300_cs_track_check(struct radeon_device *rdev, struct r300_cs_track *track) { unsigned i; unsigned long size; + unsigned prim_walk; + unsigned nverts; for (i = 0; i < track->num_cb; i++) { if (track->cb[i].robj == NULL) { @@ -769,7 +870,59 @@ int r300_cs_track_check(struct radeon_device *rdev, struct r300_cs_track *track) return -EINVAL; } } - return 0; + prim_walk = (track->vap_vf_cntl >> 4) & 0x3; + nverts = (track->vap_vf_cntl >> 16) & 0xFFFF; + switch (prim_walk) { + case 1: + for (i = 0; i < track->num_arrays; i++) { + size = track->arrays[i].esize * track->max_indx * 4; + if (track->arrays[i].robj == NULL) { + DRM_ERROR("(PW %u) Vertex array %u no buffer " + "bound\n", prim_walk, i); + return -EINVAL; + } + if (size > radeon_object_size(track->arrays[i].robj)) { + DRM_ERROR("(PW %u) Vertex array %u need %lu dwords " + "have %lu dwords\n", prim_walk, i, + size >> 2, + radeon_object_size(track->arrays[i].robj) >> 2); + DRM_ERROR("Max indices %u\n", track->max_indx); + return -EINVAL; + } + } + break; + case 2: + for (i = 0; i < track->num_arrays; i++) { + size = track->arrays[i].esize * (nverts - 1) * 4; + if (track->arrays[i].robj == NULL) { + DRM_ERROR("(PW %u) Vertex array %u no buffer " + "bound\n", prim_walk, i); + return -EINVAL; + } + if (size > radeon_object_size(track->arrays[i].robj)) { + DRM_ERROR("(PW %u) Vertex array %u need %lu dwords " + "have %lu dwords\n", prim_walk, i, size >> 2, + radeon_object_size(track->arrays[i].robj) >> 2); + return -EINVAL; + } + } + break; + case 3: + size = track->vtx_size * nverts; + if (size != track->immd_dwords) { + DRM_ERROR("IMMD draw %u dwors but needs %lu dwords\n", + track->immd_dwords, size); + DRM_ERROR("VAP_VF_CNTL.NUM_VERTICES %u, VTX_SIZE %u\n", + nverts, track->vtx_size); + return -EINVAL; + } + break; + default: + DRM_ERROR("[drm] Invalid primitive walk %d for VAP_VF_CNTL\n", + prim_walk); + return -EINVAL; + } + return r300_cs_track_texture_check(rdev, track); } static inline void r300_cs_track_clear(struct r300_cs_track *track) @@ -789,9 +942,33 @@ static inline void r300_cs_track_clear(struct r300_cs_track *track) track->zb.pitch = 8192; track->zb.cpp = 4; track->zb.offset = 0; + track->vtx_size = 0x7F; + track->immd_dwords = 0xFFFFFFFFUL; + track->num_arrays = 11; + track->max_indx = 0x00FFFFFFUL; + for (i = 0; i < track->num_arrays; i++) { + track->arrays[i].robj = NULL; + track->arrays[i].esize = 0x7F; + } + for (i = 0; i < 16; i++) { + track->textures[i].pitch = 16536; + track->textures[i].width = 16536; + track->textures[i].height = 16536; + track->textures[i].width_11 = 1 << 11; + track->textures[i].height_11 = 1 << 11; + track->textures[i].num_levels = 12; + track->textures[i].txdepth = 16; + track->textures[i].cpp = 64; + track->textures[i].tex_coord_type = 1; + track->textures[i].robj = NULL; + /* CS IB emission code makes sure texture unit are disabled */ + track->textures[i].enabled = false; + track->textures[i].roundup_w = true; + track->textures[i].roundup_h = true; + } } -static unsigned r300_auth_reg[] = { +static const unsigned r300_reg_safe_bm[159] = { 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFBF, 0xFFFFFFFF, 0xFFFFFFBF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, @@ -808,7 +985,7 @@ static unsigned r300_auth_reg[] = { 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFF03F, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, - 0xFFFFFFFF, 0xFFFFCFCC, 0xF00E9FFF, 0x007C0000, + 0xFFFFFFFF, 0xFFFFEFCE, 0xF00EBFFF, 0x007C0000, 0xF0000078, 0xFF000009, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, @@ -824,9 +1001,9 @@ static unsigned r300_auth_reg[] = { 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, - 0xFFFFFC78, 0xFFFFFFFF, 0xFFFFFFFC, 0xFFFFFFFF, + 0xFFFFFC78, 0xFFFFFFFF, 0xFFFFFFFE, 0xFFFFFFFF, 0x38FF8F50, 0xFFF88082, 0xF000000C, 0xFAE009FF, - 0x00000000, 0x00000000, 0xFFFF0000, 0x00000000, + 0x0000FFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0x00000000, 0x0000C100, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xFFFF0000, 0xFFFFFFFF, 0xFF80FFFF, @@ -848,8 +1025,8 @@ static int r300_packet0_check(struct radeon_cs_parser *p, ib = p->ib->ptr; ib_chunk = &p->chunks[p->chunk_ib_idx]; - track = (struct r300_cs_track *)p->track; - switch (reg) { + track = (struct r300_cs_track*)p->track; + switch(reg) { case RADEON_DST_PITCH_OFFSET: case RADEON_SRC_PITCH_OFFSET: r = r100_cs_packet_next_reloc(p, &reloc); @@ -907,6 +1084,7 @@ static int r300_packet0_check(struct radeon_cs_parser *p, case R300_TX_OFFSET_0+52: case R300_TX_OFFSET_0+56: case R300_TX_OFFSET_0+60: + i = (reg - R300_TX_OFFSET_0) >> 2; r = r100_cs_packet_next_reloc(p, &reloc); if (r) { DRM_ERROR("No reloc for ib[%d]=0x%04X\n", @@ -915,11 +1093,23 @@ static int r300_packet0_check(struct radeon_cs_parser *p, return r; } ib[idx] = ib_chunk->kdata[idx] + ((u32)reloc->lobj.gpu_offset); + track->textures[i].robj = reloc->robj; break; /* Tracked registers */ + case 0x2084: + /* VAP_VF_CNTL */ + track->vap_vf_cntl = ib_chunk->kdata[idx]; + break; + case 0x20B4: + /* VAP_VTX_SIZE */ + track->vtx_size = ib_chunk->kdata[idx] & 0x7F; + break; + case 0x2134: + /* VAP_VF_MAX_VTX_INDX */ + track->max_indx = ib_chunk->kdata[idx] & 0x00FFFFFFUL; + break; case 0x43E4: /* SC_SCISSOR1 */ - track->maxy = ((ib_chunk->kdata[idx] >> 13) & 0x1FFF) + 1; if (p->rdev->family < CHIP_RV515) { track->maxy -= 1440; @@ -994,8 +1184,166 @@ static int r300_packet0_check(struct radeon_cs_parser *p, /* ZB_DEPTHPITCH */ track->zb.pitch = ib_chunk->kdata[idx] & 0x3FFC; break; + case 0x4104: + for (i = 0; i < 16; i++) { + bool enabled; + + enabled = !!(ib_chunk->kdata[idx] & (1 << i)); + track->textures[i].enabled = enabled; + } + break; + case 0x44C0: + case 0x44C4: + case 0x44C8: + case 0x44CC: + case 0x44D0: + case 0x44D4: + case 0x44D8: + case 0x44DC: + case 0x44E0: + case 0x44E4: + case 0x44E8: + case 0x44EC: + case 0x44F0: + case 0x44F4: + case 0x44F8: + case 0x44FC: + /* TX_FORMAT1_[0-15] */ + i = (reg - 0x44C0) >> 2; + tmp = (ib_chunk->kdata[idx] >> 25) & 0x3; + track->textures[i].tex_coord_type = tmp; + switch ((ib_chunk->kdata[idx] & 0x1F)) { + case 0: + case 2: + case 5: + case 18: + case 20: + case 21: + track->textures[i].cpp = 1; + break; + case 1: + case 3: + case 6: + case 7: + case 10: + case 11: + case 19: + case 22: + case 24: + track->textures[i].cpp = 2; + break; + case 4: + case 8: + case 9: + case 12: + case 13: + case 23: + case 25: + case 27: + case 30: + track->textures[i].cpp = 4; + break; + case 14: + case 26: + case 28: + track->textures[i].cpp = 8; + break; + case 29: + track->textures[i].cpp = 16; + break; + default: + DRM_ERROR("Invalid texture format %u\n", + (ib_chunk->kdata[idx] & 0x1F)); + return -EINVAL; + break; + } + break; + case 0x4400: + case 0x4404: + case 0x4408: + case 0x440C: + case 0x4410: + case 0x4414: + case 0x4418: + case 0x441C: + case 0x4420: + case 0x4424: + case 0x4428: + case 0x442C: + case 0x4430: + case 0x4434: + case 0x4438: + case 0x443C: + /* TX_FILTER0_[0-15] */ + i = (reg - 0x4400) >> 2; + tmp = ib_chunk->kdata[idx] & 0x7;; + if (tmp == 2 || tmp == 4 || tmp == 6) { + track->textures[i].roundup_w = false; + } + tmp = (ib_chunk->kdata[idx] >> 3) & 0x7;; + if (tmp == 2 || tmp == 4 || tmp == 6) { + track->textures[i].roundup_h = false; + } + break; + case 0x4500: + case 0x4504: + case 0x4508: + case 0x450C: + case 0x4510: + case 0x4514: + case 0x4518: + case 0x451C: + case 0x4520: + case 0x4524: + case 0x4528: + case 0x452C: + case 0x4530: + case 0x4534: + case 0x4538: + case 0x453C: + /* TX_FORMAT2_[0-15] */ + i = (reg - 0x4500) >> 2; + tmp = ib_chunk->kdata[idx] & 0x3FFF; + track->textures[i].pitch = tmp + 1; + if (p->rdev->family >= CHIP_RV515) { + tmp = ((ib_chunk->kdata[idx] >> 15) & 1) << 11; + track->textures[i].width_11 = tmp; + tmp = ((ib_chunk->kdata[idx] >> 16) & 1) << 11; + track->textures[i].height_11 = tmp; + } + break; + case 0x4480: + case 0x4484: + case 0x4488: + case 0x448C: + case 0x4490: + case 0x4494: + case 0x4498: + case 0x449C: + case 0x44A0: + case 0x44A4: + case 0x44A8: + case 0x44AC: + case 0x44B0: + case 0x44B4: + case 0x44B8: + case 0x44BC: + /* TX_FORMAT0_[0-15] */ + i = (reg - 0x4480) >> 2; + tmp = ib_chunk->kdata[idx] & 0x7FF; + track->textures[i].width = tmp + 1; + tmp = (ib_chunk->kdata[idx] >> 11) & 0x7FF; + track->textures[i].height = tmp + 1; + tmp = (ib_chunk->kdata[idx] >> 26) & 0xF; + track->textures[i].num_levels = tmp; + tmp = ib_chunk->kdata[idx] & (1 << 31); + track->textures[i].use_pitch = !!tmp; + tmp = (ib_chunk->kdata[idx] >> 22) & 0xF; + track->textures[i].txdepth = tmp; + break; default: - printk(KERN_ERR "Forbidden register 0x%04X in cs at %d\n", reg, idx); + printk(KERN_ERR "Forbidden register 0x%04X in cs at %d\n", + reg, idx); return -EINVAL; } return 0; @@ -1015,11 +1363,12 @@ static int r300_packet3_check(struct radeon_cs_parser *p, ib = p->ib->ptr; ib_chunk = &p->chunks[p->chunk_ib_idx]; idx = pkt->idx + 1; - track = (struct r300_cs_track *)p->track; - switch (pkt->opcode) { + track = (struct r300_cs_track*)p->track; + switch(pkt->opcode) { case PACKET3_3D_LOAD_VBPNTR: - c = ib_chunk->kdata[idx++]; - for (i = 0; i < (c - 1); i += 2, idx += 3) { + c = ib_chunk->kdata[idx++] & 0x1F; + track->num_arrays = c; + for (i = 0; i < (c - 1); i+=2, idx+=3) { r = r100_cs_packet_next_reloc(p, &reloc); if (r) { DRM_ERROR("No reloc for packet3 %d\n", @@ -1028,6 +1377,9 @@ static int r300_packet3_check(struct radeon_cs_parser *p, return r; } ib[idx+1] = ib_chunk->kdata[idx+1] + ((u32)reloc->lobj.gpu_offset); + track->arrays[i + 0].robj = reloc->robj; + track->arrays[i + 0].esize = ib_chunk->kdata[idx] >> 8; + track->arrays[i + 0].esize &= 0x7F; r = r100_cs_packet_next_reloc(p, &reloc); if (r) { DRM_ERROR("No reloc for packet3 %d\n", @@ -1036,6 +1388,9 @@ static int r300_packet3_check(struct radeon_cs_parser *p, return r; } ib[idx+2] = ib_chunk->kdata[idx+2] + ((u32)reloc->lobj.gpu_offset); + track->arrays[i + 1].robj = reloc->robj; + track->arrays[i + 1].esize = ib_chunk->kdata[idx] >> 24; + track->arrays[i + 1].esize &= 0x7F; } if (c & 1) { r = r100_cs_packet_next_reloc(p, &reloc); @@ -1046,6 +1401,9 @@ static int r300_packet3_check(struct radeon_cs_parser *p, return r; } ib[idx+1] = ib_chunk->kdata[idx+1] + ((u32)reloc->lobj.gpu_offset); + track->arrays[i + 0].robj = reloc->robj; + track->arrays[i + 0].esize = ib_chunk->kdata[idx] >> 8; + track->arrays[i + 0].esize &= 0x7F; } break; case PACKET3_INDX_BUFFER: @@ -1056,14 +1414,65 @@ static int r300_packet3_check(struct radeon_cs_parser *p, return r; } ib[idx+1] = ib_chunk->kdata[idx+1] + ((u32)reloc->lobj.gpu_offset); + r = r100_cs_track_check_pkt3_indx_buffer(p, pkt, reloc->robj); + if (r) { + return r; + } break; /* Draw packet */ - case PACKET3_3D_DRAW_VBUF: case PACKET3_3D_DRAW_IMMD: - case PACKET3_3D_DRAW_INDX: - case PACKET3_3D_DRAW_VBUF_2: + /* Number of dwords is vtx_size * (num_vertices - 1) + * PRIM_WALK must be equal to 3 vertex data in embedded + * in cmd stream */ + if (((ib_chunk->kdata[idx+1] >> 4) & 0x3) != 3) { + DRM_ERROR("PRIM_WALK must be 3 for IMMD draw\n"); + return -EINVAL; + } + track->vap_vf_cntl = ib_chunk->kdata[idx+1]; + track->immd_dwords = pkt->count - 1; + r = r300_cs_track_check(p->rdev, track); + if (r) { + return r; + } + break; case PACKET3_3D_DRAW_IMMD_2: + /* Number of dwords is vtx_size * (num_vertices - 1) + * PRIM_WALK must be equal to 3 vertex data in embedded + * in cmd stream */ + if (((ib_chunk->kdata[idx] >> 4) & 0x3) != 3) { + DRM_ERROR("PRIM_WALK must be 3 for IMMD draw\n"); + return -EINVAL; + } + track->vap_vf_cntl = ib_chunk->kdata[idx]; + track->immd_dwords = pkt->count; + r = r300_cs_track_check(p->rdev, track); + if (r) { + return r; + } + break; + case PACKET3_3D_DRAW_VBUF: + track->vap_vf_cntl = ib_chunk->kdata[idx + 1]; + r = r300_cs_track_check(p->rdev, track); + if (r) { + return r; + } + break; + case PACKET3_3D_DRAW_VBUF_2: + track->vap_vf_cntl = ib_chunk->kdata[idx]; + r = r300_cs_track_check(p->rdev, track); + if (r) { + return r; + } + break; + case PACKET3_3D_DRAW_INDX: + track->vap_vf_cntl = ib_chunk->kdata[idx + 1]; + r = r300_cs_track_check(p->rdev, track); + if (r) { + return r; + } + break; case PACKET3_3D_DRAW_INDX_2: + track->vap_vf_cntl = ib_chunk->kdata[idx]; r = r300_cs_track_check(p->rdev, track); if (r) { return r; @@ -1095,8 +1504,8 @@ int r300_cs_parse(struct radeon_cs_parser *p) switch (pkt.type) { case PACKET_TYPE0: r = r100_cs_parse_packet0(p, &pkt, - r300_auth_reg, - ARRAY_SIZE(r300_auth_reg), + p->rdev->config.r300.reg_safe_bm, + p->rdev->config.r300.reg_safe_bm_size, &r300_packet0_check); break; case PACKET_TYPE2: @@ -1114,3 +1523,10 @@ int r300_cs_parse(struct radeon_cs_parser *p) } while (p->idx < p->chunks[p->chunk_ib_idx].length_dw); return 0; } + +int r300_init(struct radeon_device *rdev) +{ + rdev->config.r300.reg_safe_bm = r300_reg_safe_bm; + rdev->config.r300.reg_safe_bm_size = ARRAY_SIZE(r300_reg_safe_bm); + return 0; +} diff --git a/drivers/gpu/drm/radeon/r300.h b/drivers/gpu/drm/radeon/r300.h new file mode 100644 index 000000000000..8486b4da9d69 --- /dev/null +++ b/drivers/gpu/drm/radeon/r300.h @@ -0,0 +1,36 @@ +/* + * Copyright 2008 Advanced Micro Devices, Inc. + * Copyright 2008 Red Hat Inc. + * Copyright 2009 Jerome Glisse. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: Dave Airlie + * Alex Deucher + * Jerome Glisse + */ +#ifndef R300_H +#define R300_H + +struct r300_asic { + const unsigned *reg_safe_bm; + unsigned reg_safe_bm_size; +}; + +#endif diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h index c3f24cc56009..d61f2fc61df5 100644 --- a/drivers/gpu/drm/radeon/radeon.h +++ b/drivers/gpu/drm/radeon/radeon.h @@ -51,7 +51,7 @@ #include "radeon_mode.h" #include "radeon_reg.h" - +#include "r300.h" /* * Modules parameters. @@ -496,6 +496,7 @@ int r100_debugfs_cp_init(struct radeon_device *rdev); * ASIC specific functions. */ struct radeon_asic { + int (*init)(struct radeon_device *rdev); void (*errata)(struct radeon_device *rdev); void (*vram_info)(struct radeon_device *rdev); int (*gpu_reset)(struct radeon_device *rdev); @@ -536,6 +537,10 @@ struct radeon_asic { void (*set_clock_gating)(struct radeon_device *rdev, int enable); }; +union radeon_asic_config { + struct r300_asic r300; +}; + /* * IOCTL. @@ -573,6 +578,7 @@ struct radeon_device { struct drm_device *ddev; struct pci_dev *pdev; /* ASIC */ + union radeon_asic_config config; enum radeon_family family; unsigned long flags; int usec_timeout; @@ -763,6 +769,7 @@ static inline void radeon_ring_write(struct radeon_device *rdev, uint32_t v) /* * ASICs macro. */ +#define radeon_init(rdev) (rdev)->asic->init((rdev)) #define radeon_cs_parse(p) rdev->asic->cs_parse((p)) #define radeon_errata(rdev) (rdev)->asic->errata((rdev)) #define radeon_vram_info(rdev) (rdev)->asic->vram_info((rdev)) diff --git a/drivers/gpu/drm/radeon/radeon_asic.h b/drivers/gpu/drm/radeon/radeon_asic.h index e57d8a784e9f..e2e567395df8 100644 --- a/drivers/gpu/drm/radeon/radeon_asic.h +++ b/drivers/gpu/drm/radeon/radeon_asic.h @@ -41,6 +41,7 @@ void radeon_atom_set_clock_gating(struct radeon_device *rdev, int enable); /* * r100,rv100,rs100,rv200,rs200,r200,rv250,rs300,rv280 */ +int r100_init(struct radeon_device *rdev); uint32_t r100_mm_rreg(struct radeon_device *rdev, uint32_t reg); void r100_mm_wreg(struct radeon_device *rdev, uint32_t reg, uint32_t v); void r100_errata(struct radeon_device *rdev); @@ -72,6 +73,7 @@ int r100_copy_blit(struct radeon_device *rdev, struct radeon_fence *fence); static struct radeon_asic r100_asic = { + .init = &r100_init, .errata = &r100_errata, .vram_info = &r100_vram_info, .gpu_reset = &r100_gpu_reset, @@ -104,6 +106,7 @@ static struct radeon_asic r100_asic = { /* * r300,r350,rv350,rv380 */ +int r300_init(struct radeon_device *rdev); void r300_errata(struct radeon_device *rdev); void r300_vram_info(struct radeon_device *rdev); int r300_gpu_reset(struct radeon_device *rdev); @@ -126,6 +129,7 @@ int r300_copy_dma(struct radeon_device *rdev, unsigned num_pages, struct radeon_fence *fence); static struct radeon_asic r300_asic = { + .init = &r300_init, .errata = &r300_errata, .vram_info = &r300_vram_info, .gpu_reset = &r300_gpu_reset, @@ -162,6 +166,7 @@ void r420_vram_info(struct radeon_device *rdev); int r420_mc_init(struct radeon_device *rdev); void r420_mc_fini(struct radeon_device *rdev); static struct radeon_asic r420_asic = { + .init = &r300_init, .errata = &r420_errata, .vram_info = &r420_vram_info, .gpu_reset = &r300_gpu_reset, @@ -205,6 +210,7 @@ int rs400_gart_set_page(struct radeon_device *rdev, int i, uint64_t addr); uint32_t rs400_mc_rreg(struct radeon_device *rdev, uint32_t reg); void rs400_mc_wreg(struct radeon_device *rdev, uint32_t reg, uint32_t v); static struct radeon_asic rs400_asic = { + .init = &r300_init, .errata = &rs400_errata, .vram_info = &rs400_vram_info, .gpu_reset = &r300_gpu_reset, @@ -249,6 +255,7 @@ int rs600_gart_set_page(struct radeon_device *rdev, int i, uint64_t addr); uint32_t rs600_mc_rreg(struct radeon_device *rdev, uint32_t reg); void rs600_mc_wreg(struct radeon_device *rdev, uint32_t reg, uint32_t v); static struct radeon_asic rs600_asic = { + .init = &r300_init, .errata = &rs600_errata, .vram_info = &rs600_vram_info, .gpu_reset = &r300_gpu_reset, @@ -288,6 +295,7 @@ void rs690_mc_fini(struct radeon_device *rdev); uint32_t rs690_mc_rreg(struct radeon_device *rdev, uint32_t reg); void rs690_mc_wreg(struct radeon_device *rdev, uint32_t reg, uint32_t v); static struct radeon_asic rs690_asic = { + .init = &r300_init, .errata = &rs690_errata, .vram_info = &rs690_vram_info, .gpu_reset = &r300_gpu_reset, @@ -320,6 +328,7 @@ static struct radeon_asic rs690_asic = { /* * rv515 */ +int rv515_init(struct radeon_device *rdev); void rv515_errata(struct radeon_device *rdev); void rv515_vram_info(struct radeon_device *rdev); int rv515_gpu_reset(struct radeon_device *rdev); @@ -331,6 +340,7 @@ void rv515_ring_start(struct radeon_device *rdev); uint32_t rv515_pcie_rreg(struct radeon_device *rdev, uint32_t reg); void rv515_pcie_wreg(struct radeon_device *rdev, uint32_t reg, uint32_t v); static struct radeon_asic rv515_asic = { + .init = &rv515_init, .errata = &rv515_errata, .vram_info = &rv515_vram_info, .gpu_reset = &rv515_gpu_reset, @@ -349,7 +359,7 @@ static struct radeon_asic rv515_asic = { .irq_set = &r100_irq_set, .irq_process = &r100_irq_process, .fence_ring_emit = &r300_fence_ring_emit, - .cs_parse = &r100_cs_parse, + .cs_parse = &r300_cs_parse, .copy_blit = &r100_copy_blit, .copy_dma = &r300_copy_dma, .copy = &r100_copy_blit, @@ -368,6 +378,7 @@ void r520_vram_info(struct radeon_device *rdev); int r520_mc_init(struct radeon_device *rdev); void r520_mc_fini(struct radeon_device *rdev); static struct radeon_asic r520_asic = { + .init = &rv515_init, .errata = &r520_errata, .vram_info = &r520_vram_info, .gpu_reset = &rv515_gpu_reset, @@ -386,7 +397,7 @@ static struct radeon_asic r520_asic = { .irq_set = &r100_irq_set, .irq_process = &r100_irq_process, .fence_ring_emit = &r300_fence_ring_emit, - .cs_parse = &r100_cs_parse, + .cs_parse = &r300_cs_parse, .copy_blit = &r100_copy_blit, .copy_dma = &r300_copy_dma, .copy = &r100_copy_blit, diff --git a/drivers/gpu/drm/radeon/radeon_atombios.c b/drivers/gpu/drm/radeon/radeon_atombios.c index 786632d3e378..1f5a1a490984 100644 --- a/drivers/gpu/drm/radeon/radeon_atombios.c +++ b/drivers/gpu/drm/radeon/radeon_atombios.c @@ -835,7 +835,6 @@ radeon_atombios_get_primary_dac_info(struct radeon_encoder *encoder) struct _COMPASSIONATE_DATA *dac_info; uint8_t frev, crev; uint8_t bg, dac; - int i; struct radeon_encoder_primary_dac *p_dac = NULL; atom_parse_data_header(mode_info->atom_context, index, NULL, &frev, &crev, &data_offset); @@ -867,7 +866,6 @@ radeon_atombios_get_tv_dac_info(struct radeon_encoder *encoder) struct _COMPASSIONATE_DATA *dac_info; uint8_t frev, crev; uint8_t bg, dac; - int i; struct radeon_encoder_tv_dac *tv_dac = NULL; atom_parse_data_header(mode_info->atom_context, index, NULL, &frev, &crev, &data_offset); diff --git a/drivers/gpu/drm/radeon/radeon_combios.c b/drivers/gpu/drm/radeon/radeon_combios.c index 06e8038bc4ac..afc4db280b94 100644 --- a/drivers/gpu/drm/radeon/radeon_combios.c +++ b/drivers/gpu/drm/radeon/radeon_combios.c @@ -799,6 +799,7 @@ static struct radeon_encoder_lvds *radeon_legacy_get_lvds_info_from_regs(struct struct radeon_encoder_lvds *lvds = NULL; uint32_t fp_vert_stretch, fp_horz_stretch; uint32_t ppll_div_sel, ppll_val; + uint32_t lvds_ss_gen_cntl = RREG32(RADEON_LVDS_SS_GEN_CNTL); lvds = kzalloc(sizeof(struct radeon_encoder_lvds), GFP_KERNEL); @@ -808,6 +809,14 @@ static struct radeon_encoder_lvds *radeon_legacy_get_lvds_info_from_regs(struct fp_vert_stretch = RREG32(RADEON_FP_VERT_STRETCH); fp_horz_stretch = RREG32(RADEON_FP_HORZ_STRETCH); + /* These should be fail-safe defaults, fingers crossed */ + lvds->panel_pwr_delay = 200; + lvds->panel_vcc_delay = 2000; + + lvds->lvds_gen_cntl = RREG32(RADEON_LVDS_GEN_CNTL); + lvds->panel_digon_delay = (lvds_ss_gen_cntl >> RADEON_LVDS_PWRSEQ_DELAY1_SHIFT) & 0xf; + lvds->panel_blon_delay = (lvds_ss_gen_cntl >> RADEON_LVDS_PWRSEQ_DELAY2_SHIFT) & 0xf; + if (fp_vert_stretch & RADEON_VERT_STRETCH_ENABLE) lvds->native_mode.panel_yres = ((fp_vert_stretch & RADEON_VERT_PANEL_SIZE) >> diff --git a/drivers/gpu/drm/radeon/radeon_cp.c b/drivers/gpu/drm/radeon/radeon_cp.c index 89c4c44169f7..d8356827ef17 100644 --- a/drivers/gpu/drm/radeon/radeon_cp.c +++ b/drivers/gpu/drm/radeon/radeon_cp.c @@ -2045,11 +2045,10 @@ int radeon_driver_load(struct drm_device *dev, unsigned long flags) drm_radeon_private_t *dev_priv; int ret = 0; - dev_priv = drm_alloc(sizeof(drm_radeon_private_t), DRM_MEM_DRIVER); + dev_priv = kzalloc(sizeof(drm_radeon_private_t), GFP_KERNEL); if (dev_priv == NULL) return -ENOMEM; - memset(dev_priv, 0, sizeof(drm_radeon_private_t)); dev->dev_private = (void *)dev_priv; dev_priv->flags = flags; @@ -2103,7 +2102,7 @@ int radeon_master_create(struct drm_device *dev, struct drm_master *master) unsigned long sareapage; int ret; - master_priv = drm_calloc(1, sizeof(*master_priv), DRM_MEM_DRIVER); + master_priv = kzalloc(sizeof(*master_priv), GFP_KERNEL); if (!master_priv) return -ENOMEM; @@ -2137,7 +2136,7 @@ void radeon_master_destroy(struct drm_device *dev, struct drm_master *master) if (master_priv->sarea) drm_rmmap_locked(dev, master_priv->sarea); - drm_free(master_priv, sizeof(*master_priv), DRM_MEM_DRIVER); + kfree(master_priv); master->driver_priv = NULL; } @@ -2171,7 +2170,7 @@ int radeon_driver_unload(struct drm_device *dev) drm_rmmap(dev, dev_priv->mmio); - drm_free(dev_priv, sizeof(*dev_priv), DRM_MEM_DRIVER); + kfree(dev_priv); dev->dev_private = NULL; return 0; diff --git a/drivers/gpu/drm/radeon/radeon_device.c b/drivers/gpu/drm/radeon/radeon_device.c index 5fd2b639bf66..f30aa7274a54 100644 --- a/drivers/gpu/drm/radeon/radeon_device.c +++ b/drivers/gpu/drm/radeon/radeon_device.c @@ -470,6 +470,10 @@ int radeon_device_init(struct radeon_device *rdev, if (r) { return r; } + r = radeon_init(rdev); + if (r) { + return r; + } /* Report DMA addressing limitation */ r = pci_set_dma_mask(rdev->pdev, DMA_BIT_MASK(32)); diff --git a/drivers/gpu/drm/radeon/radeon_display.c b/drivers/gpu/drm/radeon/radeon_display.c index 5452bb9d925e..3efcf1a526be 100644 --- a/drivers/gpu/drm/radeon/radeon_display.c +++ b/drivers/gpu/drm/radeon/radeon_display.c @@ -351,7 +351,7 @@ int radeon_ddc_get_modes(struct radeon_connector *radeon_connector) radeon_i2c_do_lock(radeon_connector, 0); if (edid) { /* update digital bits here */ - if (edid->digital) + if (edid->input & DRM_EDID_INPUT_DIGITAL) radeon_connector->use_digital = 1; else radeon_connector->use_digital = 0; diff --git a/drivers/gpu/drm/radeon/radeon_drv.c b/drivers/gpu/drm/radeon/radeon_drv.c index c815a2cbf7b3..09c9fb9f6210 100644 --- a/drivers/gpu/drm/radeon/radeon_drv.c +++ b/drivers/gpu/drm/radeon/radeon_drv.c @@ -313,7 +313,7 @@ static int __init radeon_init(void) { driver = &driver_old; driver->num_ioctls = radeon_max_ioctl; -#if defined(CONFIG_DRM_RADEON_KMS) && defined(CONFIG_X86) +#if defined(CONFIG_DRM_RADEON_KMS) /* if enabled by default */ if (radeon_modeset == -1) { DRM_INFO("radeon default to kernel modesetting.\n"); diff --git a/drivers/gpu/drm/radeon/radeon_i2c.c b/drivers/gpu/drm/radeon/radeon_i2c.c index 71465ed2688a..dd438d32e5c0 100644 --- a/drivers/gpu/drm/radeon/radeon_i2c.c +++ b/drivers/gpu/drm/radeon/radeon_i2c.c @@ -162,7 +162,7 @@ struct radeon_i2c_chan *radeon_i2c_create(struct drm_device *dev, struct radeon_i2c_chan *i2c; int ret; - i2c = drm_calloc(1, sizeof(struct radeon_i2c_chan), DRM_MEM_DRIVER); + i2c = kzalloc(sizeof(struct radeon_i2c_chan), GFP_KERNEL); if (i2c == NULL) return NULL; @@ -189,7 +189,7 @@ struct radeon_i2c_chan *radeon_i2c_create(struct drm_device *dev, return i2c; out_free: - drm_free(i2c, sizeof(struct radeon_i2c_chan), DRM_MEM_DRIVER); + kfree(i2c); return NULL; } @@ -200,7 +200,7 @@ void radeon_i2c_destroy(struct radeon_i2c_chan *i2c) return; i2c_del_adapter(&i2c->adapter); - drm_free(i2c, sizeof(struct radeon_i2c_chan), DRM_MEM_DRIVER); + kfree(i2c); } struct drm_encoder *radeon_best_encoder(struct drm_connector *connector) diff --git a/drivers/gpu/drm/radeon/radeon_kms.c b/drivers/gpu/drm/radeon/radeon_kms.c index 64f42b19cbfa..4612a7c146d1 100644 --- a/drivers/gpu/drm/radeon/radeon_kms.c +++ b/drivers/gpu/drm/radeon/radeon_kms.c @@ -169,7 +169,7 @@ int radeon_master_create_kms(struct drm_device *dev, struct drm_master *master) unsigned long sareapage; int ret; - master_priv = drm_calloc(1, sizeof(*master_priv), DRM_MEM_DRIVER); + master_priv = kzalloc(sizeof(*master_priv), GFP_KERNEL); if (master_priv == NULL) { return -ENOMEM; } @@ -199,7 +199,7 @@ void radeon_master_destroy_kms(struct drm_device *dev, if (master_priv->sarea) { drm_rmmap_locked(dev, master_priv->sarea); } - drm_free(master_priv, sizeof(*master_priv), DRM_MEM_DRIVER); + kfree(master_priv); master->driver_priv = NULL; } diff --git a/drivers/gpu/drm/radeon/radeon_mem.c b/drivers/gpu/drm/radeon/radeon_mem.c index 4af5286a36fb..ed95155c4b1d 100644 --- a/drivers/gpu/drm/radeon/radeon_mem.c +++ b/drivers/gpu/drm/radeon/radeon_mem.c @@ -43,8 +43,8 @@ static struct mem_block *split_block(struct mem_block *p, int start, int size, { /* Maybe cut off the start of an existing block */ if (start > p->start) { - struct mem_block *newblock = - drm_alloc(sizeof(*newblock), DRM_MEM_BUFS); + struct mem_block *newblock = kmalloc(sizeof(*newblock), + GFP_KERNEL); if (!newblock) goto out; newblock->start = start; @@ -60,8 +60,8 @@ static struct mem_block *split_block(struct mem_block *p, int start, int size, /* Maybe cut off the end of an existing block */ if (size < p->size) { - struct mem_block *newblock = - drm_alloc(sizeof(*newblock), DRM_MEM_BUFS); + struct mem_block *newblock = kmalloc(sizeof(*newblock), + GFP_KERNEL); if (!newblock) goto out; newblock->start = start + size; @@ -118,7 +118,7 @@ static void free_block(struct mem_block *p) p->size += q->size; p->next = q->next; p->next->prev = p; - drm_free(q, sizeof(*q), DRM_MEM_BUFS); + kfree(q); } if (p->prev->file_priv == NULL) { @@ -126,7 +126,7 @@ static void free_block(struct mem_block *p) q->size += p->size; q->next = p->next; q->next->prev = q; - drm_free(p, sizeof(*q), DRM_MEM_BUFS); + kfree(p); } } @@ -134,14 +134,14 @@ static void free_block(struct mem_block *p) */ static int init_heap(struct mem_block **heap, int start, int size) { - struct mem_block *blocks = drm_alloc(sizeof(*blocks), DRM_MEM_BUFS); + struct mem_block *blocks = kmalloc(sizeof(*blocks), GFP_KERNEL); if (!blocks) return -ENOMEM; - *heap = drm_alloc(sizeof(**heap), DRM_MEM_BUFS); + *heap = kmalloc(sizeof(**heap), GFP_KERNEL); if (!*heap) { - drm_free(blocks, sizeof(*blocks), DRM_MEM_BUFS); + kfree(blocks); return -ENOMEM; } @@ -179,7 +179,7 @@ void radeon_mem_release(struct drm_file *file_priv, struct mem_block *heap) p->size += q->size; p->next = q->next; p->next->prev = p; - drm_free(q, sizeof(*q), DRM_MEM_DRIVER); + kfree(q); } } } @@ -196,10 +196,10 @@ void radeon_mem_takedown(struct mem_block **heap) for (p = (*heap)->next; p != *heap;) { struct mem_block *q = p; p = p->next; - drm_free(q, sizeof(*q), DRM_MEM_DRIVER); + kfree(q); } - drm_free(*heap, sizeof(**heap), DRM_MEM_DRIVER); + kfree(*heap); *heap = NULL; } diff --git a/drivers/gpu/drm/radeon/radeon_reg.h b/drivers/gpu/drm/radeon/radeon_reg.h index 6d3d90406a24..e1b618574461 100644 --- a/drivers/gpu/drm/radeon/radeon_reg.h +++ b/drivers/gpu/drm/radeon/radeon_reg.h @@ -3184,6 +3184,7 @@ # define RADEON_RB_BUFSZ_MASK (0x3f << 0) # define RADEON_RB_BLKSZ_SHIFT 8 # define RADEON_RB_BLKSZ_MASK (0x3f << 8) +# define RADEON_BUF_SWAP_32BIT (1 << 17) # define RADEON_MAX_FETCH_SHIFT 18 # define RADEON_MAX_FETCH_MASK (0x3 << 18) # define RADEON_RB_NO_UPDATE (1 << 27) diff --git a/drivers/gpu/drm/radeon/radeon_state.c b/drivers/gpu/drm/radeon/radeon_state.c index fa728ec6ed34..46645f3e0328 100644 --- a/drivers/gpu/drm/radeon/radeon_state.c +++ b/drivers/gpu/drm/radeon/radeon_state.c @@ -2866,12 +2866,12 @@ static int radeon_cp_cmdbuf(struct drm_device *dev, void *data, struct drm_file */ orig_bufsz = cmdbuf->bufsz; if (orig_bufsz != 0) { - kbuf = drm_alloc(cmdbuf->bufsz, DRM_MEM_DRIVER); + kbuf = kmalloc(cmdbuf->bufsz, GFP_KERNEL); if (kbuf == NULL) return -ENOMEM; if (DRM_COPY_FROM_USER(kbuf, (void __user *)cmdbuf->buf, cmdbuf->bufsz)) { - drm_free(kbuf, orig_bufsz, DRM_MEM_DRIVER); + kfree(kbuf); return -EFAULT; } cmdbuf->buf = kbuf; @@ -2884,7 +2884,7 @@ static int radeon_cp_cmdbuf(struct drm_device *dev, void *data, struct drm_file temp = r300_do_cp_cmdbuf(dev, file_priv, cmdbuf); if (orig_bufsz != 0) - drm_free(kbuf, orig_bufsz, DRM_MEM_DRIVER); + kfree(kbuf); return temp; } @@ -2991,7 +2991,7 @@ static int radeon_cp_cmdbuf(struct drm_device *dev, void *data, struct drm_file } if (orig_bufsz != 0) - drm_free(kbuf, orig_bufsz, DRM_MEM_DRIVER); + kfree(kbuf); DRM_DEBUG("DONE\n"); COMMIT_RING(); @@ -2999,7 +2999,7 @@ static int radeon_cp_cmdbuf(struct drm_device *dev, void *data, struct drm_file err: if (orig_bufsz != 0) - drm_free(kbuf, orig_bufsz, DRM_MEM_DRIVER); + kfree(kbuf); return -EINVAL; } @@ -3175,9 +3175,7 @@ int radeon_driver_open(struct drm_device *dev, struct drm_file *file_priv) struct drm_radeon_driver_file_fields *radeon_priv; DRM_DEBUG("\n"); - radeon_priv = - (struct drm_radeon_driver_file_fields *) - drm_alloc(sizeof(*radeon_priv), DRM_MEM_FILES); + radeon_priv = kmalloc(sizeof(*radeon_priv), GFP_KERNEL); if (!radeon_priv) return -ENOMEM; @@ -3196,7 +3194,7 @@ void radeon_driver_postclose(struct drm_device *dev, struct drm_file *file_priv) struct drm_radeon_driver_file_fields *radeon_priv = file_priv->driver_priv; - drm_free(radeon_priv, sizeof(*radeon_priv), DRM_MEM_FILES); + kfree(radeon_priv); } struct drm_ioctl_desc radeon_ioctls[] = { diff --git a/drivers/gpu/drm/radeon/radeon_ttm.c b/drivers/gpu/drm/radeon/radeon_ttm.c index 4c087c1510d7..1227a97f5169 100644 --- a/drivers/gpu/drm/radeon/radeon_ttm.c +++ b/drivers/gpu/drm/radeon/radeon_ttm.c @@ -133,6 +133,7 @@ static int radeon_init_mem_type(struct ttm_bo_device *bdev, uint32_t type, man->gpu_offset = 0; man->available_caching = TTM_PL_MASK_CACHING; man->default_caching = TTM_PL_FLAG_CACHED; + man->flags = TTM_MEMTYPE_FLAG_MAPPABLE | TTM_MEMTYPE_FLAG_CMA; #if __OS_HAS_AGP if (rdev->flags & RADEON_IS_AGP) { if (!(drm_core_has_AGP(rdev->ddev) && rdev->ddev->agp)) { @@ -143,8 +144,9 @@ static int radeon_init_mem_type(struct ttm_bo_device *bdev, uint32_t type, man->io_offset = rdev->mc.agp_base; man->io_size = rdev->mc.gtt_size; man->io_addr = NULL; - man->flags = TTM_MEMTYPE_FLAG_NEEDS_IOREMAP | - TTM_MEMTYPE_FLAG_MAPPABLE; + if (!rdev->ddev->agp->cant_use_aperture) + man->flags = TTM_MEMTYPE_FLAG_NEEDS_IOREMAP | + TTM_MEMTYPE_FLAG_MAPPABLE; man->available_caching = TTM_PL_FLAG_UNCACHED | TTM_PL_FLAG_WC; man->default_caching = TTM_PL_FLAG_WC; @@ -154,8 +156,6 @@ static int radeon_init_mem_type(struct ttm_bo_device *bdev, uint32_t type, man->io_offset = 0; man->io_size = 0; man->io_addr = NULL; - man->flags = TTM_MEMTYPE_FLAG_MAPPABLE | - TTM_MEMTYPE_FLAG_CMA; } break; case TTM_PL_VRAM: diff --git a/drivers/gpu/drm/radeon/rv515.c b/drivers/gpu/drm/radeon/rv515.c index 7eab95db58ac..ffea37b1b3e2 100644 --- a/drivers/gpu/drm/radeon/rv515.c +++ b/drivers/gpu/drm/radeon/rv515.c @@ -225,6 +225,8 @@ void rv515_ring_start(struct radeon_device *rdev) radeon_ring_write(rdev, R300_GEOMETRY_ROUND_NEAREST | R300_COLOR_ROUND_NEAREST); + radeon_ring_write(rdev, PACKET0(0x20C8, 0)); + radeon_ring_write(rdev, 0); radeon_ring_unlock_commit(rdev); } @@ -502,3 +504,59 @@ int rv515_debugfs_ga_info_init(struct radeon_device *rdev) return 0; #endif } + + +/* + * Asic initialization + */ +static const unsigned r500_reg_safe_bm[159] = { + 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, + 0xFFFFFFBF, 0xFFFFFFFF, 0xFFFFFFBF, 0xFFFFFFFF, + 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, + 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, + 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, + 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, + 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, + 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, + 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, + 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, + 0x17FF1FFF, 0xFFFFFFFC, 0xFFFFFFFF, 0xFF30FFBF, + 0xFFFFFFF8, 0xC3E6FFFF, 0xFFFFF6DF, 0xFFFFFFFF, + 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, + 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, + 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFF03F, + 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, + 0xFFFFFFFF, 0xFFFFEFCE, 0xF00EBFFF, 0x007C0000, + 0xF0000038, 0xFF000009, 0xFFFFFFFF, 0xFFFFFFFF, + 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, + 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, + 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, + 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, + 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, + 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, + 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, + 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, + 0xFFFFF7FF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, + 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, + 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, + 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, + 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, + 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, + 0x1FFFFC78, 0xFFFFE000, 0xFFFFFFFE, 0xFFFFFFFF, + 0x38CF8F50, 0xFFF88082, 0xFF0000FC, 0xFAE009FF, + 0x0000FFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000, + 0xFFFF8CFC, 0xFFFFC1FF, 0xFFFFFFFF, 0xFFFFFFFF, + 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, + 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFF80FFFF, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x0003FC01, 0x3FFFFCF8, 0xFE800B19, +}; + + + +int rv515_init(struct radeon_device *rdev) +{ + rdev->config.r300.reg_safe_bm = r500_reg_safe_bm; + rdev->config.r300.reg_safe_bm_size = ARRAY_SIZE(r500_reg_safe_bm); + return 0; +} diff --git a/drivers/gpu/drm/savage/savage_bci.c b/drivers/gpu/drm/savage/savage_bci.c index 456cd040f31a..bff6fc2524c8 100644 --- a/drivers/gpu/drm/savage/savage_bci.c +++ b/drivers/gpu/drm/savage/savage_bci.c @@ -298,8 +298,8 @@ static int savage_dma_init(drm_savage_private_t * dev_priv) dev_priv->nr_dma_pages = dev_priv->cmd_dma->size / (SAVAGE_DMA_PAGE_SIZE * 4); - dev_priv->dma_pages = drm_alloc(sizeof(drm_savage_dma_page_t) * - dev_priv->nr_dma_pages, DRM_MEM_DRIVER); + dev_priv->dma_pages = kmalloc(sizeof(drm_savage_dma_page_t) * + dev_priv->nr_dma_pages, GFP_KERNEL); if (dev_priv->dma_pages == NULL) return -ENOMEM; @@ -539,7 +539,7 @@ int savage_driver_load(struct drm_device *dev, unsigned long chipset) { drm_savage_private_t *dev_priv; - dev_priv = drm_alloc(sizeof(drm_savage_private_t), DRM_MEM_DRIVER); + dev_priv = kmalloc(sizeof(drm_savage_private_t), GFP_KERNEL); if (dev_priv == NULL) return -ENOMEM; @@ -671,7 +671,7 @@ int savage_driver_unload(struct drm_device *dev) { drm_savage_private_t *dev_priv = dev->dev_private; - drm_free(dev_priv, sizeof(drm_savage_private_t), DRM_MEM_DRIVER); + kfree(dev_priv); return 0; } @@ -804,8 +804,8 @@ static int savage_do_init_bci(struct drm_device * dev, drm_savage_init_t * init) dev_priv->fake_dma.offset = 0; dev_priv->fake_dma.size = SAVAGE_FAKE_DMA_SIZE; dev_priv->fake_dma.type = _DRM_SHM; - dev_priv->fake_dma.handle = drm_alloc(SAVAGE_FAKE_DMA_SIZE, - DRM_MEM_DRIVER); + dev_priv->fake_dma.handle = kmalloc(SAVAGE_FAKE_DMA_SIZE, + GFP_KERNEL); if (!dev_priv->fake_dma.handle) { DRM_ERROR("could not allocate faked DMA buffer!\n"); savage_do_cleanup_bci(dev); @@ -903,9 +903,7 @@ static int savage_do_cleanup_bci(struct drm_device * dev) drm_savage_private_t *dev_priv = dev->dev_private; if (dev_priv->cmd_dma == &dev_priv->fake_dma) { - if (dev_priv->fake_dma.handle) - drm_free(dev_priv->fake_dma.handle, - SAVAGE_FAKE_DMA_SIZE, DRM_MEM_DRIVER); + kfree(dev_priv->fake_dma.handle); } else if (dev_priv->cmd_dma && dev_priv->cmd_dma->handle && dev_priv->cmd_dma->type == _DRM_AGP && dev_priv->dma_type == SAVAGE_DMA_AGP) @@ -920,10 +918,7 @@ static int savage_do_cleanup_bci(struct drm_device * dev) dev->agp_buffer_map = NULL; } - if (dev_priv->dma_pages) - drm_free(dev_priv->dma_pages, - sizeof(drm_savage_dma_page_t) * dev_priv->nr_dma_pages, - DRM_MEM_DRIVER); + kfree(dev_priv->dma_pages); return 0; } diff --git a/drivers/gpu/drm/savage/savage_state.c b/drivers/gpu/drm/savage/savage_state.c index 5f6238fdf1fa..8a3e31599c94 100644 --- a/drivers/gpu/drm/savage/savage_state.c +++ b/drivers/gpu/drm/savage/savage_state.c @@ -988,20 +988,20 @@ int savage_bci_cmdbuf(struct drm_device *dev, void *data, struct drm_file *file_ * for locking on FreeBSD. */ if (cmdbuf->size) { - kcmd_addr = drm_alloc(cmdbuf->size * 8, DRM_MEM_DRIVER); + kcmd_addr = kmalloc(cmdbuf->size * 8, GFP_KERNEL); if (kcmd_addr == NULL) return -ENOMEM; if (DRM_COPY_FROM_USER(kcmd_addr, cmdbuf->cmd_addr, cmdbuf->size * 8)) { - drm_free(kcmd_addr, cmdbuf->size * 8, DRM_MEM_DRIVER); + kfree(kcmd_addr); return -EFAULT; } cmdbuf->cmd_addr = kcmd_addr; } if (cmdbuf->vb_size) { - kvb_addr = drm_alloc(cmdbuf->vb_size, DRM_MEM_DRIVER); + kvb_addr = kmalloc(cmdbuf->vb_size, GFP_KERNEL); if (kvb_addr == NULL) { ret = -ENOMEM; goto done; @@ -1015,8 +1015,8 @@ int savage_bci_cmdbuf(struct drm_device *dev, void *data, struct drm_file *file_ cmdbuf->vb_addr = kvb_addr; } if (cmdbuf->nbox) { - kbox_addr = drm_alloc(cmdbuf->nbox * sizeof(struct drm_clip_rect), - DRM_MEM_DRIVER); + kbox_addr = kmalloc(cmdbuf->nbox * sizeof(struct drm_clip_rect), + GFP_KERNEL); if (kbox_addr == NULL) { ret = -ENOMEM; goto done; @@ -1154,10 +1154,9 @@ int savage_bci_cmdbuf(struct drm_device *dev, void *data, struct drm_file *file_ done: /* If we didn't need to allocate them, these'll be NULL */ - drm_free(kcmd_addr, cmdbuf->size * 8, DRM_MEM_DRIVER); - drm_free(kvb_addr, cmdbuf->vb_size, DRM_MEM_DRIVER); - drm_free(kbox_addr, cmdbuf->nbox * sizeof(struct drm_clip_rect), - DRM_MEM_DRIVER); + kfree(kcmd_addr); + kfree(kvb_addr); + kfree(kbox_addr); return ret; } diff --git a/drivers/gpu/drm/sis/sis_drv.c b/drivers/gpu/drm/sis/sis_drv.c index 7dacc64e9b56..e725cc0b1155 100644 --- a/drivers/gpu/drm/sis/sis_drv.c +++ b/drivers/gpu/drm/sis/sis_drv.c @@ -40,7 +40,7 @@ static int sis_driver_load(struct drm_device *dev, unsigned long chipset) drm_sis_private_t *dev_priv; int ret; - dev_priv = drm_calloc(1, sizeof(drm_sis_private_t), DRM_MEM_DRIVER); + dev_priv = kzalloc(sizeof(drm_sis_private_t), GFP_KERNEL); if (dev_priv == NULL) return -ENOMEM; @@ -48,7 +48,7 @@ static int sis_driver_load(struct drm_device *dev, unsigned long chipset) dev_priv->chipset = chipset; ret = drm_sman_init(&dev_priv->sman, 2, 12, 8); if (ret) { - drm_free(dev_priv, sizeof(dev_priv), DRM_MEM_DRIVER); + kfree(dev_priv); } return ret; @@ -59,7 +59,7 @@ static int sis_driver_unload(struct drm_device *dev) drm_sis_private_t *dev_priv = dev->dev_private; drm_sman_takedown(&dev_priv->sman); - drm_free(dev_priv, sizeof(*dev_priv), DRM_MEM_DRIVER); + kfree(dev_priv); return 0; } diff --git a/drivers/gpu/drm/ttm/ttm_agp_backend.c b/drivers/gpu/drm/ttm/ttm_agp_backend.c index e8f6d2229d8c..4648ed2f0143 100644 --- a/drivers/gpu/drm/ttm/ttm_agp_backend.c +++ b/drivers/gpu/drm/ttm/ttm_agp_backend.c @@ -63,8 +63,7 @@ static int ttm_agp_populate(struct ttm_backend *backend, if (!page) page = dummy_read_page; - mem->memory[mem->page_count++] = - phys_to_gart(page_to_phys(page)); + mem->pages[mem->page_count++] = page; } agp_be->mem = mem; return 0; diff --git a/drivers/gpu/drm/ttm/ttm_bo.c b/drivers/gpu/drm/ttm/ttm_bo.c index 1587aeca7bea..c1c407f7cca3 100644 --- a/drivers/gpu/drm/ttm/ttm_bo.c +++ b/drivers/gpu/drm/ttm/ttm_bo.c @@ -282,7 +282,7 @@ static int ttm_bo_handle_move_mem(struct ttm_buffer_object *bo, ret = ttm_tt_set_placement_caching(bo->ttm, mem->placement); if (ret) - return ret; + goto out_err; if (mem->mem_type != TTM_PL_SYSTEM) { ret = ttm_tt_bind(bo->ttm, mem); @@ -527,9 +527,12 @@ static int ttm_bo_evict(struct ttm_buffer_object *bo, unsigned mem_type, ret = ttm_bo_wait(bo, false, interruptible, no_wait); spin_unlock(&bo->lock); - if (ret && ret != -ERESTART) { - printk(KERN_ERR TTM_PFX "Failed to expire sync object before " - "buffer eviction.\n"); + if (unlikely(ret != 0)) { + if (ret != -ERESTART) { + printk(KERN_ERR TTM_PFX + "Failed to expire sync object before " + "buffer eviction.\n"); + } goto out; } diff --git a/drivers/gpu/drm/ttm/ttm_tt.c b/drivers/gpu/drm/ttm/ttm_tt.c index c27ab3a877ad..0331fa74cd3f 100644 --- a/drivers/gpu/drm/ttm/ttm_tt.c +++ b/drivers/gpu/drm/ttm/ttm_tt.c @@ -68,7 +68,7 @@ static void ttm_tt_cache_flush_clflush(struct page *pages[], ttm_tt_clflush_page(*pages++); mb(); } -#else +#elif !defined(__powerpc__) static void ttm_tt_ipi_handler(void *null) { ; @@ -83,6 +83,15 @@ void ttm_tt_cache_flush(struct page *pages[], unsigned long num_pages) ttm_tt_cache_flush_clflush(pages, num_pages); return; } +#elif defined(__powerpc__) + unsigned long i; + + for (i = 0; i < num_pages; ++i) { + if (pages[i]) { + unsigned long start = (unsigned long)page_address(pages[i]); + flush_dcache_range(start, start + PAGE_SIZE); + } + } #else if (on_each_cpu(ttm_tt_ipi_handler, NULL, 1) != 0) printk(KERN_ERR TTM_PFX diff --git a/drivers/gpu/drm/via/via_map.c b/drivers/gpu/drm/via/via_map.c index 2c4f0b485792..6e6f91591639 100644 --- a/drivers/gpu/drm/via/via_map.c +++ b/drivers/gpu/drm/via/via_map.c @@ -96,7 +96,7 @@ int via_driver_load(struct drm_device *dev, unsigned long chipset) drm_via_private_t *dev_priv; int ret = 0; - dev_priv = drm_calloc(1, sizeof(drm_via_private_t), DRM_MEM_DRIVER); + dev_priv = kzalloc(sizeof(drm_via_private_t), GFP_KERNEL); if (dev_priv == NULL) return -ENOMEM; @@ -106,14 +106,14 @@ int via_driver_load(struct drm_device *dev, unsigned long chipset) ret = drm_sman_init(&dev_priv->sman, 2, 12, 8); if (ret) { - drm_free(dev_priv, sizeof(*dev_priv), DRM_MEM_DRIVER); + kfree(dev_priv); return ret; } ret = drm_vblank_init(dev, 1); if (ret) { drm_sman_takedown(&dev_priv->sman); - drm_free(dev_priv, sizeof(drm_via_private_t), DRM_MEM_DRIVER); + kfree(dev_priv); return ret; } @@ -126,7 +126,7 @@ int via_driver_unload(struct drm_device *dev) drm_sman_takedown(&dev_priv->sman); - drm_free(dev_priv, sizeof(drm_via_private_t), DRM_MEM_DRIVER); + kfree(dev_priv); return 0; } diff --git a/drivers/ide/at91_ide.c b/drivers/ide/at91_ide.c index fc0949a8cfde..dbfeda42b940 100644 --- a/drivers/ide/at91_ide.c +++ b/drivers/ide/at91_ide.c @@ -185,8 +185,7 @@ static void at91_ide_set_pio_mode(ide_drive_t *drive, const u8 pio) timing = ide_timing_find_mode(XFER_PIO_0 + pio); BUG_ON(!timing); - if ((pio > 2 || ata_id_has_iordy(drive->id)) && - !(ata_id_is_cfa(drive->id) && pio > 4)) + if (ide_pio_need_iordy(drive, pio)) use_iordy = 1; apply_timings(chipselect, pio, timing, use_iordy); diff --git a/drivers/ide/buddha.c b/drivers/ide/buddha.c index e3c6a5913305..ab4f169d0837 100644 --- a/drivers/ide/buddha.c +++ b/drivers/ide/buddha.c @@ -99,7 +99,7 @@ static const char *buddha_board_name[] = { "Buddha", "Catweasel", "X-Surf" }; * Check and acknowledge the interrupt status */ -static int buddha_ack_intr(ide_hwif_t *hwif) +static int buddha_test_irq(ide_hwif_t *hwif) { unsigned char ch; @@ -109,21 +109,16 @@ static int buddha_ack_intr(ide_hwif_t *hwif) return 1; } -static int xsurf_ack_intr(ide_hwif_t *hwif) +static void xsurf_clear_irq(ide_drive_t *drive) { - unsigned char ch; - - ch = z_readb(hwif->io_ports.irq_addr); - /* X-Surf needs a 0 written to IRQ register to ensure ISA bit A11 stays at 0 */ - z_writeb(0, hwif->io_ports.irq_addr); - if (!(ch & 0x80)) - return 0; - return 1; + /* + * X-Surf needs 0 written to IRQ register to ensure ISA bit A11 stays at 0 + */ + z_writeb(0, drive->hwif->io_ports.irq_addr); } static void __init buddha_setup_ports(struct ide_hw *hw, unsigned long base, - unsigned long ctl, unsigned long irq_port, - ide_ack_intr_t *ack_intr) + unsigned long ctl, unsigned long irq_port) { int i; @@ -138,10 +133,19 @@ static void __init buddha_setup_ports(struct ide_hw *hw, unsigned long base, hw->io_ports.irq_addr = irq_port; hw->irq = IRQ_AMIGA_PORTS; - hw->ack_intr = ack_intr; } +static const struct ide_port_ops buddha_port_ops = { + .test_irq = buddha_test_irq, +}; + +static const struct ide_port_ops xsurf_port_ops = { + .clear_irq = xsurf_clear_irq, + .test_irq = buddha_test_irq, +}; + static const struct ide_port_info buddha_port_info = { + .port_ops = &buddha_port_ops, .host_flags = IDE_HFLAG_MMIO | IDE_HFLAG_NO_DMA, .irq_flags = IRQF_SHARED, .chipset = ide_generic, @@ -161,6 +165,7 @@ static int __init buddha_init(void) while ((z = zorro_find_device(ZORRO_WILDCARD, z))) { unsigned long board; struct ide_hw hw[MAX_NUM_HWIFS], *hws[MAX_NUM_HWIFS]; + struct ide_port_info d = buddha_port_info; if (z->id == ZORRO_PROD_INDIVIDUAL_COMPUTERS_BUDDHA) { buddha_num_hwifs = BUDDHA_NUM_HWIFS; @@ -171,6 +176,7 @@ static int __init buddha_init(void) } else if (z->id == ZORRO_PROD_INDIVIDUAL_COMPUTERS_X_SURF) { buddha_num_hwifs = XSURF_NUM_HWIFS; type=BOARD_XSURF; + d.port_ops = &xsurf_port_ops; } else continue; @@ -203,28 +209,24 @@ fail_base2: for (i = 0; i < buddha_num_hwifs; i++) { unsigned long base, ctl, irq_port; - ide_ack_intr_t *ack_intr; if (type != BOARD_XSURF) { base = buddha_board + buddha_bases[i]; ctl = base + BUDDHA_CONTROL; irq_port = buddha_board + buddha_irqports[i]; - ack_intr = buddha_ack_intr; } else { base = buddha_board + xsurf_bases[i]; /* X-Surf has no CS1* (Control/AltStat) */ ctl = 0; irq_port = buddha_board + xsurf_irqports[i]; - ack_intr = xsurf_ack_intr; } - buddha_setup_ports(&hw[i], base, ctl, irq_port, - ack_intr); + buddha_setup_ports(&hw[i], base, ctl, irq_port); hws[i] = &hw[i]; } - ide_host_add(&buddha_port_info, hws, i, NULL); + ide_host_add(&d, hws, i, NULL); } return 0; diff --git a/drivers/ide/cmd640.c b/drivers/ide/cmd640.c index 1683ed5c7329..1a32d62ed86b 100644 --- a/drivers/ide/cmd640.c +++ b/drivers/ide/cmd640.c @@ -153,6 +153,7 @@ static int cmd640_vlb; #define ARTTIM23 0x57 #define ARTTIM23_DIS_RA2 0x04 #define ARTTIM23_DIS_RA3 0x08 +#define ARTTIM23_IDE23INTR 0x10 #define DRWTIM23 0x58 #define BRST 0x59 @@ -629,12 +630,24 @@ static void cmd640_init_dev(ide_drive_t *drive) #endif /* CONFIG_BLK_DEV_CMD640_ENHANCED */ } +static int cmd640_test_irq(ide_hwif_t *hwif) +{ + struct pci_dev *dev = to_pci_dev(hwif->dev); + int irq_reg = hwif->channel ? ARTTIM23 : CFR; + u8 irq_stat, irq_mask = hwif->channel ? ARTTIM23_IDE23INTR : + CFR_IDE01INTR; + + pci_read_config_byte(dev, irq_reg, &irq_stat); + + return (irq_stat & irq_mask) ? 1 : 0; +} static const struct ide_port_ops cmd640_port_ops = { .init_dev = cmd640_init_dev, #ifdef CONFIG_BLK_DEV_CMD640_ENHANCED .set_pio_mode = cmd640_set_pio_mode, #endif + .test_irq = cmd640_test_irq, }; static int pci_conf1(void) diff --git a/drivers/ide/cmd64x.c b/drivers/ide/cmd64x.c index 80b777e4247b..03c86209446f 100644 --- a/drivers/ide/cmd64x.c +++ b/drivers/ide/cmd64x.c @@ -7,7 +7,7 @@ * Copyright (C) 1998 David S. Miller (davem@redhat.com) * * Copyright (C) 1999-2002 Andre Hedrick <andre@linux-ide.org> - * Copyright (C) 2007 MontaVista Software, Inc. <source@mvista.com> + * Copyright (C) 2007,2009 MontaVista Software, Inc. <source@mvista.com> */ #include <linux/module.h> @@ -118,8 +118,9 @@ static void cmd64x_tune_pio(ide_drive_t *drive, const u8 pio) ide_hwif_t *hwif = drive->hwif; struct pci_dev *dev = to_pci_dev(hwif->dev); struct ide_timing *t = ide_timing_find_mode(XFER_PIO_0 + pio); + unsigned long setup_count; unsigned int cycle_time; - u8 setup_count, arttim = 0; + u8 arttim = 0; static const u8 setup_values[] = {0x40, 0x40, 0x40, 0x80, 0, 0xc0}; static const u8 arttim_regs[4] = {ARTTIM0, ARTTIM1, ARTTIM23, ARTTIM23}; @@ -140,10 +141,11 @@ static void cmd64x_tune_pio(ide_drive_t *drive, const u8 pio) if (hwif->channel) { ide_drive_t *pair = ide_get_pair_dev(drive); - drive->drive_data = setup_count; + ide_set_drivedata(drive, (void *)setup_count); if (pair) - setup_count = max_t(u8, setup_count, pair->drive_data); + setup_count = max_t(u8, setup_count, + (unsigned long)ide_get_drivedata(pair)); } if (setup_count > 5) /* shouldn't actually happen... */ @@ -226,11 +228,11 @@ static void cmd64x_set_dma_mode(ide_drive_t *drive, const u8 speed) (void) pci_write_config_byte(dev, pciU, regU); } -static int cmd648_dma_end(ide_drive_t *drive) +static void cmd648_clear_irq(ide_drive_t *drive) { ide_hwif_t *hwif = drive->hwif; - unsigned long base = hwif->dma_base - (hwif->channel * 8); - int err = ide_dma_end(drive); + struct pci_dev *dev = to_pci_dev(hwif->dev); + unsigned long base = pci_resource_start(dev, 4); u8 irq_mask = hwif->channel ? MRDMODE_INTR_CH1 : MRDMODE_INTR_CH0; u8 mrdmode = inb(base + 1); @@ -238,11 +240,9 @@ static int cmd648_dma_end(ide_drive_t *drive) /* clear the interrupt bit */ outb((mrdmode & ~(MRDMODE_INTR_CH0 | MRDMODE_INTR_CH1)) | irq_mask, base + 1); - - return err; } -static int cmd64x_dma_end(ide_drive_t *drive) +static void cmd64x_clear_irq(ide_drive_t *drive) { ide_hwif_t *hwif = drive->hwif; struct pci_dev *dev = to_pci_dev(hwif->dev); @@ -250,62 +250,40 @@ static int cmd64x_dma_end(ide_drive_t *drive) u8 irq_mask = hwif->channel ? ARTTIM23_INTR_CH1 : CFR_INTR_CH0; u8 irq_stat = 0; - int err = ide_dma_end(drive); (void) pci_read_config_byte(dev, irq_reg, &irq_stat); /* clear the interrupt bit */ (void) pci_write_config_byte(dev, irq_reg, irq_stat | irq_mask); - - return err; } -static int cmd648_dma_test_irq(ide_drive_t *drive) +static int cmd648_test_irq(ide_hwif_t *hwif) { - ide_hwif_t *hwif = drive->hwif; - unsigned long base = hwif->dma_base - (hwif->channel * 8); + struct pci_dev *dev = to_pci_dev(hwif->dev); + unsigned long base = pci_resource_start(dev, 4); u8 irq_mask = hwif->channel ? MRDMODE_INTR_CH1 : MRDMODE_INTR_CH0; - u8 dma_stat = inb(hwif->dma_base + ATA_DMA_STATUS); u8 mrdmode = inb(base + 1); -#ifdef DEBUG - printk("%s: dma_stat: 0x%02x mrdmode: 0x%02x irq_mask: 0x%02x\n", - drive->name, dma_stat, mrdmode, irq_mask); -#endif - if (!(mrdmode & irq_mask)) - return 0; - - /* return 1 if INTR asserted */ - if (dma_stat & 4) - return 1; + pr_debug("%s: mrdmode: 0x%02x irq_mask: 0x%02x\n", + hwif->name, mrdmode, irq_mask); - return 0; + return (mrdmode & irq_mask) ? 1 : 0; } -static int cmd64x_dma_test_irq(ide_drive_t *drive) +static int cmd64x_test_irq(ide_hwif_t *hwif) { - ide_hwif_t *hwif = drive->hwif; struct pci_dev *dev = to_pci_dev(hwif->dev); int irq_reg = hwif->channel ? ARTTIM23 : CFR; u8 irq_mask = hwif->channel ? ARTTIM23_INTR_CH1 : CFR_INTR_CH0; - u8 dma_stat = inb(hwif->dma_base + ATA_DMA_STATUS); u8 irq_stat = 0; (void) pci_read_config_byte(dev, irq_reg, &irq_stat); -#ifdef DEBUG - printk("%s: dma_stat: 0x%02x irq_stat: 0x%02x irq_mask: 0x%02x\n", - drive->name, dma_stat, irq_stat, irq_mask); -#endif - if (!(irq_stat & irq_mask)) - return 0; - - /* return 1 if INTR asserted */ - if (dma_stat & 4) - return 1; + pr_debug("%s: irq_stat: 0x%02x irq_mask: 0x%02x\n", + hwif->name, irq_stat, irq_mask); - return 0; + return (irq_stat & irq_mask) ? 1 : 0; } /* @@ -370,18 +348,17 @@ static u8 cmd64x_cable_detect(ide_hwif_t *hwif) static const struct ide_port_ops cmd64x_port_ops = { .set_pio_mode = cmd64x_set_pio_mode, .set_dma_mode = cmd64x_set_dma_mode, + .clear_irq = cmd64x_clear_irq, + .test_irq = cmd64x_test_irq, .cable_detect = cmd64x_cable_detect, }; -static const struct ide_dma_ops cmd64x_dma_ops = { - .dma_host_set = ide_dma_host_set, - .dma_setup = ide_dma_setup, - .dma_start = ide_dma_start, - .dma_end = cmd64x_dma_end, - .dma_test_irq = cmd64x_dma_test_irq, - .dma_lost_irq = ide_dma_lost_irq, - .dma_timer_expiry = ide_dma_sff_timer_expiry, - .dma_sff_read_status = ide_dma_sff_read_status, +static const struct ide_port_ops cmd648_port_ops = { + .set_pio_mode = cmd64x_set_pio_mode, + .set_dma_mode = cmd64x_set_dma_mode, + .clear_irq = cmd648_clear_irq, + .test_irq = cmd648_test_irq, + .cable_detect = cmd64x_cable_detect, }; static const struct ide_dma_ops cmd646_rev1_dma_ops = { @@ -395,24 +372,12 @@ static const struct ide_dma_ops cmd646_rev1_dma_ops = { .dma_sff_read_status = ide_dma_sff_read_status, }; -static const struct ide_dma_ops cmd648_dma_ops = { - .dma_host_set = ide_dma_host_set, - .dma_setup = ide_dma_setup, - .dma_start = ide_dma_start, - .dma_end = cmd648_dma_end, - .dma_test_irq = cmd648_dma_test_irq, - .dma_lost_irq = ide_dma_lost_irq, - .dma_timer_expiry = ide_dma_sff_timer_expiry, - .dma_sff_read_status = ide_dma_sff_read_status, -}; - static const struct ide_port_info cmd64x_chipsets[] __devinitdata = { { /* 0: CMD643 */ .name = DRV_NAME, .init_chipset = init_chipset_cmd64x, .enablebits = {{0x00,0x00,0x00}, {0x51,0x08,0x08}}, .port_ops = &cmd64x_port_ops, - .dma_ops = &cmd64x_dma_ops, .host_flags = IDE_HFLAG_CLEAR_SIMPLEX | IDE_HFLAG_ABUSE_PREFETCH, .pio_mask = ATA_PIO5, @@ -423,8 +388,7 @@ static const struct ide_port_info cmd64x_chipsets[] __devinitdata = { .name = DRV_NAME, .init_chipset = init_chipset_cmd64x, .enablebits = {{0x51,0x04,0x04}, {0x51,0x08,0x08}}, - .port_ops = &cmd64x_port_ops, - .dma_ops = &cmd648_dma_ops, + .port_ops = &cmd648_port_ops, .host_flags = IDE_HFLAG_SERIALIZE | IDE_HFLAG_ABUSE_PREFETCH, .pio_mask = ATA_PIO5, @@ -435,8 +399,7 @@ static const struct ide_port_info cmd64x_chipsets[] __devinitdata = { .name = DRV_NAME, .init_chipset = init_chipset_cmd64x, .enablebits = {{0x51,0x04,0x04}, {0x51,0x08,0x08}}, - .port_ops = &cmd64x_port_ops, - .dma_ops = &cmd648_dma_ops, + .port_ops = &cmd648_port_ops, .host_flags = IDE_HFLAG_ABUSE_PREFETCH, .pio_mask = ATA_PIO5, .mwdma_mask = ATA_MWDMA2, @@ -446,8 +409,7 @@ static const struct ide_port_info cmd64x_chipsets[] __devinitdata = { .name = DRV_NAME, .init_chipset = init_chipset_cmd64x, .enablebits = {{0x51,0x04,0x04}, {0x51,0x08,0x08}}, - .port_ops = &cmd64x_port_ops, - .dma_ops = &cmd648_dma_ops, + .port_ops = &cmd648_port_ops, .host_flags = IDE_HFLAG_ABUSE_PREFETCH, .pio_mask = ATA_PIO5, .mwdma_mask = ATA_MWDMA2, @@ -484,10 +446,9 @@ static int __devinit cmd64x_init_one(struct pci_dev *dev, const struct pci_devic */ if (dev->revision < 3) { d.enablebits[0].reg = 0; + d.port_ops = &cmd64x_port_ops; if (dev->revision == 1) d.dma_ops = &cmd646_rev1_dma_ops; - else - d.dma_ops = &cmd64x_dma_ops; } } } diff --git a/drivers/ide/cs5536.c b/drivers/ide/cs5536.c index 0332a95eefd4..9623b852c616 100644 --- a/drivers/ide/cs5536.c +++ b/drivers/ide/cs5536.c @@ -146,14 +146,16 @@ static void cs5536_set_pio_mode(ide_drive_t *drive, const u8 pio) struct pci_dev *pdev = to_pci_dev(drive->hwif->dev); ide_drive_t *pair = ide_get_pair_dev(drive); int cshift = (drive->dn & 1) ? IDE_CAST_D1_SHIFT : IDE_CAST_D0_SHIFT; + unsigned long timings = (unsigned long)ide_get_drivedata(drive); u32 cast; u8 cmd_pio = pio; if (pair) cmd_pio = min(pio, ide_get_best_pio_mode(pair, 255, 4)); - drive->drive_data &= (IDE_DRV_MASK << 8); - drive->drive_data |= drv_timings[pio]; + timings &= (IDE_DRV_MASK << 8); + timings |= drv_timings[pio]; + ide_set_drivedata(drive, (void *)timings); cs5536_program_dtc(drive, drv_timings[pio]); @@ -186,6 +188,7 @@ static void cs5536_set_dma_mode(ide_drive_t *drive, const u8 mode) struct pci_dev *pdev = to_pci_dev(drive->hwif->dev); int dshift = (drive->dn & 1) ? IDE_D1_SHIFT : IDE_D0_SHIFT; + unsigned long timings = (unsigned long)ide_get_drivedata(drive); u32 etc; cs5536_read(pdev, ETC, &etc); @@ -195,8 +198,9 @@ static void cs5536_set_dma_mode(ide_drive_t *drive, const u8 mode) etc |= udma_timings[mode - XFER_UDMA_0] << dshift; } else { /* MWDMA */ etc &= ~(IDE_ETC_UDMA_MASK << dshift); - drive->drive_data &= IDE_DRV_MASK; - drive->drive_data |= mwdma_timings[mode - XFER_MW_DMA_0] << 8; + timings &= IDE_DRV_MASK; + timings |= mwdma_timings[mode - XFER_MW_DMA_0] << 8; + ide_set_drivedata(drive, (void *)timings); } cs5536_write(pdev, ETC, etc); @@ -204,9 +208,11 @@ static void cs5536_set_dma_mode(ide_drive_t *drive, const u8 mode) static void cs5536_dma_start(ide_drive_t *drive) { + unsigned long timings = (unsigned long)ide_get_drivedata(drive); + if (drive->current_speed < XFER_UDMA_0 && - (drive->drive_data >> 8) != (drive->drive_data & IDE_DRV_MASK)) - cs5536_program_dtc(drive, drive->drive_data >> 8); + (timings >> 8) != (timings & IDE_DRV_MASK)) + cs5536_program_dtc(drive, timings >> 8); ide_dma_start(drive); } @@ -214,10 +220,11 @@ static void cs5536_dma_start(ide_drive_t *drive) static int cs5536_dma_end(ide_drive_t *drive) { int ret = ide_dma_end(drive); + unsigned long timings = (unsigned long)ide_get_drivedata(drive); if (drive->current_speed < XFER_UDMA_0 && - (drive->drive_data >> 8) != (drive->drive_data & IDE_DRV_MASK)) - cs5536_program_dtc(drive, drive->drive_data & IDE_DRV_MASK); + (timings >> 8) != (timings & IDE_DRV_MASK)) + cs5536_program_dtc(drive, timings & IDE_DRV_MASK); return ret; } diff --git a/drivers/ide/falconide.c b/drivers/ide/falconide.c index 22fa27389c3b..a5a07ccb81a7 100644 --- a/drivers/ide/falconide.c +++ b/drivers/ide/falconide.c @@ -128,7 +128,6 @@ static void __init falconide_setup_ports(struct ide_hw *hw) hw->io_ports.ctl_addr = ATA_HD_BASE + ATA_HD_CONTROL; hw->irq = IRQ_MFP_IDE; - hw->ack_intr = NULL; } /* diff --git a/drivers/ide/gayle.c b/drivers/ide/gayle.c index 4451a6a5dfe0..b9e517de6a82 100644 --- a/drivers/ide/gayle.c +++ b/drivers/ide/gayle.c @@ -66,7 +66,7 @@ MODULE_PARM_DESC(doubler, "enable support for IDE doublers"); * Check and acknowledge the interrupt status */ -static int gayle_ack_intr_a4000(ide_hwif_t *hwif) +static int gayle_test_irq(ide_hwif_t *hwif) { unsigned char ch; @@ -76,21 +76,16 @@ static int gayle_ack_intr_a4000(ide_hwif_t *hwif) return 1; } -static int gayle_ack_intr_a1200(ide_hwif_t *hwif) +static void gayle_a1200_clear_irq(ide_drive_t *drive) { - unsigned char ch; + ide_hwif_t *hwif = drive->hwif; - ch = z_readb(hwif->io_ports.irq_addr); - if (!(ch & GAYLE_IRQ_IDE)) - return 0; (void)z_readb(hwif->io_ports.status_addr); z_writeb(0x7c, hwif->io_ports.irq_addr); - return 1; } static void __init gayle_setup_ports(struct ide_hw *hw, unsigned long base, - unsigned long ctl, unsigned long irq_port, - ide_ack_intr_t *ack_intr) + unsigned long ctl, unsigned long irq_port) { int i; @@ -105,9 +100,17 @@ static void __init gayle_setup_ports(struct ide_hw *hw, unsigned long base, hw->io_ports.irq_addr = irq_port; hw->irq = IRQ_AMIGA_PORTS; - hw->ack_intr = ack_intr; } +static const struct ide_port_ops gayle_a4000_port_ops = { + .test_irq = gayle_test_irq, +}; + +static const struct ide_port_ops gayle_a1200_port_ops = { + .clear_irq = gayle_a1200_clear_irq, + .test_irq = gayle_test_irq, +}; + static const struct ide_port_info gayle_port_info = { .host_flags = IDE_HFLAG_MMIO | IDE_HFLAG_SERIALIZE | IDE_HFLAG_NO_DMA, @@ -123,9 +126,9 @@ static int __init gayle_init(void) { unsigned long phys_base, res_start, res_n; unsigned long base, ctrlport, irqport; - ide_ack_intr_t *ack_intr; int a4000, i, rc; struct ide_hw hw[GAYLE_NUM_HWIFS], *hws[GAYLE_NUM_HWIFS]; + struct ide_port_info d = gayle_port_info; if (!MACH_IS_AMIGA) return -ENODEV; @@ -148,11 +151,11 @@ found: if (a4000) { phys_base = GAYLE_BASE_4000; irqport = (unsigned long)ZTWO_VADDR(GAYLE_IRQ_4000); - ack_intr = gayle_ack_intr_a4000; + d.port_ops = &gayle_a4000_port_ops; } else { phys_base = GAYLE_BASE_1200; irqport = (unsigned long)ZTWO_VADDR(GAYLE_IRQ_1200); - ack_intr = gayle_ack_intr_a1200; + d.port_ops = &gayle_a1200_port_ops; } res_start = ((unsigned long)phys_base) & ~(GAYLE_NEXT_PORT-1); @@ -165,12 +168,12 @@ found: base = (unsigned long)ZTWO_VADDR(phys_base + i * GAYLE_NEXT_PORT); ctrlport = GAYLE_HAS_CONTROL_REG ? (base + GAYLE_CONTROL) : 0; - gayle_setup_ports(&hw[i], base, ctrlport, irqport, ack_intr); + gayle_setup_ports(&hw[i], base, ctrlport, irqport); hws[i] = &hw[i]; } - rc = ide_host_add(&gayle_port_info, hws, i, NULL); + rc = ide_host_add(&d, hws, i, NULL); if (rc) release_mem_region(res_start, res_n); diff --git a/drivers/ide/ht6560b.c b/drivers/ide/ht6560b.c index 2fb0f2965009..aafed8060e17 100644 --- a/drivers/ide/ht6560b.c +++ b/drivers/ide/ht6560b.c @@ -44,7 +44,12 @@ * bit3 (0x08): "1" 3 cycle time, "0" 2 cycle time (?) */ #define HT_CONFIG_PORT 0x3e6 -#define HT_CONFIG(drivea) (u8)(((drivea)->drive_data & 0xff00) >> 8) + +static inline u8 HT_CONFIG(ide_drive_t *drive) +{ + return ((unsigned long)ide_get_drivedata(drive) & 0xff00) >> 8; +} + /* * FIFO + PREFETCH (both a/b-model) */ @@ -90,7 +95,11 @@ * Active Time for each drive. Smaller value gives higher speed. * In case of failures you should probably fall back to a higher value. */ -#define HT_TIMING(drivea) (u8)((drivea)->drive_data & 0x00ff) +static inline u8 HT_TIMING(ide_drive_t *drive) +{ + return (unsigned long)ide_get_drivedata(drive) & 0x00ff; +} + #define HT_TIMING_DEFAULT 0xff /* @@ -242,23 +251,27 @@ static DEFINE_SPINLOCK(ht6560b_lock); */ static void ht_set_prefetch(ide_drive_t *drive, u8 state) { - unsigned long flags; + unsigned long flags, config; int t = HT_PREFETCH_MODE << 8; spin_lock_irqsave(&ht6560b_lock, flags); + config = (unsigned long)ide_get_drivedata(drive); + /* * Prefetch mode and unmask irq seems to conflict */ if (state) { - drive->drive_data |= t; /* enable prefetch mode */ + config |= t; /* enable prefetch mode */ drive->dev_flags |= IDE_DFLAG_NO_UNMASK; drive->dev_flags &= ~IDE_DFLAG_UNMASK; } else { - drive->drive_data &= ~t; /* disable prefetch mode */ + config &= ~t; /* disable prefetch mode */ drive->dev_flags &= ~IDE_DFLAG_NO_UNMASK; } + ide_set_drivedata(drive, (void *)config); + spin_unlock_irqrestore(&ht6560b_lock, flags); #ifdef DEBUG @@ -268,7 +281,7 @@ static void ht_set_prefetch(ide_drive_t *drive, u8 state) static void ht6560b_set_pio_mode(ide_drive_t *drive, const u8 pio) { - unsigned long flags; + unsigned long flags, config; u8 timing; switch (pio) { @@ -281,8 +294,10 @@ static void ht6560b_set_pio_mode(ide_drive_t *drive, const u8 pio) timing = ht_pio2timings(drive, pio); spin_lock_irqsave(&ht6560b_lock, flags); - drive->drive_data &= 0xff00; - drive->drive_data |= timing; + config = (unsigned long)ide_get_drivedata(drive); + config &= 0xff00; + config |= timing; + ide_set_drivedata(drive, (void *)config); spin_unlock_irqrestore(&ht6560b_lock, flags); #ifdef DEBUG @@ -299,7 +314,7 @@ static void __init ht6560b_init_dev(ide_drive_t *drive) if (hwif->channel) t |= (HT_SECONDARY_IF << 8); - drive->drive_data = t; + ide_set_drivedata(drive, (void *)t); } static int probe_ht6560b; diff --git a/drivers/ide/icside.c b/drivers/ide/icside.c index 5af3d0ffaf0a..0f67f1abbbd3 100644 --- a/drivers/ide/icside.c +++ b/drivers/ide/icside.c @@ -187,7 +187,8 @@ static const expansioncard_ops_t icside_ops_arcin_v6 = { */ static void icside_set_dma_mode(ide_drive_t *drive, const u8 xfer_mode) { - int cycle_time, use_dma_info = 0; + unsigned long cycle_time; + int use_dma_info = 0; switch (xfer_mode) { case XFER_MW_DMA_2: @@ -218,10 +219,11 @@ static void icside_set_dma_mode(ide_drive_t *drive, const u8 xfer_mode) if (use_dma_info && drive->id[ATA_ID_EIDE_DMA_TIME] > cycle_time) cycle_time = drive->id[ATA_ID_EIDE_DMA_TIME]; - drive->drive_data = cycle_time; + ide_set_drivedata(drive, (void *)cycle_time); printk("%s: %s selected (peak %dMB/s)\n", drive->name, - ide_xfer_verbose(xfer_mode), 2000 / drive->drive_data); + ide_xfer_verbose(xfer_mode), + 2000 / (unsigned long)ide_get_drivedata(drive)); } static const struct ide_port_ops icside_v6_port_ops = { @@ -277,7 +279,7 @@ static int icside_dma_setup(ide_drive_t *drive, struct ide_cmd *cmd) /* * Select the correct timing for this drive. */ - set_dma_speed(ec->dma, drive->drive_data); + set_dma_speed(ec->dma, (unsigned long)ide_get_drivedata(drive)); /* * Tell the DMA engine about the SG table and diff --git a/drivers/ide/ide-atapi.c b/drivers/ide/ide-atapi.c index 702ef64a0f12..eb2181a6a11c 100644 --- a/drivers/ide/ide-atapi.c +++ b/drivers/ide/ide-atapi.c @@ -10,6 +10,9 @@ #include <scsi/scsi.h> +#define DRV_NAME "ide-atapi" +#define PFX DRV_NAME ": " + #ifdef DEBUG #define debug_log(fmt, args...) \ printk(KERN_INFO "ide: " fmt, ## args) @@ -74,8 +77,6 @@ EXPORT_SYMBOL_GPL(ide_check_atapi_device); void ide_init_pc(struct ide_atapi_pc *pc) { memset(pc, 0, sizeof(*pc)); - pc->buf = pc->pc_buf; - pc->buf_size = IDE_PC_BUFFER_SIZE; } EXPORT_SYMBOL_GPL(ide_init_pc); @@ -84,7 +85,7 @@ EXPORT_SYMBOL_GPL(ide_init_pc); * and wait for it to be serviced. */ int ide_queue_pc_tail(ide_drive_t *drive, struct gendisk *disk, - struct ide_atapi_pc *pc) + struct ide_atapi_pc *pc, void *buf, unsigned int bufflen) { struct request *rq; int error; @@ -93,8 +94,8 @@ int ide_queue_pc_tail(ide_drive_t *drive, struct gendisk *disk, rq->cmd_type = REQ_TYPE_SPECIAL; rq->special = (char *)pc; - if (pc->req_xfer) { - error = blk_rq_map_kern(drive->queue, rq, pc->buf, pc->req_xfer, + if (buf && bufflen) { + error = blk_rq_map_kern(drive->queue, rq, buf, bufflen, GFP_NOIO); if (error) goto put_req; @@ -117,7 +118,7 @@ int ide_do_test_unit_ready(ide_drive_t *drive, struct gendisk *disk) ide_init_pc(&pc); pc.c[0] = TEST_UNIT_READY; - return ide_queue_pc_tail(drive, disk, &pc); + return ide_queue_pc_tail(drive, disk, &pc, NULL, 0); } EXPORT_SYMBOL_GPL(ide_do_test_unit_ready); @@ -132,7 +133,7 @@ int ide_do_start_stop(ide_drive_t *drive, struct gendisk *disk, int start) if (drive->media == ide_tape) pc.flags |= PC_FLAG_WAIT_FOR_DSC; - return ide_queue_pc_tail(drive, disk, &pc); + return ide_queue_pc_tail(drive, disk, &pc, NULL, 0); } EXPORT_SYMBOL_GPL(ide_do_start_stop); @@ -147,7 +148,7 @@ int ide_set_media_lock(ide_drive_t *drive, struct gendisk *disk, int on) pc.c[0] = ALLOW_MEDIUM_REMOVAL; pc.c[4] = on; - return ide_queue_pc_tail(drive, disk, &pc); + return ide_queue_pc_tail(drive, disk, &pc, NULL, 0); } EXPORT_SYMBOL_GPL(ide_set_media_lock); @@ -172,8 +173,6 @@ void ide_prep_sense(ide_drive_t *drive, struct request *rq) unsigned int cmd_len, sense_len; int err; - debug_log("%s: enter\n", __func__); - switch (drive->media) { case ide_floppy: cmd_len = 255; @@ -201,8 +200,8 @@ void ide_prep_sense(ide_drive_t *drive, struct request *rq) GFP_NOIO); if (unlikely(err)) { if (printk_ratelimit()) - printk(KERN_WARNING "%s: failed to map sense buffer\n", - drive->name); + printk(KERN_WARNING PFX "%s: failed to map sense " + "buffer\n", drive->name); return; } @@ -223,7 +222,7 @@ int ide_queue_sense_rq(ide_drive_t *drive, void *special) { /* deferred failure from ide_prep_sense() */ if (!drive->sense_rq_armed) { - printk(KERN_WARNING "%s: failed queue sense request\n", + printk(KERN_WARNING PFX "%s: error queuing a sense request\n", drive->name); return -ENOMEM; } @@ -255,8 +254,6 @@ void ide_retry_pc(ide_drive_t *drive) /* init pc from sense_rq */ ide_init_pc(pc); memcpy(pc->c, sense_rq->cmd, 12); - pc->buf = bio_data(sense_rq->bio); /* pointer to mapped address */ - pc->req_xfer = blk_rq_bytes(sense_rq); if (drive->media == ide_tape) drive->atapi_flags |= IDE_AFLAG_IGNORE_DSC; @@ -298,7 +295,7 @@ int ide_cd_expiry(ide_drive_t *drive) break; default: if (!(rq->cmd_flags & REQ_QUIET)) - printk(KERN_INFO "cmd 0x%x timed out\n", + printk(KERN_INFO PFX "cmd 0x%x timed out\n", rq->cmd[0]); wait = 0; break; @@ -332,6 +329,55 @@ void ide_read_bcount_and_ireason(ide_drive_t *drive, u16 *bcount, u8 *ireason) EXPORT_SYMBOL_GPL(ide_read_bcount_and_ireason); /* + * Check the contents of the interrupt reason register and attempt to recover if + * there are problems. + * + * Returns: + * - 0 if everything's ok + * - 1 if the request has to be terminated. + */ +int ide_check_ireason(ide_drive_t *drive, struct request *rq, int len, + int ireason, int rw) +{ + ide_hwif_t *hwif = drive->hwif; + + debug_log("ireason: 0x%x, rw: 0x%x\n", ireason, rw); + + if (ireason == (!rw << 1)) + return 0; + else if (ireason == (rw << 1)) { + printk(KERN_ERR PFX "%s: %s: wrong transfer direction!\n", + drive->name, __func__); + + if (dev_is_idecd(drive)) + ide_pad_transfer(drive, rw, len); + } else if (!rw && ireason == ATAPI_COD) { + if (dev_is_idecd(drive)) { + /* + * Some drives (ASUS) seem to tell us that status info + * is available. Just get it and ignore. + */ + (void)hwif->tp_ops->read_status(hwif); + return 0; + } + } else { + if (ireason & ATAPI_COD) + printk(KERN_ERR PFX "%s: CoD != 0 in %s\n", drive->name, + __func__); + + /* drive wants a command packet, or invalid ireason... */ + printk(KERN_ERR PFX "%s: %s: bad interrupt reason 0x%02x\n", + drive->name, __func__, ireason); + } + + if (dev_is_idecd(drive) && rq->cmd_type == REQ_TYPE_ATA_PC) + rq->cmd_flags |= REQ_FAILED; + + return 1; +} +EXPORT_SYMBOL_GPL(ide_check_ireason); + +/* * This is the usual interrupt handler which will be called during a packet * command. We will transfer some of the data (as requested by the drive) * and will re-point interrupt handler to us. @@ -365,12 +411,12 @@ static ide_startstop_t ide_pc_intr(ide_drive_t *drive) if (rc || (drive->media == ide_tape && (stat & ATA_ERR))) { if (drive->media == ide_floppy) - printk(KERN_ERR "%s: DMA %s error\n", + printk(KERN_ERR PFX "%s: DMA %s error\n", drive->name, rq_data_dir(pc->rq) ? "write" : "read"); pc->flags |= PC_FLAG_DMA_ERROR; } else - pc->xferred = pc->req_xfer; + rq->resid_len = 0; debug_log("%s: DMA finished\n", drive->name); } @@ -379,7 +425,7 @@ static ide_startstop_t ide_pc_intr(ide_drive_t *drive) int uptodate, error; debug_log("Packet command completed, %d bytes transferred\n", - pc->xferred); + blk_rq_bytes(rq)); pc->flags &= ~PC_FLAG_DMA_IN_PROGRESS; @@ -397,8 +443,8 @@ static ide_startstop_t ide_pc_intr(ide_drive_t *drive) pc->rq->errors++; if (rq->cmd[0] == REQUEST_SENSE) { - printk(KERN_ERR "%s: I/O error in request sense" - " command\n", drive->name); + printk(KERN_ERR PFX "%s: I/O error in request " + "sense command\n", drive->name); return ide_do_reset(drive); } @@ -446,8 +492,8 @@ static ide_startstop_t ide_pc_intr(ide_drive_t *drive) if (pc->flags & PC_FLAG_DMA_IN_PROGRESS) { pc->flags &= ~PC_FLAG_DMA_IN_PROGRESS; - printk(KERN_ERR "%s: The device wants to issue more interrupts " - "in DMA mode\n", drive->name); + printk(KERN_ERR PFX "%s: The device wants to issue more " + "interrupts in DMA mode\n", drive->name); ide_dma_off(drive); return ide_do_reset(drive); } @@ -455,33 +501,22 @@ static ide_startstop_t ide_pc_intr(ide_drive_t *drive) /* Get the number of bytes to transfer on this interrupt. */ ide_read_bcount_and_ireason(drive, &bcount, &ireason); - if (ireason & ATAPI_COD) { - printk(KERN_ERR "%s: CoD != 0 in %s\n", drive->name, __func__); + if (ide_check_ireason(drive, rq, bcount, ireason, write)) return ide_do_reset(drive); - } - - if (((ireason & ATAPI_IO) == ATAPI_IO) == write) { - /* Hopefully, we will never get here */ - printk(KERN_ERR "%s: We wanted to %s, but the device wants us " - "to %s!\n", drive->name, - (ireason & ATAPI_IO) ? "Write" : "Read", - (ireason & ATAPI_IO) ? "Read" : "Write"); - return ide_do_reset(drive); - } done = min_t(unsigned int, bcount, cmd->nleft); ide_pio_bytes(drive, cmd, write, done); /* Update transferred byte count */ - pc->xferred += done; + rq->resid_len -= done; bcount -= done; if (bcount) ide_pad_transfer(drive, write, bcount); - debug_log("[cmd %x] transferred %d bytes, padded %d bytes\n", - rq->cmd[0], done, bcount); + debug_log("[cmd %x] transferred %d bytes, padded %d bytes, resid: %u\n", + rq->cmd[0], done, bcount, rq->resid_len); /* And set the interrupt handler again */ ide_set_handler(drive, ide_pc_intr, timeout); @@ -515,13 +550,13 @@ static u8 ide_wait_ireason(ide_drive_t *drive, u8 ireason) while (retries-- && ((ireason & ATAPI_COD) == 0 || (ireason & ATAPI_IO))) { - printk(KERN_ERR "%s: (IO,CoD != (0,1) while issuing " + printk(KERN_ERR PFX "%s: (IO,CoD != (0,1) while issuing " "a packet command, retrying\n", drive->name); udelay(100); ireason = ide_read_ireason(drive); if (retries == 0) { - printk(KERN_ERR "%s: (IO,CoD != (0,1) while issuing " - "a packet command, ignoring\n", + printk(KERN_ERR PFX "%s: (IO,CoD != (0,1) while issuing" + " a packet command, ignoring\n", drive->name); ireason |= ATAPI_COD; ireason &= ~ATAPI_IO; @@ -552,7 +587,7 @@ static ide_startstop_t ide_transfer_pc(ide_drive_t *drive) u8 ireason; if (ide_wait_stat(&startstop, drive, ATA_DRQ, ATA_BUSY, WAIT_READY)) { - printk(KERN_ERR "%s: Strange, packet command initiated yet " + printk(KERN_ERR PFX "%s: Strange, packet command initiated yet " "DRQ isn't asserted\n", drive->name); return startstop; } @@ -594,8 +629,8 @@ static ide_startstop_t ide_transfer_pc(ide_drive_t *drive) ireason = ide_wait_ireason(drive, ireason); if ((ireason & ATAPI_COD) == 0 || (ireason & ATAPI_IO)) { - printk(KERN_ERR "%s: (IO,CoD) != (0,1) while issuing " - "a packet command\n", drive->name); + printk(KERN_ERR PFX "%s: (IO,CoD) != (0,1) while " + "issuing a packet command\n", drive->name); return ide_do_reset(drive); } @@ -633,7 +668,7 @@ ide_startstop_t ide_issue_pc(ide_drive_t *drive, struct ide_cmd *cmd) ide_hwif_t *hwif = drive->hwif; ide_expiry_t *expiry = NULL; struct request *rq = hwif->rq; - unsigned int timeout; + unsigned int timeout, bytes; u16 bcount; u8 valid_tf; u8 drq_int = !!(drive->atapi_flags & IDE_AFLAG_DRQ_INTERRUPT); @@ -649,13 +684,14 @@ ide_startstop_t ide_issue_pc(ide_drive_t *drive, struct ide_cmd *cmd) } else { pc = drive->pc; - /* We haven't transferred any data yet */ - pc->xferred = 0; - valid_tf = IDE_VALID_DEVICE; - bcount = ((drive->media == ide_tape) ? - pc->req_xfer : - min(pc->req_xfer, 63 * 1024)); + bytes = blk_rq_bytes(rq); + bcount = ((drive->media == ide_tape) ? bytes + : min_t(unsigned int, + bytes, 63 * 1024)); + + /* We haven't transferred any data yet */ + rq->resid_len = bcount; if (pc->flags & PC_FLAG_DMA_ERROR) { pc->flags &= ~PC_FLAG_DMA_ERROR; diff --git a/drivers/ide/ide-cd.c b/drivers/ide/ide-cd.c index 424140c6c400..4a19686fcfe9 100644 --- a/drivers/ide/ide-cd.c +++ b/drivers/ide/ide-cd.c @@ -92,16 +92,16 @@ static void cdrom_saw_media_change(ide_drive_t *drive) drive->atapi_flags &= ~IDE_AFLAG_TOC_VALID; } -static int cdrom_log_sense(ide_drive_t *drive, struct request *rq, - struct request_sense *sense) +static int cdrom_log_sense(ide_drive_t *drive, struct request *rq) { + struct request_sense *sense = &drive->sense_data; int log = 0; - ide_debug_log(IDE_DBG_SENSE, "sense_key: 0x%x", sense->sense_key); - if (!sense || !rq || (rq->cmd_flags & REQ_QUIET)) return 0; + ide_debug_log(IDE_DBG_SENSE, "sense_key: 0x%x", sense->sense_key); + switch (sense->sense_key) { case NO_SENSE: case RECOVERED_ERROR: @@ -140,12 +140,12 @@ static int cdrom_log_sense(ide_drive_t *drive, struct request *rq, } static void cdrom_analyze_sense_data(ide_drive_t *drive, - struct request *failed_command, - struct request_sense *sense) + struct request *failed_command) { + struct request_sense *sense = &drive->sense_data; + struct cdrom_info *info = drive->driver_data; unsigned long sector; unsigned long bio_sectors; - struct cdrom_info *info = drive->driver_data; ide_debug_log(IDE_DBG_SENSE, "error_code: 0x%x, sense_key: 0x%x", sense->error_code, sense->sense_key); @@ -154,7 +154,7 @@ static void cdrom_analyze_sense_data(ide_drive_t *drive, ide_debug_log(IDE_DBG_SENSE, "failed cmd: 0x%x", failed_command->cmd[0]); - if (!cdrom_log_sense(drive, failed_command, sense)) + if (!cdrom_log_sense(drive, failed_command)) return; /* @@ -225,15 +225,14 @@ static void ide_cd_complete_failed_rq(ide_drive_t *drive, struct request *rq) * sense pointer set. */ memcpy(failed->sense, sense, 18); - sense = failed->sense; failed->sense_len = rq->sense_len; } - cdrom_analyze_sense_data(drive, failed, sense); + cdrom_analyze_sense_data(drive, failed); if (ide_end_rq(drive, failed, -EIO, blk_rq_bytes(failed))) BUG(); } else - cdrom_analyze_sense_data(drive, NULL, sense); + cdrom_analyze_sense_data(drive, NULL); } @@ -410,50 +409,6 @@ end_request: return 2; } -/* - * Check the contents of the interrupt reason register from the cdrom - * and attempt to recover if there are problems. Returns 0 if everything's - * ok; nonzero if the request has been terminated. - */ -static int ide_cd_check_ireason(ide_drive_t *drive, struct request *rq, - int len, int ireason, int rw) -{ - ide_hwif_t *hwif = drive->hwif; - - ide_debug_log(IDE_DBG_FUNC, "ireason: 0x%x, rw: 0x%x", ireason, rw); - - /* - * ireason == 0: the drive wants to receive data from us - * ireason == 2: the drive is expecting to transfer data to us - */ - if (ireason == (!rw << 1)) - return 0; - else if (ireason == (rw << 1)) { - - /* whoops... */ - printk(KERN_ERR PFX "%s: %s: wrong transfer direction!\n", - drive->name, __func__); - - ide_pad_transfer(drive, rw, len); - } else if (rw == 0 && ireason == 1) { - /* - * Some drives (ASUS) seem to tell us that status info is - * available. Just get it and ignore. - */ - (void)hwif->tp_ops->read_status(hwif); - return 0; - } else { - /* drive wants a command packet, or invalid ireason... */ - printk(KERN_ERR PFX "%s: %s: bad interrupt reason 0x%02x\n", - drive->name, __func__, ireason); - } - - if (rq->cmd_type == REQ_TYPE_ATA_PC) - rq->cmd_flags |= REQ_FAILED; - - return -1; -} - static void ide_cd_request_sense_fixup(ide_drive_t *drive, struct ide_cmd *cmd) { struct request *rq = cmd->rq; @@ -645,8 +600,7 @@ static ide_startstop_t cdrom_newpc_intr(ide_drive_t *drive) goto out_end; } - /* check which way to transfer data */ - rc = ide_cd_check_ireason(drive, rq, len, ireason, write); + rc = ide_check_ireason(drive, rq, len, ireason, write); if (rc) goto out_end; @@ -713,7 +667,7 @@ out_end: rq->errors = -EIO; } - if (uptodate == 0) + if (uptodate == 0 && rq->bio) ide_cd_error_cmd(drive, cmd); /* make sure it's fully ended */ @@ -831,12 +785,8 @@ static ide_startstop_t ide_cd_do_request(ide_drive_t *drive, struct request *rq, /* right now this can only be a reset... */ uptodate = 1; goto out_end; - } else { - blk_dump_rq_flags(rq, DRV_NAME " bad flags"); - if (rq->errors == 0) - rq->errors = -EIO; - goto out_end; - } + } else + BUG(); /* prepare sense request for this command */ ide_prep_sense(drive, rq); diff --git a/drivers/ide/ide-disk.c b/drivers/ide/ide-disk.c index 6a1de2169709..695181120cdb 100644 --- a/drivers/ide/ide-disk.c +++ b/drivers/ide/ide-disk.c @@ -184,14 +184,7 @@ static ide_startstop_t ide_do_rw_disk(ide_drive_t *drive, struct request *rq, ide_hwif_t *hwif = drive->hwif; BUG_ON(drive->dev_flags & IDE_DFLAG_BLOCKED); - - if (!blk_fs_request(rq)) { - blk_dump_rq_flags(rq, "ide_do_rw_disk - bad command"); - if (rq->errors == 0) - rq->errors = -EIO; - ide_complete_rq(drive, -EIO, ide_rq_bytes(rq)); - return ide_stopped; - } + BUG_ON(!blk_fs_request(rq)); ledtrig_ide_activity(); diff --git a/drivers/ide/ide-floppy.c b/drivers/ide/ide-floppy.c index 650981758f15..8b3f204f7d73 100644 --- a/drivers/ide/ide-floppy.c +++ b/drivers/ide/ide-floppy.c @@ -77,7 +77,8 @@ static int ide_floppy_callback(ide_drive_t *drive, int dsc) (rq && blk_pc_request(rq))) uptodate = 1; /* FIXME */ else if (pc->c[0] == GPCMD_REQUEST_SENSE) { - u8 *buf = pc->buf; + + u8 *buf = bio_data(rq->bio); if (!pc->error) { floppy->sense_key = buf[2] & 0x0F; @@ -209,8 +210,7 @@ static void idefloppy_create_rw_cmd(ide_drive_t *drive, pc->rq = rq; if (rq->cmd_flags & REQ_RW) pc->flags |= PC_FLAG_WRITING; - pc->buf = NULL; - pc->req_xfer = pc->buf_size = blocks * floppy->block_size; + pc->flags |= PC_FLAG_DMA_OK; } @@ -225,9 +225,6 @@ static void idefloppy_blockpc_cmd(struct ide_disk_obj *floppy, if (rq_data_dir(rq) == WRITE) pc->flags |= PC_FLAG_WRITING; } - /* pio will be performed by ide_pio_bytes() which handles sg fine */ - pc->buf = NULL; - pc->req_xfer = pc->buf_size = blk_rq_bytes(rq); } static ide_startstop_t ide_floppy_do_request(ide_drive_t *drive, @@ -272,10 +269,8 @@ static ide_startstop_t ide_floppy_do_request(ide_drive_t *drive, } else if (blk_pc_request(rq)) { pc = &floppy->queued_pc; idefloppy_blockpc_cmd(floppy, pc, rq); - } else { - blk_dump_rq_flags(rq, PFX "unsupported command in queue"); - goto out_end; - } + } else + BUG(); ide_prep_sense(drive, rq); @@ -286,8 +281,8 @@ static ide_startstop_t ide_floppy_do_request(ide_drive_t *drive, cmd.rq = rq; - if (blk_fs_request(rq) || pc->req_xfer) { - ide_init_sg_cmd(&cmd, pc->req_xfer); + if (blk_fs_request(rq) || blk_rq_bytes(rq)) { + ide_init_sg_cmd(&cmd, blk_rq_bytes(rq)); ide_map_sg(drive, &cmd); } @@ -311,33 +306,33 @@ static int ide_floppy_get_flexible_disk_page(ide_drive_t *drive, { struct ide_disk_obj *floppy = drive->driver_data; struct gendisk *disk = floppy->disk; - u8 *page; + u8 *page, buf[40]; int capacity, lba_capacity; u16 transfer_rate, sector_size, cyls, rpm; u8 heads, sectors; ide_floppy_create_mode_sense_cmd(pc, IDEFLOPPY_FLEXIBLE_DISK_PAGE); - if (ide_queue_pc_tail(drive, disk, pc)) { + if (ide_queue_pc_tail(drive, disk, pc, buf, pc->req_xfer)) { printk(KERN_ERR PFX "Can't get flexible disk page params\n"); return 1; } - if (pc->buf[3] & 0x80) + if (buf[3] & 0x80) drive->dev_flags |= IDE_DFLAG_WP; else drive->dev_flags &= ~IDE_DFLAG_WP; set_disk_ro(disk, !!(drive->dev_flags & IDE_DFLAG_WP)); - page = &pc->buf[8]; + page = &buf[8]; - transfer_rate = be16_to_cpup((__be16 *)&pc->buf[8 + 2]); - sector_size = be16_to_cpup((__be16 *)&pc->buf[8 + 6]); - cyls = be16_to_cpup((__be16 *)&pc->buf[8 + 8]); - rpm = be16_to_cpup((__be16 *)&pc->buf[8 + 28]); - heads = pc->buf[8 + 4]; - sectors = pc->buf[8 + 5]; + transfer_rate = be16_to_cpup((__be16 *)&buf[8 + 2]); + sector_size = be16_to_cpup((__be16 *)&buf[8 + 6]); + cyls = be16_to_cpup((__be16 *)&buf[8 + 8]); + rpm = be16_to_cpup((__be16 *)&buf[8 + 28]); + heads = buf[8 + 4]; + sectors = buf[8 + 5]; capacity = cyls * heads * sectors * sector_size; @@ -387,22 +382,19 @@ static int ide_floppy_get_capacity(ide_drive_t *drive) drive->capacity64 = 0; ide_floppy_create_read_capacity_cmd(&pc); - pc.buf = &pc_buf[0]; - pc.buf_size = sizeof(pc_buf); - - if (ide_queue_pc_tail(drive, disk, &pc)) { + if (ide_queue_pc_tail(drive, disk, &pc, pc_buf, pc.req_xfer)) { printk(KERN_ERR PFX "Can't get floppy parameters\n"); return 1; } - header_len = pc.buf[3]; - cap_desc = &pc.buf[4]; + header_len = pc_buf[3]; + cap_desc = &pc_buf[4]; desc_cnt = header_len / 8; /* capacity descriptor of 8 bytes */ for (i = 0; i < desc_cnt; i++) { unsigned int desc_start = 4 + i*8; - blocks = be32_to_cpup((__be32 *)&pc.buf[desc_start]); - length = be16_to_cpup((__be16 *)&pc.buf[desc_start + 6]); + blocks = be32_to_cpup((__be32 *)&pc_buf[desc_start]); + length = be16_to_cpup((__be16 *)&pc_buf[desc_start + 6]); ide_debug_log(IDE_DBG_PROBE, "Descriptor %d: %dkB, %d blocks, " "%d sector size", @@ -415,7 +407,7 @@ static int ide_floppy_get_capacity(ide_drive_t *drive) * the code below is valid only for the 1st descriptor, ie i=0 */ - switch (pc.buf[desc_start + 4] & 0x03) { + switch (pc_buf[desc_start + 4] & 0x03) { /* Clik! drive returns this instead of CAPACITY_CURRENT */ case CAPACITY_UNFORMATTED: if (!(drive->atapi_flags & IDE_AFLAG_CLIK_DRIVE)) @@ -464,7 +456,7 @@ static int ide_floppy_get_capacity(ide_drive_t *drive) break; } ide_debug_log(IDE_DBG_PROBE, "Descriptor 0 Code: %d", - pc.buf[desc_start + 4] & 0x03); + pc_buf[desc_start + 4] & 0x03); } /* Clik! disk does not support get_flexible_disk_page */ diff --git a/drivers/ide/ide-floppy_ioctl.c b/drivers/ide/ide-floppy_ioctl.c index cd8a42027ede..9c2288234dea 100644 --- a/drivers/ide/ide-floppy_ioctl.c +++ b/drivers/ide/ide-floppy_ioctl.c @@ -47,15 +47,13 @@ static int ide_floppy_get_format_capacities(ide_drive_t *drive, return -EINVAL; ide_floppy_create_read_capacity_cmd(pc); - pc->buf = &pc_buf[0]; - pc->buf_size = sizeof(pc_buf); - if (ide_queue_pc_tail(drive, floppy->disk, pc)) { + if (ide_queue_pc_tail(drive, floppy->disk, pc, pc_buf, pc->req_xfer)) { printk(KERN_ERR "ide-floppy: Can't get floppy parameters\n"); return -EIO; } - header_len = pc->buf[3]; + header_len = pc_buf[3]; desc_cnt = header_len / 8; /* capacity descriptor of 8 bytes */ u_index = 0; @@ -72,8 +70,8 @@ static int ide_floppy_get_format_capacities(ide_drive_t *drive, if (u_index >= u_array_size) break; /* User-supplied buffer too small */ - blocks = be32_to_cpup((__be32 *)&pc->buf[desc_start]); - length = be16_to_cpup((__be16 *)&pc->buf[desc_start + 6]); + blocks = be32_to_cpup((__be32 *)&pc_buf[desc_start]); + length = be16_to_cpup((__be16 *)&pc_buf[desc_start + 6]); if (put_user(blocks, argp)) return -EFAULT; @@ -94,40 +92,42 @@ static int ide_floppy_get_format_capacities(ide_drive_t *drive, return 0; } -static void ide_floppy_create_format_unit_cmd(struct ide_atapi_pc *pc, int b, - int l, int flags) +static void ide_floppy_create_format_unit_cmd(struct ide_atapi_pc *pc, + u8 *buf, int b, int l, + int flags) { ide_init_pc(pc); pc->c[0] = GPCMD_FORMAT_UNIT; pc->c[1] = 0x17; - memset(pc->buf, 0, 12); - pc->buf[1] = 0xA2; + memset(buf, 0, 12); + buf[1] = 0xA2; /* Default format list header, u8 1: FOV/DCRT/IMM bits set */ if (flags & 1) /* Verify bit on... */ - pc->buf[1] ^= 0x20; /* ... turn off DCRT bit */ - pc->buf[3] = 8; + buf[1] ^= 0x20; /* ... turn off DCRT bit */ + buf[3] = 8; - put_unaligned(cpu_to_be32(b), (unsigned int *)(&pc->buf[4])); - put_unaligned(cpu_to_be32(l), (unsigned int *)(&pc->buf[8])); - pc->buf_size = 12; + put_unaligned(cpu_to_be32(b), (unsigned int *)(&buf[4])); + put_unaligned(cpu_to_be32(l), (unsigned int *)(&buf[8])); + pc->req_xfer = 12; pc->flags |= PC_FLAG_WRITING; } static int ide_floppy_get_sfrp_bit(ide_drive_t *drive, struct ide_atapi_pc *pc) { struct ide_disk_obj *floppy = drive->driver_data; + u8 buf[20]; drive->atapi_flags &= ~IDE_AFLAG_SRFP; ide_floppy_create_mode_sense_cmd(pc, IDEFLOPPY_CAPABILITIES_PAGE); pc->flags |= PC_FLAG_SUPPRESS_ERROR; - if (ide_queue_pc_tail(drive, floppy->disk, pc)) + if (ide_queue_pc_tail(drive, floppy->disk, pc, buf, pc->req_xfer)) return 1; - if (pc->buf[8 + 2] & 0x40) + if (buf[8 + 2] & 0x40) drive->atapi_flags |= IDE_AFLAG_SRFP; return 0; @@ -137,6 +137,7 @@ static int ide_floppy_format_unit(ide_drive_t *drive, struct ide_atapi_pc *pc, int __user *arg) { struct ide_disk_obj *floppy = drive->driver_data; + u8 buf[12]; int blocks, length, flags, err = 0; if (floppy->openers > 1) { @@ -170,9 +171,9 @@ static int ide_floppy_format_unit(ide_drive_t *drive, struct ide_atapi_pc *pc, } ide_floppy_get_sfrp_bit(drive, pc); - ide_floppy_create_format_unit_cmd(pc, blocks, length, flags); + ide_floppy_create_format_unit_cmd(pc, buf, blocks, length, flags); - if (ide_queue_pc_tail(drive, floppy->disk, pc)) + if (ide_queue_pc_tail(drive, floppy->disk, pc, buf, pc->req_xfer)) err = -EIO; out: @@ -196,11 +197,13 @@ static int ide_floppy_get_format_progress(ide_drive_t *drive, int __user *arg) { struct ide_disk_obj *floppy = drive->driver_data; + u8 sense_buf[18]; int progress_indication = 0x10000; if (drive->atapi_flags & IDE_AFLAG_SRFP) { ide_create_request_sense_cmd(drive, pc); - if (ide_queue_pc_tail(drive, floppy->disk, pc)) + if (ide_queue_pc_tail(drive, floppy->disk, pc, sense_buf, + pc->req_xfer)) return -EIO; if (floppy->sense_key == 2 && diff --git a/drivers/ide/ide-io.c b/drivers/ide/ide-io.c index 272cc38f6dbe..1059f809b809 100644 --- a/drivers/ide/ide-io.c +++ b/drivers/ide/ide-io.c @@ -683,8 +683,9 @@ void ide_timer_expiry (unsigned long data) } else if (drive_is_ready(drive)) { if (drive->waiting_for_dma) hwif->dma_ops->dma_lost_irq(drive); - if (hwif->ack_intr) - hwif->ack_intr(hwif); + if (hwif->port_ops && hwif->port_ops->clear_irq) + hwif->port_ops->clear_irq(drive); + printk(KERN_WARNING "%s: lost interrupt\n", drive->name); startstop = handler(drive); @@ -803,7 +804,8 @@ irqreturn_t ide_intr (int irq, void *dev_id) spin_lock_irqsave(&hwif->lock, flags); - if (hwif->ack_intr && hwif->ack_intr(hwif) == 0) + if (hwif->port_ops && hwif->port_ops->test_irq && + hwif->port_ops->test_irq(hwif) == 0) goto out; handler = hwif->handler; diff --git a/drivers/ide/ide-ioctls.c b/drivers/ide/ide-ioctls.c index 5991b23793f2..82f252c3ee6e 100644 --- a/drivers/ide/ide-ioctls.c +++ b/drivers/ide/ide-ioctls.c @@ -118,7 +118,6 @@ static int ide_cmd_ioctl(ide_drive_t *drive, unsigned long arg) u8 args[4], xfer_rate = 0; struct ide_cmd cmd; struct ide_taskfile *tf = &cmd.tf; - u16 *id = drive->id; if (NULL == (void *) arg) { struct request *rq; @@ -161,14 +160,10 @@ static int ide_cmd_ioctl(ide_drive_t *drive, unsigned long arg) if (tf->command == ATA_CMD_SET_FEATURES && tf->feature == SETFEATURES_XFER && - tf->nsect >= XFER_SW_DMA_0 && - (id[ATA_ID_UDMA_MODES] || - id[ATA_ID_MWDMA_MODES] || - id[ATA_ID_SWDMA_MODES])) { - xfer_rate = args[1]; - if (tf->nsect > XFER_UDMA_2 && !eighty_ninty_three(drive)) { - printk(KERN_WARNING "%s: UDMA speeds >UDMA33 cannot " - "be set\n", drive->name); + tf->nsect >= XFER_SW_DMA_0) { + xfer_rate = ide_find_dma_mode(drive, XFER_UDMA_6); + if (xfer_rate != tf->nsect) { + err = -EINVAL; goto abort; } } diff --git a/drivers/ide/ide-probe.c b/drivers/ide/ide-probe.c index 79e0af3fd158..51af4eea0d36 100644 --- a/drivers/ide/ide-probe.c +++ b/drivers/ide/ide-probe.c @@ -1170,7 +1170,6 @@ static void ide_init_port_hw(ide_hwif_t *hwif, struct ide_hw *hw) hwif->irq = hw->irq; hwif->dev = hw->dev; hwif->gendev.parent = hw->parent ? hw->parent : hw->dev; - hwif->ack_intr = hw->ack_intr; hwif->config_data = hw->config; } @@ -1378,6 +1377,9 @@ int ide_host_register(struct ide_host *host, const struct ide_port_info *d, ide_init_port(hwif, i & 1, d); ide_port_cable_detect(hwif); + + hwif->port_flags |= IDE_PFLAG_PROBING; + ide_port_init_devices(hwif); } @@ -1388,6 +1390,8 @@ int ide_host_register(struct ide_host *host, const struct ide_port_info *d, if (ide_probe_port(hwif) == 0) hwif->present = 1; + hwif->port_flags &= ~IDE_PFLAG_PROBING; + if ((hwif->host_flags & IDE_HFLAG_4DRIVES) == 0 || hwif->mate == NULL || hwif->mate->present == 0) { if (ide_register_port(hwif)) { @@ -1569,11 +1573,20 @@ EXPORT_SYMBOL_GPL(ide_host_remove); void ide_port_scan(ide_hwif_t *hwif) { + int rc; + ide_port_apply_params(hwif); ide_port_cable_detect(hwif); + + hwif->port_flags |= IDE_PFLAG_PROBING; + ide_port_init_devices(hwif); - if (ide_probe_port(hwif) < 0) + rc = ide_probe_port(hwif); + + hwif->port_flags &= ~IDE_PFLAG_PROBING; + + if (rc < 0) return; hwif->present = 1; diff --git a/drivers/ide/ide-tape.c b/drivers/ide/ide-tape.c index 4b447a8a49d4..013dc595fab6 100644 --- a/drivers/ide/ide-tape.c +++ b/drivers/ide/ide-tape.c @@ -279,10 +279,12 @@ static void ide_tape_put(struct ide_tape_obj *tape) * called on each failed packet command retry to analyze the request sense. We * currently do not utilize this information. */ -static void idetape_analyze_error(ide_drive_t *drive, u8 *sense) +static void idetape_analyze_error(ide_drive_t *drive) { idetape_tape_t *tape = drive->driver_data; struct ide_atapi_pc *pc = drive->failed_pc; + struct request *rq = drive->hwif->rq; + u8 *sense = bio_data(rq->bio); tape->sense_key = sense[2] & 0xF; tape->asc = sense[12]; @@ -291,11 +293,9 @@ static void idetape_analyze_error(ide_drive_t *drive, u8 *sense) debug_log(DBG_ERR, "pc = %x, sense key = %x, asc = %x, ascq = %x\n", pc->c[0], tape->sense_key, tape->asc, tape->ascq); - /* Correct pc->xferred by asking the tape. */ + /* correct remaining bytes to transfer */ if (pc->flags & PC_FLAG_DMA_ERROR) - pc->xferred = pc->req_xfer - - tape->blk_size * - get_unaligned_be32(&sense[3]); + rq->resid_len = tape->blk_size * get_unaligned_be32(&sense[3]); /* * If error was the result of a zero-length read or write command, @@ -329,7 +329,7 @@ static void idetape_analyze_error(ide_drive_t *drive, u8 *sense) pc->flags |= PC_FLAG_ABORT; } if (!(pc->flags & PC_FLAG_ABORT) && - pc->xferred) + (blk_rq_bytes(rq) - rq->resid_len)) pc->retries = IDETAPE_MAX_PC_RETRIES + 1; } } @@ -354,12 +354,13 @@ static int ide_tape_callback(ide_drive_t *drive, int dsc) if (pc->c[0] == REQUEST_SENSE) { if (uptodate) - idetape_analyze_error(drive, pc->buf); + idetape_analyze_error(drive); else printk(KERN_ERR "ide-tape: Error in REQUEST SENSE " "itself - Aborting request!\n"); } else if (pc->c[0] == READ_6 || pc->c[0] == WRITE_6) { - int blocks = pc->xferred / tape->blk_size; + unsigned int blocks = + (blk_rq_bytes(rq) - rq->resid_len) / tape->blk_size; tape->avg_size += blocks * tape->blk_size; @@ -371,38 +372,12 @@ static int ide_tape_callback(ide_drive_t *drive, int dsc) } tape->first_frame += blocks; - rq->resid_len -= blocks * tape->blk_size; if (pc->error) { uptodate = 0; err = pc->error; } - } else if (pc->c[0] == READ_POSITION && uptodate) { - u8 *readpos = pc->buf; - - debug_log(DBG_SENSE, "BOP - %s\n", - (readpos[0] & 0x80) ? "Yes" : "No"); - debug_log(DBG_SENSE, "EOP - %s\n", - (readpos[0] & 0x40) ? "Yes" : "No"); - - if (readpos[0] & 0x4) { - printk(KERN_INFO "ide-tape: Block location is unknown" - "to the tape\n"); - clear_bit(ilog2(IDE_AFLAG_ADDRESS_VALID), - &drive->atapi_flags); - uptodate = 0; - err = IDE_DRV_ERROR_GENERAL; - } else { - debug_log(DBG_SENSE, "Block Location - %u\n", - be32_to_cpup((__be32 *)&readpos[4])); - - tape->partition = readpos[1]; - tape->first_frame = be32_to_cpup((__be32 *)&readpos[4]); - set_bit(ilog2(IDE_AFLAG_ADDRESS_VALID), - &drive->atapi_flags); - } } - rq->errors = err; return uptodate; @@ -477,6 +452,7 @@ static ide_startstop_t ide_tape_issue_pc(ide_drive_t *drive, struct ide_atapi_pc *pc) { idetape_tape_t *tape = drive->driver_data; + struct request *rq = drive->hwif->rq; if (drive->failed_pc == NULL && pc->c[0] != REQUEST_SENSE) drive->failed_pc = pc; @@ -486,7 +462,6 @@ static ide_startstop_t ide_tape_issue_pc(ide_drive_t *drive, if (pc->retries > IDETAPE_MAX_PC_RETRIES || (pc->flags & PC_FLAG_ABORT)) { - unsigned int done = blk_rq_bytes(drive->hwif->rq); /* * We will "abort" retrying a packet command in case legitimate @@ -510,7 +485,7 @@ static ide_startstop_t ide_tape_issue_pc(ide_drive_t *drive, drive->failed_pc = NULL; drive->pc_callback(drive, 0); - ide_complete_rq(drive, -EIO, done); + ide_complete_rq(drive, -EIO, blk_rq_bytes(rq)); return ide_stopped; } debug_log(DBG_SENSE, "Retry #%d, cmd = %02X\n", pc->retries, pc->c[0]); @@ -579,15 +554,13 @@ static void ide_tape_create_rw_cmd(idetape_tape_t *tape, struct ide_atapi_pc *pc, struct request *rq, u8 opcode) { - unsigned int length = blk_rq_sectors(rq); + unsigned int length = blk_rq_sectors(rq) / (tape->blk_size >> 9); ide_init_pc(pc); put_unaligned(cpu_to_be32(length), (unsigned int *) &pc->c[1]); pc->c[1] = 1; - pc->buf = NULL; - pc->buf_size = length * tape->blk_size; - pc->req_xfer = pc->buf_size; - if (pc->req_xfer == tape->buffer_size) + + if (blk_rq_bytes(rq) == tape->buffer_size) pc->flags |= PC_FLAG_DMA_OK; if (opcode == READ_6) @@ -613,15 +586,7 @@ static ide_startstop_t idetape_do_request(ide_drive_t *drive, debug_log(DBG_SENSE, "sector: %llu, nr_sectors: %u\n" (unsigned long long)blk_rq_pos(rq), blk_rq_sectors(rq)); - if (!(blk_special_request(rq) || blk_sense_request(rq))) { - /* We do not support buffer cache originated requests. */ - printk(KERN_NOTICE "ide-tape: %s: Unsupported request in " - "request queue (%d)\n", drive->name, rq->cmd_type); - if (blk_fs_request(rq) == 0 && rq->errors == 0) - rq->errors = -EIO; - ide_complete_rq(drive, -EIO, ide_rq_bytes(rq)); - return ide_stopped; - } + BUG_ON(!(blk_special_request(rq) || blk_sense_request(rq))); /* Retry a failed packet command */ if (drive->failed_pc && drive->pc->c[0] == REQUEST_SENSE) { @@ -713,7 +678,7 @@ out: cmd.rq = rq; - ide_init_sg_cmd(&cmd, pc->req_xfer); + ide_init_sg_cmd(&cmd, blk_rq_bytes(rq)); ide_map_sg(drive, &cmd); return ide_tape_issue_pc(drive, &cmd, pc); @@ -767,33 +732,53 @@ static int idetape_flush_tape_buffers(ide_drive_t *drive) int rc; idetape_create_write_filemark_cmd(drive, &pc, 0); - rc = ide_queue_pc_tail(drive, tape->disk, &pc); + rc = ide_queue_pc_tail(drive, tape->disk, &pc, NULL, 0); if (rc) return rc; idetape_wait_ready(drive, 60 * 5 * HZ); return 0; } -static void idetape_create_read_position_cmd(struct ide_atapi_pc *pc) -{ - ide_init_pc(pc); - pc->c[0] = READ_POSITION; - pc->req_xfer = 20; -} - -static int idetape_read_position(ide_drive_t *drive) +static int ide_tape_read_position(ide_drive_t *drive) { idetape_tape_t *tape = drive->driver_data; struct ide_atapi_pc pc; - int position; + u8 buf[20]; debug_log(DBG_PROCS, "Enter %s\n", __func__); - idetape_create_read_position_cmd(&pc); - if (ide_queue_pc_tail(drive, tape->disk, &pc)) + /* prep cmd */ + ide_init_pc(&pc); + pc.c[0] = READ_POSITION; + pc.req_xfer = 20; + + if (ide_queue_pc_tail(drive, tape->disk, &pc, buf, pc.req_xfer)) return -1; - position = tape->first_frame; - return position; + + if (!pc.error) { + debug_log(DBG_SENSE, "BOP - %s\n", + (buf[0] & 0x80) ? "Yes" : "No"); + debug_log(DBG_SENSE, "EOP - %s\n", + (buf[0] & 0x40) ? "Yes" : "No"); + + if (buf[0] & 0x4) { + printk(KERN_INFO "ide-tape: Block location is unknown" + "to the tape\n"); + clear_bit(ilog2(IDE_AFLAG_ADDRESS_VALID), + &drive->atapi_flags); + return -1; + } else { + debug_log(DBG_SENSE, "Block Location - %u\n", + be32_to_cpup((__be32 *)&buf[4])); + + tape->partition = buf[1]; + tape->first_frame = be32_to_cpup((__be32 *)&buf[4]); + set_bit(ilog2(IDE_AFLAG_ADDRESS_VALID), + &drive->atapi_flags); + } + } + + return tape->first_frame; } static void idetape_create_locate_cmd(ide_drive_t *drive, @@ -836,19 +821,21 @@ static int idetape_position_tape(ide_drive_t *drive, unsigned int block, { idetape_tape_t *tape = drive->driver_data; struct gendisk *disk = tape->disk; - int retval; + int ret; struct ide_atapi_pc pc; if (tape->chrdev_dir == IDETAPE_DIR_READ) __ide_tape_discard_merge_buffer(drive); idetape_wait_ready(drive, 60 * 5 * HZ); idetape_create_locate_cmd(drive, &pc, block, partition, skip); - retval = ide_queue_pc_tail(drive, disk, &pc); - if (retval) - return (retval); + ret = ide_queue_pc_tail(drive, disk, &pc, NULL, 0); + if (ret) + return ret; - idetape_create_read_position_cmd(&pc); - return ide_queue_pc_tail(drive, disk, &pc); + ret = ide_tape_read_position(drive); + if (ret < 0) + return ret; + return 0; } static void ide_tape_discard_merge_buffer(ide_drive_t *drive, @@ -859,7 +846,7 @@ static void ide_tape_discard_merge_buffer(ide_drive_t *drive, __ide_tape_discard_merge_buffer(drive); if (restore_position) { - position = idetape_read_position(drive); + position = ide_tape_read_position(drive); seek = position > 0 ? position : 0; if (idetape_position_tape(drive, seek, 0, 0)) { printk(KERN_INFO "ide-tape: %s: position_tape failed in" @@ -1039,20 +1026,19 @@ static int idetape_rewind_tape(ide_drive_t *drive) { struct ide_tape_obj *tape = drive->driver_data; struct gendisk *disk = tape->disk; - int retval; struct ide_atapi_pc pc; + int ret; debug_log(DBG_SENSE, "Enter %s\n", __func__); idetape_create_rewind_cmd(drive, &pc); - retval = ide_queue_pc_tail(drive, disk, &pc); - if (retval) - return retval; + ret = ide_queue_pc_tail(drive, disk, &pc, NULL, 0); + if (ret) + return ret; - idetape_create_read_position_cmd(&pc); - retval = ide_queue_pc_tail(drive, disk, &pc); - if (retval) - return retval; + ret = ide_tape_read_position(drive); + if (ret < 0) + return ret; return 0; } @@ -1119,7 +1105,7 @@ static int idetape_space_over_filemarks(ide_drive_t *drive, short mt_op, case MTBSF: idetape_create_space_cmd(&pc, mt_count - count, IDETAPE_SPACE_OVER_FILEMARK); - return ide_queue_pc_tail(drive, disk, &pc); + return ide_queue_pc_tail(drive, disk, &pc, NULL, 0); case MTFSFM: case MTBSFM: if (!sprev) @@ -1259,7 +1245,7 @@ static int idetape_write_filemark(ide_drive_t *drive) /* Write a filemark */ idetape_create_write_filemark_cmd(drive, &pc, 1); - if (ide_queue_pc_tail(drive, tape->disk, &pc)) { + if (ide_queue_pc_tail(drive, tape->disk, &pc, NULL, 0)) { printk(KERN_ERR "ide-tape: Couldn't write a filemark\n"); return -EIO; } @@ -1345,11 +1331,11 @@ static int idetape_mtioctop(ide_drive_t *drive, short mt_op, int mt_count) IDETAPE_LU_RETENSION_MASK | IDETAPE_LU_LOAD_MASK); case MTEOM: idetape_create_space_cmd(&pc, 0, IDETAPE_SPACE_TO_EOD); - return ide_queue_pc_tail(drive, disk, &pc); + return ide_queue_pc_tail(drive, disk, &pc, NULL, 0); case MTERASE: (void)idetape_rewind_tape(drive); idetape_create_erase_cmd(&pc); - return ide_queue_pc_tail(drive, disk, &pc); + return ide_queue_pc_tail(drive, disk, &pc, NULL, 0); case MTSETBLK: if (mt_count) { if (mt_count < tape->blk_size || @@ -1415,7 +1401,7 @@ static int idetape_chrdev_ioctl(struct inode *inode, struct file *file, if (cmd == MTIOCGET || cmd == MTIOCPOS) { block_offset = tape->valid / (tape->blk_size * tape->user_bs_factor); - position = idetape_read_position(drive); + position = ide_tape_read_position(drive); if (position < 0) return -EIO; } @@ -1458,9 +1444,10 @@ static void ide_tape_get_bsize_from_bdesc(ide_drive_t *drive) { idetape_tape_t *tape = drive->driver_data; struct ide_atapi_pc pc; + u8 buf[12]; idetape_create_mode_sense_cmd(&pc, IDETAPE_BLOCK_DESCRIPTOR); - if (ide_queue_pc_tail(drive, tape->disk, &pc)) { + if (ide_queue_pc_tail(drive, tape->disk, &pc, buf, pc.req_xfer)) { printk(KERN_ERR "ide-tape: Can't get block descriptor\n"); if (tape->blk_size == 0) { printk(KERN_WARNING "ide-tape: Cannot deal with zero " @@ -1469,10 +1456,10 @@ static void ide_tape_get_bsize_from_bdesc(ide_drive_t *drive) } return; } - tape->blk_size = (pc.buf[4 + 5] << 16) + - (pc.buf[4 + 6] << 8) + - pc.buf[4 + 7]; - tape->drv_write_prot = (pc.buf[2] & 0x80) >> 7; + tape->blk_size = (buf[4 + 5] << 16) + + (buf[4 + 6] << 8) + + buf[4 + 7]; + tape->drv_write_prot = (buf[2] & 0x80) >> 7; } static int idetape_chrdev_open(struct inode *inode, struct file *filp) @@ -1517,7 +1504,7 @@ static int idetape_chrdev_open(struct inode *inode, struct file *filp) goto out_put_tape; } - idetape_read_position(drive); + ide_tape_read_position(drive); if (!test_bit(ilog2(IDE_AFLAG_ADDRESS_VALID), &drive->atapi_flags)) (void)idetape_rewind_tape(drive); @@ -1615,17 +1602,14 @@ static void idetape_get_inquiry_results(ide_drive_t *drive) char fw_rev[4], vendor_id[8], product_id[16]; idetape_create_inquiry_cmd(&pc); - pc.buf = &pc_buf[0]; - pc.buf_size = sizeof(pc_buf); - - if (ide_queue_pc_tail(drive, tape->disk, &pc)) { + if (ide_queue_pc_tail(drive, tape->disk, &pc, pc_buf, pc.req_xfer)) { printk(KERN_ERR "ide-tape: %s: can't get INQUIRY results\n", tape->name); return; } - memcpy(vendor_id, &pc.buf[8], 8); - memcpy(product_id, &pc.buf[16], 16); - memcpy(fw_rev, &pc.buf[32], 4); + memcpy(vendor_id, &pc_buf[8], 8); + memcpy(product_id, &pc_buf[16], 16); + memcpy(fw_rev, &pc_buf[32], 4); ide_fixstring(vendor_id, 8, 0); ide_fixstring(product_id, 16, 0); @@ -1643,11 +1627,11 @@ static void idetape_get_mode_sense_results(ide_drive_t *drive) { idetape_tape_t *tape = drive->driver_data; struct ide_atapi_pc pc; - u8 *caps; + u8 buf[24], *caps; u8 speed, max_speed; idetape_create_mode_sense_cmd(&pc, IDETAPE_CAPABILITIES_PAGE); - if (ide_queue_pc_tail(drive, tape->disk, &pc)) { + if (ide_queue_pc_tail(drive, tape->disk, &pc, buf, pc.req_xfer)) { printk(KERN_ERR "ide-tape: Can't get tape parameters - assuming" " some default values\n"); tape->blk_size = 512; @@ -1656,7 +1640,7 @@ static void idetape_get_mode_sense_results(ide_drive_t *drive) put_unaligned(6*52, (u16 *)&tape->caps[16]); return; } - caps = pc.buf + 4 + pc.buf[3]; + caps = buf + 4 + buf[3]; /* convert to host order and save for later use */ speed = be16_to_cpup((__be16 *)&caps[14]); diff --git a/drivers/ide/ide-xfer-mode.c b/drivers/ide/ide-xfer-mode.c index af44be9d546c..46d203ce60cc 100644 --- a/drivers/ide/ide-xfer-mode.c +++ b/drivers/ide/ide-xfer-mode.c @@ -107,6 +107,18 @@ u8 ide_get_best_pio_mode(ide_drive_t *drive, u8 mode_wanted, u8 max_mode) } EXPORT_SYMBOL_GPL(ide_get_best_pio_mode); +int ide_pio_need_iordy(ide_drive_t *drive, const u8 pio) +{ + /* + * IORDY may lead to controller lock up on certain controllers + * if the port is not occupied. + */ + if (pio == 0 && (drive->hwif->port_flags & IDE_PFLAG_PROBING)) + return 0; + return ata_id_pio_need_iordy(drive->id, pio); +} +EXPORT_SYMBOL_GPL(ide_pio_need_iordy); + int ide_set_pio_mode(ide_drive_t *drive, const u8 mode) { ide_hwif_t *hwif = drive->hwif; diff --git a/drivers/ide/it8172.c b/drivers/ide/it8172.c index e021078cd06b..0d266a5b524d 100644 --- a/drivers/ide/it8172.c +++ b/drivers/ide/it8172.c @@ -66,7 +66,7 @@ static void it8172_set_pio_mode(ide_drive_t *drive, const u8 pio) if (drive->media == ide_disk) /* enable prefetch */ drive_enables |= 0x0004 << (drive->dn * 4); - if (ata_id_has_iordy(drive->id)) + if (ide_pio_need_iordy(drive, pio)) /* enable IORDY sample-point */ drive_enables |= 0x0002 << (drive->dn * 4); diff --git a/drivers/ide/it8213.c b/drivers/ide/it8213.c index d7969b6d139e..47976167796a 100644 --- a/drivers/ide/it8213.c +++ b/drivers/ide/it8213.c @@ -50,7 +50,7 @@ static void it8213_set_pio_mode(ide_drive_t *drive, const u8 pio) control |= 1; /* Programmable timing on */ if (drive->media != ide_disk) control |= 4; /* ATAPI */ - if (pio > 2) + if (ide_pio_need_iordy(drive, pio)) control |= 2; /* IORDY */ if (is_slave) { master_data |= 0x4000; diff --git a/drivers/ide/macide.c b/drivers/ide/macide.c index 1447c8c90565..505ec43e5606 100644 --- a/drivers/ide/macide.c +++ b/drivers/ide/macide.c @@ -53,17 +53,20 @@ volatile unsigned char *ide_ifr = (unsigned char *) (IDE_BASE + IDE_IFR); -int macide_ack_intr(ide_hwif_t* hwif) +int macide_test_irq(ide_hwif_t *hwif) { - if (*ide_ifr & 0x20) { - *ide_ifr &= ~0x20; + if (*ide_ifr & 0x20) return 1; - } return 0; } +static void macide_clear_irq(ide_drive_t *drive) +{ + *ide_ifr &= ~0x20; +} + static void __init macide_setup_ports(struct ide_hw *hw, unsigned long base, - int irq, ide_ack_intr_t *ack_intr) + int irq) { int i; @@ -75,10 +78,15 @@ static void __init macide_setup_ports(struct ide_hw *hw, unsigned long base, hw->io_ports.ctl_addr = base + IDE_CONTROL; hw->irq = irq; - hw->ack_intr = ack_intr; } +static const struct ide_port_ops macide_port_ops = { + .clear_irq = macide_clear_irq, + .test_irq = macide_test_irq, +}; + static const struct ide_port_info macide_port_info = { + .port_ops = &macide_port_ops, .host_flags = IDE_HFLAG_MMIO | IDE_HFLAG_NO_DMA, .irq_flags = IRQF_SHARED, .chipset = ide_generic, @@ -93,10 +101,10 @@ static const char *mac_ide_name[] = static int __init macide_init(void) { - ide_ack_intr_t *ack_intr; unsigned long base; int irq; struct ide_hw hw, *hws[] = { &hw }; + struct ide_port_info d = macide_port_info; if (!MACH_IS_MAC) return -ENODEV; @@ -104,17 +112,15 @@ static int __init macide_init(void) switch (macintosh_config->ide_type) { case MAC_IDE_QUADRA: base = IDE_BASE; - ack_intr = macide_ack_intr; irq = IRQ_NUBUS_F; break; case MAC_IDE_PB: base = IDE_BASE; - ack_intr = macide_ack_intr; irq = IRQ_NUBUS_C; break; case MAC_IDE_BABOON: base = BABOON_BASE; - ack_intr = NULL; + d.port_ops = NULL; irq = IRQ_BABOON_1; break; default: @@ -124,9 +130,9 @@ static int __init macide_init(void) printk(KERN_INFO "ide: Macintosh %s IDE controller\n", mac_ide_name[macintosh_config->ide_type - 1]); - macide_setup_ports(&hw, base, irq, ack_intr); + macide_setup_ports(&hw, base, irq); - return ide_host_add(&macide_port_info, hws, 1, NULL); + return ide_host_add(&d, hws, 1, NULL); } module_init(macide_init); diff --git a/drivers/ide/opti621.c b/drivers/ide/opti621.c index 6048eda3cd61..f1d70d6630fe 100644 --- a/drivers/ide/opti621.c +++ b/drivers/ide/opti621.c @@ -138,6 +138,7 @@ static void opti621_set_pio_mode(ide_drive_t *drive, const u8 pio) ide_hwif_t *hwif = drive->hwif; ide_drive_t *pair = ide_get_pair_dev(drive); unsigned long flags; + unsigned long mode = XFER_PIO_0 + pio, pair_mode; u8 tim, misc, addr_pio = pio, clk; /* DRDY is default 2 (by OPTi Databook) */ @@ -150,11 +151,12 @@ static void opti621_set_pio_mode(ide_drive_t *drive, const u8 pio) { 0x48, 0x34, 0x21, 0x10, 0x10 } /* 25 MHz */ }; - drive->drive_data = XFER_PIO_0 + pio; + ide_set_drivedata(drive, (void *)mode); if (pair) { - if (pair->drive_data && pair->drive_data < drive->drive_data) - addr_pio = pair->drive_data - XFER_PIO_0; + pair_mode = (unsigned long)ide_get_drivedata(pair); + if (pair_mode && pair_mode < mode) + addr_pio = pair_mode - XFER_PIO_0; } spin_lock_irqsave(&opti621_lock, flags); diff --git a/drivers/ide/pdc202xx_old.c b/drivers/ide/pdc202xx_old.c index b6abf7e52cac..cb812f3700e8 100644 --- a/drivers/ide/pdc202xx_old.c +++ b/drivers/ide/pdc202xx_old.c @@ -73,7 +73,7 @@ static void pdc202xx_set_mode(ide_drive_t *drive, const u8 speed) * Prefetch_EN / IORDY_EN / PA[3:0] bits of register A */ AP &= ~0x3f; - if (ata_id_iordy_disable(drive->id)) + if (ide_pio_need_iordy(drive, speed - XFER_PIO_0)) AP |= 0x20; /* set IORDY_EN bit */ if (drive->media == ide_disk) AP |= 0x10; /* set Prefetch_EN bit */ @@ -104,6 +104,27 @@ static void pdc202xx_set_pio_mode(ide_drive_t *drive, const u8 pio) pdc202xx_set_mode(drive, XFER_PIO_0 + pio); } +static int pdc202xx_test_irq(ide_hwif_t *hwif) +{ + struct pci_dev *dev = to_pci_dev(hwif->dev); + unsigned long high_16 = pci_resource_start(dev, 4); + u8 sc1d = inb(high_16 + 0x1d); + + if (hwif->channel) { + /* + * bit 7: error, bit 6: interrupting, + * bit 5: FIFO full, bit 4: FIFO empty + */ + return ((sc1d & 0x50) == 0x40) ? 1 : 0; + } else { + /* + * bit 3: error, bit 2: interrupting, + * bit 1: FIFO full, bit 0: FIFO empty + */ + return ((sc1d & 0x05) == 0x04) ? 1 : 0; + } +} + static u8 pdc2026x_cable_detect(ide_hwif_t *hwif) { struct pci_dev *dev = to_pci_dev(hwif->dev); @@ -231,6 +252,7 @@ static void __devinit pdc202ata4_fixup_irq(struct pci_dev *dev, static const struct ide_port_ops pdc20246_port_ops = { .set_pio_mode = pdc202xx_set_pio_mode, .set_dma_mode = pdc202xx_set_mode, + .test_irq = pdc202xx_test_irq, }; static const struct ide_port_ops pdc2026x_port_ops = { diff --git a/drivers/ide/piix.c b/drivers/ide/piix.c index 69860dea3820..bf14f39bd3a7 100644 --- a/drivers/ide/piix.c +++ b/drivers/ide/piix.c @@ -98,7 +98,7 @@ static void piix_set_pio_mode(ide_drive_t *drive, const u8 pio) control |= 1; /* Programmable timing on */ if (drive->media == ide_disk) control |= 4; /* Prefetch, post write */ - if (pio > 2) + if (ide_pio_need_iordy(drive, pio)) control |= 2; /* IORDY */ if (is_slave) { master_data |= 0x4000; diff --git a/drivers/ide/q40ide.c b/drivers/ide/q40ide.c index ab49a97023d9..90786083b439 100644 --- a/drivers/ide/q40ide.c +++ b/drivers/ide/q40ide.c @@ -51,9 +51,7 @@ static int q40ide_default_irq(unsigned long base) /* * Addresses are pretranslated for Q40 ISA access. */ -static void q40_ide_setup_ports(struct ide_hw *hw, unsigned long base, - ide_ack_intr_t *ack_intr, - int irq) +static void q40_ide_setup_ports(struct ide_hw *hw, unsigned long base, int irq) { memset(hw, 0, sizeof(*hw)); /* BIG FAT WARNING: @@ -69,7 +67,6 @@ static void q40_ide_setup_ports(struct ide_hw *hw, unsigned long base, hw->io_ports.ctl_addr = Q40_ISA_IO_B(base + 0x206); hw->irq = irq; - hw->ack_intr = ack_intr; } static void q40ide_input_data(ide_drive_t *drive, struct ide_cmd *cmd, @@ -156,7 +153,7 @@ static int __init q40ide_init(void) release_region(pcide_bases[i], 8); continue; } - q40_ide_setup_ports(&hw[i], pcide_bases[i], NULL, + q40_ide_setup_ports(&hw[i], pcide_bases[i], q40ide_default_irq(pcide_bases[i])); hws[i] = &hw[i]; diff --git a/drivers/ide/qd65xx.c b/drivers/ide/qd65xx.c index c9a134986891..74696edc8d1d 100644 --- a/drivers/ide/qd65xx.c +++ b/drivers/ide/qd65xx.c @@ -180,8 +180,11 @@ static int qd_find_disk_type (ide_drive_t *drive, static void qd_set_timing (ide_drive_t *drive, u8 timing) { - drive->drive_data &= 0xff00; - drive->drive_data |= timing; + unsigned long data = (unsigned long)ide_get_drivedata(drive); + + data &= 0xff00; + data |= timing; + ide_set_drivedata(drive, (void *)data); printk(KERN_DEBUG "%s: %#x\n", drive->name, timing); } @@ -292,7 +295,7 @@ static void __init qd6500_init_dev(ide_drive_t *drive) u8 base = (hwif->config_data & 0xff00) >> 8; u8 config = QD_CONFIG(hwif); - drive->drive_data = QD6500_DEF_DATA; + ide_set_drivedata(drive, (void *)QD6500_DEF_DATA); } static void __init qd6580_init_dev(ide_drive_t *drive) @@ -308,7 +311,7 @@ static void __init qd6580_init_dev(ide_drive_t *drive) } else t2 = t1 = hwif->channel ? QD6580_DEF_DATA2 : QD6580_DEF_DATA; - drive->drive_data = (drive->dn & 1) ? t2 : t1; + ide_set_drivedata(drive, (void *)((drive->dn & 1) ? t2 : t1)); } static const struct ide_tp_ops qd65xx_tp_ops = { diff --git a/drivers/ide/qd65xx.h b/drivers/ide/qd65xx.h index d7e67a1a1dcc..1fba2a5f281c 100644 --- a/drivers/ide/qd65xx.h +++ b/drivers/ide/qd65xx.h @@ -31,8 +31,15 @@ #define QD_CONFIG(hwif) ((hwif)->config_data & 0x00ff) -#define QD_TIMING(drive) (u8)(((drive)->drive_data) & 0x00ff) -#define QD_TIMREG(drive) (u8)((((drive)->drive_data) & 0xff00) >> 8) +static inline u8 QD_TIMING(ide_drive_t *drive) +{ + return (unsigned long)ide_get_drivedata(drive) & 0x00ff; +} + +static inline u8 QD_TIMREG(ide_drive_t *drive) +{ + return ((unsigned long)ide_get_drivedata(drive) & 0xff00) >> 8; +} #define QD6500_DEF_DATA ((QD_TIM1_PORT<<8) | (QD_ID3 ? 0x0c : 0x08)) #define QD6580_DEF_DATA ((QD_TIM1_PORT<<8) | (QD_ID3 ? 0x0a : 0x00)) diff --git a/drivers/ide/sgiioc4.c b/drivers/ide/sgiioc4.c index 5f37f168f944..b7d61dc64096 100644 --- a/drivers/ide/sgiioc4.c +++ b/drivers/ide/sgiioc4.c @@ -1,6 +1,6 @@ /* * Copyright (c) 2003-2006 Silicon Graphics, Inc. All Rights Reserved. - * Copyright (C) 2008 MontaVista Software, Inc. + * Copyright (C) 2008-2009 MontaVista Software, Inc. * * This program is free software; you can redistribute it and/or modify it * under the terms of version 2 of the GNU General Public License @@ -29,8 +29,7 @@ #include <linux/blkdev.h> #include <linux/scatterlist.h> #include <linux/ioc4.h> -#include <asm/io.h> - +#include <linux/io.h> #include <linux/ide.h> #define DRV_NAME "SGIIOC4" @@ -72,7 +71,7 @@ #define IOC4_CMD_CTL_BLK_SIZE 0x20 #define IOC4_SUPPORTED_FIRMWARE_REV 46 -typedef struct { +struct ioc4_dma_regs { u32 timing_reg0; u32 timing_reg1; u32 low_mem_ptr; @@ -82,17 +81,18 @@ typedef struct { u32 dev_byte_count; u32 mem_byte_count; u32 status; -} ioc4_dma_regs_t; +}; /* Each Physical Region Descriptor Entry size is 16 bytes (2 * 64 bits) */ /* IOC4 has only 1 IDE channel */ -#define IOC4_PRD_BYTES 16 -#define IOC4_PRD_ENTRIES (PAGE_SIZE /(4*IOC4_PRD_BYTES)) +#define IOC4_PRD_BYTES 16 +#define IOC4_PRD_ENTRIES (PAGE_SIZE / (4 * IOC4_PRD_BYTES)) -static void -sgiioc4_init_hwif_ports(struct ide_hw *hw, unsigned long data_port, - unsigned long ctrl_port, unsigned long irq_port) +static void sgiioc4_init_hwif_ports(struct ide_hw *hw, + unsigned long data_port, + unsigned long ctrl_port, + unsigned long irq_port) { unsigned long reg = data_port; int i; @@ -105,13 +105,11 @@ sgiioc4_init_hwif_ports(struct ide_hw *hw, unsigned long data_port, hw->io_ports.irq_addr = irq_port; } -static int -sgiioc4_checkirq(ide_hwif_t * hwif) +static int sgiioc4_checkirq(ide_hwif_t *hwif) { - unsigned long intr_addr = - hwif->io_ports.irq_addr + IOC4_INTR_REG * 4; + unsigned long intr_addr = hwif->io_ports.irq_addr + IOC4_INTR_REG * 4; - if ((u8)readl((void __iomem *)intr_addr) & 0x03) + if (readl((void __iomem *)intr_addr) & 0x03) return 1; return 0; @@ -119,8 +117,7 @@ sgiioc4_checkirq(ide_hwif_t * hwif) static u8 sgiioc4_read_status(ide_hwif_t *); -static int -sgiioc4_clearirq(ide_drive_t * drive) +static int sgiioc4_clearirq(ide_drive_t *drive) { u32 intr_reg; ide_hwif_t *hwif = drive->hwif; @@ -158,12 +155,10 @@ sgiioc4_clearirq(ide_drive_t * drive) readl((void __iomem *)(io_ports->irq_addr + 4)); pci_read_config_dword(dev, PCI_COMMAND, &pci_stat_cmd_reg); - printk(KERN_ERR - "%s(%s) : PCI Bus Error when doing DMA:" - " status-cmd reg is 0x%x\n", + printk(KERN_ERR "%s(%s): PCI Bus Error when doing DMA: " + "status-cmd reg is 0x%x\n", __func__, drive->name, pci_stat_cmd_reg); - printk(KERN_ERR - "%s(%s) : PCI Error Address is 0x%x%x\n", + printk(KERN_ERR "%s(%s): PCI Error Address is 0x%x%x\n", __func__, drive->name, pci_err_addr_high, pci_err_addr_low); /* Clear the PCI Error indicator */ @@ -189,8 +184,7 @@ static void sgiioc4_dma_start(ide_drive_t *drive) writel(temp_reg, (void __iomem *)ioc4_dma_addr); } -static u32 -sgiioc4_ide_dma_stop(ide_hwif_t *hwif, u64 dma_base) +static u32 sgiioc4_ide_dma_stop(ide_hwif_t *hwif, u64 dma_base) { unsigned long ioc4_dma_addr = dma_base + IOC4_DMA_CTRL * 4; u32 ioc4_dma; @@ -227,7 +221,7 @@ static int sgiioc4_dma_end(ide_drive_t *drive) } /* - * The IOC4 will DMA 1's to the ending dma area to indicate that + * The IOC4 will DMA 1's to the ending DMA area to indicate that * previous data DMA is complete. This is necessary because of relaxed * ordering between register reads and DMA writes on the Altix. */ @@ -265,7 +259,7 @@ static void sgiioc4_set_dma_mode(ide_drive_t *drive, const u8 speed) { } -/* returns 1 if dma irq issued, 0 otherwise */ +/* Returns 1 if DMA IRQ issued, 0 otherwise */ static int sgiioc4_dma_test_irq(ide_drive_t *drive) { return sgiioc4_checkirq(drive->hwif); @@ -286,8 +280,7 @@ static void sgiioc4_resetproc(ide_drive_t *drive) sgiioc4_clearirq(drive); } -static void -sgiioc4_dma_lost_irq(ide_drive_t * drive) +static void sgiioc4_dma_lost_irq(ide_drive_t *drive) { sgiioc4_resetproc(drive); @@ -313,13 +306,13 @@ static u8 sgiioc4_read_status(ide_hwif_t *hwif) return reg; } -/* Creates a dma map for the scatter-gather list entries */ -static int __devinit -ide_dma_sgiioc4(ide_hwif_t *hwif, const struct ide_port_info *d) +/* Creates a DMA map for the scatter-gather list entries */ +static int __devinit ide_dma_sgiioc4(ide_hwif_t *hwif, + const struct ide_port_info *d) { struct pci_dev *dev = to_pci_dev(hwif->dev); unsigned long dma_base = pci_resource_start(dev, 0) + IOC4_DMA_OFFSET; - int num_ports = sizeof (ioc4_dma_regs_t); + int num_ports = sizeof(struct ioc4_dma_regs); void *pad; printk(KERN_INFO " %s: MMIO-DMA\n", hwif->name); @@ -362,8 +355,7 @@ dma_pci_alloc_failure: } /* Initializes the IOC4 DMA Engine */ -static void -sgiioc4_configure_for_dma(int dma_direction, ide_drive_t * drive) +static void sgiioc4_configure_for_dma(int dma_direction, ide_drive_t *drive) { u32 ioc4_dma; ide_hwif_t *hwif = drive->hwif; @@ -374,31 +366,27 @@ sgiioc4_configure_for_dma(int dma_direction, ide_drive_t * drive) ioc4_dma = readl((void __iomem *)ioc4_dma_addr); if (ioc4_dma & IOC4_S_DMA_ACTIVE) { - printk(KERN_WARNING - "%s(%s):Warning!! DMA from previous transfer was still active\n", - __func__, drive->name); + printk(KERN_WARNING "%s(%s): Warning!! DMA from previous " + "transfer was still active\n", __func__, drive->name); writel(IOC4_S_DMA_STOP, (void __iomem *)ioc4_dma_addr); ioc4_dma = sgiioc4_ide_dma_stop(hwif, dma_base); if (ioc4_dma & IOC4_S_DMA_STOP) - printk(KERN_ERR - "%s(%s) : IOC4 Dma STOP bit is still 1\n", - __func__, drive->name); + printk(KERN_ERR "%s(%s): IOC4 DMA STOP bit is " + "still 1\n", __func__, drive->name); } ioc4_dma = readl((void __iomem *)ioc4_dma_addr); if (ioc4_dma & IOC4_S_DMA_ERROR) { - printk(KERN_WARNING - "%s(%s) : Warning!! - DMA Error during Previous" - " transfer | status 0x%x\n", + printk(KERN_WARNING "%s(%s): Warning!! DMA Error during " + "previous transfer, status 0x%x\n", __func__, drive->name, ioc4_dma); writel(IOC4_S_DMA_STOP, (void __iomem *)ioc4_dma_addr); ioc4_dma = sgiioc4_ide_dma_stop(hwif, dma_base); if (ioc4_dma & IOC4_S_DMA_STOP) - printk(KERN_ERR - "%s(%s) : IOC4 DMA STOP bit is still 1\n", - __func__, drive->name); + printk(KERN_ERR "%s(%s): IOC4 DMA STOP bit is " + "still 1\n", __func__, drive->name); } /* Address of the Scatter Gather List */ @@ -408,20 +396,22 @@ sgiioc4_configure_for_dma(int dma_direction, ide_drive_t * drive) /* Address of the Ending DMA */ memset(ide_get_hwifdata(hwif), 0, IOC4_IDE_CACHELINE_SIZE); ending_dma_addr = cpu_to_le32(hwif->extra_base); - writel(ending_dma_addr, (void __iomem *)(dma_base + IOC4_DMA_END_ADDR * 4)); + writel(ending_dma_addr, (void __iomem *)(dma_base + + IOC4_DMA_END_ADDR * 4)); writel(dma_direction, (void __iomem *)ioc4_dma_addr); } -/* IOC4 Scatter Gather list Format */ +/* IOC4 Scatter Gather list Format */ /* 128 Bit entries to support 64 bit addresses in the future */ /* The Scatter Gather list Entry should be in the BIG-ENDIAN Format */ /* --------------------------------------------------------------------- */ -/* | Upper 32 bits - Zero | Lower 32 bits- address | */ +/* | Upper 32 bits - Zero | Lower 32 bits- address | */ /* --------------------------------------------------------------------- */ /* | Upper 32 bits - Zero |EOL| 15 unused | 16 Bit Length| */ /* --------------------------------------------------------------------- */ -/* Creates the scatter gather list, DMA Table */ +/* Creates the scatter gather list, DMA Table */ + static int sgiioc4_build_dmatable(ide_drive_t *drive, struct ide_cmd *cmd) { ide_hwif_t *hwif = drive->hwif; @@ -448,8 +438,10 @@ static int sgiioc4_build_dmatable(ide_drive_t *drive, struct ide_cmd *cmd) if (bcount > cur_len) bcount = cur_len; - /* put the addr, length in - * the IOC4 dma-table format */ + /* + * Put the address, length in + * the IOC4 dma-table format + */ *table = 0x0; table++; *table = cpu_to_be32(cur_addr); @@ -540,8 +532,7 @@ static const struct ide_port_info sgiioc4_port_info __devinitconst = { .mwdma_mask = ATA_MWDMA2_ONLY, }; -static int __devinit -sgiioc4_ide_setup_pci_device(struct pci_dev *dev) +static int __devinit sgiioc4_ide_setup_pci_device(struct pci_dev *dev) { unsigned long cmd_base, irqport; unsigned long bar0, cmd_phys_base, ctl; @@ -549,7 +540,7 @@ sgiioc4_ide_setup_pci_device(struct pci_dev *dev) struct ide_hw hw, *hws[] = { &hw }; int rc; - /* Get the CmdBlk and CtrlBlk Base Registers */ + /* Get the CmdBlk and CtrlBlk base registers */ bar0 = pci_resource_start(dev, 0); virt_base = pci_ioremap_bar(dev, 0); if (virt_base == NULL) { @@ -557,9 +548,9 @@ sgiioc4_ide_setup_pci_device(struct pci_dev *dev) DRV_NAME, bar0); return -ENOMEM; } - cmd_base = (unsigned long) virt_base + IOC4_CMD_OFFSET; - ctl = (unsigned long) virt_base + IOC4_CTRL_OFFSET; - irqport = (unsigned long) virt_base + IOC4_INTR_OFFSET; + cmd_base = (unsigned long)virt_base + IOC4_CMD_OFFSET; + ctl = (unsigned long)virt_base + IOC4_CTRL_OFFSET; + irqport = (unsigned long)virt_base + IOC4_INTR_OFFSET; cmd_phys_base = bar0 + IOC4_CMD_OFFSET; if (request_mem_region(cmd_phys_base, IOC4_CMD_CTL_BLK_SIZE, @@ -577,7 +568,7 @@ sgiioc4_ide_setup_pci_device(struct pci_dev *dev) hw.irq = dev->irq; hw.dev = &dev->dev; - /* Initializing chipset IRQ Registers */ + /* Initialize chipset IRQ registers */ writel(0x03, (void __iomem *)(irqport + IOC4_INTR_SET * 4)); rc = ide_host_add(&sgiioc4_port_info, hws, 1, NULL); @@ -590,8 +581,7 @@ req_mem_rgn_err: return rc; } -static unsigned int __devinit -pci_init_sgiioc4(struct pci_dev *dev) +static unsigned int __devinit pci_init_sgiioc4(struct pci_dev *dev) { int ret; @@ -611,10 +601,10 @@ out: return ret; } -int __devinit -ioc4_ide_attach_one(struct ioc4_driver_data *idd) +int __devinit ioc4_ide_attach_one(struct ioc4_driver_data *idd) { - /* PCI-RT does not bring out IDE connection. + /* + * PCI-RT does not bring out IDE connection. * Do not attach to this particular IOC4. */ if (idd->idd_variant == IOC4_VARIANT_PCI_RT) @@ -627,7 +617,6 @@ static struct ioc4_submodule __devinitdata ioc4_ide_submodule = { .is_name = "IOC4_ide", .is_owner = THIS_MODULE, .is_probe = ioc4_ide_attach_one, -/* .is_remove = ioc4_ide_remove_one, */ }; static int __init ioc4_ide_init(void) diff --git a/drivers/ide/siimage.c b/drivers/ide/siimage.c index bd82d228608c..d95df528562f 100644 --- a/drivers/ide/siimage.c +++ b/drivers/ide/siimage.c @@ -32,7 +32,6 @@ * smarter code in libata. * * TODO: - * - IORDY fixes * - VDMA support */ @@ -234,8 +233,7 @@ static u8 sil_sata_udma_filter(ide_drive_t *drive) * @pio: PIO mode number * * Load the timing settings for this device mode into the - * controller. If we are in PIO mode 3 or 4 turn on IORDY - * monitoring (bit 9). The TF timing is bits 31:16 + * controller. */ static void sil_set_pio_mode(ide_drive_t *drive, u8 pio) @@ -276,13 +274,16 @@ static void sil_set_pio_mode(ide_drive_t *drive, u8 pio) /* now set up IORDY */ speedp = sil_ioread16(dev, tfaddr - 2); speedp &= ~0x200; - if (pio > 2) - speedp |= 0x200; - sil_iowrite16(dev, speedp, tfaddr - 2); mode = sil_ioread8(dev, base + addr_mask); mode &= ~(unit ? 0x30 : 0x03); - mode |= unit ? 0x10 : 0x01; + + if (ide_pio_need_iordy(drive, pio)) { + speedp |= 0x200; + mode |= unit ? 0x10 : 0x01; + } + + sil_iowrite16(dev, speedp, tfaddr - 2); sil_iowrite8(dev, mode, base + addr_mask); } @@ -337,24 +338,14 @@ static void sil_set_dma_mode(ide_drive_t *drive, const u8 speed) sil_iowrite16(dev, ultra, ua); } -/* returns 1 if dma irq issued, 0 otherwise */ -static int siimage_io_dma_test_irq(ide_drive_t *drive) +static int sil_test_irq(ide_hwif_t *hwif) { - ide_hwif_t *hwif = drive->hwif; struct pci_dev *dev = to_pci_dev(hwif->dev); - u8 dma_altstat = 0; unsigned long addr = siimage_selreg(hwif, 1); + u8 val = sil_ioread8(dev, addr); - /* return 1 if INTR asserted */ - if (inb(hwif->dma_base + ATA_DMA_STATUS) & 4) - return 1; - - /* return 1 if Device INTR asserted */ - pci_read_config_byte(dev, addr, &dma_altstat); - if (dma_altstat & 8) - return 0; /* return 1; */ - - return 0; + /* Return 1 if INTRQ asserted */ + return (val & 8) ? 1 : 0; } /** @@ -368,7 +359,6 @@ static int siimage_io_dma_test_irq(ide_drive_t *drive) static int siimage_mmio_dma_test_irq(ide_drive_t *drive) { ide_hwif_t *hwif = drive->hwif; - unsigned long addr = siimage_selreg(hwif, 0x1); void __iomem *sata_error_addr = (void __iomem *)hwif->sata_scr[SATA_ERROR_OFFSET]; @@ -397,10 +387,6 @@ static int siimage_mmio_dma_test_irq(ide_drive_t *drive) if (readb((void __iomem *)(hwif->dma_base + ATA_DMA_STATUS)) & 4) return 1; - /* return 1 if Device INTR asserted */ - if (readb((void __iomem *)addr) & 8) - return 0; /* return 1; */ - return 0; } @@ -409,7 +395,7 @@ static int siimage_dma_test_irq(ide_drive_t *drive) if (drive->hwif->host_flags & IDE_HFLAG_MMIO) return siimage_mmio_dma_test_irq(drive); else - return siimage_io_dma_test_irq(drive); + return ide_dma_test_irq(drive); } /** @@ -694,6 +680,7 @@ static const struct ide_port_ops sil_pata_port_ops = { .set_pio_mode = sil_set_pio_mode, .set_dma_mode = sil_set_dma_mode, .quirkproc = sil_quirkproc, + .test_irq = sil_test_irq, .udma_filter = sil_pata_udma_filter, .cable_detect = sil_cable_detect, }; @@ -704,6 +691,7 @@ static const struct ide_port_ops sil_sata_port_ops = { .reset_poll = sil_sata_reset_poll, .pre_reset = sil_sata_pre_reset, .quirkproc = sil_quirkproc, + .test_irq = sil_test_irq, .udma_filter = sil_sata_udma_filter, .cable_detect = sil_cable_detect, }; diff --git a/drivers/ide/sl82c105.c b/drivers/ide/sl82c105.c index 0924abff52ff..d698da470d6f 100644 --- a/drivers/ide/sl82c105.c +++ b/drivers/ide/sl82c105.c @@ -61,8 +61,7 @@ static unsigned int get_pio_timings(ide_drive_t *drive, u8 pio) if (cmd_off == 0) cmd_off = 1; - if ((pio > 2 || ata_id_has_iordy(drive->id)) && - !(pio > 4 && ata_id_is_cfa(drive->id))) + if (ide_pio_need_iordy(drive, pio)) iordy = 0x40; return (cmd_on - 1) << 8 | (cmd_off - 1) | iordy; @@ -74,6 +73,7 @@ static unsigned int get_pio_timings(ide_drive_t *drive, u8 pio) static void sl82c105_set_pio_mode(ide_drive_t *drive, const u8 pio) { struct pci_dev *dev = to_pci_dev(drive->hwif->dev); + unsigned long timings = (unsigned long)ide_get_drivedata(drive); int reg = 0x44 + drive->dn * 4; u16 drv_ctrl; @@ -83,8 +83,9 @@ static void sl82c105_set_pio_mode(ide_drive_t *drive, const u8 pio) * Store the PIO timings so that we can restore them * in case DMA will be turned off... */ - drive->drive_data &= 0xffff0000; - drive->drive_data |= drv_ctrl; + timings &= 0xffff0000; + timings |= drv_ctrl; + ide_set_drivedata(drive, (void *)timings); pci_write_config_word(dev, reg, drv_ctrl); pci_read_config_word (dev, reg, &drv_ctrl); @@ -100,6 +101,7 @@ static void sl82c105_set_pio_mode(ide_drive_t *drive, const u8 pio) static void sl82c105_set_dma_mode(ide_drive_t *drive, const u8 speed) { static u16 mwdma_timings[] = {0x0707, 0x0201, 0x0200}; + unsigned long timings = (unsigned long)ide_get_drivedata(drive); u16 drv_ctrl; DBG(("sl82c105_tune_chipset(drive:%s, speed:%s)\n", @@ -111,8 +113,19 @@ static void sl82c105_set_dma_mode(ide_drive_t *drive, const u8 speed) * Store the DMA timings so that we can actually program * them when DMA will be turned on... */ - drive->drive_data &= 0x0000ffff; - drive->drive_data |= (unsigned long)drv_ctrl << 16; + timings &= 0x0000ffff; + timings |= (unsigned long)drv_ctrl << 16; + ide_set_drivedata(drive, (void *)timings); +} + +static int sl82c105_test_irq(ide_hwif_t *hwif) +{ + struct pci_dev *dev = to_pci_dev(hwif->dev); + u32 val, mask = hwif->channel ? CTRL_IDE_IRQB : CTRL_IDE_IRQA; + + pci_read_config_dword(dev, 0x40, &val); + + return (val & mask) ? 1 : 0; } /* @@ -185,7 +198,8 @@ static void sl82c105_dma_start(ide_drive_t *drive) DBG(("%s(drive:%s)\n", __func__, drive->name)); - pci_write_config_word(dev, reg, drive->drive_data >> 16); + pci_write_config_word(dev, reg, + (unsigned long)ide_get_drivedata(drive) >> 16); sl82c105_reset_host(dev); ide_dma_start(drive); @@ -210,7 +224,8 @@ static int sl82c105_dma_end(ide_drive_t *drive) ret = ide_dma_end(drive); - pci_write_config_word(dev, reg, drive->drive_data); + pci_write_config_word(dev, reg, + (unsigned long)ide_get_drivedata(drive)); return ret; } @@ -289,6 +304,7 @@ static const struct ide_port_ops sl82c105_port_ops = { .set_pio_mode = sl82c105_set_pio_mode, .set_dma_mode = sl82c105_set_dma_mode, .resetproc = sl82c105_resetproc, + .test_irq = sl82c105_test_irq, }; static const struct ide_dma_ops sl82c105_dma_ops = { diff --git a/drivers/ide/slc90e66.c b/drivers/ide/slc90e66.c index f55d7d6313e8..9aec78d3bcff 100644 --- a/drivers/ide/slc90e66.c +++ b/drivers/ide/slc90e66.c @@ -44,7 +44,7 @@ static void slc90e66_set_pio_mode(ide_drive_t *drive, const u8 pio) control |= 1; /* Programmable timing on */ if (drive->media == ide_disk) control |= 4; /* Prefetch, post write */ - if (pio > 2) + if (ide_pio_need_iordy(drive, pio)) control |= 2; /* IORDY */ if (is_slave) { master_data |= 0x4000; diff --git a/drivers/input/evdev.c b/drivers/input/evdev.c index 7a7a026ba712..114efd8dc8f5 100644 --- a/drivers/input/evdev.c +++ b/drivers/input/evdev.c @@ -25,7 +25,6 @@ struct evdev { int exist; int open; int minor; - char name[16]; struct input_handle handle; wait_queue_head_t wait; struct evdev_client *grab; @@ -609,7 +608,8 @@ static long evdev_do_ioctl(struct file *file, unsigned int cmd, p, compat_mode); if (_IOC_NR(cmd) == _IOC_NR(EVIOCGNAME(0))) - return str_to_user(dev->name, _IOC_SIZE(cmd), p); + return str_to_user(dev_name(&evdev->dev), + _IOC_SIZE(cmd), p); if (_IOC_NR(cmd) == _IOC_NR(EVIOCGPHYS(0))) return str_to_user(dev->phys, _IOC_SIZE(cmd), p); @@ -626,8 +626,11 @@ static long evdev_do_ioctl(struct file *file, unsigned int cmd, abs.maximum = dev->absmax[t]; abs.fuzz = dev->absfuzz[t]; abs.flat = dev->absflat[t]; + abs.resolution = dev->absres[t]; - if (copy_to_user(p, &abs, sizeof(struct input_absinfo))) + if (copy_to_user(p, &abs, min_t(size_t, + _IOC_SIZE(cmd), + sizeof(struct input_absinfo)))) return -EFAULT; return 0; @@ -654,8 +657,9 @@ static long evdev_do_ioctl(struct file *file, unsigned int cmd, t = _IOC_NR(cmd) & ABS_MAX; - if (copy_from_user(&abs, p, - sizeof(struct input_absinfo))) + if (copy_from_user(&abs, p, min_t(size_t, + _IOC_SIZE(cmd), + sizeof(struct input_absinfo)))) return -EFAULT; /* @@ -670,6 +674,8 @@ static long evdev_do_ioctl(struct file *file, unsigned int cmd, dev->absmax[t] = abs.maximum; dev->absfuzz[t] = abs.fuzz; dev->absflat[t] = abs.flat; + dev->absres[t] = _IOC_SIZE(cmd) < sizeof(struct input_absinfo) ? + 0 : abs.resolution; spin_unlock_irq(&dev->event_lock); @@ -807,16 +813,15 @@ static int evdev_connect(struct input_handler *handler, struct input_dev *dev, mutex_init(&evdev->mutex); init_waitqueue_head(&evdev->wait); - snprintf(evdev->name, sizeof(evdev->name), "event%d", minor); + dev_set_name(&evdev->dev, "event%d", minor); evdev->exist = 1; evdev->minor = minor; evdev->handle.dev = input_get_device(dev); - evdev->handle.name = evdev->name; + evdev->handle.name = dev_name(&evdev->dev); evdev->handle.handler = handler; evdev->handle.private = evdev; - dev_set_name(&evdev->dev, evdev->name); evdev->dev.devt = MKDEV(INPUT_MAJOR, EVDEV_MINOR_BASE + minor); evdev->dev.class = &input_class; evdev->dev.parent = &dev->dev; diff --git a/drivers/input/gameport/fm801-gp.c b/drivers/input/gameport/fm801-gp.c index 1dec00e20dbc..8a1810f88b9e 100644 --- a/drivers/input/gameport/fm801-gp.c +++ b/drivers/input/gameport/fm801-gp.c @@ -167,5 +167,6 @@ module_exit(fm801_gp_exit); MODULE_DEVICE_TABLE(pci, fm801_gp_id_table); +MODULE_DESCRIPTION("FM801 gameport driver"); MODULE_AUTHOR("Takashi Iwai <tiwai@suse.de>"); MODULE_LICENSE("GPL"); diff --git a/drivers/input/gameport/gameport.c b/drivers/input/gameport/gameport.c index 2d175b5928ff..ac11be08585e 100644 --- a/drivers/input/gameport/gameport.c +++ b/drivers/input/gameport/gameport.c @@ -30,16 +30,6 @@ MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>"); MODULE_DESCRIPTION("Generic gameport layer"); MODULE_LICENSE("GPL"); -EXPORT_SYMBOL(__gameport_register_port); -EXPORT_SYMBOL(gameport_unregister_port); -EXPORT_SYMBOL(__gameport_register_driver); -EXPORT_SYMBOL(gameport_unregister_driver); -EXPORT_SYMBOL(gameport_open); -EXPORT_SYMBOL(gameport_close); -EXPORT_SYMBOL(gameport_set_phys); -EXPORT_SYMBOL(gameport_start_polling); -EXPORT_SYMBOL(gameport_stop_polling); - /* * gameport_mutex protects entire gameport subsystem and is taken * every time gameport port or driver registrered or unregistered. @@ -162,6 +152,7 @@ void gameport_start_polling(struct gameport *gameport) spin_unlock(&gameport->timer_lock); } +EXPORT_SYMBOL(gameport_start_polling); void gameport_stop_polling(struct gameport *gameport) { @@ -172,6 +163,7 @@ void gameport_stop_polling(struct gameport *gameport) spin_unlock(&gameport->timer_lock); } +EXPORT_SYMBOL(gameport_stop_polling); static void gameport_run_poll_handler(unsigned long d) { @@ -516,6 +508,7 @@ void gameport_set_phys(struct gameport *gameport, const char *fmt, ...) vsnprintf(gameport->phys, sizeof(gameport->phys), fmt, args); va_end(args); } +EXPORT_SYMBOL(gameport_set_phys); /* * Prepare gameport port for registration. @@ -658,6 +651,7 @@ void __gameport_register_port(struct gameport *gameport, struct module *owner) gameport_init_port(gameport); gameport_queue_event(gameport, owner, GAMEPORT_REGISTER_PORT); } +EXPORT_SYMBOL(__gameport_register_port); /* * Synchronously unregisters gameport port. @@ -669,6 +663,7 @@ void gameport_unregister_port(struct gameport *gameport) gameport_destroy_port(gameport); mutex_unlock(&gameport_mutex); } +EXPORT_SYMBOL(gameport_unregister_port); /* @@ -728,7 +723,7 @@ int __gameport_register_driver(struct gameport_driver *drv, struct module *owner * Temporarily disable automatic binding because probing * takes long time and we are better off doing it in kgameportd */ - drv->ignore = 1; + drv->ignore = true; error = driver_register(&drv->driver); if (error) { @@ -741,7 +736,7 @@ int __gameport_register_driver(struct gameport_driver *drv, struct module *owner /* * Reset ignore flag and let kgameportd bind the driver to free ports */ - drv->ignore = 0; + drv->ignore = false; error = gameport_queue_event(drv, NULL, GAMEPORT_ATTACH_DRIVER); if (error) { driver_unregister(&drv->driver); @@ -750,6 +745,7 @@ int __gameport_register_driver(struct gameport_driver *drv, struct module *owner return 0; } +EXPORT_SYMBOL(__gameport_register_driver); void gameport_unregister_driver(struct gameport_driver *drv) { @@ -757,7 +753,7 @@ void gameport_unregister_driver(struct gameport_driver *drv) mutex_lock(&gameport_mutex); - drv->ignore = 1; /* so gameport_find_driver ignores it */ + drv->ignore = true; /* so gameport_find_driver ignores it */ gameport_remove_pending_events(drv); start_over: @@ -774,6 +770,7 @@ start_over: mutex_unlock(&gameport_mutex); } +EXPORT_SYMBOL(gameport_unregister_driver); static int gameport_bus_match(struct device *dev, struct device_driver *drv) { @@ -812,6 +809,7 @@ int gameport_open(struct gameport *gameport, struct gameport_driver *drv, int mo gameport_set_drv(gameport, drv); return 0; } +EXPORT_SYMBOL(gameport_open); void gameport_close(struct gameport *gameport) { @@ -822,6 +820,7 @@ void gameport_close(struct gameport *gameport) if (gameport->close) gameport->close(gameport); } +EXPORT_SYMBOL(gameport_close); static int __init gameport_init(void) { diff --git a/drivers/input/joydev.c b/drivers/input/joydev.c index 012a5e753991..0e12f89276a3 100644 --- a/drivers/input/joydev.c +++ b/drivers/input/joydev.c @@ -39,7 +39,6 @@ struct joydev { int exist; int open; int minor; - char name[16]; struct input_handle handle; wait_queue_head_t wait; struct list_head client_list; @@ -537,12 +536,14 @@ static int joydev_ioctl_common(struct joydev *joydev, default: if ((cmd & ~IOCSIZE_MASK) == JSIOCGNAME(0)) { int len; - if (!dev->name) + const char *name = dev_name(&dev->dev); + + if (!name) return 0; - len = strlen(dev->name) + 1; + len = strlen(name) + 1; if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd); - if (copy_to_user(argp, dev->name, len)) + if (copy_to_user(argp, name, len)) return -EFAULT; return len; } @@ -742,13 +743,13 @@ static int joydev_connect(struct input_handler *handler, struct input_dev *dev, mutex_init(&joydev->mutex); init_waitqueue_head(&joydev->wait); - snprintf(joydev->name, sizeof(joydev->name), "js%d", minor); + dev_set_name(&joydev->dev, "js%d", minor); joydev->exist = 1; joydev->minor = minor; joydev->exist = 1; joydev->handle.dev = input_get_device(dev); - joydev->handle.name = joydev->name; + joydev->handle.name = dev_name(&joydev->dev); joydev->handle.handler = handler; joydev->handle.private = joydev; @@ -797,7 +798,6 @@ static int joydev_connect(struct input_handler *handler, struct input_dev *dev, } } - dev_set_name(&joydev->dev, joydev->name); joydev->dev.devt = MKDEV(INPUT_MAJOR, JOYDEV_MINOR_BASE + minor); joydev->dev.class = &input_class; joydev->dev.parent = &dev->dev; diff --git a/drivers/input/keyboard/Kconfig b/drivers/input/keyboard/Kconfig index ea2638b41982..9d8f796c6745 100644 --- a/drivers/input/keyboard/Kconfig +++ b/drivers/input/keyboard/Kconfig @@ -250,6 +250,17 @@ config KEYBOARD_HP7XX To compile this driver as a module, choose M here: the module will be called jornada720_kbd. +config KEYBOARD_LM8323 + tristate "LM8323 keypad chip" + depends on I2C + depends on LEDS_CLASS + help + If you say yes here you get support for the National Semiconductor + LM8323 keypad controller. + + To compile this driver as a module, choose M here: the + module will be called lm8323. + config KEYBOARD_OMAP tristate "TI OMAP keypad support" depends on (ARCH_OMAP1 || ARCH_OMAP2) @@ -332,4 +343,14 @@ config KEYBOARD_SH_KEYSC To compile this driver as a module, choose M here: the module will be called sh_keysc. + +config KEYBOARD_EP93XX + tristate "EP93xx Matrix Keypad support" + depends on ARCH_EP93XX + help + Say Y here to enable the matrix keypad on the Cirrus EP93XX. + + To compile this driver as a module, choose M here: the + module will be called ep93xx_keypad. + endif diff --git a/drivers/input/keyboard/Makefile b/drivers/input/keyboard/Makefile index 36351e1190f9..156b647a259b 100644 --- a/drivers/input/keyboard/Makefile +++ b/drivers/input/keyboard/Makefile @@ -18,6 +18,7 @@ obj-$(CONFIG_KEYBOARD_SPITZ) += spitzkbd.o obj-$(CONFIG_KEYBOARD_TOSA) += tosakbd.o obj-$(CONFIG_KEYBOARD_HIL) += hil_kbd.o obj-$(CONFIG_KEYBOARD_HIL_OLD) += hilkbd.o +obj-$(CONFIG_KEYBOARD_LM8323) += lm8323.o obj-$(CONFIG_KEYBOARD_OMAP) += omap-keypad.o obj-$(CONFIG_KEYBOARD_PXA27x) += pxa27x_keypad.o obj-$(CONFIG_KEYBOARD_PXA930_ROTARY) += pxa930_rotary.o @@ -28,3 +29,4 @@ obj-$(CONFIG_KEYBOARD_HP7XX) += jornada720_kbd.o obj-$(CONFIG_KEYBOARD_MAPLE) += maple_keyb.o obj-$(CONFIG_KEYBOARD_BFIN) += bf54x-keys.o obj-$(CONFIG_KEYBOARD_SH_KEYSC) += sh_keysc.o +obj-$(CONFIG_KEYBOARD_EP93XX) += ep93xx_keypad.o diff --git a/drivers/input/keyboard/ep93xx_keypad.c b/drivers/input/keyboard/ep93xx_keypad.c new file mode 100644 index 000000000000..181d30e3018e --- /dev/null +++ b/drivers/input/keyboard/ep93xx_keypad.c @@ -0,0 +1,470 @@ +/* + * Driver for the Cirrus EP93xx matrix keypad controller. + * + * Copyright (c) 2008 H Hartley Sweeten <hsweeten@visionengravers.com> + * + * Based on the pxa27x matrix keypad controller by Rodolfo Giometti. + * + * 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. + * + * NOTE: + * + * The 3-key reset is triggered by pressing the 3 keys in + * Row 0, Columns 2, 4, and 7 at the same time. This action can + * be disabled by setting the EP93XX_KEYPAD_DISABLE_3_KEY flag. + * + * Normal operation for the matrix does not autorepeat the key press. + * This action can be enabled by setting the EP93XX_KEYPAD_AUTOREPEAT + * flag. + */ + +#include <linux/platform_device.h> +#include <linux/interrupt.h> +#include <linux/input.h> +#include <linux/clk.h> + +#include <mach/hardware.h> +#include <mach/gpio.h> +#include <mach/ep93xx_keypad.h> + +/* + * Keypad Interface Register offsets + */ +#define KEY_INIT 0x00 /* Key Scan Initialization register */ +#define KEY_DIAG 0x04 /* Key Scan Diagnostic register */ +#define KEY_REG 0x08 /* Key Value Capture register */ + +/* Key Scan Initialization Register bit defines */ +#define KEY_INIT_DBNC_MASK (0x00ff0000) +#define KEY_INIT_DBNC_SHIFT (16) +#define KEY_INIT_DIS3KY (1<<15) +#define KEY_INIT_DIAG (1<<14) +#define KEY_INIT_BACK (1<<13) +#define KEY_INIT_T2 (1<<12) +#define KEY_INIT_PRSCL_MASK (0x000003ff) +#define KEY_INIT_PRSCL_SHIFT (0) + +/* Key Scan Diagnostic Register bit defines */ +#define KEY_DIAG_MASK (0x0000003f) +#define KEY_DIAG_SHIFT (0) + +/* Key Value Capture Register bit defines */ +#define KEY_REG_K (1<<15) +#define KEY_REG_INT (1<<14) +#define KEY_REG_2KEYS (1<<13) +#define KEY_REG_1KEY (1<<12) +#define KEY_REG_KEY2_MASK (0x00000fc0) +#define KEY_REG_KEY2_SHIFT (6) +#define KEY_REG_KEY1_MASK (0x0000003f) +#define KEY_REG_KEY1_SHIFT (0) + +#define keypad_readl(off) __raw_readl(keypad->mmio_base + (off)) +#define keypad_writel(v, off) __raw_writel((v), keypad->mmio_base + (off)) + +#define MAX_MATRIX_KEY_NUM (MAX_MATRIX_KEY_ROWS * MAX_MATRIX_KEY_COLS) + +struct ep93xx_keypad { + struct ep93xx_keypad_platform_data *pdata; + + struct clk *clk; + struct input_dev *input_dev; + void __iomem *mmio_base; + + int irq; + int enabled; + + int key1; + int key2; + + unsigned int matrix_keycodes[MAX_MATRIX_KEY_NUM]; +}; + +static void ep93xx_keypad_build_keycode(struct ep93xx_keypad *keypad) +{ + struct ep93xx_keypad_platform_data *pdata = keypad->pdata; + struct input_dev *input_dev = keypad->input_dev; + int i; + + for (i = 0; i < pdata->matrix_key_map_size; i++) { + unsigned int key = pdata->matrix_key_map[i]; + int row = (key >> 28) & 0xf; + int col = (key >> 24) & 0xf; + int code = key & 0xffffff; + + keypad->matrix_keycodes[(row << 3) + col] = code; + __set_bit(code, input_dev->keybit); + } +} + +static irqreturn_t ep93xx_keypad_irq_handler(int irq, void *dev_id) +{ + struct ep93xx_keypad *keypad = dev_id; + struct input_dev *input_dev = keypad->input_dev; + unsigned int status = keypad_readl(KEY_REG); + int keycode, key1, key2; + + keycode = (status & KEY_REG_KEY1_MASK) >> KEY_REG_KEY1_SHIFT; + key1 = keypad->matrix_keycodes[keycode]; + + keycode = (status & KEY_REG_KEY2_MASK) >> KEY_REG_KEY2_SHIFT; + key2 = keypad->matrix_keycodes[keycode]; + + if (status & KEY_REG_2KEYS) { + if (keypad->key1 && key1 != keypad->key1 && key2 != keypad->key1) + input_report_key(input_dev, keypad->key1, 0); + + if (keypad->key2 && key1 != keypad->key2 && key2 != keypad->key2) + input_report_key(input_dev, keypad->key2, 0); + + input_report_key(input_dev, key1, 1); + input_report_key(input_dev, key2, 1); + + keypad->key1 = key1; + keypad->key2 = key2; + + } else if (status & KEY_REG_1KEY) { + if (keypad->key1 && key1 != keypad->key1) + input_report_key(input_dev, keypad->key1, 0); + + if (keypad->key2 && key1 != keypad->key2) + input_report_key(input_dev, keypad->key2, 0); + + input_report_key(input_dev, key1, 1); + + keypad->key1 = key1; + keypad->key2 = 0; + + } else { + input_report_key(input_dev, keypad->key1, 0); + input_report_key(input_dev, keypad->key2, 0); + + keypad->key1 = keypad->key2 = 0; + } + input_sync(input_dev); + + return IRQ_HANDLED; +} + +static void ep93xx_keypad_config(struct ep93xx_keypad *keypad) +{ + struct ep93xx_keypad_platform_data *pdata = keypad->pdata; + unsigned int val = 0; + + clk_set_rate(keypad->clk, pdata->flags & EP93XX_KEYPAD_KDIV); + + if (pdata->flags & EP93XX_KEYPAD_DISABLE_3_KEY) + val |= KEY_INIT_DIS3KY; + if (pdata->flags & EP93XX_KEYPAD_DIAG_MODE) + val |= KEY_INIT_DIAG; + if (pdata->flags & EP93XX_KEYPAD_BACK_DRIVE) + val |= KEY_INIT_BACK; + if (pdata->flags & EP93XX_KEYPAD_TEST_MODE) + val |= KEY_INIT_T2; + + val |= ((pdata->debounce << KEY_INIT_DBNC_SHIFT) & KEY_INIT_DBNC_MASK); + + val |= ((pdata->prescale << KEY_INIT_PRSCL_SHIFT) & KEY_INIT_PRSCL_MASK); + + keypad_writel(val, KEY_INIT); +} + +static int ep93xx_keypad_open(struct input_dev *pdev) +{ + struct ep93xx_keypad *keypad = input_get_drvdata(pdev); + + if (!keypad->enabled) { + ep93xx_keypad_config(keypad); + clk_enable(keypad->clk); + keypad->enabled = 1; + } + + return 0; +} + +static void ep93xx_keypad_close(struct input_dev *pdev) +{ + struct ep93xx_keypad *keypad = input_get_drvdata(pdev); + + if (keypad->enabled) { + clk_disable(keypad->clk); + keypad->enabled = 0; + } +} + + +#ifdef CONFIG_PM +/* + * NOTE: I don't know if this is correct, or will work on the ep93xx. + * + * None of the existing ep93xx drivers have power management support. + * But, this is basically what the pxa27x_keypad driver does. + */ +static int ep93xx_keypad_suspend(struct platform_device *pdev, + pm_message_t state) +{ + struct ep93xx_keypad *keypad = platform_get_drvdata(pdev); + struct input_dev *input_dev = keypad->input_dev; + + mutex_lock(&input_dev->mutex); + + if (keypad->enabled) { + clk_disable(keypad->clk); + keypad->enabled = 0; + } + + mutex_unlock(&input_dev->mutex); + + if (device_may_wakeup(&pdev->dev)) + enable_irq_wake(keypad->irq); + + return 0; +} + +static int ep93xx_keypad_resume(struct platform_device *pdev) +{ + struct ep93xx_keypad *keypad = platform_get_drvdata(pdev); + struct input_dev *input_dev = keypad->input_dev; + + if (device_may_wakeup(&pdev->dev)) + disable_irq_wake(keypad->irq); + + mutex_lock(&input_dev->mutex); + + if (input_dev->users) { + if (!keypad->enabled) { + ep93xx_keypad_config(keypad); + clk_enable(keypad->clk); + keypad->enabled = 1; + } + } + + mutex_unlock(&input_dev->mutex); + + return 0; +} +#else /* !CONFIG_PM */ +#define ep93xx_keypad_suspend NULL +#define ep93xx_keypad_resume NULL +#endif /* !CONFIG_PM */ + +static int __devinit ep93xx_keypad_probe(struct platform_device *pdev) +{ + struct ep93xx_keypad *keypad; + struct ep93xx_keypad_platform_data *pdata = pdev->dev.platform_data; + struct input_dev *input_dev; + struct resource *res; + int irq, err, i, gpio; + + if (!pdata || + !pdata->matrix_key_rows || + pdata->matrix_key_rows > MAX_MATRIX_KEY_ROWS || + !pdata->matrix_key_cols || + pdata->matrix_key_cols > MAX_MATRIX_KEY_COLS) { + dev_err(&pdev->dev, "invalid or missing platform data\n"); + return -EINVAL; + } + + keypad = kzalloc(sizeof(struct ep93xx_keypad), GFP_KERNEL); + if (!keypad) { + dev_err(&pdev->dev, "failed to allocate driver data\n"); + return -ENOMEM; + } + + keypad->pdata = pdata; + + irq = platform_get_irq(pdev, 0); + if (irq < 0) { + dev_err(&pdev->dev, "failed to get keypad irq\n"); + err = -ENXIO; + goto failed_free; + } + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) { + dev_err(&pdev->dev, "failed to get I/O memory\n"); + err = -ENXIO; + goto failed_free; + } + + res = request_mem_region(res->start, resource_size(res), pdev->name); + if (!res) { + dev_err(&pdev->dev, "failed to request I/O memory\n"); + err = -EBUSY; + goto failed_free; + } + + keypad->mmio_base = ioremap(res->start, resource_size(res)); + if (keypad->mmio_base == NULL) { + dev_err(&pdev->dev, "failed to remap I/O memory\n"); + err = -ENXIO; + goto failed_free_mem; + } + + /* Request the needed GPIO's */ + gpio = EP93XX_GPIO_LINE_ROW0; + for (i = 0; i < keypad->pdata->matrix_key_rows; i++, gpio++) { + err = gpio_request(gpio, pdev->name); + if (err) { + dev_err(&pdev->dev, "failed to request gpio-%d\n", + gpio); + goto failed_free_rows; + } + } + + gpio = EP93XX_GPIO_LINE_COL0; + for (i = 0; i < keypad->pdata->matrix_key_cols; i++, gpio++) { + err = gpio_request(gpio, pdev->name); + if (err) { + dev_err(&pdev->dev, "failed to request gpio-%d\n", + gpio); + goto failed_free_cols; + } + } + + keypad->clk = clk_get(&pdev->dev, "key_clk"); + if (IS_ERR(keypad->clk)) { + dev_err(&pdev->dev, "failed to get keypad clock\n"); + err = PTR_ERR(keypad->clk); + goto failed_free_io; + } + + /* Create and register the input driver */ + input_dev = input_allocate_device(); + if (!input_dev) { + dev_err(&pdev->dev, "failed to allocate input device\n"); + err = -ENOMEM; + goto failed_put_clk; + } + + keypad->input_dev = input_dev; + + input_dev->name = pdev->name; + input_dev->id.bustype = BUS_HOST; + input_dev->open = ep93xx_keypad_open; + input_dev->close = ep93xx_keypad_close; + input_dev->dev.parent = &pdev->dev; + input_dev->keycode = keypad->matrix_keycodes; + input_dev->keycodesize = sizeof(keypad->matrix_keycodes[0]); + input_dev->keycodemax = ARRAY_SIZE(keypad->matrix_keycodes); + + input_set_drvdata(input_dev, keypad); + + input_dev->evbit[0] = BIT_MASK(EV_KEY); + if (keypad->pdata->flags & EP93XX_KEYPAD_AUTOREPEAT) + input_dev->evbit[0] |= BIT_MASK(EV_REP); + + ep93xx_keypad_build_keycode(keypad); + platform_set_drvdata(pdev, keypad); + + err = request_irq(irq, ep93xx_keypad_irq_handler, IRQF_DISABLED, + pdev->name, keypad); + if (err) { + dev_err(&pdev->dev, "failed to request IRQ\n"); + goto failed_free_dev; + } + + keypad->irq = irq; + + /* Register the input device */ + err = input_register_device(input_dev); + if (err) { + dev_err(&pdev->dev, "failed to register input device\n"); + goto failed_free_irq; + } + + device_init_wakeup(&pdev->dev, 1); + + return 0; + +failed_free_irq: + free_irq(irq, pdev); + platform_set_drvdata(pdev, NULL); +failed_free_dev: + input_free_device(input_dev); +failed_put_clk: + clk_put(keypad->clk); +failed_free_io: + i = keypad->pdata->matrix_key_cols - 1; + gpio = EP93XX_GPIO_LINE_COL0 + i; +failed_free_cols: + for ( ; i >= 0; i--, gpio--) + gpio_free(gpio); + i = keypad->pdata->matrix_key_rows - 1; + gpio = EP93XX_GPIO_LINE_ROW0 + i; +failed_free_rows: + for ( ; i >= 0; i--, gpio--) + gpio_free(gpio); + iounmap(keypad->mmio_base); +failed_free_mem: + release_mem_region(res->start, resource_size(res)); +failed_free: + kfree(keypad); + return err; +} + +static int __devexit ep93xx_keypad_remove(struct platform_device *pdev) +{ + struct ep93xx_keypad *keypad = platform_get_drvdata(pdev); + struct resource *res; + int i, gpio; + + free_irq(keypad->irq, pdev); + + platform_set_drvdata(pdev, NULL); + + if (keypad->enabled) + clk_disable(keypad->clk); + clk_put(keypad->clk); + + input_unregister_device(keypad->input_dev); + + i = keypad->pdata->matrix_key_cols - 1; + gpio = EP93XX_GPIO_LINE_COL0 + i; + for ( ; i >= 0; i--, gpio--) + gpio_free(gpio); + + i = keypad->pdata->matrix_key_rows - 1; + gpio = EP93XX_GPIO_LINE_ROW0 + i; + for ( ; i >= 0; i--, gpio--) + gpio_free(gpio); + + iounmap(keypad->mmio_base); + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + release_mem_region(res->start, resource_size(res)); + + kfree(keypad); + + return 0; +} + +static struct platform_driver ep93xx_keypad_driver = { + .driver = { + .name = "ep93xx-keypad", + .owner = THIS_MODULE, + }, + .probe = ep93xx_keypad_probe, + .remove = __devexit_p(ep93xx_keypad_remove), + .suspend = ep93xx_keypad_suspend, + .resume = ep93xx_keypad_resume, +}; + +static int __init ep93xx_keypad_init(void) +{ + return platform_driver_register(&ep93xx_keypad_driver); +} + +static void __exit ep93xx_keypad_exit(void) +{ + platform_driver_unregister(&ep93xx_keypad_driver); +} + +module_init(ep93xx_keypad_init); +module_exit(ep93xx_keypad_exit); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("H Hartley Sweeten <hsweeten@visionengravers.com>"); +MODULE_DESCRIPTION("EP93xx Matrix Keypad Controller"); +MODULE_ALIAS("platform:ep93xx-keypad"); diff --git a/drivers/input/keyboard/gpio_keys.c b/drivers/input/keyboard/gpio_keys.c index ad67d763fdbd..2157cd7de00c 100644 --- a/drivers/input/keyboard/gpio_keys.c +++ b/drivers/input/keyboard/gpio_keys.c @@ -22,13 +22,14 @@ #include <linux/platform_device.h> #include <linux/input.h> #include <linux/gpio_keys.h> +#include <linux/workqueue.h> #include <asm/gpio.h> struct gpio_button_data { struct gpio_keys_button *button; struct input_dev *input; - struct timer_list timer; + struct delayed_work work; }; struct gpio_keys_drvdata { @@ -36,8 +37,10 @@ struct gpio_keys_drvdata { struct gpio_button_data data[0]; }; -static void gpio_keys_report_event(struct gpio_button_data *bdata) +static void gpio_keys_report_event(struct work_struct *work) { + struct gpio_button_data *bdata = + container_of(work, struct gpio_button_data, work.work); struct gpio_keys_button *button = bdata->button; struct input_dev *input = bdata->input; unsigned int type = button->type ?: EV_KEY; @@ -47,25 +50,17 @@ static void gpio_keys_report_event(struct gpio_button_data *bdata) input_sync(input); } -static void gpio_check_button(unsigned long _data) -{ - struct gpio_button_data *data = (struct gpio_button_data *)_data; - - gpio_keys_report_event(data); -} - static irqreturn_t gpio_keys_isr(int irq, void *dev_id) { struct gpio_button_data *bdata = dev_id; struct gpio_keys_button *button = bdata->button; + unsigned long delay; BUG_ON(irq != gpio_to_irq(button->gpio)); - if (button->debounce_interval) - mod_timer(&bdata->timer, - jiffies + msecs_to_jiffies(button->debounce_interval)); - else - gpio_keys_report_event(bdata); + delay = button->debounce_interval ? + msecs_to_jiffies(button->debounce_interval) : 0; + schedule_delayed_work(&bdata->work, delay); return IRQ_HANDLED; } @@ -112,8 +107,7 @@ static int __devinit gpio_keys_probe(struct platform_device *pdev) bdata->input = input; bdata->button = button; - setup_timer(&bdata->timer, - gpio_check_button, (unsigned long)bdata); + INIT_DELAYED_WORK(&bdata->work, gpio_keys_report_event); error = gpio_request(button->gpio, button->desc ?: "gpio_keys"); if (error < 0) { @@ -142,8 +136,7 @@ static int __devinit gpio_keys_probe(struct platform_device *pdev) } error = request_irq(irq, gpio_keys_isr, - IRQF_SAMPLE_RANDOM | IRQF_TRIGGER_RISING | - IRQF_TRIGGER_FALLING, + IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, button->desc ? button->desc : "gpio_keys", bdata); if (error) { @@ -173,8 +166,7 @@ static int __devinit gpio_keys_probe(struct platform_device *pdev) fail2: while (--i >= 0) { free_irq(gpio_to_irq(pdata->buttons[i].gpio), &ddata->data[i]); - if (pdata->buttons[i].debounce_interval) - del_timer_sync(&ddata->data[i].timer); + cancel_delayed_work_sync(&ddata->data[i].work); gpio_free(pdata->buttons[i].gpio); } @@ -198,8 +190,7 @@ static int __devexit gpio_keys_remove(struct platform_device *pdev) for (i = 0; i < pdata->nbuttons; i++) { int irq = gpio_to_irq(pdata->buttons[i].gpio); free_irq(irq, &ddata->data[i]); - if (pdata->buttons[i].debounce_interval) - del_timer_sync(&ddata->data[i].timer); + cancel_delayed_work_sync(&ddata->data[i].work); gpio_free(pdata->buttons[i].gpio); } diff --git a/drivers/input/keyboard/lm8323.c b/drivers/input/keyboard/lm8323.c new file mode 100644 index 000000000000..574eda2a4957 --- /dev/null +++ b/drivers/input/keyboard/lm8323.c @@ -0,0 +1,878 @@ +/* + * drivers/i2c/chips/lm8323.c + * + * Copyright (C) 2007-2009 Nokia Corporation + * + * Written by Daniel Stone <daniel.stone@nokia.com> + * Timo O. Karjalainen <timo.o.karjalainen@nokia.com> + * + * Updated by Felipe Balbi <felipe.balbi@nokia.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation (version 2 of the License only). + * + * 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 + */ + +#include <linux/module.h> +#include <linux/i2c.h> +#include <linux/interrupt.h> +#include <linux/sched.h> +#include <linux/mutex.h> +#include <linux/delay.h> +#include <linux/input.h> +#include <linux/leds.h> +#include <linux/i2c/lm8323.h> + +/* Commands to send to the chip. */ +#define LM8323_CMD_READ_ID 0x80 /* Read chip ID. */ +#define LM8323_CMD_WRITE_CFG 0x81 /* Set configuration item. */ +#define LM8323_CMD_READ_INT 0x82 /* Get interrupt status. */ +#define LM8323_CMD_RESET 0x83 /* Reset, same as external one */ +#define LM8323_CMD_WRITE_PORT_SEL 0x85 /* Set GPIO in/out. */ +#define LM8323_CMD_WRITE_PORT_STATE 0x86 /* Set GPIO pullup. */ +#define LM8323_CMD_READ_PORT_SEL 0x87 /* Get GPIO in/out. */ +#define LM8323_CMD_READ_PORT_STATE 0x88 /* Get GPIO pullup. */ +#define LM8323_CMD_READ_FIFO 0x89 /* Read byte from FIFO. */ +#define LM8323_CMD_RPT_READ_FIFO 0x8a /* Read FIFO (no increment). */ +#define LM8323_CMD_SET_ACTIVE 0x8b /* Set active time. */ +#define LM8323_CMD_READ_ERR 0x8c /* Get error status. */ +#define LM8323_CMD_READ_ROTATOR 0x8e /* Read rotator status. */ +#define LM8323_CMD_SET_DEBOUNCE 0x8f /* Set debouncing time. */ +#define LM8323_CMD_SET_KEY_SIZE 0x90 /* Set keypad size. */ +#define LM8323_CMD_READ_KEY_SIZE 0x91 /* Get keypad size. */ +#define LM8323_CMD_READ_CFG 0x92 /* Get configuration item. */ +#define LM8323_CMD_WRITE_CLOCK 0x93 /* Set clock config. */ +#define LM8323_CMD_READ_CLOCK 0x94 /* Get clock config. */ +#define LM8323_CMD_PWM_WRITE 0x95 /* Write PWM script. */ +#define LM8323_CMD_START_PWM 0x96 /* Start PWM engine. */ +#define LM8323_CMD_STOP_PWM 0x97 /* Stop PWM engine. */ + +/* Interrupt status. */ +#define INT_KEYPAD 0x01 /* Key event. */ +#define INT_ROTATOR 0x02 /* Rotator event. */ +#define INT_ERROR 0x08 /* Error: use CMD_READ_ERR. */ +#define INT_NOINIT 0x10 /* Lost configuration. */ +#define INT_PWM1 0x20 /* PWM1 stopped. */ +#define INT_PWM2 0x40 /* PWM2 stopped. */ +#define INT_PWM3 0x80 /* PWM3 stopped. */ + +/* Errors (signalled by INT_ERROR, read with CMD_READ_ERR). */ +#define ERR_BADPAR 0x01 /* Bad parameter. */ +#define ERR_CMDUNK 0x02 /* Unknown command. */ +#define ERR_KEYOVR 0x04 /* Too many keys pressed. */ +#define ERR_FIFOOVER 0x40 /* FIFO overflow. */ + +/* Configuration keys (CMD_{WRITE,READ}_CFG). */ +#define CFG_MUX1SEL 0x01 /* Select MUX1_OUT input. */ +#define CFG_MUX1EN 0x02 /* Enable MUX1_OUT. */ +#define CFG_MUX2SEL 0x04 /* Select MUX2_OUT input. */ +#define CFG_MUX2EN 0x08 /* Enable MUX2_OUT. */ +#define CFG_PSIZE 0x20 /* Package size (must be 0). */ +#define CFG_ROTEN 0x40 /* Enable rotator. */ + +/* Clock settings (CMD_{WRITE,READ}_CLOCK). */ +#define CLK_RCPWM_INTERNAL 0x00 +#define CLK_RCPWM_EXTERNAL 0x03 +#define CLK_SLOWCLKEN 0x08 /* Enable 32.768kHz clock. */ +#define CLK_SLOWCLKOUT 0x40 /* Enable slow pulse output. */ + +/* The possible addresses corresponding to CONFIG1 and CONFIG2 pin wirings. */ +#define LM8323_I2C_ADDR00 (0x84 >> 1) /* 1000 010x */ +#define LM8323_I2C_ADDR01 (0x86 >> 1) /* 1000 011x */ +#define LM8323_I2C_ADDR10 (0x88 >> 1) /* 1000 100x */ +#define LM8323_I2C_ADDR11 (0x8A >> 1) /* 1000 101x */ + +/* Key event fifo length */ +#define LM8323_FIFO_LEN 15 + +/* Commands for PWM engine; feed in with PWM_WRITE. */ +/* Load ramp counter from duty cycle field (range 0 - 0xff). */ +#define PWM_SET(v) (0x4000 | ((v) & 0xff)) +/* Go to start of script. */ +#define PWM_GOTOSTART 0x0000 +/* + * Stop engine (generates interrupt). If reset is 1, clear the program + * counter, else leave it. + */ +#define PWM_END(reset) (0xc000 | (!!(reset) << 11)) +/* + * Ramp. If s is 1, divide clock by 512, else divide clock by 16. + * Take t clock scales (up to 63) per step, for n steps (up to 126). + * If u is set, ramp up, else ramp down. + */ +#define PWM_RAMP(s, t, n, u) ((!!(s) << 14) | ((t) & 0x3f) << 8 | \ + ((n) & 0x7f) | ((u) ? 0 : 0x80)) +/* + * Loop (i.e. jump back to pos) for a given number of iterations (up to 63). + * If cnt is zero, execute until PWM_END is encountered. + */ +#define PWM_LOOP(cnt, pos) (0xa000 | (((cnt) & 0x3f) << 7) | \ + ((pos) & 0x3f)) +/* + * Wait for trigger. Argument is a mask of channels, shifted by the channel + * number, e.g. 0xa for channels 3 and 1. Note that channels are numbered + * from 1, not 0. + */ +#define PWM_WAIT_TRIG(chans) (0xe000 | (((chans) & 0x7) << 6)) +/* Send trigger. Argument is same as PWM_WAIT_TRIG. */ +#define PWM_SEND_TRIG(chans) (0xe000 | ((chans) & 0x7)) + +struct lm8323_pwm { + int id; + int fade_time; + int brightness; + int desired_brightness; + bool enabled; + bool running; + /* pwm lock */ + struct mutex lock; + struct work_struct work; + struct led_classdev cdev; + struct lm8323_chip *chip; +}; + +struct lm8323_chip { + /* device lock */ + struct mutex lock; + struct i2c_client *client; + struct work_struct work; + struct input_dev *idev; + bool kp_enabled; + bool pm_suspend; + unsigned keys_down; + char phys[32]; + unsigned short keymap[LM8323_KEYMAP_SIZE]; + int size_x; + int size_y; + int debounce_time; + int active_time; + struct lm8323_pwm pwm[LM8323_NUM_PWMS]; +}; + +#define client_to_lm8323(c) container_of(c, struct lm8323_chip, client) +#define dev_to_lm8323(d) container_of(d, struct lm8323_chip, client->dev) +#define work_to_lm8323(w) container_of(w, struct lm8323_chip, work) +#define cdev_to_pwm(c) container_of(c, struct lm8323_pwm, cdev) +#define work_to_pwm(w) container_of(w, struct lm8323_pwm, work) + +#define LM8323_MAX_DATA 8 + +/* + * To write, we just access the chip's address in write mode, and dump the + * command and data out on the bus. The command byte and data are taken as + * sequential u8s out of varargs, to a maximum of LM8323_MAX_DATA. + */ +static int lm8323_write(struct lm8323_chip *lm, int len, ...) +{ + int ret, i; + va_list ap; + u8 data[LM8323_MAX_DATA]; + + va_start(ap, len); + + if (unlikely(len > LM8323_MAX_DATA)) { + dev_err(&lm->client->dev, "tried to send %d bytes\n", len); + va_end(ap); + return 0; + } + + for (i = 0; i < len; i++) + data[i] = va_arg(ap, int); + + va_end(ap); + + /* + * If the host is asleep while we send the data, we can get a NACK + * back while it wakes up, so try again, once. + */ + ret = i2c_master_send(lm->client, data, len); + if (unlikely(ret == -EREMOTEIO)) + ret = i2c_master_send(lm->client, data, len); + if (unlikely(ret != len)) + dev_err(&lm->client->dev, "sent %d bytes of %d total\n", + len, ret); + + return ret; +} + +/* + * To read, we first send the command byte to the chip and end the transaction, + * then access the chip in read mode, at which point it will send the data. + */ +static int lm8323_read(struct lm8323_chip *lm, u8 cmd, u8 *buf, int len) +{ + int ret; + + /* + * If the host is asleep while we send the byte, we can get a NACK + * back while it wakes up, so try again, once. + */ + ret = i2c_master_send(lm->client, &cmd, 1); + if (unlikely(ret == -EREMOTEIO)) + ret = i2c_master_send(lm->client, &cmd, 1); + if (unlikely(ret != 1)) { + dev_err(&lm->client->dev, "sending read cmd 0x%02x failed\n", + cmd); + return 0; + } + + ret = i2c_master_recv(lm->client, buf, len); + if (unlikely(ret != len)) + dev_err(&lm->client->dev, "wanted %d bytes, got %d\n", + len, ret); + + return ret; +} + +/* + * Set the chip active time (idle time before it enters halt). + */ +static void lm8323_set_active_time(struct lm8323_chip *lm, int time) +{ + lm8323_write(lm, 2, LM8323_CMD_SET_ACTIVE, time >> 2); +} + +/* + * The signals are AT-style: the low 7 bits are the keycode, and the top + * bit indicates the state (1 for down, 0 for up). + */ +static inline u8 lm8323_whichkey(u8 event) +{ + return event & 0x7f; +} + +static inline int lm8323_ispress(u8 event) +{ + return (event & 0x80) ? 1 : 0; +} + +static void process_keys(struct lm8323_chip *lm) +{ + u8 event; + u8 key_fifo[LM8323_FIFO_LEN + 1]; + int old_keys_down = lm->keys_down; + int ret; + int i = 0; + + /* + * Read all key events from the FIFO at once. Next READ_FIFO clears the + * FIFO even if we didn't read all events previously. + */ + ret = lm8323_read(lm, LM8323_CMD_READ_FIFO, key_fifo, LM8323_FIFO_LEN); + + if (ret < 0) { + dev_err(&lm->client->dev, "Failed reading fifo \n"); + return; + } + key_fifo[ret] = 0; + + while ((event = key_fifo[i++])) { + u8 key = lm8323_whichkey(event); + int isdown = lm8323_ispress(event); + unsigned short keycode = lm->keymap[key]; + + dev_vdbg(&lm->client->dev, "key 0x%02x %s\n", + key, isdown ? "down" : "up"); + + if (lm->kp_enabled) { + input_event(lm->idev, EV_MSC, MSC_SCAN, key); + input_report_key(lm->idev, keycode, isdown); + input_sync(lm->idev); + } + + if (isdown) + lm->keys_down++; + else + lm->keys_down--; + } + + /* + * Errata: We need to ensure that the chip never enters halt mode + * during a keypress, so set active time to 0. When it's released, + * we can enter halt again, so set the active time back to normal. + */ + if (!old_keys_down && lm->keys_down) + lm8323_set_active_time(lm, 0); + if (old_keys_down && !lm->keys_down) + lm8323_set_active_time(lm, lm->active_time); +} + +static void lm8323_process_error(struct lm8323_chip *lm) +{ + u8 error; + + if (lm8323_read(lm, LM8323_CMD_READ_ERR, &error, 1) == 1) { + if (error & ERR_FIFOOVER) + dev_vdbg(&lm->client->dev, "fifo overflow!\n"); + if (error & ERR_KEYOVR) + dev_vdbg(&lm->client->dev, + "more than two keys pressed\n"); + if (error & ERR_CMDUNK) + dev_vdbg(&lm->client->dev, + "unknown command submitted\n"); + if (error & ERR_BADPAR) + dev_vdbg(&lm->client->dev, "bad command parameter\n"); + } +} + +static void lm8323_reset(struct lm8323_chip *lm) +{ + /* The docs say we must pass 0xAA as the data byte. */ + lm8323_write(lm, 2, LM8323_CMD_RESET, 0xAA); +} + +static int lm8323_configure(struct lm8323_chip *lm) +{ + int keysize = (lm->size_x << 4) | lm->size_y; + int clock = (CLK_SLOWCLKEN | CLK_RCPWM_EXTERNAL); + int debounce = lm->debounce_time >> 2; + int active = lm->active_time >> 2; + + /* + * Active time must be greater than the debounce time: if it's + * a close-run thing, give ourselves a 12ms buffer. + */ + if (debounce >= active) + active = debounce + 3; + + lm8323_write(lm, 2, LM8323_CMD_WRITE_CFG, 0); + lm8323_write(lm, 2, LM8323_CMD_WRITE_CLOCK, clock); + lm8323_write(lm, 2, LM8323_CMD_SET_KEY_SIZE, keysize); + lm8323_set_active_time(lm, lm->active_time); + lm8323_write(lm, 2, LM8323_CMD_SET_DEBOUNCE, debounce); + lm8323_write(lm, 3, LM8323_CMD_WRITE_PORT_STATE, 0xff, 0xff); + lm8323_write(lm, 3, LM8323_CMD_WRITE_PORT_SEL, 0, 0); + + /* + * Not much we can do about errors at this point, so just hope + * for the best. + */ + + return 0; +} + +static void pwm_done(struct lm8323_pwm *pwm) +{ + mutex_lock(&pwm->lock); + pwm->running = false; + if (pwm->desired_brightness != pwm->brightness) + schedule_work(&pwm->work); + mutex_unlock(&pwm->lock); +} + +/* + * Bottom half: handle the interrupt by posting key events, or dealing with + * errors appropriately. + */ +static void lm8323_work(struct work_struct *work) +{ + struct lm8323_chip *lm = work_to_lm8323(work); + u8 ints; + int i; + + mutex_lock(&lm->lock); + + while ((lm8323_read(lm, LM8323_CMD_READ_INT, &ints, 1) == 1) && ints) { + if (likely(ints & INT_KEYPAD)) + process_keys(lm); + if (ints & INT_ROTATOR) { + /* We don't currently support the rotator. */ + dev_vdbg(&lm->client->dev, "rotator fired\n"); + } + if (ints & INT_ERROR) { + dev_vdbg(&lm->client->dev, "error!\n"); + lm8323_process_error(lm); + } + if (ints & INT_NOINIT) { + dev_err(&lm->client->dev, "chip lost config; " + "reinitialising\n"); + lm8323_configure(lm); + } + for (i = 0; i < LM8323_NUM_PWMS; i++) { + if (ints & (1 << (INT_PWM1 + i))) { + dev_vdbg(&lm->client->dev, + "pwm%d engine completed\n", i); + pwm_done(&lm->pwm[i]); + } + } + } + + mutex_unlock(&lm->lock); +} + +/* + * We cannot use I2C in interrupt context, so we just schedule work. + */ +static irqreturn_t lm8323_irq(int irq, void *data) +{ + struct lm8323_chip *lm = data; + + schedule_work(&lm->work); + + return IRQ_HANDLED; +} + +/* + * Read the chip ID. + */ +static int lm8323_read_id(struct lm8323_chip *lm, u8 *buf) +{ + int bytes; + + bytes = lm8323_read(lm, LM8323_CMD_READ_ID, buf, 2); + if (unlikely(bytes != 2)) + return -EIO; + + return 0; +} + +static void lm8323_write_pwm_one(struct lm8323_pwm *pwm, int pos, u16 cmd) +{ + lm8323_write(pwm->chip, 4, LM8323_CMD_PWM_WRITE, (pos << 2) | pwm->id, + (cmd & 0xff00) >> 8, cmd & 0x00ff); +} + +/* + * Write a script into a given PWM engine, concluding with PWM_END. + * If 'kill' is nonzero, the engine will be shut down at the end + * of the script, producing a zero output. Otherwise the engine + * will be kept running at the final PWM level indefinitely. + */ +static void lm8323_write_pwm(struct lm8323_pwm *pwm, int kill, + int len, const u16 *cmds) +{ + int i; + + for (i = 0; i < len; i++) + lm8323_write_pwm_one(pwm, i, cmds[i]); + + lm8323_write_pwm_one(pwm, i++, PWM_END(kill)); + lm8323_write(pwm->chip, 2, LM8323_CMD_START_PWM, pwm->id); + pwm->running = true; +} + +static void lm8323_pwm_work(struct work_struct *work) +{ + struct lm8323_pwm *pwm = work_to_pwm(work); + int div512, perstep, steps, hz, up, kill; + u16 pwm_cmds[3]; + int num_cmds = 0; + + mutex_lock(&pwm->lock); + + /* + * Do nothing if we're already at the requested level, + * or previous setting is not yet complete. In the latter + * case we will be called again when the previous PWM script + * finishes. + */ + if (pwm->running || pwm->desired_brightness == pwm->brightness) + goto out; + + kill = (pwm->desired_brightness == 0); + up = (pwm->desired_brightness > pwm->brightness); + steps = abs(pwm->desired_brightness - pwm->brightness); + + /* + * Convert time (in ms) into a divisor (512 or 16 on a refclk of + * 32768Hz), and number of ticks per step. + */ + if ((pwm->fade_time / steps) > (32768 / 512)) { + div512 = 1; + hz = 32768 / 512; + } else { + div512 = 0; + hz = 32768 / 16; + } + + perstep = (hz * pwm->fade_time) / (steps * 1000); + + if (perstep == 0) + perstep = 1; + else if (perstep > 63) + perstep = 63; + + while (steps) { + int s; + + s = min(126, steps); + pwm_cmds[num_cmds++] = PWM_RAMP(div512, perstep, s, up); + steps -= s; + } + + lm8323_write_pwm(pwm, kill, num_cmds, pwm_cmds); + pwm->brightness = pwm->desired_brightness; + + out: + mutex_unlock(&pwm->lock); +} + +static void lm8323_pwm_set_brightness(struct led_classdev *led_cdev, + enum led_brightness brightness) +{ + struct lm8323_pwm *pwm = cdev_to_pwm(led_cdev); + struct lm8323_chip *lm = pwm->chip; + + mutex_lock(&pwm->lock); + pwm->desired_brightness = brightness; + mutex_unlock(&pwm->lock); + + if (in_interrupt()) { + schedule_work(&pwm->work); + } else { + /* + * Schedule PWM work as usual unless we are going into suspend + */ + mutex_lock(&lm->lock); + if (likely(!lm->pm_suspend)) + schedule_work(&pwm->work); + else + lm8323_pwm_work(&pwm->work); + mutex_unlock(&lm->lock); + } +} + +static ssize_t lm8323_pwm_show_time(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct led_classdev *led_cdev = dev_get_drvdata(dev); + struct lm8323_pwm *pwm = cdev_to_pwm(led_cdev); + + return sprintf(buf, "%d\n", pwm->fade_time); +} + +static ssize_t lm8323_pwm_store_time(struct device *dev, + struct device_attribute *attr, const char *buf, size_t len) +{ + struct led_classdev *led_cdev = dev_get_drvdata(dev); + struct lm8323_pwm *pwm = cdev_to_pwm(led_cdev); + int ret; + unsigned long time; + + ret = strict_strtoul(buf, 10, &time); + /* Numbers only, please. */ + if (ret) + return -EINVAL; + + pwm->fade_time = time; + + return strlen(buf); +} +static DEVICE_ATTR(time, 0644, lm8323_pwm_show_time, lm8323_pwm_store_time); + +static int init_pwm(struct lm8323_chip *lm, int id, struct device *dev, + const char *name) +{ + struct lm8323_pwm *pwm; + + BUG_ON(id > 3); + + pwm = &lm->pwm[id - 1]; + + pwm->id = id; + pwm->fade_time = 0; + pwm->brightness = 0; + pwm->desired_brightness = 0; + pwm->running = false; + pwm->enabled = false; + INIT_WORK(&pwm->work, lm8323_pwm_work); + mutex_init(&pwm->lock); + pwm->chip = lm; + + if (name) { + pwm->cdev.name = name; + pwm->cdev.brightness_set = lm8323_pwm_set_brightness; + if (led_classdev_register(dev, &pwm->cdev) < 0) { + dev_err(dev, "couldn't register PWM %d\n", id); + return -1; + } + if (device_create_file(pwm->cdev.dev, + &dev_attr_time) < 0) { + dev_err(dev, "couldn't register time attribute\n"); + led_classdev_unregister(&pwm->cdev); + return -1; + } + pwm->enabled = true; + } + + return 0; +} + +static struct i2c_driver lm8323_i2c_driver; + +static ssize_t lm8323_show_disable(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct lm8323_chip *lm = dev_get_drvdata(dev); + + return sprintf(buf, "%u\n", !lm->kp_enabled); +} + +static ssize_t lm8323_set_disable(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct lm8323_chip *lm = dev_get_drvdata(dev); + int ret; + unsigned long i; + + ret = strict_strtoul(buf, 10, &i); + + mutex_lock(&lm->lock); + lm->kp_enabled = !i; + mutex_unlock(&lm->lock); + + return count; +} +static DEVICE_ATTR(disable_kp, 0644, lm8323_show_disable, lm8323_set_disable); + +static int __devinit lm8323_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct lm8323_platform_data *pdata = client->dev.platform_data; + struct input_dev *idev; + struct lm8323_chip *lm; + int i, err; + unsigned long tmo; + u8 data[2]; + + if (!pdata || !pdata->size_x || !pdata->size_y) { + dev_err(&client->dev, "missing platform_data\n"); + return -EINVAL; + } + + if (pdata->size_x > 8) { + dev_err(&client->dev, "invalid x size %d specified\n", + pdata->size_x); + return -EINVAL; + } + + if (pdata->size_y > 12) { + dev_err(&client->dev, "invalid y size %d specified\n", + pdata->size_y); + return -EINVAL; + } + + lm = kzalloc(sizeof *lm, GFP_KERNEL); + idev = input_allocate_device(); + if (!lm || !idev) { + err = -ENOMEM; + goto fail1; + } + + i2c_set_clientdata(client, lm); + + lm->client = client; + lm->idev = idev; + mutex_init(&lm->lock); + INIT_WORK(&lm->work, lm8323_work); + + lm->size_x = pdata->size_x; + lm->size_y = pdata->size_y; + dev_vdbg(&client->dev, "Keypad size: %d x %d\n", + lm->size_x, lm->size_y); + + lm->debounce_time = pdata->debounce_time; + lm->active_time = pdata->active_time; + + lm8323_reset(lm); + + /* Nothing's set up to service the IRQ yet, so just spin for max. + * 100ms until we can configure. */ + tmo = jiffies + msecs_to_jiffies(100); + while (lm8323_read(lm, LM8323_CMD_READ_INT, data, 1) == 1) { + if (data[0] & INT_NOINIT) + break; + + if (time_after(jiffies, tmo)) { + dev_err(&client->dev, + "timeout waiting for initialisation\n"); + break; + } + + msleep(1); + } + + lm8323_configure(lm); + + /* If a true probe check the device */ + if (lm8323_read_id(lm, data) != 0) { + dev_err(&client->dev, "device not found\n"); + err = -ENODEV; + goto fail1; + } + + for (i = 0; i < LM8323_NUM_PWMS; i++) { + err = init_pwm(lm, i + 1, &client->dev, pdata->pwm_names[i]); + if (err < 0) + goto fail2; + } + + lm->kp_enabled = true; + err = device_create_file(&client->dev, &dev_attr_disable_kp); + if (err < 0) + goto fail2; + + idev->name = pdata->name ? : "LM8323 keypad"; + snprintf(lm->phys, sizeof(lm->phys), + "%s/input-kp", dev_name(&client->dev)); + idev->phys = lm->phys; + + idev->evbit[0] = BIT(EV_KEY) | BIT(EV_MSC); + __set_bit(MSC_SCAN, idev->mscbit); + for (i = 0; i < LM8323_KEYMAP_SIZE; i++) { + __set_bit(pdata->keymap[i], idev->keybit); + lm->keymap[i] = pdata->keymap[i]; + } + __clear_bit(KEY_RESERVED, idev->keybit); + + if (pdata->repeat) + __set_bit(EV_REP, idev->evbit); + + err = input_register_device(idev); + if (err) { + dev_dbg(&client->dev, "error registering input device\n"); + goto fail3; + } + + err = request_irq(client->irq, lm8323_irq, + IRQF_TRIGGER_FALLING | IRQF_DISABLED, + "lm8323", lm); + if (err) { + dev_err(&client->dev, "could not get IRQ %d\n", client->irq); + goto fail4; + } + + device_init_wakeup(&client->dev, 1); + enable_irq_wake(client->irq); + + return 0; + +fail4: + input_unregister_device(idev); + idev = NULL; +fail3: + device_remove_file(&client->dev, &dev_attr_disable_kp); +fail2: + while (--i >= 0) + if (lm->pwm[i].enabled) + led_classdev_unregister(&lm->pwm[i].cdev); +fail1: + input_free_device(idev); + kfree(lm); + return err; +} + +static int __devexit lm8323_remove(struct i2c_client *client) +{ + struct lm8323_chip *lm = i2c_get_clientdata(client); + int i; + + disable_irq_wake(client->irq); + free_irq(client->irq, lm); + cancel_work_sync(&lm->work); + + input_unregister_device(lm->idev); + + device_remove_file(&lm->client->dev, &dev_attr_disable_kp); + + for (i = 0; i < 3; i++) + if (lm->pwm[i].enabled) + led_classdev_unregister(&lm->pwm[i].cdev); + + kfree(lm); + + return 0; +} + +#ifdef CONFIG_PM +/* + * We don't need to explicitly suspend the chip, as it already switches off + * when there's no activity. + */ +static int lm8323_suspend(struct i2c_client *client, pm_message_t mesg) +{ + struct lm8323_chip *lm = i2c_get_clientdata(client); + int i; + + set_irq_wake(client->irq, 0); + disable_irq(client->irq); + + mutex_lock(&lm->lock); + lm->pm_suspend = true; + mutex_unlock(&lm->lock); + + for (i = 0; i < 3; i++) + if (lm->pwm[i].enabled) + led_classdev_suspend(&lm->pwm[i].cdev); + + return 0; +} + +static int lm8323_resume(struct i2c_client *client) +{ + struct lm8323_chip *lm = i2c_get_clientdata(client); + int i; + + mutex_lock(&lm->lock); + lm->pm_suspend = false; + mutex_unlock(&lm->lock); + + for (i = 0; i < 3; i++) + if (lm->pwm[i].enabled) + led_classdev_resume(&lm->pwm[i].cdev); + + enable_irq(client->irq); + set_irq_wake(client->irq, 1); + + return 0; +} +#else +#define lm8323_suspend NULL +#define lm8323_resume NULL +#endif + +static const struct i2c_device_id lm8323_id[] = { + { "lm8323", 0 }, + { } +}; + +static struct i2c_driver lm8323_i2c_driver = { + .driver = { + .name = "lm8323", + }, + .probe = lm8323_probe, + .remove = __devexit_p(lm8323_remove), + .suspend = lm8323_suspend, + .resume = lm8323_resume, + .id_table = lm8323_id, +}; +MODULE_DEVICE_TABLE(i2c, lm8323_id); + +static int __init lm8323_init(void) +{ + return i2c_add_driver(&lm8323_i2c_driver); +} +module_init(lm8323_init); + +static void __exit lm8323_exit(void) +{ + i2c_del_driver(&lm8323_i2c_driver); +} +module_exit(lm8323_exit); + +MODULE_AUTHOR("Timo O. Karjalainen <timo.o.karjalainen@nokia.com>"); +MODULE_AUTHOR("Daniel Stone"); +MODULE_AUTHOR("Felipe Balbi <felipe.balbi@nokia.com>"); +MODULE_DESCRIPTION("LM8323 keypad driver"); +MODULE_LICENSE("GPL"); + diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig index 06f46fcc0772..1acfa3a05aad 100644 --- a/drivers/input/misc/Kconfig +++ b/drivers/input/misc/Kconfig @@ -193,6 +193,16 @@ config INPUT_CM109 To compile this driver as a module, choose M here: the module will be called cm109. +config INPUT_TWL4030_PWRBUTTON + tristate "TWL4030 Power button Driver" + depends on TWL4030_CORE + help + Say Y here if you want to enable power key reporting via the + TWL4030 family of chips. + + To compile this driver as a module, choose M here. The module will + be called twl4030_pwrbutton. + config INPUT_UINPUT tristate "User level driver support" help @@ -250,4 +260,13 @@ config INPUT_RB532_BUTTON To compile this driver as a module, choose M here: the module will be called rb532_button. +config INPUT_DM355EVM + tristate "TI DaVinci DM355 EVM Keypad and IR Remote" + depends on MFD_DM355EVM_MSP + help + Supports the pushbuttons and IR remote used with + the DM355 EVM board. + + To compile this driver as a module, choose M here: the + module will be called dm355evm_keys. endif diff --git a/drivers/input/misc/Makefile b/drivers/input/misc/Makefile index eb3f407baedf..0d979fd4cd57 100644 --- a/drivers/input/misc/Makefile +++ b/drivers/input/misc/Makefile @@ -10,6 +10,7 @@ obj-$(CONFIG_INPUT_ATI_REMOTE2) += ati_remote2.o obj-$(CONFIG_INPUT_ATLAS_BTNS) += atlas_btns.o obj-$(CONFIG_INPUT_CM109) += cm109.o obj-$(CONFIG_INPUT_COBALT_BTNS) += cobalt_btns.o +obj-$(CONFIG_INPUT_DM355EVM) += dm355evm_keys.o obj-$(CONFIG_HP_SDC_RTC) += hp_sdc_rtc.o obj-$(CONFIG_INPUT_IXP4XX_BEEPER) += ixp4xx-beeper.o obj-$(CONFIG_INPUT_KEYSPAN_REMOTE) += keyspan_remote.o @@ -21,6 +22,7 @@ obj-$(CONFIG_INPUT_RB532_BUTTON) += rb532_button.o obj-$(CONFIG_INPUT_GPIO_ROTARY_ENCODER) += rotary_encoder.o obj-$(CONFIG_INPUT_SGI_BTNS) += sgi_btns.o obj-$(CONFIG_INPUT_SPARCSPKR) += sparcspkr.o +obj-$(CONFIG_INPUT_TWL4030_PWRBUTTON) += twl4030-pwrbutton.o obj-$(CONFIG_INPUT_UINPUT) += uinput.o obj-$(CONFIG_INPUT_WISTRON_BTNS) += wistron_btns.o obj-$(CONFIG_INPUT_YEALINK) += yealink.o diff --git a/drivers/input/misc/ati_remote2.c b/drivers/input/misc/ati_remote2.c index 922c05141585..0501f0e65157 100644 --- a/drivers/input/misc/ati_remote2.c +++ b/drivers/input/misc/ati_remote2.c @@ -509,7 +509,7 @@ static int ati_remote2_setkeycode(struct input_dev *idev, int scancode, int keyc old_keycode = ar2->keycode[mode][index]; ar2->keycode[mode][index] = keycode; - set_bit(keycode, idev->keybit); + __set_bit(keycode, idev->keybit); for (mode = 0; mode < ATI_REMOTE2_MODES; mode++) { for (index = 0; index < ARRAY_SIZE(ati_remote2_key_table); index++) { @@ -518,7 +518,7 @@ static int ati_remote2_setkeycode(struct input_dev *idev, int scancode, int keyc } } - clear_bit(old_keycode, idev->keybit); + __clear_bit(old_keycode, idev->keybit); return 0; } @@ -543,7 +543,7 @@ static int ati_remote2_input_init(struct ati_remote2 *ar2) for (mode = 0; mode < ATI_REMOTE2_MODES; mode++) { for (index = 0; index < ARRAY_SIZE(ati_remote2_key_table); index++) { ar2->keycode[mode][index] = ati_remote2_key_table[index].keycode; - set_bit(ar2->keycode[mode][index], idev->keybit); + __set_bit(ar2->keycode[mode][index], idev->keybit); } } @@ -554,11 +554,11 @@ static int ati_remote2_input_init(struct ati_remote2 *ar2) ar2->keycode[ATI_REMOTE2_AUX3][index] = KEY_PROG3; ar2->keycode[ATI_REMOTE2_AUX4][index] = KEY_PROG4; ar2->keycode[ATI_REMOTE2_PC][index] = KEY_PC; - set_bit(KEY_PROG1, idev->keybit); - set_bit(KEY_PROG2, idev->keybit); - set_bit(KEY_PROG3, idev->keybit); - set_bit(KEY_PROG4, idev->keybit); - set_bit(KEY_PC, idev->keybit); + __set_bit(KEY_PROG1, idev->keybit); + __set_bit(KEY_PROG2, idev->keybit); + __set_bit(KEY_PROG3, idev->keybit); + __set_bit(KEY_PROG4, idev->keybit); + __set_bit(KEY_PC, idev->keybit); idev->rep[REP_DELAY] = 250; idev->rep[REP_PERIOD] = 33; diff --git a/drivers/input/misc/dm355evm_keys.c b/drivers/input/misc/dm355evm_keys.c new file mode 100644 index 000000000000..a63315ce4a6c --- /dev/null +++ b/drivers/input/misc/dm355evm_keys.c @@ -0,0 +1,329 @@ +/* + * dm355evm_keys.c - support buttons and IR remote on DM355 EVM board + * + * Copyright (c) 2008 by David Brownell + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/input.h> +#include <linux/platform_device.h> +#include <linux/interrupt.h> + +#include <linux/i2c/dm355evm_msp.h> + + +/* + * The MSP430 firmware on the DM355 EVM monitors on-board pushbuttons + * and an IR receptor used for the remote control. When any key is + * pressed, or its autorepeat kicks in, an event is sent. This driver + * read those events from the small (32 event) queue and reports them. + * + * Because we communicate with the MSP430 using I2C, and all I2C calls + * in Linux sleep, we need to cons up a kind of threaded IRQ handler + * using a work_struct. The IRQ is active low, but we use it through + * the GPIO controller so we can trigger on falling edges. + * + * Note that physically there can only be one of these devices. + * + * This driver was tested with firmware revision A4. + */ +struct dm355evm_keys { + struct work_struct work; + struct input_dev *input; + struct device *dev; + int irq; +}; + +static irqreturn_t dm355evm_keys_irq(int irq, void *_keys) +{ + struct dm355evm_keys *keys = _keys; + + schedule_work(&keys->work); + return IRQ_HANDLED; +} + +/* These initial keycodes can be remapped by dm355evm_setkeycode(). */ +static struct { + u16 event; + u16 keycode; +} dm355evm_keys[] = { + + /* + * Pushbuttons on the EVM board ... note that the labels for these + * are SW10/SW11/etc on the PC board. The left/right orientation + * comes only from the firmware's documentation, and presumes the + * power connector is immediately in front of you and the IR sensor + * is to the right. (That is, rotate the board counter-clockwise + * by 90 degrees from the SW10/etc and "DM355 EVM" labels.) + */ + { 0x00d8, KEY_OK, }, /* SW12 */ + { 0x00b8, KEY_UP, }, /* SW13 */ + { 0x00e8, KEY_DOWN, }, /* SW11 */ + { 0x0078, KEY_LEFT, }, /* SW14 */ + { 0x00f0, KEY_RIGHT, }, /* SW10 */ + + /* + * IR buttons ... codes assigned to match the universal remote + * provided with the EVM (Philips PM4S) using DVD code 0020. + * + * These event codes match firmware documentation, but other + * remote controls could easily send more RC5-encoded events. + * The PM4S manual was used in several cases to help select + * a keycode reflecting the intended usage. + * + * RC5 codes are 14 bits, with two start bits (0x3 prefix) + * and a toggle bit (masked out below). + */ + { 0x300c, KEY_POWER, }, /* NOTE: docs omit this */ + { 0x3000, KEY_NUMERIC_0, }, + { 0x3001, KEY_NUMERIC_1, }, + { 0x3002, KEY_NUMERIC_2, }, + { 0x3003, KEY_NUMERIC_3, }, + { 0x3004, KEY_NUMERIC_4, }, + { 0x3005, KEY_NUMERIC_5, }, + { 0x3006, KEY_NUMERIC_6, }, + { 0x3007, KEY_NUMERIC_7, }, + { 0x3008, KEY_NUMERIC_8, }, + { 0x3009, KEY_NUMERIC_9, }, + { 0x3022, KEY_ENTER, }, + { 0x30ec, KEY_MODE, }, /* "tv/vcr/..." */ + { 0x300f, KEY_SELECT, }, /* "info" */ + { 0x3020, KEY_CHANNELUP, }, /* "up" */ + { 0x302e, KEY_MENU, }, /* "in/out" */ + { 0x3011, KEY_VOLUMEDOWN, }, /* "left" */ + { 0x300d, KEY_MUTE, }, /* "ok" */ + { 0x3010, KEY_VOLUMEUP, }, /* "right" */ + { 0x301e, KEY_SUBTITLE, }, /* "cc" */ + { 0x3021, KEY_CHANNELDOWN, }, /* "down" */ + { 0x3022, KEY_PREVIOUS, }, + { 0x3026, KEY_SLEEP, }, + { 0x3172, KEY_REWIND, }, /* NOTE: docs wrongly say 0x30ca */ + { 0x3175, KEY_PLAY, }, + { 0x3174, KEY_FASTFORWARD, }, + { 0x3177, KEY_RECORD, }, + { 0x3176, KEY_STOP, }, + { 0x3169, KEY_PAUSE, }, +}; + +static void dm355evm_keys_work(struct work_struct *work) +{ + struct dm355evm_keys *keys; + int status; + + keys = container_of(work, struct dm355evm_keys, work); + + /* For simplicity we ignore INPUT_COUNT and just read + * events until we get the "queue empty" indicator. + * Reading INPUT_LOW decrements the count. + */ + for (;;) { + static u16 last_event; + u16 event; + int keycode; + int i; + + status = dm355evm_msp_read(DM355EVM_MSP_INPUT_HIGH); + if (status < 0) { + dev_dbg(keys->dev, "input high err %d\n", + status); + break; + } + event = status << 8; + + status = dm355evm_msp_read(DM355EVM_MSP_INPUT_LOW); + if (status < 0) { + dev_dbg(keys->dev, "input low err %d\n", + status); + break; + } + event |= status; + if (event == 0xdead) + break; + + /* Press and release a button: two events, same code. + * Press and hold (autorepeat), then release: N events + * (N > 2), same code. For RC5 buttons the toggle bits + * distinguish (for example) "1-autorepeat" from "1 1"; + * but PCB buttons don't support that bit. + * + * So we must synthesize release events. We do that by + * mapping events to a press/release event pair; then + * to avoid adding extra events, skip the second event + * of each pair. + */ + if (event == last_event) { + last_event = 0; + continue; + } + last_event = event; + + /* ignore the RC5 toggle bit */ + event &= ~0x0800; + + /* find the key, or leave it as unknown */ + keycode = KEY_UNKNOWN; + for (i = 0; i < ARRAY_SIZE(dm355evm_keys); i++) { + if (dm355evm_keys[i].event != event) + continue; + keycode = dm355evm_keys[i].keycode; + break; + } + dev_dbg(keys->dev, + "input event 0x%04x--> keycode %d\n", + event, keycode); + + /* report press + release */ + input_report_key(keys->input, keycode, 1); + input_sync(keys->input); + input_report_key(keys->input, keycode, 0); + input_sync(keys->input); + } +} + +static int dm355evm_setkeycode(struct input_dev *dev, int index, int keycode) +{ + u16 old_keycode; + unsigned i; + + if (((unsigned)index) >= ARRAY_SIZE(dm355evm_keys)) + return -EINVAL; + + old_keycode = dm355evm_keys[index].keycode; + dm355evm_keys[index].keycode = keycode; + set_bit(keycode, dev->keybit); + + for (i = 0; i < ARRAY_SIZE(dm355evm_keys); i++) { + if (dm355evm_keys[index].keycode == old_keycode) + goto done; + } + clear_bit(old_keycode, dev->keybit); +done: + return 0; +} + +static int dm355evm_getkeycode(struct input_dev *dev, int index, int *keycode) +{ + if (((unsigned)index) >= ARRAY_SIZE(dm355evm_keys)) + return -EINVAL; + + return dm355evm_keys[index].keycode; +} + +/*----------------------------------------------------------------------*/ + +static int __devinit dm355evm_keys_probe(struct platform_device *pdev) +{ + struct dm355evm_keys *keys; + struct input_dev *input; + int status; + int i; + + /* allocate instance struct and input dev */ + keys = kzalloc(sizeof *keys, GFP_KERNEL); + input = input_allocate_device(); + if (!keys || !input) { + status = -ENOMEM; + goto fail1; + } + + keys->dev = &pdev->dev; + keys->input = input; + INIT_WORK(&keys->work, dm355evm_keys_work); + + /* set up "threaded IRQ handler" */ + status = platform_get_irq(pdev, 0); + if (status < 0) + goto fail1; + keys->irq = status; + + input_set_drvdata(input, keys); + + input->name = "DM355 EVM Controls"; + input->phys = "dm355evm/input0"; + input->dev.parent = &pdev->dev; + + input->id.bustype = BUS_I2C; + input->id.product = 0x0355; + input->id.version = dm355evm_msp_read(DM355EVM_MSP_FIRMREV); + + input->evbit[0] = BIT(EV_KEY); + for (i = 0; i < ARRAY_SIZE(dm355evm_keys); i++) + __set_bit(dm355evm_keys[i].keycode, input->keybit); + + input->setkeycode = dm355evm_setkeycode; + input->getkeycode = dm355evm_getkeycode; + + /* REVISIT: flush the event queue? */ + + status = request_irq(keys->irq, dm355evm_keys_irq, + IRQF_TRIGGER_FALLING, + dev_name(&pdev->dev), keys); + if (status < 0) + goto fail1; + + /* register */ + status = input_register_device(input); + if (status < 0) + goto fail2; + + platform_set_drvdata(pdev, keys); + + return 0; + +fail2: + free_irq(keys->irq, keys); +fail1: + input_free_device(input); + kfree(keys); + dev_err(&pdev->dev, "can't register, err %d\n", status); + + return status; +} + +static int __devexit dm355evm_keys_remove(struct platform_device *pdev) +{ + struct dm355evm_keys *keys = platform_get_drvdata(pdev); + + free_irq(keys->irq, keys); + input_unregister_device(keys->input); + kfree(keys); + + return 0; +} + +/* REVISIT: add suspend/resume when DaVinci supports it. The IRQ should + * be able to wake up the system. When device_may_wakeup(&pdev->dev), call + * enable_irq_wake() on suspend, and disable_irq_wake() on resume. + */ + +/* + * I2C is used to talk to the MSP430, but this platform device is + * exposed by an MFD driver that manages I2C communications. + */ +static struct platform_driver dm355evm_keys_driver = { + .probe = dm355evm_keys_probe, + .remove = __devexit_p(dm355evm_keys_remove), + .driver = { + .owner = THIS_MODULE, + .name = "dm355evm_keys", + }, +}; + +static int __init dm355evm_keys_init(void) +{ + return platform_driver_register(&dm355evm_keys_driver); +} +module_init(dm355evm_keys_init); + +static void __exit dm355evm_keys_exit(void) +{ + platform_driver_unregister(&dm355evm_keys_driver); +} +module_exit(dm355evm_keys_exit); + +MODULE_LICENSE("GPL"); diff --git a/drivers/input/misc/rotary_encoder.c b/drivers/input/misc/rotary_encoder.c index 5bb3ab51b8c6..c806fbf1e174 100644 --- a/drivers/input/misc/rotary_encoder.c +++ b/drivers/input/misc/rotary_encoder.c @@ -26,13 +26,17 @@ #define DRV_NAME "rotary-encoder" struct rotary_encoder { - unsigned int irq_a; - unsigned int irq_b; - unsigned int pos; - unsigned int armed; - unsigned int dir; struct input_dev *input; struct rotary_encoder_platform_data *pdata; + + unsigned int axis; + unsigned int pos; + + unsigned int irq_a; + unsigned int irq_b; + + bool armed; + unsigned char dir; /* 0 - clockwise, 1 - CCW */ }; static irqreturn_t rotary_encoder_irq(int irq, void *dev_id) @@ -53,21 +57,32 @@ static irqreturn_t rotary_encoder_irq(int irq, void *dev_id) if (!encoder->armed) break; - if (encoder->dir) { - /* turning counter-clockwise */ - encoder->pos += pdata->steps; - encoder->pos--; - encoder->pos %= pdata->steps; + if (pdata->relative_axis) { + input_report_rel(encoder->input, pdata->axis, + encoder->dir ? -1 : 1); } else { - /* turning clockwise */ - encoder->pos++; - encoder->pos %= pdata->steps; + unsigned int pos = encoder->pos; + + if (encoder->dir) { + /* turning counter-clockwise */ + if (pdata->rollover) + pos += pdata->steps; + if (pos) + pos--; + } else { + /* turning clockwise */ + if (pdata->rollover || pos < pdata->steps) + pos++; + } + if (pdata->rollover) + pos %= pdata->steps; + encoder->pos = pos; + input_report_abs(encoder->input, pdata->axis, + encoder->pos); } - - input_report_abs(encoder->input, pdata->axis, encoder->pos); input_sync(encoder->input); - encoder->armed = 0; + encoder->armed = false; break; case 0x1: @@ -77,7 +92,7 @@ static irqreturn_t rotary_encoder_irq(int irq, void *dev_id) break; case 0x3: - encoder->armed = 1; + encoder->armed = true; break; } @@ -113,9 +128,15 @@ static int __devinit rotary_encoder_probe(struct platform_device *pdev) input->name = pdev->name; input->id.bustype = BUS_HOST; input->dev.parent = &pdev->dev; - input->evbit[0] = BIT_MASK(EV_ABS); - input_set_abs_params(encoder->input, - pdata->axis, 0, pdata->steps, 0, 1); + + if (pdata->relative_axis) { + input->evbit[0] = BIT_MASK(EV_REL); + input->relbit[0] = BIT_MASK(pdata->axis); + } else { + input->evbit[0] = BIT_MASK(EV_ABS); + input_set_abs_params(encoder->input, + pdata->axis, 0, pdata->steps, 0, 1); + } err = input_register_device(input); if (err) { diff --git a/drivers/input/misc/twl4030-pwrbutton.c b/drivers/input/misc/twl4030-pwrbutton.c new file mode 100644 index 000000000000..f5fc9974a111 --- /dev/null +++ b/drivers/input/misc/twl4030-pwrbutton.c @@ -0,0 +1,145 @@ +/** + * twl4030-pwrbutton.c - TWL4030 Power Button Input Driver + * + * Copyright (C) 2008-2009 Nokia Corporation + * + * Written by Peter De Schrijver <peter.de-schrijver@nokia.com> + * Several fixes by Felipe Balbi <felipe.balbi@nokia.com> + * + * This file is subject to the terms and conditions of the GNU General + * Public License. See the file "COPYING" in the main directory of this + * archive for more details. + * + * 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 + */ + +#include <linux/module.h> +#include <linux/init.h> +#include <linux/kernel.h> +#include <linux/errno.h> +#include <linux/input.h> +#include <linux/interrupt.h> +#include <linux/platform_device.h> +#include <linux/i2c/twl4030.h> + +#define PWR_PWRON_IRQ (1 << 0) + +#define STS_HW_CONDITIONS 0xf + +static irqreturn_t powerbutton_irq(int irq, void *_pwr) +{ + struct input_dev *pwr = _pwr; + int err; + u8 value; + +#ifdef CONFIG_LOCKDEP + /* WORKAROUND for lockdep forcing IRQF_DISABLED on us, which + * we don't want and can't tolerate since this is a threaded + * IRQ and can sleep due to the i2c reads it has to issue. + * Although it might be friendlier not to borrow this thread + * context... + */ + local_irq_enable(); +#endif + + err = twl4030_i2c_read_u8(TWL4030_MODULE_PM_MASTER, &value, + STS_HW_CONDITIONS); + if (!err) { + input_report_key(pwr, KEY_POWER, value & PWR_PWRON_IRQ); + input_sync(pwr); + } else { + dev_err(pwr->dev.parent, "twl4030: i2c error %d while reading" + " TWL4030 PM_MASTER STS_HW_CONDITIONS register\n", err); + } + + return IRQ_HANDLED; +} + +static int __devinit twl4030_pwrbutton_probe(struct platform_device *pdev) +{ + struct input_dev *pwr; + int irq = platform_get_irq(pdev, 0); + int err; + + pwr = input_allocate_device(); + if (!pwr) { + dev_dbg(&pdev->dev, "Can't allocate power button\n"); + return -ENOMEM; + } + + pwr->evbit[0] = BIT_MASK(EV_KEY); + pwr->keybit[BIT_WORD(KEY_POWER)] = BIT_MASK(KEY_POWER); + pwr->name = "twl4030_pwrbutton"; + pwr->phys = "twl4030_pwrbutton/input0"; + pwr->dev.parent = &pdev->dev; + + err = request_irq(irq, powerbutton_irq, + IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING, + "twl4030_pwrbutton", pwr); + if (err < 0) { + dev_dbg(&pdev->dev, "Can't get IRQ for pwrbutton: %d\n", err); + goto free_input_dev; + } + + err = input_register_device(pwr); + if (err) { + dev_dbg(&pdev->dev, "Can't register power button: %d\n", err); + goto free_irq; + } + + platform_set_drvdata(pdev, pwr); + + return 0; + +free_irq: + free_irq(irq, NULL); +free_input_dev: + input_free_device(pwr); + return err; +} + +static int __devexit twl4030_pwrbutton_remove(struct platform_device *pdev) +{ + struct input_dev *pwr = platform_get_drvdata(pdev); + int irq = platform_get_irq(pdev, 0); + + free_irq(irq, pwr); + input_unregister_device(pwr); + + return 0; +} + +struct platform_driver twl4030_pwrbutton_driver = { + .probe = twl4030_pwrbutton_probe, + .remove = __devexit_p(twl4030_pwrbutton_remove), + .driver = { + .name = "twl4030_pwrbutton", + .owner = THIS_MODULE, + }, +}; + +static int __init twl4030_pwrbutton_init(void) +{ + return platform_driver_register(&twl4030_pwrbutton_driver); +} +module_init(twl4030_pwrbutton_init); + +static void __exit twl4030_pwrbutton_exit(void) +{ + platform_driver_unregister(&twl4030_pwrbutton_driver); +} +module_exit(twl4030_pwrbutton_exit); + +MODULE_ALIAS("platform:twl4030_pwrbutton"); +MODULE_DESCRIPTION("Triton2 Power Button"); +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Peter De Schrijver <peter.de-schrijver@nokia.com>"); +MODULE_AUTHOR("Felipe Balbi <felipe.balbi@nokia.com>"); + diff --git a/drivers/input/misc/uinput.c b/drivers/input/misc/uinput.c index 46b7caeb2817..c5a49aba418f 100644 --- a/drivers/input/misc/uinput.c +++ b/drivers/input/misc/uinput.c @@ -54,27 +54,28 @@ static int uinput_dev_event(struct input_dev *dev, unsigned int type, unsigned i return 0; } +/* Atomically allocate an ID for the given request. Returns 0 on success. */ static int uinput_request_alloc_id(struct uinput_device *udev, struct uinput_request *request) { - /* Atomically allocate an ID for the given request. Returns 0 on success. */ int id; int err = -1; spin_lock(&udev->requests_lock); - for (id = 0; id < UINPUT_NUM_REQUESTS; id++) + for (id = 0; id < UINPUT_NUM_REQUESTS; id++) { if (!udev->requests[id]) { request->id = id; udev->requests[id] = request; err = 0; break; } + } spin_unlock(&udev->requests_lock); return err; } -static struct uinput_request* uinput_request_find(struct uinput_device *udev, int id) +static struct uinput_request *uinput_request_find(struct uinput_device *udev, int id) { /* Find an input request, by ID. Returns NULL if the ID isn't valid. */ if (id >= UINPUT_NUM_REQUESTS || id < 0) @@ -99,14 +100,51 @@ static void uinput_request_done(struct uinput_device *udev, struct uinput_reques complete(&request->done); } -static int uinput_request_submit(struct input_dev *dev, struct uinput_request *request) +static int uinput_request_submit(struct uinput_device *udev, struct uinput_request *request) { + int retval; + + retval = uinput_request_reserve_slot(udev, request); + if (retval) + return retval; + + retval = mutex_lock_interruptible(&udev->mutex); + if (retval) + return retval; + + if (udev->state != UIST_CREATED) { + retval = -ENODEV; + goto out; + } + /* Tell our userspace app about this new request by queueing an input event */ - uinput_dev_event(dev, EV_UINPUT, request->code, request->id); + uinput_dev_event(udev->dev, EV_UINPUT, request->code, request->id); + + out: + mutex_unlock(&udev->mutex); + return retval; +} + +/* + * Fail all ouitstanding requests so handlers don't wait for the userspace + * to finish processing them. + */ +static void uinput_flush_requests(struct uinput_device *udev) +{ + struct uinput_request *request; + int i; + + spin_lock(&udev->requests_lock); + + for (i = 0; i < UINPUT_NUM_REQUESTS; i++) { + request = udev->requests[i]; + if (request) { + request->retval = -ENODEV; + uinput_request_done(udev, request); + } + } - /* Wait for the request to complete */ - wait_for_completion(&request->done); - return request->retval; + spin_unlock(&udev->requests_lock); } static void uinput_dev_set_gain(struct input_dev *dev, u16 gain) @@ -126,6 +164,7 @@ static int uinput_dev_playback(struct input_dev *dev, int effect_id, int value) static int uinput_dev_upload_effect(struct input_dev *dev, struct ff_effect *effect, struct ff_effect *old) { + struct uinput_device *udev = input_get_drvdata(dev); struct uinput_request request; int retval; @@ -146,15 +185,18 @@ static int uinput_dev_upload_effect(struct input_dev *dev, struct ff_effect *eff request.u.upload.effect = effect; request.u.upload.old = old; - retval = uinput_request_reserve_slot(input_get_drvdata(dev), &request); - if (!retval) - retval = uinput_request_submit(dev, &request); + retval = uinput_request_submit(udev, &request); + if (!retval) { + wait_for_completion(&request.done); + retval = request.retval; + } return retval; } static int uinput_dev_erase_effect(struct input_dev *dev, int effect_id) { + struct uinput_device *udev = input_get_drvdata(dev); struct uinput_request request; int retval; @@ -166,9 +208,11 @@ static int uinput_dev_erase_effect(struct input_dev *dev, int effect_id) request.code = UI_FF_ERASE; request.u.effect_id = effect_id; - retval = uinput_request_reserve_slot(input_get_drvdata(dev), &request); - if (!retval) - retval = uinput_request_submit(dev, &request); + retval = uinput_request_submit(udev, &request); + if (!retval) { + wait_for_completion(&request.done); + retval = request.retval; + } return retval; } @@ -176,20 +220,24 @@ static int uinput_dev_erase_effect(struct input_dev *dev, int effect_id) static void uinput_destroy_device(struct uinput_device *udev) { const char *name, *phys; + struct input_dev *dev = udev->dev; + enum uinput_state old_state = udev->state; - if (udev->dev) { - name = udev->dev->name; - phys = udev->dev->phys; - if (udev->state == UIST_CREATED) - input_unregister_device(udev->dev); - else - input_free_device(udev->dev); + udev->state = UIST_NEW_DEVICE; + + if (dev) { + name = dev->name; + phys = dev->phys; + if (old_state == UIST_CREATED) { + uinput_flush_requests(udev); + input_unregister_device(dev); + } else { + input_free_device(dev); + } kfree(name); kfree(phys); udev->dev = NULL; } - - udev->state = UIST_NEW_DEVICE; } static int uinput_create_device(struct uinput_device *udev) diff --git a/drivers/input/mouse/Kconfig b/drivers/input/mouse/Kconfig index c66cc3d08c2f..8a2c5b14c8d8 100644 --- a/drivers/input/mouse/Kconfig +++ b/drivers/input/mouse/Kconfig @@ -303,4 +303,22 @@ config MOUSE_MAPLE To compile this driver as a module choose M here: the module will be called maplemouse. +config MOUSE_SYNAPTICS_I2C + tristate "Synaptics I2C Touchpad support" + depends on I2C + help + This driver supports Synaptics I2C touchpad controller on eXeda + mobile device. + The device will not work the synaptics X11 driver because + (i) it reports only relative coordinates and has no capabilities + to report absolute coordinates + (ii) the eXeda device itself uses Xfbdev as X Server and it does + not allow using xf86-input-* drivers. + + Say y here if you have eXeda device and want to use a Synaptics + I2C Touchpad. + + To compile this driver as a module, choose M here: the + module will be called synaptics_i2c. + endif diff --git a/drivers/input/mouse/Makefile b/drivers/input/mouse/Makefile index 472189468d67..010f265ec152 100644 --- a/drivers/input/mouse/Makefile +++ b/drivers/input/mouse/Makefile @@ -18,6 +18,7 @@ obj-$(CONFIG_MOUSE_PS2) += psmouse.o obj-$(CONFIG_MOUSE_PXA930_TRKBALL) += pxa930_trkball.o obj-$(CONFIG_MOUSE_RISCPC) += rpcmouse.o obj-$(CONFIG_MOUSE_SERIAL) += sermouse.o +obj-$(CONFIG_MOUSE_SYNAPTICS_I2C) += synaptics_i2c.o obj-$(CONFIG_MOUSE_VSXXXAA) += vsxxxaa.o psmouse-objs := psmouse-base.o synaptics.o diff --git a/drivers/input/mouse/alps.c b/drivers/input/mouse/alps.c index daecc75c72e6..5547e2429fbe 100644 --- a/drivers/input/mouse/alps.c +++ b/drivers/input/mouse/alps.c @@ -38,25 +38,25 @@ static const struct alps_model_info alps_model_data[] = { { { 0x32, 0x02, 0x14 }, 0xf8, 0xf8, ALPS_PASS | ALPS_DUALPOINT }, /* Toshiba Salellite Pro M10 */ - { { 0x33, 0x02, 0x0a }, 0x88, 0xf8, ALPS_OLDPROTO }, /* UMAX-530T */ + { { 0x33, 0x02, 0x0a }, 0x88, 0xf8, ALPS_OLDPROTO }, /* UMAX-530T */ { { 0x53, 0x02, 0x0a }, 0xf8, 0xf8, 0 }, { { 0x53, 0x02, 0x14 }, 0xf8, 0xf8, 0 }, - { { 0x60, 0x03, 0xc8 }, 0xf8, 0xf8, 0 }, /* HP ze1115 */ + { { 0x60, 0x03, 0xc8 }, 0xf8, 0xf8, 0 }, /* HP ze1115 */ { { 0x63, 0x02, 0x0a }, 0xf8, 0xf8, 0 }, { { 0x63, 0x02, 0x14 }, 0xf8, 0xf8, 0 }, - { { 0x63, 0x02, 0x28 }, 0xf8, 0xf8, ALPS_FW_BK_2 }, /* Fujitsu Siemens S6010 */ - { { 0x63, 0x02, 0x3c }, 0x8f, 0x8f, ALPS_WHEEL }, /* Toshiba Satellite S2400-103 */ - { { 0x63, 0x02, 0x50 }, 0xef, 0xef, ALPS_FW_BK_1 }, /* NEC Versa L320 */ + { { 0x63, 0x02, 0x28 }, 0xf8, 0xf8, ALPS_FW_BK_2 }, /* Fujitsu Siemens S6010 */ + { { 0x63, 0x02, 0x3c }, 0x8f, 0x8f, ALPS_WHEEL }, /* Toshiba Satellite S2400-103 */ + { { 0x63, 0x02, 0x50 }, 0xef, 0xef, ALPS_FW_BK_1 }, /* NEC Versa L320 */ { { 0x63, 0x02, 0x64 }, 0xf8, 0xf8, 0 }, - { { 0x63, 0x03, 0xc8 }, 0xf8, 0xf8, ALPS_PASS }, /* Dell Latitude D800 */ - { { 0x73, 0x00, 0x0a }, 0xf8, 0xf8, ALPS_DUALPOINT }, /* ThinkPad R61 8918-5QG */ + { { 0x63, 0x03, 0xc8 }, 0xf8, 0xf8, ALPS_PASS | ALPS_DUALPOINT }, /* Dell Latitude D800 */ + { { 0x73, 0x00, 0x0a }, 0xf8, 0xf8, ALPS_DUALPOINT }, /* ThinkPad R61 8918-5QG */ { { 0x73, 0x02, 0x0a }, 0xf8, 0xf8, 0 }, - { { 0x73, 0x02, 0x14 }, 0xf8, 0xf8, ALPS_FW_BK_2 }, /* Ahtec Laptop */ + { { 0x73, 0x02, 0x14 }, 0xf8, 0xf8, ALPS_FW_BK_2 }, /* Ahtec Laptop */ { { 0x20, 0x02, 0x0e }, 0xf8, 0xf8, ALPS_PASS | ALPS_DUALPOINT }, /* XXX */ { { 0x22, 0x02, 0x0a }, 0xf8, 0xf8, ALPS_PASS | ALPS_DUALPOINT }, { { 0x22, 0x02, 0x14 }, 0xff, 0xff, ALPS_PASS | ALPS_DUALPOINT }, /* Dell Latitude D600 */ { { 0x62, 0x02, 0x14 }, 0xcf, 0xcf, ALPS_PASS | ALPS_DUALPOINT }, /* Dell Latitude E6500 */ - { { 0x73, 0x02, 0x50 }, 0xcf, 0xcf, ALPS_FW_BK_1 } /* Dell Vostro 1400 */ + { { 0x73, 0x02, 0x50 }, 0xcf, 0xcf, ALPS_FW_BK_1 }, /* Dell Vostro 1400 */ }; /* @@ -132,18 +132,23 @@ static void alps_process_packet(struct psmouse *psmouse) ges = packet[2] & 1; fin = packet[2] & 2; - input_report_key(dev, BTN_LEFT, left); - input_report_key(dev, BTN_RIGHT, right); - input_report_key(dev, BTN_MIDDLE, middle); - if ((priv->i->flags & ALPS_DUALPOINT) && z == 127) { input_report_rel(dev2, REL_X, (x > 383 ? (x - 768) : x)); input_report_rel(dev2, REL_Y, -(y > 255 ? (y - 512) : y)); + + input_report_key(dev2, BTN_LEFT, left); + input_report_key(dev2, BTN_RIGHT, right); + input_report_key(dev2, BTN_MIDDLE, middle); + input_sync(dev); input_sync(dev2); return; } + input_report_key(dev, BTN_LEFT, left); + input_report_key(dev, BTN_RIGHT, right); + input_report_key(dev, BTN_MIDDLE, middle); + /* Convert hardware tap to a reasonable Z value */ if (ges && !fin) z = 40; diff --git a/drivers/input/mouse/appletouch.c b/drivers/input/mouse/appletouch.c index e0140fdc02a5..908b5b44052f 100644 --- a/drivers/input/mouse/appletouch.c +++ b/drivers/input/mouse/appletouch.c @@ -361,7 +361,7 @@ static int atp_calculate_abs(int *xy_sensors, int nb_sensors, int fact, (!is_increasing && xy_sensors[i - 1] < xy_sensors[i])) { (*fingers)++; is_increasing = 1; - } else if (i > 0 && xy_sensors[i - 1] >= xy_sensors[i]) { + } else if (i > 0 && (xy_sensors[i - 1] - xy_sensors[i] > threshold)) { is_increasing = 0; } diff --git a/drivers/input/mouse/lifebook.c b/drivers/input/mouse/lifebook.c index 15ac3205ac05..dcd4236af1e3 100644 --- a/drivers/input/mouse/lifebook.c +++ b/drivers/input/mouse/lifebook.c @@ -159,21 +159,22 @@ static psmouse_ret_t lifebook_process_byte(struct psmouse *psmouse) if (!dev2) printk(KERN_WARNING "lifebook.c: got relative packet " "but no relative device set up\n"); - } else if (lifebook_use_6byte_proto) { - input_report_abs(dev1, ABS_X, - ((packet[1] & 0x3f) << 6) | (packet[2] & 0x3f)); - input_report_abs(dev1, ABS_Y, - 4096 - (((packet[4] & 0x3f) << 6) | (packet[5] & 0x3f))); } else { - input_report_abs(dev1, ABS_X, - (packet[1] | ((packet[0] & 0x30) << 4))); - input_report_abs(dev1, ABS_Y, - 1024 - (packet[2] | ((packet[0] & 0xC0) << 2))); + if (lifebook_use_6byte_proto) { + input_report_abs(dev1, ABS_X, + ((packet[1] & 0x3f) << 6) | (packet[2] & 0x3f)); + input_report_abs(dev1, ABS_Y, + 4096 - (((packet[4] & 0x3f) << 6) | (packet[5] & 0x3f))); + } else { + input_report_abs(dev1, ABS_X, + (packet[1] | ((packet[0] & 0x30) << 4))); + input_report_abs(dev1, ABS_Y, + 1024 - (packet[2] | ((packet[0] & 0xC0) << 2))); + } + input_report_key(dev1, BTN_TOUCH, packet[0] & 0x04); + input_sync(dev1); } - input_report_key(dev1, BTN_TOUCH, packet[0] & 0x04); - input_sync(dev1); - if (dev2) { if (relative_packet) { input_report_rel(dev2, REL_X, diff --git a/drivers/input/mouse/psmouse-base.c b/drivers/input/mouse/psmouse-base.c index f8f86de694bb..b407b355dceb 100644 --- a/drivers/input/mouse/psmouse-base.c +++ b/drivers/input/mouse/psmouse-base.c @@ -327,7 +327,9 @@ static irqreturn_t psmouse_interrupt(struct serio *serio, goto out; } - if (psmouse->packet[1] == PSMOUSE_RET_ID) { + if (psmouse->packet[1] == PSMOUSE_RET_ID || + (psmouse->type == PSMOUSE_HGPK && + psmouse->packet[1] == PSMOUSE_RET_BAT)) { __psmouse_set_state(psmouse, PSMOUSE_IGNORE); serio_reconnect(serio); goto out; diff --git a/drivers/input/mouse/synaptics.c b/drivers/input/mouse/synaptics.c index f3e4f7b0240d..19984bf06cad 100644 --- a/drivers/input/mouse/synaptics.c +++ b/drivers/input/mouse/synaptics.c @@ -180,6 +180,29 @@ static int synaptics_identify(struct psmouse *psmouse) return -1; } +/* + * Read touchpad resolution + * Resolution is left zero if touchpad does not support the query + */ +static int synaptics_resolution(struct psmouse *psmouse) +{ + struct synaptics_data *priv = psmouse->private; + unsigned char res[3]; + + if (SYN_ID_MAJOR(priv->identity) < 4) + return 0; + + if (synaptics_send_cmd(psmouse, SYN_QUE_RESOLUTION, res)) + return 0; + + if ((res[0] != 0) && (res[1] & 0x80) && (res[2] != 0)) { + priv->x_res = res[0]; /* x resolution in units/mm */ + priv->y_res = res[2]; /* y resolution in units/mm */ + } + + return 0; +} + static int synaptics_query_hardware(struct psmouse *psmouse) { if (synaptics_identify(psmouse)) @@ -188,6 +211,8 @@ static int synaptics_query_hardware(struct psmouse *psmouse) return -1; if (synaptics_capability(psmouse)) return -1; + if (synaptics_resolution(psmouse)) + return -1; return 0; } @@ -563,6 +588,9 @@ static void set_input_params(struct input_dev *dev, struct synaptics_data *priv) clear_bit(EV_REL, dev->evbit); clear_bit(REL_X, dev->relbit); clear_bit(REL_Y, dev->relbit); + + dev->absres[ABS_X] = priv->x_res; + dev->absres[ABS_Y] = priv->y_res; } static void synaptics_disconnect(struct psmouse *psmouse) diff --git a/drivers/input/mouse/synaptics.h b/drivers/input/mouse/synaptics.h index 02aa4cf7bc77..302382151752 100644 --- a/drivers/input/mouse/synaptics.h +++ b/drivers/input/mouse/synaptics.h @@ -97,6 +97,8 @@ struct synaptics_data { unsigned long int capabilities; /* Capabilities */ unsigned long int ext_cap; /* Extended Capabilities */ unsigned long int identity; /* Identification */ + int x_res; /* X resolution in units/mm */ + int y_res; /* Y resolution in units/mm */ unsigned char pkt_type; /* packet type - old, new, etc */ unsigned char mode; /* current mode byte */ diff --git a/drivers/input/mouse/synaptics_i2c.c b/drivers/input/mouse/synaptics_i2c.c new file mode 100644 index 000000000000..eac9fdde7ee9 --- /dev/null +++ b/drivers/input/mouse/synaptics_i2c.c @@ -0,0 +1,676 @@ +/* + * Synaptics touchpad with I2C interface + * + * Copyright (C) 2009 Compulab, Ltd. + * Mike Rapoport <mike@compulab.co.il> + * Igor Grinberg <grinberg@compulab.co.il> + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file COPYING in the main directory of this archive for + * more details. + */ + +#include <linux/module.h> +#include <linux/i2c.h> +#include <linux/irq.h> +#include <linux/interrupt.h> +#include <linux/input.h> +#include <linux/delay.h> +#include <linux/workqueue.h> + +#define DRIVER_NAME "synaptics_i2c" +/* maximum product id is 15 characters */ +#define PRODUCT_ID_LENGTH 15 +#define REGISTER_LENGTH 8 + +/* + * after soft reset, we should wait for 1 ms + * before the device becomes operational + */ +#define SOFT_RESET_DELAY_MS 3 +/* and after hard reset, we should wait for max 500ms */ +#define HARD_RESET_DELAY_MS 500 + +/* Registers by SMBus address */ +#define PAGE_SEL_REG 0xff +#define DEVICE_STATUS_REG 0x09 + +/* Registers by RMI address */ +#define DEV_CONTROL_REG 0x0000 +#define INTERRUPT_EN_REG 0x0001 +#define ERR_STAT_REG 0x0002 +#define INT_REQ_STAT_REG 0x0003 +#define DEV_COMMAND_REG 0x0004 + +#define RMI_PROT_VER_REG 0x0200 +#define MANUFACT_ID_REG 0x0201 +#define PHYS_INT_VER_REG 0x0202 +#define PROD_PROPERTY_REG 0x0203 +#define INFO_QUERY_REG0 0x0204 +#define INFO_QUERY_REG1 (INFO_QUERY_REG0 + 1) +#define INFO_QUERY_REG2 (INFO_QUERY_REG0 + 2) +#define INFO_QUERY_REG3 (INFO_QUERY_REG0 + 3) + +#define PRODUCT_ID_REG0 0x0210 +#define PRODUCT_ID_REG1 (PRODUCT_ID_REG0 + 1) +#define PRODUCT_ID_REG2 (PRODUCT_ID_REG0 + 2) +#define PRODUCT_ID_REG3 (PRODUCT_ID_REG0 + 3) +#define PRODUCT_ID_REG4 (PRODUCT_ID_REG0 + 4) +#define PRODUCT_ID_REG5 (PRODUCT_ID_REG0 + 5) +#define PRODUCT_ID_REG6 (PRODUCT_ID_REG0 + 6) +#define PRODUCT_ID_REG7 (PRODUCT_ID_REG0 + 7) +#define PRODUCT_ID_REG8 (PRODUCT_ID_REG0 + 8) +#define PRODUCT_ID_REG9 (PRODUCT_ID_REG0 + 9) +#define PRODUCT_ID_REG10 (PRODUCT_ID_REG0 + 10) +#define PRODUCT_ID_REG11 (PRODUCT_ID_REG0 + 11) +#define PRODUCT_ID_REG12 (PRODUCT_ID_REG0 + 12) +#define PRODUCT_ID_REG13 (PRODUCT_ID_REG0 + 13) +#define PRODUCT_ID_REG14 (PRODUCT_ID_REG0 + 14) +#define PRODUCT_ID_REG15 (PRODUCT_ID_REG0 + 15) + +#define DATA_REG0 0x0400 +#define ABS_PRESSURE_REG 0x0401 +#define ABS_MSB_X_REG 0x0402 +#define ABS_LSB_X_REG (ABS_MSB_X_REG + 1) +#define ABS_MSB_Y_REG 0x0404 +#define ABS_LSB_Y_REG (ABS_MSB_Y_REG + 1) +#define REL_X_REG 0x0406 +#define REL_Y_REG 0x0407 + +#define DEV_QUERY_REG0 0x1000 +#define DEV_QUERY_REG1 (DEV_QUERY_REG0 + 1) +#define DEV_QUERY_REG2 (DEV_QUERY_REG0 + 2) +#define DEV_QUERY_REG3 (DEV_QUERY_REG0 + 3) +#define DEV_QUERY_REG4 (DEV_QUERY_REG0 + 4) +#define DEV_QUERY_REG5 (DEV_QUERY_REG0 + 5) +#define DEV_QUERY_REG6 (DEV_QUERY_REG0 + 6) +#define DEV_QUERY_REG7 (DEV_QUERY_REG0 + 7) +#define DEV_QUERY_REG8 (DEV_QUERY_REG0 + 8) + +#define GENERAL_2D_CONTROL_REG 0x1041 +#define SENSOR_SENSITIVITY_REG 0x1044 +#define SENS_MAX_POS_MSB_REG 0x1046 +#define SENS_MAX_POS_LSB_REG (SENS_MAX_POS_UPPER_REG + 1) + +/* Register bits */ +/* Device Control Register Bits */ +#define REPORT_RATE_1ST_BIT 6 + +/* Interrupt Enable Register Bits (INTERRUPT_EN_REG) */ +#define F10_ABS_INT_ENA 0 +#define F10_REL_INT_ENA 1 +#define F20_INT_ENA 2 + +/* Interrupt Request Register Bits (INT_REQ_STAT_REG | DEVICE_STATUS_REG) */ +#define F10_ABS_INT_REQ 0 +#define F10_REL_INT_REQ 1 +#define F20_INT_REQ 2 +/* Device Status Register Bits (DEVICE_STATUS_REG) */ +#define STAT_CONFIGURED 6 +#define STAT_ERROR 7 + +/* Device Command Register Bits (DEV_COMMAND_REG) */ +#define RESET_COMMAND 0x01 +#define REZERO_COMMAND 0x02 + +/* Data Register 0 Bits (DATA_REG0) */ +#define GESTURE 3 + +/* Device Query Registers Bits */ +/* DEV_QUERY_REG3 */ +#define HAS_PALM_DETECT 1 +#define HAS_MULTI_FING 2 +#define HAS_SCROLLER 4 +#define HAS_2D_SCROLL 5 + +/* General 2D Control Register Bits (GENERAL_2D_CONTROL_REG) */ +#define NO_DECELERATION 1 +#define REDUCE_REPORTING 3 +#define NO_FILTER 5 + +/* Function Masks */ +/* Device Control Register Masks (DEV_CONTROL_REG) */ +#define REPORT_RATE_MSK 0xc0 +#define SLEEP_MODE_MSK 0x07 + +/* Device Sleep Modes */ +#define FULL_AWAKE 0x0 +#define NORMAL_OP 0x1 +#define LOW_PWR_OP 0x2 +#define VERY_LOW_PWR_OP 0x3 +#define SENS_SLEEP 0x4 +#define SLEEP_MOD 0x5 +#define DEEP_SLEEP 0x6 +#define HIBERNATE 0x7 + +/* Interrupt Register Mask */ +/* (INT_REQ_STAT_REG | DEVICE_STATUS_REG | INTERRUPT_EN_REG) */ +#define INT_ENA_REQ_MSK 0x07 +#define INT_ENA_ABS_MSK 0x01 +#define INT_ENA_REL_MSK 0x02 +#define INT_ENA_F20_MSK 0x04 + +/* Device Status Register Masks (DEVICE_STATUS_REG) */ +#define CONFIGURED_MSK 0x40 +#define ERROR_MSK 0x80 + +/* Data Register 0 Masks */ +#define FINGER_WIDTH_MSK 0xf0 +#define GESTURE_MSK 0x08 +#define SENSOR_STATUS_MSK 0x07 + +/* + * MSB Position Register Masks + * ABS_MSB_X_REG | ABS_MSB_Y_REG | SENS_MAX_POS_MSB_REG | + * DEV_QUERY_REG3 | DEV_QUERY_REG5 + */ +#define MSB_POSITION_MSK 0x1f + +/* Device Query Registers Masks */ + +/* DEV_QUERY_REG2 */ +#define NUM_EXTRA_POS_MSK 0x07 + +/* When in IRQ mode read the device every THREAD_IRQ_SLEEP_SECS */ +#define THREAD_IRQ_SLEEP_SECS 2 +#define THREAD_IRQ_SLEEP_MSECS (THREAD_IRQ_SLEEP_SECS * MSEC_PER_SEC) + +/* + * When in Polling mode and no data received for NO_DATA_THRES msecs + * reduce the polling rate to NO_DATA_SLEEP_MSECS + */ +#define NO_DATA_THRES (MSEC_PER_SEC) +#define NO_DATA_SLEEP_MSECS (MSEC_PER_SEC / 4) + +/* Control touchpad's No Deceleration option */ +static int no_decel = 1; +module_param(no_decel, bool, 0644); +MODULE_PARM_DESC(no_decel, "No Deceleration. Default = 1 (on)"); + +/* Control touchpad's Reduced Reporting option */ +static int reduce_report; +module_param(reduce_report, bool, 0644); +MODULE_PARM_DESC(reduce_report, "Reduced Reporting. Default = 0 (off)"); + +/* Control touchpad's No Filter option */ +static int no_filter; +module_param(no_filter, bool, 0644); +MODULE_PARM_DESC(no_filter, "No Filter. Default = 0 (off)"); + +/* + * touchpad Attention line is Active Low and Open Drain, + * therefore should be connected to pulled up line + * and the irq configuration should be set to Falling Edge Trigger + */ +/* Control IRQ / Polling option */ +static int polling_req; +module_param(polling_req, bool, 0444); +MODULE_PARM_DESC(polling_req, "Request Polling. Default = 0 (use irq)"); + +/* Control Polling Rate */ +static int scan_rate = 80; +module_param(scan_rate, int, 0644); +MODULE_PARM_DESC(scan_rate, "Polling rate in times/sec. Default = 80"); + +/* The main device structure */ +struct synaptics_i2c { + struct i2c_client *client; + struct input_dev *input; + struct delayed_work dwork; + int no_data_count; + int no_decel_param; + int reduce_report_param; + int no_filter_param; + int scan_rate_param; + int scan_ms; +}; + +static inline void set_scan_rate(struct synaptics_i2c *touch, int scan_rate) +{ + touch->scan_ms = MSEC_PER_SEC / scan_rate; + touch->scan_rate_param = scan_rate; +} + +/* + * Driver's initial design makes no race condition possible on i2c bus, + * so there is no need in any locking. + * Keep it in mind, while playing with the code. + */ +static s32 synaptics_i2c_reg_get(struct i2c_client *client, u16 reg) +{ + int ret; + + ret = i2c_smbus_write_byte_data(client, PAGE_SEL_REG, reg >> 8); + if (ret == 0) + ret = i2c_smbus_read_byte_data(client, reg & 0xff); + + return ret; +} + +static s32 synaptics_i2c_reg_set(struct i2c_client *client, u16 reg, u8 val) +{ + int ret; + + ret = i2c_smbus_write_byte_data(client, PAGE_SEL_REG, reg >> 8); + if (ret == 0) + ret = i2c_smbus_write_byte_data(client, reg & 0xff, val); + + return ret; +} + +static s32 synaptics_i2c_word_get(struct i2c_client *client, u16 reg) +{ + int ret; + + ret = i2c_smbus_write_byte_data(client, PAGE_SEL_REG, reg >> 8); + if (ret == 0) + ret = i2c_smbus_read_word_data(client, reg & 0xff); + + return ret; +} + +static int synaptics_i2c_config(struct i2c_client *client) +{ + int ret, control; + u8 int_en; + + /* set Report Rate to Device Highest (>=80) and Sleep to normal */ + ret = synaptics_i2c_reg_set(client, DEV_CONTROL_REG, 0xc1); + if (ret) + return ret; + + /* set Interrupt Disable to Func20 / Enable to Func10) */ + int_en = (polling_req) ? 0 : INT_ENA_ABS_MSK | INT_ENA_REL_MSK; + ret = synaptics_i2c_reg_set(client, INTERRUPT_EN_REG, int_en); + if (ret) + return ret; + + control = synaptics_i2c_reg_get(client, GENERAL_2D_CONTROL_REG); + /* No Deceleration */ + control |= no_decel ? 1 << NO_DECELERATION : 0; + /* Reduced Reporting */ + control |= reduce_report ? 1 << REDUCE_REPORTING : 0; + /* No Filter */ + control |= no_filter ? 1 << NO_FILTER : 0; + ret = synaptics_i2c_reg_set(client, GENERAL_2D_CONTROL_REG, control); + if (ret) + return ret; + + return 0; +} + +static int synaptics_i2c_reset_config(struct i2c_client *client) +{ + int ret; + + /* Reset the Touchpad */ + ret = synaptics_i2c_reg_set(client, DEV_COMMAND_REG, RESET_COMMAND); + if (ret) { + dev_err(&client->dev, "Unable to reset device\n"); + } else { + msleep(SOFT_RESET_DELAY_MS); + ret = synaptics_i2c_config(client); + if (ret) + dev_err(&client->dev, "Unable to config device\n"); + } + + return ret; +} + +static int synaptics_i2c_check_error(struct i2c_client *client) +{ + int status, ret = 0; + + status = i2c_smbus_read_byte_data(client, DEVICE_STATUS_REG) & + (CONFIGURED_MSK | ERROR_MSK); + + if (status != CONFIGURED_MSK) + ret = synaptics_i2c_reset_config(client); + + return ret; +} + +static bool synaptics_i2c_get_input(struct synaptics_i2c *touch) +{ + struct input_dev *input = touch->input; + int xy_delta, gesture; + s32 data; + s8 x_delta, y_delta; + + /* Deal with spontanious resets and errors */ + if (synaptics_i2c_check_error(touch->client)) + return 0; + + /* Get Gesture Bit */ + data = synaptics_i2c_reg_get(touch->client, DATA_REG0); + gesture = (data >> GESTURE) & 0x1; + + /* + * Get Relative axes. we have to get them in one shot, + * so we get 2 bytes starting from REL_X_REG. + */ + xy_delta = synaptics_i2c_word_get(touch->client, REL_X_REG) & 0xffff; + + /* Separate X from Y */ + x_delta = xy_delta & 0xff; + y_delta = (xy_delta >> REGISTER_LENGTH) & 0xff; + + /* Report the button event */ + input_report_key(input, BTN_LEFT, gesture); + + /* Report the deltas */ + input_report_rel(input, REL_X, x_delta); + input_report_rel(input, REL_Y, -y_delta); + input_sync(input); + + return xy_delta || gesture; +} + +static irqreturn_t synaptics_i2c_irq(int irq, void *dev_id) +{ + struct synaptics_i2c *touch = dev_id; + + /* + * We want to have the work run immediately but it might have + * already been scheduled with a delay, that's why we have to + * cancel it first. + */ + cancel_delayed_work(&touch->dwork); + schedule_delayed_work(&touch->dwork, 0); + + return IRQ_HANDLED; +} + +static void synaptics_i2c_check_params(struct synaptics_i2c *touch) +{ + bool reset = false; + + if (scan_rate != touch->scan_rate_param) + set_scan_rate(touch, scan_rate); + + if (no_decel != touch->no_decel_param) { + touch->no_decel_param = no_decel; + reset = true; + } + + if (no_filter != touch->no_filter_param) { + touch->no_filter_param = no_filter; + reset = true; + } + + if (reduce_report != touch->reduce_report_param) { + touch->reduce_report_param = reduce_report; + reset = true; + } + + if (reset) + synaptics_i2c_reset_config(touch->client); +} + +/* Control the Device polling rate / Work Handler sleep time */ +unsigned long synaptics_i2c_adjust_delay(struct synaptics_i2c *touch, + bool have_data) +{ + unsigned long delay, nodata_count_thres; + + if (polling_req) { + delay = touch->scan_ms; + if (have_data) { + touch->no_data_count = 0; + } else { + nodata_count_thres = NO_DATA_THRES / touch->scan_ms; + if (touch->no_data_count < nodata_count_thres) + touch->no_data_count++; + else + delay = NO_DATA_SLEEP_MSECS; + } + return msecs_to_jiffies(delay); + } else { + delay = msecs_to_jiffies(THREAD_IRQ_SLEEP_MSECS); + return round_jiffies_relative(delay); + } +} + +/* Work Handler */ +static void synaptics_i2c_work_handler(struct work_struct *work) +{ + bool have_data; + struct synaptics_i2c *touch = + container_of(work, struct synaptics_i2c, dwork.work); + unsigned long delay; + + synaptics_i2c_check_params(touch); + + have_data = synaptics_i2c_get_input(touch); + delay = synaptics_i2c_adjust_delay(touch, have_data); + + /* + * While interrupt driven, there is no real need to poll the device. + * But touchpads are very sensitive, so there could be errors + * related to physical environment and the attention line isn't + * neccesarily asserted. In such case we can lose the touchpad. + * We poll the device once in THREAD_IRQ_SLEEP_SECS and + * if error is detected, we try to reset and reconfigure the touchpad. + */ + schedule_delayed_work(&touch->dwork, delay); +} + +static int synaptics_i2c_open(struct input_dev *input) +{ + struct synaptics_i2c *touch = input_get_drvdata(input); + int ret; + + ret = synaptics_i2c_reset_config(touch->client); + if (ret) + return ret; + + if (polling_req) + schedule_delayed_work(&touch->dwork, + msecs_to_jiffies(NO_DATA_SLEEP_MSECS)); + + return 0; +} + +static void synaptics_i2c_close(struct input_dev *input) +{ + struct synaptics_i2c *touch = input_get_drvdata(input); + + if (!polling_req) + synaptics_i2c_reg_set(touch->client, INTERRUPT_EN_REG, 0); + + cancel_delayed_work_sync(&touch->dwork); + + /* Save some power */ + synaptics_i2c_reg_set(touch->client, DEV_CONTROL_REG, DEEP_SLEEP); +} + +static void synaptics_i2c_set_input_params(struct synaptics_i2c *touch) +{ + struct input_dev *input = touch->input; + + input->name = touch->client->name; + input->phys = touch->client->adapter->name; + input->id.bustype = BUS_I2C; + input->id.version = synaptics_i2c_word_get(touch->client, + INFO_QUERY_REG0); + input->dev.parent = &touch->client->dev; + input->open = synaptics_i2c_open; + input->close = synaptics_i2c_close; + input_set_drvdata(input, touch); + + /* Register the device as mouse */ + __set_bit(EV_REL, input->evbit); + __set_bit(REL_X, input->relbit); + __set_bit(REL_Y, input->relbit); + + /* Register device's buttons and keys */ + __set_bit(EV_KEY, input->evbit); + __set_bit(BTN_LEFT, input->keybit); +} + +struct synaptics_i2c *synaptics_i2c_touch_create(struct i2c_client *client) +{ + struct synaptics_i2c *touch; + + touch = kzalloc(sizeof(struct synaptics_i2c), GFP_KERNEL); + if (!touch) + return NULL; + + touch->client = client; + touch->no_decel_param = no_decel; + touch->scan_rate_param = scan_rate; + set_scan_rate(touch, scan_rate); + INIT_DELAYED_WORK(&touch->dwork, synaptics_i2c_work_handler); + + return touch; +} + +static int __devinit synaptics_i2c_probe(struct i2c_client *client, + const struct i2c_device_id *dev_id) +{ + int ret; + struct synaptics_i2c *touch; + + touch = synaptics_i2c_touch_create(client); + if (!touch) + return -ENOMEM; + + i2c_set_clientdata(client, touch); + + ret = synaptics_i2c_reset_config(client); + if (ret) + goto err_mem_free; + + if (client->irq < 1) + polling_req = 1; + + touch->input = input_allocate_device(); + if (!touch->input) { + ret = -ENOMEM; + goto err_mem_free; + } + + synaptics_i2c_set_input_params(touch); + + if (!polling_req) { + dev_dbg(&touch->client->dev, + "Requesting IRQ: %d\n", touch->client->irq); + + ret = request_irq(touch->client->irq, synaptics_i2c_irq, + IRQF_DISABLED|IRQ_TYPE_EDGE_FALLING, + DRIVER_NAME, touch); + if (ret) { + dev_warn(&touch->client->dev, + "IRQ request failed: %d, " + "falling back to polling\n", ret); + polling_req = 1; + synaptics_i2c_reg_set(touch->client, + INTERRUPT_EN_REG, 0); + } + } + + if (polling_req) + dev_dbg(&touch->client->dev, + "Using polling at rate: %d times/sec\n", scan_rate); + + /* Register the device in input subsystem */ + ret = input_register_device(touch->input); + if (ret) { + dev_err(&client->dev, + "Input device register failed: %d\n", ret); + goto err_input_free; + } + return 0; + +err_input_free: + input_free_device(touch->input); +err_mem_free: + i2c_set_clientdata(client, NULL); + kfree(touch); + + return ret; +} + +static int __devexit synaptics_i2c_remove(struct i2c_client *client) +{ + struct synaptics_i2c *touch = i2c_get_clientdata(client); + + if (!polling_req) + free_irq(touch->client->irq, touch); + + input_unregister_device(touch->input); + i2c_set_clientdata(client, NULL); + kfree(touch); + + return 0; +} + +#ifdef CONFIG_PM +static int synaptics_i2c_suspend(struct i2c_client *client, pm_message_t mesg) +{ + struct synaptics_i2c *touch = i2c_get_clientdata(client); + + cancel_delayed_work_sync(&touch->dwork); + + /* Save some power */ + synaptics_i2c_reg_set(touch->client, DEV_CONTROL_REG, DEEP_SLEEP); + + return 0; +} + +static int synaptics_i2c_resume(struct i2c_client *client) +{ + int ret; + struct synaptics_i2c *touch = i2c_get_clientdata(client); + + ret = synaptics_i2c_reset_config(client); + if (ret) + return ret; + + schedule_delayed_work(&touch->dwork, + msecs_to_jiffies(NO_DATA_SLEEP_MSECS)); + + return 0; +} +#else +#define synaptics_i2c_suspend NULL +#define synaptics_i2c_resume NULL +#endif + +static const struct i2c_device_id synaptics_i2c_id_table[] = { + { "synaptics_i2c", 0 }, + { }, +}; +MODULE_DEVICE_TABLE(i2c, synaptics_i2c_id_table); + +static struct i2c_driver synaptics_i2c_driver = { + .driver = { + .name = DRIVER_NAME, + .owner = THIS_MODULE, + }, + + .probe = synaptics_i2c_probe, + .remove = __devexit_p(synaptics_i2c_remove), + + .suspend = synaptics_i2c_suspend, + .resume = synaptics_i2c_resume, + .id_table = synaptics_i2c_id_table, +}; + +static int __init synaptics_i2c_init(void) +{ + return i2c_add_driver(&synaptics_i2c_driver); +} + +static void __exit synaptics_i2c_exit(void) +{ + i2c_del_driver(&synaptics_i2c_driver); +} + +module_init(synaptics_i2c_init); +module_exit(synaptics_i2c_exit); + +MODULE_DESCRIPTION("Synaptics I2C touchpad driver"); +MODULE_AUTHOR("Mike Rapoport, Igor Grinberg, Compulab"); +MODULE_LICENSE("GPL"); + diff --git a/drivers/input/mousedev.c b/drivers/input/mousedev.c index 17fd6d46d082..966b8868f792 100644 --- a/drivers/input/mousedev.c +++ b/drivers/input/mousedev.c @@ -60,7 +60,6 @@ struct mousedev { int exist; int open; int minor; - char name[16]; struct input_handle handle; wait_queue_head_t wait; struct list_head client_list; @@ -863,19 +862,17 @@ static struct mousedev *mousedev_create(struct input_dev *dev, init_waitqueue_head(&mousedev->wait); if (minor == MOUSEDEV_MIX) - strlcpy(mousedev->name, "mice", sizeof(mousedev->name)); + dev_set_name(&mousedev->dev, "mice"); else - snprintf(mousedev->name, sizeof(mousedev->name), - "mouse%d", minor); + dev_set_name(&mousedev->dev, "mouse%d", minor); mousedev->minor = minor; mousedev->exist = 1; mousedev->handle.dev = input_get_device(dev); - mousedev->handle.name = mousedev->name; + mousedev->handle.name = dev_name(&mousedev->dev); mousedev->handle.handler = handler; mousedev->handle.private = mousedev; - dev_set_name(&mousedev->dev, mousedev->name); mousedev->dev.class = &input_class; if (dev) mousedev->dev.parent = &dev->dev; diff --git a/drivers/input/serio/i8042.c b/drivers/input/serio/i8042.c index 3cffb704e374..f919bf57293c 100644 --- a/drivers/input/serio/i8042.c +++ b/drivers/input/serio/i8042.c @@ -10,6 +10,7 @@ * the Free Software Foundation. */ +#include <linux/types.h> #include <linux/delay.h> #include <linux/module.h> #include <linux/interrupt.h> @@ -921,6 +922,9 @@ static void i8042_dritek_enable(void) #endif #ifdef CONFIG_PM + +static bool i8042_suspended; + /* * Here we try to restore the original BIOS settings. We only want to * do that once, when we really suspend, not when we taking memory @@ -930,11 +934,9 @@ static void i8042_dritek_enable(void) static int i8042_suspend(struct platform_device *dev, pm_message_t state) { - if (dev->dev.power.power_state.event != state.event) { - if (state.event == PM_EVENT_SUSPEND) - i8042_controller_reset(); - - dev->dev.power.power_state = state; + if (!i8042_suspended && state.event == PM_EVENT_SUSPEND) { + i8042_controller_reset(); + i8042_suspended = true; } return 0; @@ -952,7 +954,7 @@ static int i8042_resume(struct platform_device *dev) /* * Do not bother with restoring state if we haven't suspened yet */ - if (dev->dev.power.power_state.event == PM_EVENT_ON) + if (!i8042_suspended) return 0; error = i8042_controller_check(); @@ -998,10 +1000,9 @@ static int i8042_resume(struct platform_device *dev) if (i8042_ports[I8042_KBD_PORT_NO].serio) i8042_enable_kbd_port(); + i8042_suspended = false; i8042_interrupt(0, NULL); - dev->dev.power.power_state = PMSG_ON; - return 0; } #endif /* CONFIG_PM */ diff --git a/drivers/input/serio/serio.c b/drivers/input/serio/serio.c index bc033250dfcd..fb17573f8f2d 100644 --- a/drivers/input/serio/serio.c +++ b/drivers/input/serio/serio.c @@ -41,17 +41,6 @@ MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>"); MODULE_DESCRIPTION("Serio abstraction core"); MODULE_LICENSE("GPL"); -EXPORT_SYMBOL(serio_interrupt); -EXPORT_SYMBOL(__serio_register_port); -EXPORT_SYMBOL(serio_unregister_port); -EXPORT_SYMBOL(serio_unregister_child_port); -EXPORT_SYMBOL(__serio_register_driver); -EXPORT_SYMBOL(serio_unregister_driver); -EXPORT_SYMBOL(serio_open); -EXPORT_SYMBOL(serio_close); -EXPORT_SYMBOL(serio_rescan); -EXPORT_SYMBOL(serio_reconnect); - /* * serio_mutex protects entire serio subsystem and is taken every time * serio port or driver registrered or unregistered. @@ -506,9 +495,9 @@ static ssize_t serio_set_bind_mode(struct device *dev, struct device_attribute * retval = count; if (!strncmp(buf, "manual", count)) { - serio->manual_bind = 1; + serio->manual_bind = true; } else if (!strncmp(buf, "auto", count)) { - serio->manual_bind = 0; + serio->manual_bind = false; } else { retval = -EINVAL; } @@ -581,7 +570,7 @@ static void serio_add_port(struct serio *serio) "serio: device_add() failed for %s (%s), error: %d\n", serio->phys, serio->name, error); else { - serio->registered = 1; + serio->registered = true; error = sysfs_create_group(&serio->dev.kobj, &serio_id_attr_group); if (error) printk(KERN_ERR @@ -617,7 +606,7 @@ static void serio_destroy_port(struct serio *serio) if (serio->registered) { sysfs_remove_group(&serio->dev.kobj, &serio_id_attr_group); device_del(&serio->dev); - serio->registered = 0; + serio->registered = false; } list_del_init(&serio->node); @@ -692,11 +681,13 @@ void serio_rescan(struct serio *serio) { serio_queue_event(serio, NULL, SERIO_RESCAN_PORT); } +EXPORT_SYMBOL(serio_rescan); void serio_reconnect(struct serio *serio) { serio_queue_event(serio, NULL, SERIO_RECONNECT_CHAIN); } +EXPORT_SYMBOL(serio_reconnect); /* * Submits register request to kseriod for subsequent execution. @@ -707,6 +698,7 @@ void __serio_register_port(struct serio *serio, struct module *owner) serio_init_port(serio); serio_queue_event(serio, owner, SERIO_REGISTER_PORT); } +EXPORT_SYMBOL(__serio_register_port); /* * Synchronously unregisters serio port. @@ -718,6 +710,7 @@ void serio_unregister_port(struct serio *serio) serio_destroy_port(serio); mutex_unlock(&serio_mutex); } +EXPORT_SYMBOL(serio_unregister_port); /* * Safely unregisters child port if one is present. @@ -731,6 +724,7 @@ void serio_unregister_child_port(struct serio *serio) } mutex_unlock(&serio_mutex); } +EXPORT_SYMBOL(serio_unregister_child_port); /* @@ -756,9 +750,9 @@ static ssize_t serio_driver_set_bind_mode(struct device_driver *drv, const char retval = count; if (!strncmp(buf, "manual", count)) { - serio_drv->manual_bind = 1; + serio_drv->manual_bind = true; } else if (!strncmp(buf, "auto", count)) { - serio_drv->manual_bind = 0; + serio_drv->manual_bind = false; } else { retval = -EINVAL; } @@ -818,7 +812,7 @@ static void serio_attach_driver(struct serio_driver *drv) int __serio_register_driver(struct serio_driver *drv, struct module *owner, const char *mod_name) { - int manual_bind = drv->manual_bind; + bool manual_bind = drv->manual_bind; int error; drv->driver.bus = &serio_bus; @@ -829,7 +823,7 @@ int __serio_register_driver(struct serio_driver *drv, struct module *owner, cons * Temporarily disable automatic binding because probing * takes long time and we are better off doing it in kseriod */ - drv->manual_bind = 1; + drv->manual_bind = true; error = driver_register(&drv->driver); if (error) { @@ -844,7 +838,7 @@ int __serio_register_driver(struct serio_driver *drv, struct module *owner, cons * driver to free ports */ if (!manual_bind) { - drv->manual_bind = 0; + drv->manual_bind = false; error = serio_queue_event(drv, NULL, SERIO_ATTACH_DRIVER); if (error) { driver_unregister(&drv->driver); @@ -854,6 +848,7 @@ int __serio_register_driver(struct serio_driver *drv, struct module *owner, cons return 0; } +EXPORT_SYMBOL(__serio_register_driver); void serio_unregister_driver(struct serio_driver *drv) { @@ -861,7 +856,7 @@ void serio_unregister_driver(struct serio_driver *drv) mutex_lock(&serio_mutex); - drv->manual_bind = 1; /* so serio_find_driver ignores it */ + drv->manual_bind = true; /* so serio_find_driver ignores it */ serio_remove_pending_events(drv); start_over: @@ -877,6 +872,7 @@ start_over: driver_unregister(&drv->driver); mutex_unlock(&serio_mutex); } +EXPORT_SYMBOL(serio_unregister_driver); static void serio_set_drv(struct serio *serio, struct serio_driver *drv) { @@ -937,11 +933,11 @@ static int serio_uevent(struct device *dev, struct kobj_uevent_env *env) #ifdef CONFIG_PM static int serio_suspend(struct device *dev, pm_message_t state) { - if (dev->power.power_state.event != state.event) { - if (state.event == PM_EVENT_SUSPEND) - serio_cleanup(to_serio_port(dev)); + struct serio *serio = to_serio_port(dev); - dev->power.power_state = state; + if (!serio->suspended && state.event == PM_EVENT_SUSPEND) { + serio_cleanup(serio); + serio->suspended = true; } return 0; @@ -949,14 +945,15 @@ static int serio_suspend(struct device *dev, pm_message_t state) static int serio_resume(struct device *dev) { + struct serio *serio = to_serio_port(dev); + /* * Driver reconnect can take a while, so better let kseriod * deal with it. */ - if (dev->power.power_state.event != PM_EVENT_ON) { - dev->power.power_state = PMSG_ON; - serio_queue_event(to_serio_port(dev), NULL, - SERIO_RECONNECT_PORT); + if (serio->suspended) { + serio->suspended = false; + serio_queue_event(serio, NULL, SERIO_RECONNECT_PORT); } return 0; @@ -974,6 +971,7 @@ int serio_open(struct serio *serio, struct serio_driver *drv) } return 0; } +EXPORT_SYMBOL(serio_open); /* called from serio_driver->connect/disconnect methods under serio_mutex */ void serio_close(struct serio *serio) @@ -983,6 +981,7 @@ void serio_close(struct serio *serio) serio_set_drv(serio, NULL); } +EXPORT_SYMBOL(serio_close); irqreturn_t serio_interrupt(struct serio *serio, unsigned char data, unsigned int dfl) @@ -1003,6 +1002,7 @@ irqreturn_t serio_interrupt(struct serio *serio, return ret; } +EXPORT_SYMBOL(serio_interrupt); static struct bus_type serio_bus = { .name = "serio", diff --git a/drivers/input/tablet/gtco.c b/drivers/input/tablet/gtco.c index 2e18a1c0c351..3d32d3f4e486 100644 --- a/drivers/input/tablet/gtco.c +++ b/drivers/input/tablet/gtco.c @@ -1050,4 +1050,5 @@ static void __exit gtco_exit(void) module_init(gtco_init); module_exit(gtco_exit); +MODULE_DESCRIPTION("GTCO digitizer USB driver"); MODULE_LICENSE("GPL"); diff --git a/drivers/input/tablet/wacom.h b/drivers/input/tablet/wacom.h index 9710bfd49cf9..9114ae1c7488 100644 --- a/drivers/input/tablet/wacom.h +++ b/drivers/input/tablet/wacom.h @@ -68,6 +68,7 @@ * v1.48 (pc) - Added support for Bamboo1, BambooFun, and Cintiq 12WX * v1.49 (pc) - Added support for USB Tablet PC (0x90, 0x93, and 0x9A) * v1.50 (pc) - Fixed a TabletPC touch bug in 2.6.28 + * v1.51 (pc) - Added support for Intuos4 */ /* @@ -88,7 +89,7 @@ /* * Version Information */ -#define DRIVER_VERSION "v1.50" +#define DRIVER_VERSION "v1.51" #define DRIVER_AUTHOR "Vojtech Pavlik <vojtech@ucw.cz>" #define DRIVER_DESC "USB Wacom Graphire and Wacom Intuos tablet driver" #define DRIVER_LICENSE "GPL" @@ -128,6 +129,8 @@ extern void input_dev_g(struct input_dev *input_dev, struct wacom_wac *wacom_wac extern void input_dev_i3s(struct input_dev *input_dev, struct wacom_wac *wacom_wac); extern void input_dev_i3(struct input_dev *input_dev, struct wacom_wac *wacom_wac); extern void input_dev_i(struct input_dev *input_dev, struct wacom_wac *wacom_wac); +extern void input_dev_i4s(struct input_dev *input_dev, struct wacom_wac *wacom_wac); +extern void input_dev_i4(struct input_dev *input_dev, struct wacom_wac *wacom_wac); extern void input_dev_pl(struct input_dev *input_dev, struct wacom_wac *wacom_wac); extern void input_dev_pt(struct input_dev *input_dev, struct wacom_wac *wacom_wac); extern void input_dev_mo(struct input_dev *input_dev, struct wacom_wac *wacom_wac); diff --git a/drivers/input/tablet/wacom_sys.c b/drivers/input/tablet/wacom_sys.c index b8624f27abf9..a9d5031b855e 100644 --- a/drivers/input/tablet/wacom_sys.c +++ b/drivers/input/tablet/wacom_sys.c @@ -229,6 +229,19 @@ void input_dev_i3(struct input_dev *input_dev, struct wacom_wac *wacom_wac) input_set_abs_params(input_dev, ABS_RY, 0, 4096, 0, 0); } +void input_dev_i4s(struct input_dev *input_dev, struct wacom_wac *wacom_wac) +{ + input_dev->keybit[BIT_WORD(BTN_DIGI)] |= BIT_MASK(BTN_TOOL_FINGER); + input_dev->keybit[BIT_WORD(BTN_MISC)] |= BIT_MASK(BTN_0) | BIT_MASK(BTN_1) | BIT_MASK(BTN_2) | BIT_MASK(BTN_3); + input_dev->keybit[BIT_WORD(BTN_MISC)] |= BIT_MASK(BTN_4) | BIT_MASK(BTN_5) | BIT_MASK(BTN_6); + input_set_abs_params(input_dev, ABS_Z, -900, 899, 0, 0); +} + +void input_dev_i4(struct input_dev *input_dev, struct wacom_wac *wacom_wac) +{ + input_dev->keybit[BIT_WORD(BTN_MISC)] |= BIT_MASK(BTN_7) | BIT_MASK(BTN_8); +} + void input_dev_bee(struct input_dev *input_dev, struct wacom_wac *wacom_wac) { input_dev->keybit[BIT_WORD(BTN_MISC)] |= BIT_MASK(BTN_8) | BIT_MASK(BTN_9); diff --git a/drivers/input/tablet/wacom_wac.c b/drivers/input/tablet/wacom_wac.c index 2638811c61ac..38bf86384aeb 100644 --- a/drivers/input/tablet/wacom_wac.c +++ b/drivers/input/tablet/wacom_wac.c @@ -283,10 +283,11 @@ static int wacom_graphire_irq(struct wacom_wac *wacom, void *wcombo) static int wacom_intuos_inout(struct wacom_wac *wacom, void *wcombo) { unsigned char *data = wacom->data; - int idx; + int idx = 0; /* tool number */ - idx = data[1] & 0x01; + if (wacom->features->type == INTUOS) + idx = data[1] & 0x01; /* Enter report */ if ((data[1] & 0xfc) == 0xc0) { @@ -299,6 +300,7 @@ static int wacom_intuos_inout(struct wacom_wac *wacom, void *wcombo) switch (wacom->id[idx]) { case 0x812: /* Inking pen */ case 0x801: /* Intuos3 Inking pen */ + case 0x20802: /* Intuos4 Classic Pen */ case 0x012: wacom->tool[idx] = BTN_TOOL_PENCIL; break; @@ -308,6 +310,9 @@ static int wacom_intuos_inout(struct wacom_wac *wacom, void *wcombo) case 0x823: /* Intuos3 Grip Pen */ case 0x813: /* Intuos3 Classic Pen */ case 0x885: /* Intuos3 Marker Pen */ + case 0x802: /* Intuos4 Grip Pen Eraser */ + case 0x804: /* Intuos4 Marker Pen */ + case 0x40802: /* Intuos4 Classic Pen */ case 0x022: wacom->tool[idx] = BTN_TOOL_PEN; break; @@ -319,10 +324,12 @@ static int wacom_intuos_inout(struct wacom_wac *wacom, void *wcombo) case 0x09c: case 0x094: case 0x017: /* Intuos3 2D Mouse */ + case 0x806: /* Intuos4 Mouse */ wacom->tool[idx] = BTN_TOOL_MOUSE; break; case 0x096: /* Lens cursor */ case 0x097: /* Intuos3 Lens cursor */ + case 0x006: /* Intuos4 Lens cursor */ wacom->tool[idx] = BTN_TOOL_LENS; break; case 0x82a: /* Eraser */ @@ -333,12 +340,17 @@ static int wacom_intuos_inout(struct wacom_wac *wacom, void *wcombo) case 0x82b: /* Intuos3 Grip Pen Eraser */ case 0x81b: /* Intuos3 Classic Pen Eraser */ case 0x91b: /* Intuos3 Airbrush Eraser */ + case 0x80c: /* Intuos4 Marker Pen Eraser */ + case 0x80a: /* Intuos4 Grip Pen Eraser */ + case 0x4080a: /* Intuos4 Classic Pen Eraser */ + case 0x90a: /* Intuos4 Airbrush Eraser */ wacom->tool[idx] = BTN_TOOL_RUBBER; break; case 0xd12: case 0x912: case 0x112: case 0x913: /* Intuos3 Airbrush */ + case 0x902: /* Intuos4 Airbrush */ wacom->tool[idx] = BTN_TOOL_AIRBRUSH; break; default: /* Unknown tool */ @@ -349,9 +361,15 @@ static int wacom_intuos_inout(struct wacom_wac *wacom, void *wcombo) /* Exit report */ if ((data[1] & 0xfe) == 0x80) { + /* + * Reset all states otherwise we lose the initial states + * when in-prox next time + */ wacom_report_abs(wcombo, ABS_X, 0); wacom_report_abs(wcombo, ABS_Y, 0); wacom_report_abs(wcombo, ABS_DISTANCE, 0); + wacom_report_abs(wcombo, ABS_TILT_X, 0); + wacom_report_abs(wcombo, ABS_TILT_Y, 0); if (wacom->tool[idx] >= BTN_TOOL_MOUSE) { wacom_report_key(wcombo, BTN_LEFT, 0); wacom_report_key(wcombo, BTN_MIDDLE, 0); @@ -362,8 +380,6 @@ static int wacom_intuos_inout(struct wacom_wac *wacom, void *wcombo) wacom_report_abs(wcombo, ABS_RZ, 0); } else { wacom_report_abs(wcombo, ABS_PRESSURE, 0); - wacom_report_abs(wcombo, ABS_TILT_X, 0); - wacom_report_abs(wcombo, ABS_TILT_Y, 0); wacom_report_key(wcombo, BTN_STYLUS, 0); wacom_report_key(wcombo, BTN_STYLUS2, 0); wacom_report_key(wcombo, BTN_TOUCH, 0); @@ -372,6 +388,7 @@ static int wacom_intuos_inout(struct wacom_wac *wacom, void *wcombo) wacom_report_key(wcombo, wacom->tool[idx], 0); wacom_report_abs(wcombo, ABS_MISC, 0); /* reset tool id */ wacom_input_event(wcombo, EV_MSC, MSC_SERIAL, wacom->serial[idx]); + wacom->id[idx] = 0; return 2; } return 0; @@ -385,6 +402,8 @@ static void wacom_intuos_general(struct wacom_wac *wacom, void *wcombo) /* general pen packet */ if ((data[1] & 0xb8) == 0xa0) { t = (data[6] << 2) | ((data[7] >> 6) & 3); + if (wacom->features->type >= INTUOS4S && wacom->features->type <= INTUOS4L) + t = (t << 1) | (data[1] & 1); wacom_report_abs(wcombo, ABS_PRESSURE, t); wacom_report_abs(wcombo, ABS_TILT_X, ((data[7] << 1) & 0x7e) | (data[8] >> 7)); @@ -409,7 +428,7 @@ static int wacom_intuos_irq(struct wacom_wac *wacom, void *wcombo) { unsigned char *data = wacom->data; unsigned int t; - int idx, result; + int idx = 0, result; if (data[0] != 2 && data[0] != 5 && data[0] != 6 && data[0] != 12) { dbg("wacom_intuos_irq: received unknown report #%d", data[0]); @@ -417,7 +436,8 @@ static int wacom_intuos_irq(struct wacom_wac *wacom, void *wcombo) } /* tool number */ - idx = data[1] & 0x01; + if (wacom->features->type == INTUOS) + idx = data[1] & 0x01; /* pad packets. Works as a second tool and is always in prox */ if (data[0] == 12) { @@ -425,25 +445,54 @@ static int wacom_intuos_irq(struct wacom_wac *wacom, void *wcombo) if (wacom->tool[1] != BTN_TOOL_FINGER) wacom->tool[1] = BTN_TOOL_FINGER; - wacom_report_key(wcombo, BTN_0, (data[5] & 0x01)); - wacom_report_key(wcombo, BTN_1, (data[5] & 0x02)); - wacom_report_key(wcombo, BTN_2, (data[5] & 0x04)); - wacom_report_key(wcombo, BTN_3, (data[5] & 0x08)); - wacom_report_key(wcombo, BTN_4, (data[6] & 0x01)); - wacom_report_key(wcombo, BTN_5, (data[6] & 0x02)); - wacom_report_key(wcombo, BTN_6, (data[6] & 0x04)); - wacom_report_key(wcombo, BTN_7, (data[6] & 0x08)); - wacom_report_key(wcombo, BTN_8, (data[5] & 0x10)); - wacom_report_key(wcombo, BTN_9, (data[6] & 0x10)); - wacom_report_abs(wcombo, ABS_RX, ((data[1] & 0x1f) << 8) | data[2]); - wacom_report_abs(wcombo, ABS_RY, ((data[3] & 0x1f) << 8) | data[4]); - - if ((data[5] & 0x1f) | (data[6] & 0x1f) | (data[1] & 0x1f) | - data[2] | (data[3] & 0x1f) | data[4]) - wacom_report_key(wcombo, wacom->tool[1], 1); - else - wacom_report_key(wcombo, wacom->tool[1], 0); - wacom_report_abs(wcombo, ABS_MISC, PAD_DEVICE_ID); + if (wacom->features->type >= INTUOS4S && wacom->features->type <= INTUOS4L) { + wacom_report_key(wcombo, BTN_0, (data[2] & 0x01)); + wacom_report_key(wcombo, BTN_1, (data[3] & 0x01)); + wacom_report_key(wcombo, BTN_2, (data[3] & 0x02)); + wacom_report_key(wcombo, BTN_3, (data[3] & 0x04)); + wacom_report_key(wcombo, BTN_4, (data[3] & 0x08)); + wacom_report_key(wcombo, BTN_5, (data[3] & 0x10)); + wacom_report_key(wcombo, BTN_6, (data[3] & 0x20)); + if (data[1] & 0x80) { + wacom_report_abs(wcombo, ABS_WHEEL, (data[1] & 0x7f)); + } else { + /* Out of proximity, clear wheel value. */ + wacom_report_abs(wcombo, ABS_WHEEL, 0); + } + if (wacom->features->type != INTUOS4S) { + wacom_report_key(wcombo, BTN_7, (data[3] & 0x40)); + wacom_report_key(wcombo, BTN_8, (data[3] & 0x80)); + } + if (data[1] | (data[2] & 0x01) | data[3]) { + wacom_report_key(wcombo, wacom->tool[1], 1); + wacom_report_abs(wcombo, ABS_MISC, PAD_DEVICE_ID); + } else { + wacom_report_key(wcombo, wacom->tool[1], 0); + wacom_report_abs(wcombo, ABS_MISC, 0); + } + } else { + wacom_report_key(wcombo, BTN_0, (data[5] & 0x01)); + wacom_report_key(wcombo, BTN_1, (data[5] & 0x02)); + wacom_report_key(wcombo, BTN_2, (data[5] & 0x04)); + wacom_report_key(wcombo, BTN_3, (data[5] & 0x08)); + wacom_report_key(wcombo, BTN_4, (data[6] & 0x01)); + wacom_report_key(wcombo, BTN_5, (data[6] & 0x02)); + wacom_report_key(wcombo, BTN_6, (data[6] & 0x04)); + wacom_report_key(wcombo, BTN_7, (data[6] & 0x08)); + wacom_report_key(wcombo, BTN_8, (data[5] & 0x10)); + wacom_report_key(wcombo, BTN_9, (data[6] & 0x10)); + wacom_report_abs(wcombo, ABS_RX, ((data[1] & 0x1f) << 8) | data[2]); + wacom_report_abs(wcombo, ABS_RY, ((data[3] & 0x1f) << 8) | data[4]); + + if ((data[5] & 0x1f) | (data[6] & 0x1f) | (data[1] & 0x1f) | + data[2] | (data[3] & 0x1f) | data[4]) { + wacom_report_key(wcombo, wacom->tool[1], 1); + wacom_report_abs(wcombo, ABS_MISC, PAD_DEVICE_ID); + } else { + wacom_report_key(wcombo, wacom->tool[1], 0); + wacom_report_abs(wcombo, ABS_MISC, 0); + } + } wacom_input_event(wcombo, EV_MSC, MSC_SERIAL, 0xffffffff); return 1; } @@ -453,10 +502,16 @@ static int wacom_intuos_irq(struct wacom_wac *wacom, void *wcombo) if (result) return result-1; - /* Only large I3 and I1 & I2 support Lense Cursor */ + /* don't proceed if we don't know the ID */ + if (!wacom->id[idx]) + return 0; + + /* Only large Intuos support Lense Cursor */ if ((wacom->tool[idx] == BTN_TOOL_LENS) && ((wacom->features->type == INTUOS3) - || (wacom->features->type == INTUOS3S))) + || (wacom->features->type == INTUOS3S) + || (wacom->features->type == INTUOS4) + || (wacom->features->type == INTUOS4S))) return 0; /* Cintiq doesn't send data when RDY bit isn't set */ @@ -476,8 +531,8 @@ static int wacom_intuos_irq(struct wacom_wac *wacom, void *wcombo) /* process general packets */ wacom_intuos_general(wacom, wcombo); - /* 4D mouse, 2D mouse, marker pen rotation, or Lens cursor packets */ - if ((data[1] & 0xbc) == 0xa8 || (data[1] & 0xbe) == 0xb0) { + /* 4D mouse, 2D mouse, marker pen rotation, tilt mouse, or Lens cursor packets */ + if ((data[1] & 0xbc) == 0xa8 || (data[1] & 0xbe) == 0xb0 || (data[1] & 0xbc) == 0xac) { if (data[1] & 0x02) { /* Rotation packet */ @@ -506,20 +561,36 @@ static int wacom_intuos_irq(struct wacom_wac *wacom, void *wcombo) wacom_report_abs(wcombo, ABS_THROTTLE, (data[8] & 0x08) ? -t : t); } else if (wacom->tool[idx] == BTN_TOOL_MOUSE) { - /* 2D mouse packet */ - wacom_report_key(wcombo, BTN_LEFT, data[8] & 0x04); - wacom_report_key(wcombo, BTN_MIDDLE, data[8] & 0x08); - wacom_report_key(wcombo, BTN_RIGHT, data[8] & 0x10); - wacom_report_rel(wcombo, REL_WHEEL, (data[8] & 0x01) + /* I4 mouse */ + if (wacom->features->type >= INTUOS4S && wacom->features->type <= INTUOS4L) { + wacom_report_key(wcombo, BTN_LEFT, data[6] & 0x01); + wacom_report_key(wcombo, BTN_MIDDLE, data[6] & 0x02); + wacom_report_key(wcombo, BTN_RIGHT, data[6] & 0x04); + wacom_report_rel(wcombo, REL_WHEEL, ((data[7] & 0x80) >> 7) + - ((data[7] & 0x40) >> 6)); + wacom_report_key(wcombo, BTN_SIDE, data[6] & 0x08); + wacom_report_key(wcombo, BTN_EXTRA, data[6] & 0x10); + + wacom_report_abs(wcombo, ABS_TILT_X, + ((data[7] << 1) & 0x7e) | (data[8] >> 7)); + wacom_report_abs(wcombo, ABS_TILT_Y, data[8] & 0x7f); + } else { + /* 2D mouse packet */ + wacom_report_key(wcombo, BTN_LEFT, data[8] & 0x04); + wacom_report_key(wcombo, BTN_MIDDLE, data[8] & 0x08); + wacom_report_key(wcombo, BTN_RIGHT, data[8] & 0x10); + wacom_report_rel(wcombo, REL_WHEEL, (data[8] & 0x01) - ((data[8] & 0x02) >> 1)); - /* I3 2D mouse side buttons */ - if (wacom->features->type >= INTUOS3S && wacom->features->type <= INTUOS3L) { - wacom_report_key(wcombo, BTN_SIDE, data[8] & 0x40); - wacom_report_key(wcombo, BTN_EXTRA, data[8] & 0x20); + /* I3 2D mouse side buttons */ + if (wacom->features->type >= INTUOS3S && wacom->features->type <= INTUOS3L) { + wacom_report_key(wcombo, BTN_SIDE, data[8] & 0x40); + wacom_report_key(wcombo, BTN_EXTRA, data[8] & 0x20); + } } - - } else if (wacom->features->type < INTUOS3S || wacom->features->type == INTUOS3L) { + } else if ((wacom->features->type < INTUOS3S || wacom->features->type == INTUOS3L || + wacom->features->type == INTUOS4L) && + wacom->tool[idx] == BTN_TOOL_LENS) { /* Lens cursor packets */ wacom_report_key(wcombo, BTN_LEFT, data[8] & 0x01); wacom_report_key(wcombo, BTN_MIDDLE, data[8] & 0x02); @@ -581,6 +652,7 @@ static int wacom_tpc_irq(struct wacom_wac *wacom, void *wcombo) } } else if (touchOut || !prox) { /* force touch out-prox */ wacom_report_abs(wcombo, ABS_MISC, TOUCH_DEVICE_ID); + wacom_report_key(wcombo, wacom->tool[1], 0); wacom_report_key(wcombo, BTN_TOUCH, 0); touchOut = 0; touchInProx = 1; @@ -669,6 +741,9 @@ int wacom_wac_irq(struct wacom_wac *wacom_wac, void *wcombo) case INTUOS3S: case INTUOS3: case INTUOS3L: + case INTUOS4S: + case INTUOS4: + case INTUOS4L: case CINTIQ: case WACOM_BEE: return wacom_intuos_irq(wacom_wac, wcombo); @@ -706,6 +781,14 @@ void wacom_init_input_dev(struct input_dev *input_dev, struct wacom_wac *wacom_w case INTUOS: input_dev_i(input_dev, wacom_wac); break; + case INTUOS4: + case INTUOS4L: + input_dev_i4(input_dev, wacom_wac); + /* fall through */ + case INTUOS4S: + input_dev_i4s(input_dev, wacom_wac); + input_dev_i(input_dev, wacom_wac); + break; case PL: case PTU: case TABLETPC: @@ -766,6 +849,10 @@ static struct wacom_features wacom_features[] = { { "Wacom Intuos3 12x19", 10, 97536, 60960, 1023, 63, INTUOS3L }, { "Wacom Intuos3 6x11", 10, 54204, 31750, 1023, 63, INTUOS3 }, { "Wacom Intuos3 4x6", 10, 31496, 19685, 1023, 63, INTUOS3S }, + { "Wacom Intuos4 4x6", 10, 31496, 19685, 2047, 63, INTUOS4S }, + { "Wacom Intuos4 6x9", 10, 44704, 27940, 2047, 63, INTUOS4 }, + { "Wacom Intuos4 8x13", 10, 65024, 40640, 2047, 63, INTUOS4L }, + { "Wacom Intuos4 12x19", 10, 97536, 60960, 2047, 63, INTUOS4L }, { "Wacom Cintiq 21UX", 10, 87200, 65600, 1023, 63, CINTIQ }, { "Wacom Cintiq 20WSX", 10, 86680, 54180, 1023, 63, WACOM_BEE }, { "Wacom Cintiq 12WX", 10, 53020, 33440, 1023, 63, WACOM_BEE }, @@ -825,6 +912,10 @@ static struct usb_device_id wacom_ids[] = { { USB_DEVICE(USB_VENDOR_ID_WACOM, 0xB4) }, { USB_DEVICE(USB_VENDOR_ID_WACOM, 0xB5) }, { USB_DEVICE(USB_VENDOR_ID_WACOM, 0xB7) }, + { USB_DEVICE(USB_VENDOR_ID_WACOM, 0xB8) }, + { USB_DEVICE(USB_VENDOR_ID_WACOM, 0xB9) }, + { USB_DEVICE(USB_VENDOR_ID_WACOM, 0xBA) }, + { USB_DEVICE(USB_VENDOR_ID_WACOM, 0xBB) }, { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x3F) }, { USB_DEVICE(USB_VENDOR_ID_WACOM, 0xC5) }, { USB_DEVICE(USB_VENDOR_ID_WACOM, 0xC6) }, diff --git a/drivers/input/tablet/wacom_wac.h b/drivers/input/tablet/wacom_wac.h index f9c8b69673b7..c10235aba7e5 100644 --- a/drivers/input/tablet/wacom_wac.h +++ b/drivers/input/tablet/wacom_wac.h @@ -25,6 +25,9 @@ enum { INTUOS3S, INTUOS3, INTUOS3L, + INTUOS4S, + INTUOS4, + INTUOS4L, CINTIQ, WACOM_BEE, WACOM_MO, diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig index b01fd61dadcc..72e2712c7e2a 100644 --- a/drivers/input/touchscreen/Kconfig +++ b/drivers/input/touchscreen/Kconfig @@ -111,6 +111,15 @@ config TOUCHSCREEN_DA9034 Say Y here to enable the support for the touchscreen found on Dialog Semiconductor DA9034 PMIC. +config TOUCHSCREEN_EETI + tristate "EETI touchscreen panel support" + depends on I2C + help + Say Y here to enable support for I2C connected EETI touch panels. + + To compile this driver as a module, choose M here: the + module will be called eeti_ts. + config TOUCHSCREEN_FUJITSU tristate "Fujitsu serial touchscreen" select SERIO @@ -341,6 +350,21 @@ config TOUCHSCREEN_WM9713 Say Y here to enable support for the Wolfson Microelectronics WM9713 touchscreen controller. +config TOUCHSCREEN_WM97XX_ATMEL + tristate "WM97xx Atmel accelerated touch" + depends on TOUCHSCREEN_WM97XX && (AVR32 || ARCH_AT91) + help + Say Y here for support for streaming mode with WM97xx touchscreens + on Atmel AT91 or AVR32 systems with an AC97C module. + + Be aware that this will use channel B in the controller for + streaming data, this must not conflict with other AC97C drivers. + + If unsure, say N. + + To compile this driver as a module, choose M here: the module will + be called atmel-wm97xx. + config TOUCHSCREEN_WM97XX_MAINSTONE tristate "WM97xx Mainstone accelerated touch" depends on TOUCHSCREEN_WM97XX && ARCH_PXA @@ -466,4 +490,12 @@ config TOUCHSCREEN_TSC2007 To compile this driver as a module, choose M here: the module will be called tsc2007. +config TOUCHSCREEN_W90X900 + tristate "W90P910 touchscreen driver" + help + Say Y here if you have a W90P910 based touchscreen. + + To compile this driver as a module, choose M here: the + module will be called w90p910_ts. + endif diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile index 6700f7b9d165..3e1c5e0b952f 100644 --- a/drivers/input/touchscreen/Makefile +++ b/drivers/input/touchscreen/Makefile @@ -13,6 +13,7 @@ obj-$(CONFIG_TOUCHSCREEN_ATMEL_TSADCC) += atmel_tsadcc.o obj-$(CONFIG_TOUCHSCREEN_BITSY) += h3600_ts_input.o obj-$(CONFIG_TOUCHSCREEN_CORGI) += corgi_ts.o obj-$(CONFIG_TOUCHSCREEN_GUNZE) += gunze.o +obj-$(CONFIG_TOUCHSCREEN_EETI) += eeti_ts.o obj-$(CONFIG_TOUCHSCREEN_ELO) += elo.o obj-$(CONFIG_TOUCHSCREEN_FUJITSU) += fujitsu_ts.o obj-$(CONFIG_TOUCHSCREEN_INEXIO) += inexio.o @@ -35,5 +36,7 @@ obj-$(CONFIG_TOUCHSCREEN_DA9034) += da9034-ts.o wm97xx-ts-$(CONFIG_TOUCHSCREEN_WM9705) += wm9705.o wm97xx-ts-$(CONFIG_TOUCHSCREEN_WM9712) += wm9712.o wm97xx-ts-$(CONFIG_TOUCHSCREEN_WM9713) += wm9713.o +obj-$(CONFIG_TOUCHSCREEN_WM97XX_ATMEL) += atmel-wm97xx.o obj-$(CONFIG_TOUCHSCREEN_WM97XX_MAINSTONE) += mainstone-wm97xx.o obj-$(CONFIG_TOUCHSCREEN_WM97XX_ZYLONITE) += zylonite-wm97xx.o +obj-$(CONFIG_TOUCHSCREEN_W90X900) += w90p910_ts.o diff --git a/drivers/input/touchscreen/ads7846.c b/drivers/input/touchscreen/ads7846.c index 2b01e56568f8..ba9d38c3f412 100644 --- a/drivers/input/touchscreen/ads7846.c +++ b/drivers/input/touchscreen/ads7846.c @@ -83,6 +83,7 @@ struct ads7846_packet { struct ads7846 { struct input_dev *input; char phys[32]; + char name[32]; struct spi_device *spi; @@ -97,6 +98,8 @@ struct ads7846 { u16 x_plate_ohms; u16 pressure_max; + bool swap_xy; + struct ads7846_packet *packet; struct spi_transfer xfer[18]; @@ -599,6 +602,10 @@ static void ads7846_rx(void *ads) dev_dbg(&ts->spi->dev, "DOWN\n"); #endif } + + if (ts->swap_xy) + swap(x, y); + input_report_abs(input, ABS_X, x); input_report_abs(input, ABS_Y, y); input_report_abs(input, ABS_PRESSURE, Rt); @@ -917,6 +924,7 @@ static int __devinit ads7846_probe(struct spi_device *spi) ts->spi = spi; ts->input = input_dev; ts->vref_mv = pdata->vref_mv; + ts->swap_xy = pdata->swap_xy; hrtimer_init(&ts->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); ts->timer.function = ads7846_timer; @@ -958,8 +966,9 @@ static int __devinit ads7846_probe(struct spi_device *spi) ts->wait_for_sync = pdata->wait_for_sync ? : null_wait_for_sync; snprintf(ts->phys, sizeof(ts->phys), "%s/input0", dev_name(&spi->dev)); + snprintf(ts->name, sizeof(ts->name), "ADS%d Touchscreen", ts->model); - input_dev->name = "ADS784x Touchscreen"; + input_dev->name = ts->name; input_dev->phys = ts->phys; input_dev->dev.parent = &spi->dev; @@ -1141,9 +1150,15 @@ static int __devinit ads7846_probe(struct spi_device *spi) if (request_irq(spi->irq, ads7846_irq, IRQF_TRIGGER_FALLING, spi->dev.driver->name, ts)) { - dev_dbg(&spi->dev, "irq %d busy?\n", spi->irq); - err = -EBUSY; - goto err_free_gpio; + dev_info(&spi->dev, + "trying pin change workaround on irq %d\n", spi->irq); + err = request_irq(spi->irq, ads7846_irq, + IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING, + spi->dev.driver->name, ts); + if (err) { + dev_dbg(&spi->dev, "irq %d busy?\n", spi->irq); + goto err_free_gpio; + } } err = ads784x_hwmon_register(spi, ts); diff --git a/drivers/input/touchscreen/atmel-wm97xx.c b/drivers/input/touchscreen/atmel-wm97xx.c new file mode 100644 index 000000000000..35377f583e28 --- /dev/null +++ b/drivers/input/touchscreen/atmel-wm97xx.c @@ -0,0 +1,446 @@ +/* + * Atmel AT91 and AVR32 continuous touch screen driver for Wolfson WM97xx AC97 + * codecs. + * + * Copyright (C) 2008 - 2009 Atmel Corporation + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published by + * the Free Software Foundation. + */ +#include <linux/module.h> +#include <linux/moduleparam.h> +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/delay.h> +#include <linux/irq.h> +#include <linux/interrupt.h> +#include <linux/wm97xx.h> +#include <linux/timer.h> +#include <linux/gpio.h> +#include <linux/io.h> + +#define AC97C_ICA 0x10 +#define AC97C_CBRHR 0x30 +#define AC97C_CBSR 0x38 +#define AC97C_CBMR 0x3c +#define AC97C_IER 0x54 +#define AC97C_IDR 0x58 + +#define AC97C_RXRDY (1 << 4) +#define AC97C_OVRUN (1 << 5) + +#define AC97C_CMR_SIZE_20 (0 << 16) +#define AC97C_CMR_SIZE_18 (1 << 16) +#define AC97C_CMR_SIZE_16 (2 << 16) +#define AC97C_CMR_SIZE_10 (3 << 16) +#define AC97C_CMR_CEM_LITTLE (1 << 18) +#define AC97C_CMR_CEM_BIG (0 << 18) +#define AC97C_CMR_CENA (1 << 21) + +#define AC97C_INT_CBEVT (1 << 4) + +#define AC97C_SR_CAEVT (1 << 3) + +#define AC97C_CH_MASK(slot) \ + (0x7 << (3 * (slot - 3))) +#define AC97C_CH_ASSIGN(slot, channel) \ + (AC97C_CHANNEL_##channel << (3 * (slot - 3))) +#define AC97C_CHANNEL_NONE 0x0 +#define AC97C_CHANNEL_B 0x2 + +#define ac97c_writel(chip, reg, val) \ + __raw_writel((val), (chip)->regs + AC97C_##reg) +#define ac97c_readl(chip, reg) \ + __raw_readl((chip)->regs + AC97C_##reg) + +#ifdef CONFIG_CPU_AT32AP700X +#define ATMEL_WM97XX_AC97C_IOMEM (0xfff02800) +#define ATMEL_WM97XX_AC97C_IRQ (29) +#define ATMEL_WM97XX_GPIO_DEFAULT (32+16) /* Pin 16 on port B. */ +#else +#error Unkown CPU, this driver only supports AT32AP700X CPUs. +#endif + +struct continuous { + u16 id; /* codec id */ + u8 code; /* continuous code */ + u8 reads; /* number of coord reads per read cycle */ + u32 speed; /* number of coords per second */ +}; + +#define WM_READS(sp) ((sp / HZ) + 1) + +static const struct continuous cinfo[] = { + {WM9705_ID2, 0, WM_READS(94), 94}, + {WM9705_ID2, 1, WM_READS(188), 188}, + {WM9705_ID2, 2, WM_READS(375), 375}, + {WM9705_ID2, 3, WM_READS(750), 750}, + {WM9712_ID2, 0, WM_READS(94), 94}, + {WM9712_ID2, 1, WM_READS(188), 188}, + {WM9712_ID2, 2, WM_READS(375), 375}, + {WM9712_ID2, 3, WM_READS(750), 750}, + {WM9713_ID2, 0, WM_READS(94), 94}, + {WM9713_ID2, 1, WM_READS(120), 120}, + {WM9713_ID2, 2, WM_READS(154), 154}, + {WM9713_ID2, 3, WM_READS(188), 188}, +}; + +/* Continuous speed index. */ +static int sp_idx; + +/* + * Pen sampling frequency (Hz) in continuous mode. + */ +static int cont_rate = 188; +module_param(cont_rate, int, 0); +MODULE_PARM_DESC(cont_rate, "Sampling rate in continuous mode (Hz)"); + +/* + * Pen down detection. + * + * This driver can either poll or use an interrupt to indicate a pen down + * event. If the irq request fails then it will fall back to polling mode. + */ +static int pen_int = 1; +module_param(pen_int, int, 0); +MODULE_PARM_DESC(pen_int, "Pen down detection (1 = interrupt, 0 = polling)"); + +/* + * Pressure readback. + * + * Set to 1 to read back pen down pressure. + */ +static int pressure; +module_param(pressure, int, 0); +MODULE_PARM_DESC(pressure, "Pressure readback (1 = pressure, 0 = no pressure)"); + +/* + * AC97 touch data slot. + * + * Touch screen readback data ac97 slot. + */ +static int ac97_touch_slot = 5; +module_param(ac97_touch_slot, int, 0); +MODULE_PARM_DESC(ac97_touch_slot, "Touch screen data slot AC97 number"); + +/* + * GPIO line number. + * + * Set to GPIO number where the signal from the WM97xx device is hooked up. + */ +static int atmel_gpio_line = ATMEL_WM97XX_GPIO_DEFAULT; +module_param(atmel_gpio_line, int, 0); +MODULE_PARM_DESC(atmel_gpio_line, "GPIO line number connected to WM97xx"); + +struct atmel_wm97xx { + struct wm97xx *wm; + struct timer_list pen_timer; + void __iomem *regs; + unsigned long ac97c_irq; + unsigned long gpio_pen; + unsigned long gpio_irq; + unsigned short x; + unsigned short y; +}; + +static irqreturn_t atmel_wm97xx_channel_b_interrupt(int irq, void *dev_id) +{ + struct atmel_wm97xx *atmel_wm97xx = dev_id; + struct wm97xx *wm = atmel_wm97xx->wm; + int status = ac97c_readl(atmel_wm97xx, CBSR); + irqreturn_t retval = IRQ_NONE; + + if (status & AC97C_OVRUN) { + dev_dbg(&wm->touch_dev->dev, "AC97C overrun\n"); + ac97c_readl(atmel_wm97xx, CBRHR); + retval = IRQ_HANDLED; + } else if (status & AC97C_RXRDY) { + u16 data; + u16 value; + u16 source; + u16 pen_down; + + data = ac97c_readl(atmel_wm97xx, CBRHR); + value = data & 0x0fff; + source = data & WM97XX_ADCSRC_MASK; + pen_down = (data & WM97XX_PEN_DOWN) >> 8; + + if (source == WM97XX_ADCSEL_X) + atmel_wm97xx->x = value; + if (source == WM97XX_ADCSEL_Y) + atmel_wm97xx->y = value; + + if (!pressure && source == WM97XX_ADCSEL_Y) { + input_report_abs(wm->input_dev, ABS_X, atmel_wm97xx->x); + input_report_abs(wm->input_dev, ABS_Y, atmel_wm97xx->y); + input_report_key(wm->input_dev, BTN_TOUCH, pen_down); + input_sync(wm->input_dev); + } else if (pressure && source == WM97XX_ADCSEL_PRES) { + input_report_abs(wm->input_dev, ABS_X, atmel_wm97xx->x); + input_report_abs(wm->input_dev, ABS_Y, atmel_wm97xx->y); + input_report_abs(wm->input_dev, ABS_PRESSURE, value); + input_report_key(wm->input_dev, BTN_TOUCH, value); + input_sync(wm->input_dev); + } + + retval = IRQ_HANDLED; + } + + return retval; +} + +static void atmel_wm97xx_acc_pen_up(struct wm97xx *wm) +{ + struct atmel_wm97xx *atmel_wm97xx = platform_get_drvdata(wm->touch_dev); + struct input_dev *input_dev = wm->input_dev; + int pen_down = gpio_get_value(atmel_wm97xx->gpio_pen); + + if (pen_down != 0) { + mod_timer(&atmel_wm97xx->pen_timer, + jiffies + msecs_to_jiffies(1)); + } else { + if (pressure) + input_report_abs(input_dev, ABS_PRESSURE, 0); + input_report_key(input_dev, BTN_TOUCH, 0); + input_sync(input_dev); + } +} + +static void atmel_wm97xx_pen_timer(unsigned long data) +{ + atmel_wm97xx_acc_pen_up((struct wm97xx *)data); +} + +static int atmel_wm97xx_acc_startup(struct wm97xx *wm) +{ + struct atmel_wm97xx *atmel_wm97xx = platform_get_drvdata(wm->touch_dev); + int idx = 0; + + if (wm->ac97 == NULL) + return -ENODEV; + + for (idx = 0; idx < ARRAY_SIZE(cinfo); idx++) { + if (wm->id != cinfo[idx].id) + continue; + + sp_idx = idx; + + if (cont_rate <= cinfo[idx].speed) + break; + } + + wm->acc_rate = cinfo[sp_idx].code; + wm->acc_slot = ac97_touch_slot; + dev_info(&wm->touch_dev->dev, "atmel accelerated touchscreen driver, " + "%d samples/sec\n", cinfo[sp_idx].speed); + + if (pen_int) { + unsigned long reg; + + wm->pen_irq = atmel_wm97xx->gpio_irq; + + switch (wm->id) { + case WM9712_ID2: /* Fall through. */ + case WM9713_ID2: + /* + * Use GPIO 13 (PEN_DOWN) to assert GPIO line 3 + * (PENDOWN). + */ + wm97xx_config_gpio(wm, WM97XX_GPIO_13, WM97XX_GPIO_IN, + WM97XX_GPIO_POL_HIGH, + WM97XX_GPIO_STICKY, + WM97XX_GPIO_WAKE); + wm97xx_config_gpio(wm, WM97XX_GPIO_3, WM97XX_GPIO_OUT, + WM97XX_GPIO_POL_HIGH, + WM97XX_GPIO_NOTSTICKY, + WM97XX_GPIO_NOWAKE); + case WM9705_ID2: /* Fall through. */ + /* + * Enable touch data slot in AC97 controller channel B. + */ + reg = ac97c_readl(atmel_wm97xx, ICA); + reg &= ~AC97C_CH_MASK(wm->acc_slot); + reg |= AC97C_CH_ASSIGN(wm->acc_slot, B); + ac97c_writel(atmel_wm97xx, ICA, reg); + + /* + * Enable channel and interrupt for RXRDY and OVERRUN. + */ + ac97c_writel(atmel_wm97xx, CBMR, AC97C_CMR_CENA + | AC97C_CMR_CEM_BIG + | AC97C_CMR_SIZE_16 + | AC97C_OVRUN + | AC97C_RXRDY); + /* Dummy read to empty RXRHR. */ + ac97c_readl(atmel_wm97xx, CBRHR); + /* + * Enable interrupt for channel B in the AC97 + * controller. + */ + ac97c_writel(atmel_wm97xx, IER, AC97C_INT_CBEVT); + break; + default: + dev_err(&wm->touch_dev->dev, "pen down irq not " + "supported on this device\n"); + pen_int = 0; + break; + } + } + + return 0; +} + +static void atmel_wm97xx_acc_shutdown(struct wm97xx *wm) +{ + if (pen_int) { + struct atmel_wm97xx *atmel_wm97xx = + platform_get_drvdata(wm->touch_dev); + unsigned long ica; + + switch (wm->id & 0xffff) { + case WM9705_ID2: /* Fall through. */ + case WM9712_ID2: /* Fall through. */ + case WM9713_ID2: + /* Disable slot and turn off channel B interrupts. */ + ica = ac97c_readl(atmel_wm97xx, ICA); + ica &= ~AC97C_CH_MASK(wm->acc_slot); + ac97c_writel(atmel_wm97xx, ICA, ica); + ac97c_writel(atmel_wm97xx, IDR, AC97C_INT_CBEVT); + ac97c_writel(atmel_wm97xx, CBMR, 0); + wm->pen_irq = 0; + break; + default: + dev_err(&wm->touch_dev->dev, "unknown codec\n"); + break; + } + } +} + +static void atmel_wm97xx_irq_enable(struct wm97xx *wm, int enable) +{ + /* Intentionally left empty. */ +} + +static struct wm97xx_mach_ops atmel_mach_ops = { + .acc_enabled = 1, + .acc_pen_up = atmel_wm97xx_acc_pen_up, + .acc_startup = atmel_wm97xx_acc_startup, + .acc_shutdown = atmel_wm97xx_acc_shutdown, + .irq_enable = atmel_wm97xx_irq_enable, + .irq_gpio = WM97XX_GPIO_3, +}; + +static int __init atmel_wm97xx_probe(struct platform_device *pdev) +{ + struct wm97xx *wm = platform_get_drvdata(pdev); + struct atmel_wm97xx *atmel_wm97xx; + int ret; + + atmel_wm97xx = kzalloc(sizeof(struct atmel_wm97xx), GFP_KERNEL); + if (!atmel_wm97xx) { + dev_dbg(&pdev->dev, "out of memory\n"); + return -ENOMEM; + } + + atmel_wm97xx->wm = wm; + atmel_wm97xx->regs = (void *)ATMEL_WM97XX_AC97C_IOMEM; + atmel_wm97xx->ac97c_irq = ATMEL_WM97XX_AC97C_IRQ; + atmel_wm97xx->gpio_pen = atmel_gpio_line; + atmel_wm97xx->gpio_irq = gpio_to_irq(atmel_wm97xx->gpio_pen); + + setup_timer(&atmel_wm97xx->pen_timer, atmel_wm97xx_pen_timer, + (unsigned long)wm); + + ret = request_irq(atmel_wm97xx->ac97c_irq, + atmel_wm97xx_channel_b_interrupt, + IRQF_SHARED, "atmel-wm97xx-ch-b", atmel_wm97xx); + if (ret) { + dev_dbg(&pdev->dev, "could not request ac97c irq\n"); + goto err; + } + + platform_set_drvdata(pdev, atmel_wm97xx); + + ret = wm97xx_register_mach_ops(wm, &atmel_mach_ops); + if (ret) + goto err_irq; + + return ret; + +err_irq: + free_irq(atmel_wm97xx->ac97c_irq, atmel_wm97xx); +err: + platform_set_drvdata(pdev, NULL); + kfree(atmel_wm97xx); + return ret; +} + +static int __exit atmel_wm97xx_remove(struct platform_device *pdev) +{ + struct atmel_wm97xx *atmel_wm97xx = platform_get_drvdata(pdev); + struct wm97xx *wm = atmel_wm97xx->wm; + + ac97c_writel(atmel_wm97xx, IDR, AC97C_INT_CBEVT); + free_irq(atmel_wm97xx->ac97c_irq, atmel_wm97xx); + del_timer_sync(&atmel_wm97xx->pen_timer); + wm97xx_unregister_mach_ops(wm); + platform_set_drvdata(pdev, NULL); + kfree(atmel_wm97xx); + + return 0; +} + +#ifdef CONFIG_PM +static int atmel_wm97xx_suspend(struct platform_device *pdev, pm_message_t msg) +{ + struct atmel_wm97xx *atmel_wm97xx = platform_get_drvdata(pdev); + + ac97c_writel(atmel_wm97xx, IDR, AC97C_INT_CBEVT); + disable_irq(atmel_wm97xx->gpio_irq); + del_timer_sync(&atmel_wm97xx->pen_timer); + + return 0; +} + +static int atmel_wm97xx_resume(struct platform_device *pdev) +{ + struct atmel_wm97xx *atmel_wm97xx = platform_get_drvdata(pdev); + struct wm97xx *wm = atmel_wm97xx->wm; + + if (wm->input_dev->users) { + enable_irq(atmel_wm97xx->gpio_irq); + ac97c_writel(atmel_wm97xx, IER, AC97C_INT_CBEVT); + } + + return 0; +} +#else +#define atmel_wm97xx_suspend NULL +#define atmel_wm97xx_resume NULL +#endif + +static struct platform_driver atmel_wm97xx_driver = { + .remove = __exit_p(atmel_wm97xx_remove), + .driver = { + .name = "wm97xx-touch", + }, + .suspend = atmel_wm97xx_suspend, + .resume = atmel_wm97xx_resume, +}; + +static int __init atmel_wm97xx_init(void) +{ + return platform_driver_probe(&atmel_wm97xx_driver, atmel_wm97xx_probe); +} +module_init(atmel_wm97xx_init); + +static void __exit atmel_wm97xx_exit(void) +{ + platform_driver_unregister(&atmel_wm97xx_driver); +} +module_exit(atmel_wm97xx_exit); + +MODULE_AUTHOR("Hans-Christian Egtvedt <hans-christian.egtvedt@atmel.com>"); +MODULE_DESCRIPTION("wm97xx continuous touch driver for Atmel AT91 and AVR32"); +MODULE_LICENSE("GPL"); diff --git a/drivers/input/touchscreen/eeti_ts.c b/drivers/input/touchscreen/eeti_ts.c new file mode 100644 index 000000000000..3ab92222a525 --- /dev/null +++ b/drivers/input/touchscreen/eeti_ts.c @@ -0,0 +1,286 @@ +/* + * Touch Screen driver for EETI's I2C connected touch screen panels + * Copyright (c) 2009 Daniel Mack <daniel@caiaq.de> + * + * See EETI's software guide for the protocol specification: + * http://home.eeti.com.tw/web20/eg/guide.htm + * + * Based on migor_ts.c + * Copyright (c) 2008 Magnus Damm + * Copyright (c) 2007 Ujjwal Pande <ujjwal@kenati.com> + * + * This file 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 file 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 library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include <linux/module.h> +#include <linux/moduleparam.h> +#include <linux/kernel.h> +#include <linux/input.h> +#include <linux/interrupt.h> +#include <linux/i2c.h> +#include <linux/timer.h> +#include <linux/gpio.h> + +static int flip_x; +module_param(flip_x, bool, 0644); +MODULE_PARM_DESC(flip_x, "flip x coordinate"); + +static int flip_y; +module_param(flip_y, bool, 0644); +MODULE_PARM_DESC(flip_y, "flip y coordinate"); + +struct eeti_ts_priv { + struct i2c_client *client; + struct input_dev *input; + struct work_struct work; + struct mutex mutex; + int irq; +}; + +#define EETI_TS_BITDEPTH (11) +#define EETI_MAXVAL ((1 << (EETI_TS_BITDEPTH + 1)) - 1) + +#define REPORT_BIT_PRESSED (1 << 0) +#define REPORT_BIT_AD0 (1 << 1) +#define REPORT_BIT_AD1 (1 << 2) +#define REPORT_BIT_HAS_PRESSURE (1 << 6) +#define REPORT_RES_BITS(v) (((v) >> 1) + EETI_TS_BITDEPTH) + +static void eeti_ts_read(struct work_struct *work) +{ + char buf[6]; + unsigned int x, y, res, pressed, to = 100; + struct eeti_ts_priv *priv = + container_of(work, struct eeti_ts_priv, work); + + mutex_lock(&priv->mutex); + + while (!gpio_get_value(irq_to_gpio(priv->irq)) && --to) + i2c_master_recv(priv->client, buf, sizeof(buf)); + + if (!to) { + dev_err(&priv->client->dev, + "unable to clear IRQ - line stuck?\n"); + goto out; + } + + /* drop non-report packets */ + if (!(buf[0] & 0x80)) + goto out; + + pressed = buf[0] & REPORT_BIT_PRESSED; + res = REPORT_RES_BITS(buf[0] & (REPORT_BIT_AD0 | REPORT_BIT_AD1)); + x = buf[2] | (buf[1] << 8); + y = buf[4] | (buf[3] << 8); + + /* fix the range to 11 bits */ + x >>= res - EETI_TS_BITDEPTH; + y >>= res - EETI_TS_BITDEPTH; + + if (flip_x) + x = EETI_MAXVAL - x; + + if (flip_y) + y = EETI_MAXVAL - y; + + if (buf[0] & REPORT_BIT_HAS_PRESSURE) + input_report_abs(priv->input, ABS_PRESSURE, buf[5]); + + input_report_abs(priv->input, ABS_X, x); + input_report_abs(priv->input, ABS_Y, y); + input_report_key(priv->input, BTN_TOUCH, !!pressed); + input_sync(priv->input); + +out: + mutex_unlock(&priv->mutex); +} + +static irqreturn_t eeti_ts_isr(int irq, void *dev_id) +{ + struct eeti_ts_priv *priv = dev_id; + + /* postpone I2C transactions as we are atomic */ + schedule_work(&priv->work); + + return IRQ_HANDLED; +} + +static int eeti_ts_open(struct input_dev *dev) +{ + struct eeti_ts_priv *priv = input_get_drvdata(dev); + + enable_irq(priv->irq); + + /* Read the events once to arm the IRQ */ + eeti_ts_read(&priv->work); + + return 0; +} + +static void eeti_ts_close(struct input_dev *dev) +{ + struct eeti_ts_priv *priv = input_get_drvdata(dev); + + disable_irq(priv->irq); + cancel_work_sync(&priv->work); +} + +static int __devinit eeti_ts_probe(struct i2c_client *client, + const struct i2c_device_id *idp) +{ + struct eeti_ts_priv *priv; + struct input_dev *input; + int err = -ENOMEM; + + /* In contrast to what's described in the datasheet, there seems + * to be no way of probing the presence of that device using I2C + * commands. So we need to blindly believe it is there, and wait + * for interrupts to occur. */ + + priv = kzalloc(sizeof(*priv), GFP_KERNEL); + if (!priv) { + dev_err(&client->dev, "failed to allocate driver data\n"); + goto err0; + } + + mutex_init(&priv->mutex); + input = input_allocate_device(); + + if (!input) { + dev_err(&client->dev, "Failed to allocate input device.\n"); + goto err1; + } + + input->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS); + input->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH); + + input_set_abs_params(input, ABS_X, 0, EETI_MAXVAL, 0, 0); + input_set_abs_params(input, ABS_Y, 0, EETI_MAXVAL, 0, 0); + input_set_abs_params(input, ABS_PRESSURE, 0, 0xff, 0, 0); + + input->name = client->name; + input->id.bustype = BUS_I2C; + input->dev.parent = &client->dev; + input->open = eeti_ts_open; + input->close = eeti_ts_close; + + priv->client = client; + priv->input = input; + priv->irq = client->irq; + + INIT_WORK(&priv->work, eeti_ts_read); + i2c_set_clientdata(client, priv); + input_set_drvdata(input, priv); + + err = input_register_device(input); + if (err) + goto err1; + + err = request_irq(priv->irq, eeti_ts_isr, IRQF_TRIGGER_FALLING, + client->name, priv); + if (err) { + dev_err(&client->dev, "Unable to request touchscreen IRQ.\n"); + goto err2; + } + + /* Disable the irq for now. It will be enabled once the input device + * is opened. */ + disable_irq(priv->irq); + + device_init_wakeup(&client->dev, 0); + return 0; + +err2: + input_unregister_device(input); + input = NULL; /* so we dont try to free it below */ +err1: + input_free_device(input); + i2c_set_clientdata(client, NULL); + kfree(priv); +err0: + return err; +} + +static int __devexit eeti_ts_remove(struct i2c_client *client) +{ + struct eeti_ts_priv *priv = i2c_get_clientdata(client); + + free_irq(priv->irq, priv); + input_unregister_device(priv->input); + i2c_set_clientdata(client, NULL); + kfree(priv); + + return 0; +} + +#ifdef CONFIG_PM +static int eeti_ts_suspend(struct i2c_client *client, pm_message_t mesg) +{ + struct eeti_ts_priv *priv = i2c_get_clientdata(client); + + if (device_may_wakeup(&client->dev)) + enable_irq_wake(priv->irq); + + return 0; +} + +static int eeti_ts_resume(struct i2c_client *client) +{ + struct eeti_ts_priv *priv = i2c_get_clientdata(client); + + if (device_may_wakeup(&client->dev)) + disable_irq_wake(priv->irq); + + return 0; +} +#else +#define eeti_ts_suspend NULL +#define eeti_ts_resume NULL +#endif + +static const struct i2c_device_id eeti_ts_id[] = { + { "eeti_ts", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, eeti_ts_id); + +static struct i2c_driver eeti_ts_driver = { + .driver = { + .name = "eeti_ts", + }, + .probe = eeti_ts_probe, + .remove = __devexit_p(eeti_ts_remove), + .suspend = eeti_ts_suspend, + .resume = eeti_ts_resume, + .id_table = eeti_ts_id, +}; + +static int __init eeti_ts_init(void) +{ + return i2c_add_driver(&eeti_ts_driver); +} + +static void __exit eeti_ts_exit(void) +{ + i2c_del_driver(&eeti_ts_driver); +} + +MODULE_DESCRIPTION("EETI Touchscreen driver"); +MODULE_AUTHOR("Daniel Mack <daniel@caiaq.de>"); +MODULE_LICENSE("GPL"); + +module_init(eeti_ts_init); +module_exit(eeti_ts_exit); + diff --git a/drivers/input/touchscreen/tsc2007.c b/drivers/input/touchscreen/tsc2007.c index 948e167557f1..880f58c6a7c4 100644 --- a/drivers/input/touchscreen/tsc2007.c +++ b/drivers/input/touchscreen/tsc2007.c @@ -257,7 +257,7 @@ static int tsc2007_probe(struct i2c_client *client, struct input_dev *input_dev; int err; - if (!pdata) { + if (!pdata || !pdata->get_pendown_state) { dev_err(&client->dev, "platform data is required!\n"); return -EINVAL; } diff --git a/drivers/input/touchscreen/w90p910_ts.c b/drivers/input/touchscreen/w90p910_ts.c new file mode 100644 index 000000000000..6071f5882572 --- /dev/null +++ b/drivers/input/touchscreen/w90p910_ts.c @@ -0,0 +1,350 @@ +/* + * Copyright (c) 2008 Nuvoton technology corporation. + * + * Wan ZongShun <mcuos.com@gmail.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation;version 2 of the License. + * + */ + +#include <linux/delay.h> +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/io.h> +#include <linux/input.h> +#include <linux/interrupt.h> + +/* ADC controller bit defines */ +#define ADC_DELAY 0xf00 +#define ADC_DOWN 0x01 +#define ADC_TSC_Y (0x01 << 8) +#define ADC_TSC_X (0x00 << 8) +#define TSC_FOURWIRE (~(0x03 << 1)) +#define ADC_CLK_EN (0x01 << 28) /* ADC clock enable */ +#define ADC_READ_CON (0x01 << 12) +#define ADC_CONV (0x01 << 13) +#define ADC_SEMIAUTO (0x01 << 14) +#define ADC_WAITTRIG (0x03 << 14) +#define ADC_RST1 (0x01 << 16) +#define ADC_RST0 (0x00 << 16) +#define ADC_EN (0x01 << 17) +#define ADC_INT (0x01 << 18) +#define WT_INT (0x01 << 20) +#define ADC_INT_EN (0x01 << 21) +#define LVD_INT_EN (0x01 << 22) +#define WT_INT_EN (0x01 << 23) +#define ADC_DIV (0x04 << 1) /* div = 6 */ + +enum ts_state { + TS_WAIT_NEW_PACKET, /* We are waiting next touch report */ + TS_WAIT_X_COORD, /* We are waiting for ADC to report X coord */ + TS_WAIT_Y_COORD, /* We are waiting for ADC to report Y coord */ + TS_IDLE, /* Input device is closed, don't do anything */ +}; + +struct w90p910_ts { + struct input_dev *input; + struct timer_list timer; + int irq_num; + void __iomem *clocken; + void __iomem *ts_reg; + spinlock_t lock; + enum ts_state state; +}; + +static void w90p910_report_event(struct w90p910_ts *w90p910_ts, bool down) +{ + struct input_dev *dev = w90p910_ts->input; + + if (down) { + input_report_abs(dev, ABS_X, + __raw_readl(w90p910_ts->ts_reg + 0x0c)); + input_report_abs(dev, ABS_Y, + __raw_readl(w90p910_ts->ts_reg + 0x10)); + } + + input_report_key(dev, BTN_TOUCH, down); + input_sync(dev); +} + +static void w90p910_prepare_x_reading(struct w90p910_ts *w90p910_ts) +{ + unsigned long ctlreg; + + __raw_writel(ADC_TSC_X, w90p910_ts->ts_reg + 0x04); + ctlreg = __raw_readl(w90p910_ts->ts_reg); + ctlreg &= ~(ADC_WAITTRIG | WT_INT | WT_INT_EN); + ctlreg |= ADC_SEMIAUTO | ADC_INT_EN | ADC_CONV; + __raw_writel(ctlreg, w90p910_ts->ts_reg); + + w90p910_ts->state = TS_WAIT_X_COORD; +} + +static void w90p910_prepare_y_reading(struct w90p910_ts *w90p910_ts) +{ + unsigned long ctlreg; + + __raw_writel(ADC_TSC_Y, w90p910_ts->ts_reg + 0x04); + ctlreg = __raw_readl(w90p910_ts->ts_reg); + ctlreg &= ~(ADC_WAITTRIG | ADC_INT | WT_INT_EN); + ctlreg |= ADC_SEMIAUTO | ADC_INT_EN | ADC_CONV; + __raw_writel(ctlreg, w90p910_ts->ts_reg); + + w90p910_ts->state = TS_WAIT_Y_COORD; +} + +static void w90p910_prepare_next_packet(struct w90p910_ts *w90p910_ts) +{ + unsigned long ctlreg; + + ctlreg = __raw_readl(w90p910_ts->ts_reg); + ctlreg &= ~(ADC_INT | ADC_INT_EN | ADC_SEMIAUTO | ADC_CONV); + ctlreg |= ADC_WAITTRIG | WT_INT_EN; + __raw_writel(ctlreg, w90p910_ts->ts_reg); + + w90p910_ts->state = TS_WAIT_NEW_PACKET; +} + +static irqreturn_t w90p910_ts_interrupt(int irq, void *dev_id) +{ + struct w90p910_ts *w90p910_ts = dev_id; + unsigned long flags; + + spin_lock_irqsave(&w90p910_ts->lock, flags); + + switch (w90p910_ts->state) { + case TS_WAIT_NEW_PACKET: + /* + * The controller only generates interrupts when pen + * is down. + */ + del_timer(&w90p910_ts->timer); + w90p910_prepare_x_reading(w90p910_ts); + break; + + + case TS_WAIT_X_COORD: + w90p910_prepare_y_reading(w90p910_ts); + break; + + case TS_WAIT_Y_COORD: + w90p910_report_event(w90p910_ts, true); + w90p910_prepare_next_packet(w90p910_ts); + mod_timer(&w90p910_ts->timer, jiffies + msecs_to_jiffies(100)); + break; + + case TS_IDLE: + break; + } + + spin_unlock_irqrestore(&w90p910_ts->lock, flags); + + return IRQ_HANDLED; +} + +static void w90p910_check_pen_up(unsigned long data) +{ + struct w90p910_ts *w90p910_ts = (struct w90p910_ts *) data; + unsigned long flags; + + spin_lock_irqsave(&w90p910_ts->lock, flags); + + if (w90p910_ts->state == TS_WAIT_NEW_PACKET && + !(__raw_readl(w90p910_ts->ts_reg + 0x04) & ADC_DOWN)) { + + w90p910_report_event(w90p910_ts, false); + } + + spin_unlock_irqrestore(&w90p910_ts->lock, flags); +} + +static int w90p910_open(struct input_dev *dev) +{ + struct w90p910_ts *w90p910_ts = input_get_drvdata(dev); + unsigned long val; + + /* enable the ADC clock */ + val = __raw_readl(w90p910_ts->clocken); + __raw_writel(val | ADC_CLK_EN, w90p910_ts->clocken); + + __raw_writel(ADC_RST1, w90p910_ts->ts_reg); + msleep(1); + __raw_writel(ADC_RST0, w90p910_ts->ts_reg); + msleep(1); + + /* set delay and screen type */ + val = __raw_readl(w90p910_ts->ts_reg + 0x04); + __raw_writel(val & TSC_FOURWIRE, w90p910_ts->ts_reg + 0x04); + __raw_writel(ADC_DELAY, w90p910_ts->ts_reg + 0x08); + + w90p910_ts->state = TS_WAIT_NEW_PACKET; + wmb(); + + /* set trigger mode */ + val = __raw_readl(w90p910_ts->ts_reg); + val |= ADC_WAITTRIG | ADC_DIV | ADC_EN | WT_INT_EN; + __raw_writel(val, w90p910_ts->ts_reg); + + return 0; +} + +static void w90p910_close(struct input_dev *dev) +{ + struct w90p910_ts *w90p910_ts = input_get_drvdata(dev); + unsigned long val; + + /* disable trigger mode */ + + spin_lock_irq(&w90p910_ts->lock); + + w90p910_ts->state = TS_IDLE; + + val = __raw_readl(w90p910_ts->ts_reg); + val &= ~(ADC_WAITTRIG | ADC_DIV | ADC_EN | WT_INT_EN | ADC_INT_EN); + __raw_writel(val, w90p910_ts->ts_reg); + + spin_unlock_irq(&w90p910_ts->lock); + + /* Now that interrupts are shut off we can safely delete timer */ + del_timer_sync(&w90p910_ts->timer); + + /* stop the ADC clock */ + val = __raw_readl(w90p910_ts->clocken); + __raw_writel(val & ~ADC_CLK_EN, w90p910_ts->clocken); +} + +static int __devinit w90x900ts_probe(struct platform_device *pdev) +{ + struct w90p910_ts *w90p910_ts; + struct input_dev *input_dev; + struct resource *res; + int err; + + w90p910_ts = kzalloc(sizeof(struct w90p910_ts), GFP_KERNEL); + input_dev = input_allocate_device(); + if (!w90p910_ts || !input_dev) { + err = -ENOMEM; + goto fail1; + } + + w90p910_ts->input = input_dev; + w90p910_ts->state = TS_IDLE; + spin_lock_init(&w90p910_ts->lock); + setup_timer(&w90p910_ts->timer, w90p910_check_pen_up, + (unsigned long)&w90p910_ts); + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) { + err = -ENXIO; + goto fail1; + } + + if (!request_mem_region(res->start, res->end - res->start + 1, + pdev->name)) { + err = -EBUSY; + goto fail1; + } + + w90p910_ts->ts_reg = ioremap(res->start, res->end - res->start + 1); + if (!w90p910_ts->ts_reg) { + err = -ENOMEM; + goto fail2; + } + + res = platform_get_resource(pdev, IORESOURCE_MEM, 1); + if (!res) { + err = -ENXIO; + goto fail3; + } + + w90p910_ts->clocken = (void __iomem *)res->start; + + input_dev->name = "W90P910 TouchScreen"; + input_dev->phys = "w90p910ts/event0"; + input_dev->id.bustype = BUS_HOST; + input_dev->id.vendor = 0x0005; + input_dev->id.product = 0x0001; + input_dev->id.version = 0x0100; + input_dev->dev.parent = &pdev->dev; + input_dev->open = w90p910_open; + input_dev->close = w90p910_close; + + input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS); + input_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH); + + input_set_abs_params(input_dev, ABS_X, 0, 0x400, 0, 0); + input_set_abs_params(input_dev, ABS_Y, 0, 0x400, 0, 0); + + input_set_drvdata(input_dev, w90p910_ts); + + w90p910_ts->irq_num = platform_get_irq(pdev, 0); + if (request_irq(w90p910_ts->irq_num, w90p910_ts_interrupt, + IRQF_DISABLED, "w90p910ts", w90p910_ts)) { + err = -EBUSY; + goto fail3; + } + + err = input_register_device(w90p910_ts->input); + if (err) + goto fail4; + + platform_set_drvdata(pdev, w90p910_ts); + + return 0; + +fail4: free_irq(w90p910_ts->irq_num, w90p910_ts); +fail3: iounmap(w90p910_ts->ts_reg); +fail2: release_mem_region(res->start, res->end - res->start + 1); +fail1: input_free_device(input_dev); + kfree(w90p910_ts); + return err; +} + +static int __devexit w90x900ts_remove(struct platform_device *pdev) +{ + struct w90p910_ts *w90p910_ts = platform_get_drvdata(pdev); + struct resource *res; + + free_irq(w90p910_ts->irq_num, w90p910_ts); + del_timer_sync(&w90p910_ts->timer); + iounmap(w90p910_ts->ts_reg); + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + release_mem_region(res->start, res->end - res->start + 1); + + input_unregister_device(w90p910_ts->input); + kfree(w90p910_ts); + + platform_set_drvdata(pdev, NULL); + + return 0; +} + +static struct platform_driver w90x900ts_driver = { + .probe = w90x900ts_probe, + .remove = __devexit_p(w90x900ts_remove), + .driver = { + .name = "w90x900-ts", + .owner = THIS_MODULE, + }, +}; + +static int __init w90x900ts_init(void) +{ + return platform_driver_register(&w90x900ts_driver); +} + +static void __exit w90x900ts_exit(void) +{ + platform_driver_unregister(&w90x900ts_driver); +} + +module_init(w90x900ts_init); +module_exit(w90x900ts_exit); + +MODULE_AUTHOR("Wan ZongShun <mcuos.com@gmail.com>"); +MODULE_DESCRIPTION("w90p910 touch screen driver!"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:w90p910-ts"); diff --git a/drivers/mfd/ucb1400_core.c b/drivers/mfd/ucb1400_core.c index 178159e264ce..78c2135c5de6 100644 --- a/drivers/mfd/ucb1400_core.c +++ b/drivers/mfd/ucb1400_core.c @@ -23,6 +23,26 @@ #include <linux/module.h> #include <linux/ucb1400.h> +unsigned int ucb1400_adc_read(struct snd_ac97 *ac97, u16 adc_channel, + int adcsync) +{ + unsigned int val; + + if (adcsync) + adc_channel |= UCB_ADC_SYNC_ENA; + + ucb1400_reg_write(ac97, UCB_ADC_CR, UCB_ADC_ENA | adc_channel); + ucb1400_reg_write(ac97, UCB_ADC_CR, UCB_ADC_ENA | adc_channel | + UCB_ADC_START); + + while (!((val = ucb1400_reg_read(ac97, UCB_ADC_DATA)) + & UCB_ADC_DAT_VALID)) + schedule_timeout_uninterruptible(1); + + return val & UCB_ADC_DAT_MASK; +} +EXPORT_SYMBOL_GPL(ucb1400_adc_read); + static int ucb1400_core_probe(struct device *dev) { int err; diff --git a/fs/fat/inode.c b/fs/fat/inode.c index 304b411cb8bc..8970d8c49bb0 100644 --- a/fs/fat/inode.c +++ b/fs/fat/inode.c @@ -966,7 +966,7 @@ static int parse_options(char *options, int is_vfat, int silent, int *debug, opts->fs_uid = current_uid(); opts->fs_gid = current_gid(); - opts->fs_fmask = current_umask(); + opts->fs_fmask = opts->fs_dmask = current_umask(); opts->allow_utime = -1; opts->codepage = fat_default_codepage; opts->iocharset = fat_default_iocharset; diff --git a/include/drm/drmP.h b/include/drm/drmP.h index d4ddc22e46bb..45b67d9c39c1 100644 --- a/include/drm/drmP.h +++ b/include/drm/drmP.h @@ -34,9 +34,6 @@ #ifndef _DRM_P_H_ #define _DRM_P_H_ -/* If you want the memory alloc debug functionality, change define below */ -/* #define DEBUG_MEMORY */ - #ifdef __KERNEL__ #ifdef __alpha__ /* add include of current.h so that "current" is defined @@ -133,31 +130,6 @@ extern void drm_ut_debug_printk(unsigned int request_level, #define DRM_FLAG_DEBUG 0x01 -#define DRM_MEM_DMA 0 -#define DRM_MEM_SAREA 1 -#define DRM_MEM_DRIVER 2 -#define DRM_MEM_MAGIC 3 -#define DRM_MEM_IOCTLS 4 -#define DRM_MEM_MAPS 5 -#define DRM_MEM_VMAS 6 -#define DRM_MEM_BUFS 7 -#define DRM_MEM_SEGS 8 -#define DRM_MEM_PAGES 9 -#define DRM_MEM_FILES 10 -#define DRM_MEM_QUEUES 11 -#define DRM_MEM_CMDS 12 -#define DRM_MEM_MAPPINGS 13 -#define DRM_MEM_BUFLISTS 14 -#define DRM_MEM_AGPLISTS 15 -#define DRM_MEM_TOTALAGP 16 -#define DRM_MEM_BOUNDAGP 17 -#define DRM_MEM_CTXBITMAP 18 -#define DRM_MEM_STUB 19 -#define DRM_MEM_SGLISTS 20 -#define DRM_MEM_CTXLIST 21 -#define DRM_MEM_MM 22 -#define DRM_MEM_HASHTAB 23 - #define DRM_MAX_CTXBITMAP (PAGE_SIZE * 8) #define DRM_MAP_HASH_OFFSET 0x10000000 @@ -1517,24 +1489,6 @@ static __inline__ void drm_core_dropmap(struct drm_local_map *map) { } -#ifndef DEBUG_MEMORY -/** Wrapper around kmalloc() */ -static __inline__ void *drm_alloc(size_t size, int area) -{ - return kmalloc(size, GFP_KERNEL); -} - -/** Wrapper around kfree() */ -static __inline__ void drm_free(void *pt, size_t size, int area) -{ - kfree(pt); -} - -/** Wrapper around kcalloc() */ -static __inline__ void *drm_calloc(size_t nmemb, size_t size, int area) -{ - return kcalloc(nmemb, size, GFP_KERNEL); -} static __inline__ void *drm_calloc_large(size_t nmemb, size_t size) { @@ -1555,12 +1509,6 @@ static __inline void drm_free_large(void *ptr) vfree(ptr); } -#else -extern void *drm_alloc(size_t size, int area); -extern void drm_free(void *pt, size_t size, int area); -extern void *drm_calloc(size_t nmemb, size_t size, int area); -#endif - /*@}*/ #endif /* __KERNEL__ */ diff --git a/include/drm/drm_edid.h b/include/drm/drm_edid.h index a11cc9d32591..c263e4d71754 100644 --- a/include/drm/drm_edid.h +++ b/include/drm/drm_edid.h @@ -28,53 +28,49 @@ #define EDID_LENGTH 128 #define DDC_ADDR 0x50 -#ifdef BIG_ENDIAN -#error "EDID structure is little endian, need big endian versions" -#else - struct est_timings { u8 t1; u8 t2; u8 mfg_rsvd; } __attribute__((packed)); +/* 00=16:10, 01=4:3, 10=5:4, 11=16:9 */ +#define EDID_TIMING_ASPECT_SHIFT 0 +#define EDID_TIMING_ASPECT_MASK (0x3 << EDID_TIMING_ASPECT_SHIFT) + +/* need to add 60 */ +#define EDID_TIMING_VFREQ_SHIFT 2 +#define EDID_TIMING_VFREQ_MASK (0x3f << EDID_TIMING_VFREQ_SHIFT) + struct std_timing { u8 hsize; /* need to multiply by 8 then add 248 */ - u8 vfreq:6; /* need to add 60 */ - u8 aspect_ratio:2; /* 00=16:10, 01=4:3, 10=5:4, 11=16:9 */ + u8 vfreq_aspect; } __attribute__((packed)); +#define DRM_EDID_PT_HSYNC_POSITIVE (1 << 6) +#define DRM_EDID_PT_VSYNC_POSITIVE (1 << 5) +#define DRM_EDID_PT_SEPARATE_SYNC (3 << 3) +#define DRM_EDID_PT_STEREO (1 << 2) +#define DRM_EDID_PT_INTERLACED (1 << 1) + /* If detailed data is pixel timing */ struct detailed_pixel_timing { u8 hactive_lo; u8 hblank_lo; - u8 hblank_hi:4; - u8 hactive_hi:4; + u8 hactive_hblank_hi; u8 vactive_lo; u8 vblank_lo; - u8 vblank_hi:4; - u8 vactive_hi:4; + u8 vactive_vblank_hi; u8 hsync_offset_lo; u8 hsync_pulse_width_lo; - u8 vsync_pulse_width_lo:4; - u8 vsync_offset_lo:4; - u8 vsync_pulse_width_hi:2; - u8 vsync_offset_hi:2; - u8 hsync_pulse_width_hi:2; - u8 hsync_offset_hi:2; + u8 vsync_offset_pulse_width_lo; + u8 hsync_vsync_offset_pulse_width_hi; u8 width_mm_lo; u8 height_mm_lo; - u8 height_mm_hi:4; - u8 width_mm_hi:4; + u8 width_height_mm_hi; u8 hborder; u8 vborder; - u8 unknown0:1; - u8 hsync_positive:1; - u8 vsync_positive:1; - u8 separate_sync:2; - u8 stereo:1; - u8 unknown6:1; - u8 interlaced:1; + u8 misc; } __attribute__((packed)); /* If it's not pixel timing, it'll be one of the below */ @@ -88,18 +84,16 @@ struct detailed_data_monitor_range { u8 min_hfreq_khz; u8 max_hfreq_khz; u8 pixel_clock_mhz; /* need to multiply by 10 */ - u16 sec_gtf_toggle; /* A000=use above, 20=use below */ /* FIXME: byte order */ + __le16 sec_gtf_toggle; /* A000=use above, 20=use below */ u8 hfreq_start_khz; /* need to multiply by 2 */ u8 c; /* need to divide by 2 */ - u16 m; /* FIXME: byte order */ + __le16 m; u8 k; u8 j; /* need to divide by 2 */ } __attribute__((packed)); struct detailed_data_wpindex { - u8 white_y_lo:2; - u8 white_x_lo:2; - u8 pad:4; + u8 white_xy_lo; /* Upper 2 bits each */ u8 white_x_hi; u8 white_y_hi; u8 gamma; /* need to divide by 100 then add 1 */ @@ -134,13 +128,29 @@ struct detailed_non_pixel { #define EDID_DETAIL_MONITOR_SERIAL 0xff struct detailed_timing { - u16 pixel_clock; /* need to multiply by 10 KHz */ /* FIXME: byte order */ + __le16 pixel_clock; /* need to multiply by 10 KHz */ union { struct detailed_pixel_timing pixel_data; struct detailed_non_pixel other_data; } data; } __attribute__((packed)); +#define DRM_EDID_INPUT_SERRATION_VSYNC (1 << 7) +#define DRM_EDID_INPUT_SYNC_ON_GREEN (1 << 5) +#define DRM_EDID_INPUT_COMPOSITE_SYNC (1 << 4) +#define DRM_EDID_INPUT_SEPARATE_SYNCS (1 << 3) +#define DRM_EDID_INPUT_BLANK_TO_BLACK (1 << 2) +#define DRM_EDID_INPUT_VIDEO_LEVEL (3 << 1) +#define DRM_EDID_INPUT_DIGITAL (1 << 0) /* bits above must be zero if set */ + +#define DRM_EDID_FEATURE_DEFAULT_GTF (1 << 7) +#define DRM_EDID_FEATURE_PREFERRED_TIMING (1 << 6) +#define DRM_EDID_FEATURE_STANDARD_COLOR (1 << 5) +#define DRM_EDID_FEATURE_DISPLAY_TYPE (3 << 3) /* 00=mono, 01=rgb, 10=non-rgb, 11=unknown */ +#define DRM_EDID_FEATURE_PM_ACTIVE_OFF (1 << 2) +#define DRM_EDID_FEATURE_PM_SUSPEND (1 << 1) +#define DRM_EDID_FEATURE_PM_STANDBY (1 << 0) + struct edid { u8 header[8]; /* Vendor & product info */ @@ -153,25 +163,11 @@ struct edid { u8 version; u8 revision; /* Display info: */ - /* input definition */ - u8 serration_vsync:1; - u8 sync_on_green:1; - u8 composite_sync:1; - u8 separate_syncs:1; - u8 blank_to_black:1; - u8 video_level:2; - u8 digital:1; /* bits below must be zero if set */ + u8 input; u8 width_cm; u8 height_cm; u8 gamma; - /* feature support */ - u8 default_gtf:1; - u8 preferred_timing:1; - u8 standard_color:1; - u8 display_type:2; /* 00=mono, 01=rgb, 10=non-rgb, 11=unknown */ - u8 pm_active_off:1; - u8 pm_suspend:1; - u8 pm_standby:1; + u8 features; /* Color characteristics */ u8 red_green_lo; u8 black_white_lo; @@ -195,8 +191,6 @@ struct edid { u8 checksum; } __attribute__((packed)); -#endif /* little endian structs */ - #define EDID_PRODUCT_ID(e) ((e)->prod_code[0] | ((e)->prod_code[1] << 8)) #endif /* __DRM_EDID_H__ */ diff --git a/include/drm/drm_memory_debug.h b/include/drm/drm_memory_debug.h deleted file mode 100644 index 6463271deea8..000000000000 --- a/include/drm/drm_memory_debug.h +++ /dev/null @@ -1,309 +0,0 @@ -/** - * \file drm_memory_debug.h - * Memory management wrappers for DRM. - * - * \author Rickard E. (Rik) Faith <faith@valinux.com> - * \author Gareth Hughes <gareth@valinux.com> - */ - -/* - * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas. - * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California. - * All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the - * Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice (including the next - * paragraph) shall be included in all copies or substantial portions of the - * Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR - * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, - * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - */ - -#include "drmP.h" - -typedef struct drm_mem_stats { - const char *name; - int succeed_count; - int free_count; - int fail_count; - unsigned long bytes_allocated; - unsigned long bytes_freed; -} drm_mem_stats_t; - -static DEFINE_SPINLOCK(drm_mem_lock); -static unsigned long drm_ram_available = 0; /* In pages */ -static unsigned long drm_ram_used = 0; -static drm_mem_stats_t drm_mem_stats[] = -{ - [DRM_MEM_DMA] = {"dmabufs"}, - [DRM_MEM_SAREA] = {"sareas"}, - [DRM_MEM_DRIVER] = {"driver"}, - [DRM_MEM_MAGIC] = {"magic"}, - [DRM_MEM_IOCTLS] = {"ioctltab"}, - [DRM_MEM_MAPS] = {"maplist"}, - [DRM_MEM_VMAS] = {"vmalist"}, - [DRM_MEM_BUFS] = {"buflist"}, - [DRM_MEM_SEGS] = {"seglist"}, - [DRM_MEM_PAGES] = {"pagelist"}, - [DRM_MEM_FILES] = {"files"}, - [DRM_MEM_QUEUES] = {"queues"}, - [DRM_MEM_CMDS] = {"commands"}, - [DRM_MEM_MAPPINGS] = {"mappings"}, - [DRM_MEM_BUFLISTS] = {"buflists"}, - [DRM_MEM_AGPLISTS] = {"agplist"}, - [DRM_MEM_SGLISTS] = {"sglist"}, - [DRM_MEM_TOTALAGP] = {"totalagp"}, - [DRM_MEM_BOUNDAGP] = {"boundagp"}, - [DRM_MEM_CTXBITMAP] = {"ctxbitmap"}, - [DRM_MEM_CTXLIST] = {"ctxlist"}, - [DRM_MEM_STUB] = {"stub"}, - {NULL, 0,} /* Last entry must be null */ -}; - -void drm_mem_init (void) { - drm_mem_stats_t *mem; - struct sysinfo si; - - for (mem = drm_mem_stats; mem->name; ++mem) { - mem->succeed_count = 0; - mem->free_count = 0; - mem->fail_count = 0; - mem->bytes_allocated = 0; - mem->bytes_freed = 0; - } - - si_meminfo(&si); - drm_ram_available = si.totalram; - drm_ram_used = 0; -} - -/* drm_mem_info is called whenever a process reads /dev/drm/mem. */ - -static int drm__mem_info (char *buf, char **start, off_t offset, - int request, int *eof, void *data) { - drm_mem_stats_t *pt; - int len = 0; - - if (offset > DRM_PROC_LIMIT) { - *eof = 1; - return 0; - } - - *eof = 0; - *start = &buf[offset]; - - DRM_PROC_PRINT(" total counts " - " | outstanding \n"); - DRM_PROC_PRINT("type alloc freed fail bytes freed" - " | allocs bytes\n\n"); - DRM_PROC_PRINT("%-9.9s %5d %5d %4d %10lu kB |\n", - "system", 0, 0, 0, - drm_ram_available << (PAGE_SHIFT - 10)); - DRM_PROC_PRINT("%-9.9s %5d %5d %4d %10lu kB |\n", - "locked", 0, 0, 0, drm_ram_used >> 10); - DRM_PROC_PRINT("\n"); - for (pt = drm_mem_stats; pt->name; pt++) { - DRM_PROC_PRINT("%-9.9s %5d %5d %4d %10lu %10lu | %6d %10ld\n", - pt->name, - pt->succeed_count, - pt->free_count, - pt->fail_count, - pt->bytes_allocated, - pt->bytes_freed, - pt->succeed_count - pt->free_count, - (long)pt->bytes_allocated - - (long)pt->bytes_freed); - } - - if (len > request + offset) - return request; - *eof = 1; - return len - offset; -} - -int drm_mem_info (char *buf, char **start, off_t offset, - int len, int *eof, void *data) { - int ret; - - spin_lock(&drm_mem_lock); - ret = drm__mem_info (buf, start, offset, len, eof, data); - spin_unlock(&drm_mem_lock); - return ret; -} - -void *drm_alloc (size_t size, int area) { - void *pt; - - if (!size) { - DRM_MEM_ERROR(area, "Allocating 0 bytes\n"); - return NULL; - } - - if (!(pt = kmalloc(size, GFP_KERNEL))) { - spin_lock(&drm_mem_lock); - ++drm_mem_stats[area].fail_count; - spin_unlock(&drm_mem_lock); - return NULL; - } - spin_lock(&drm_mem_lock); - ++drm_mem_stats[area].succeed_count; - drm_mem_stats[area].bytes_allocated += size; - spin_unlock(&drm_mem_lock); - return pt; -} - -void *drm_calloc (size_t nmemb, size_t size, int area) { - void *addr; - - addr = drm_alloc (nmemb * size, area); - if (addr != NULL) - memset((void *)addr, 0, size * nmemb); - - return addr; -} - -void *drm_realloc (void *oldpt, size_t oldsize, size_t size, int area) { - void *pt; - - if (!(pt = drm_alloc (size, area))) - return NULL; - if (oldpt && oldsize) { - memcpy(pt, oldpt, oldsize); - drm_free (oldpt, oldsize, area); - } - return pt; -} - -void drm_free (void *pt, size_t size, int area) { - int alloc_count; - int free_count; - - if (!pt) - DRM_MEM_ERROR(area, "Attempt to free NULL pointer\n"); - else - kfree(pt); - spin_lock(&drm_mem_lock); - drm_mem_stats[area].bytes_freed += size; - free_count = ++drm_mem_stats[area].free_count; - alloc_count = drm_mem_stats[area].succeed_count; - spin_unlock(&drm_mem_lock); - if (free_count > alloc_count) { - DRM_MEM_ERROR(area, "Excess frees: %d frees, %d allocs\n", - free_count, alloc_count); - } -} - -#if __OS_HAS_AGP - -DRM_AGP_MEM *drm_alloc_agp (drm_device_t *dev, int pages, u32 type) { - DRM_AGP_MEM *handle; - - if (!pages) { - DRM_MEM_ERROR(DRM_MEM_TOTALAGP, "Allocating 0 pages\n"); - return NULL; - } - - if ((handle = drm_agp_allocate_memory (pages, type))) { - spin_lock(&drm_mem_lock); - ++drm_mem_stats[DRM_MEM_TOTALAGP].succeed_count; - drm_mem_stats[DRM_MEM_TOTALAGP].bytes_allocated - += pages << PAGE_SHIFT; - spin_unlock(&drm_mem_lock); - return handle; - } - spin_lock(&drm_mem_lock); - ++drm_mem_stats[DRM_MEM_TOTALAGP].fail_count; - spin_unlock(&drm_mem_lock); - return NULL; -} - -int drm_free_agp (DRM_AGP_MEM * handle, int pages) { - int alloc_count; - int free_count; - int retval = -EINVAL; - - if (!handle) { - DRM_MEM_ERROR(DRM_MEM_TOTALAGP, - "Attempt to free NULL AGP handle\n"); - return retval; - } - - if (drm_agp_free_memory (handle)) { - spin_lock(&drm_mem_lock); - free_count = ++drm_mem_stats[DRM_MEM_TOTALAGP].free_count; - alloc_count = drm_mem_stats[DRM_MEM_TOTALAGP].succeed_count; - drm_mem_stats[DRM_MEM_TOTALAGP].bytes_freed - += pages << PAGE_SHIFT; - spin_unlock(&drm_mem_lock); - if (free_count > alloc_count) { - DRM_MEM_ERROR(DRM_MEM_TOTALAGP, - "Excess frees: %d frees, %d allocs\n", - free_count, alloc_count); - } - return 0; - } - return retval; -} - -int drm_bind_agp (DRM_AGP_MEM * handle, unsigned int start) { - int retcode = -EINVAL; - - if (!handle) { - DRM_MEM_ERROR(DRM_MEM_BOUNDAGP, - "Attempt to bind NULL AGP handle\n"); - return retcode; - } - - if (!(retcode = drm_agp_bind_memory (handle, start))) { - spin_lock(&drm_mem_lock); - ++drm_mem_stats[DRM_MEM_BOUNDAGP].succeed_count; - drm_mem_stats[DRM_MEM_BOUNDAGP].bytes_allocated - += handle->page_count << PAGE_SHIFT; - spin_unlock(&drm_mem_lock); - return retcode; - } - spin_lock(&drm_mem_lock); - ++drm_mem_stats[DRM_MEM_BOUNDAGP].fail_count; - spin_unlock(&drm_mem_lock); - return retcode; -} - -int drm_unbind_agp (DRM_AGP_MEM * handle) { - int alloc_count; - int free_count; - int retcode = -EINVAL; - - if (!handle) { - DRM_MEM_ERROR(DRM_MEM_BOUNDAGP, - "Attempt to unbind NULL AGP handle\n"); - return retcode; - } - - if ((retcode = drm_agp_unbind_memory (handle))) - return retcode; - spin_lock(&drm_mem_lock); - free_count = ++drm_mem_stats[DRM_MEM_BOUNDAGP].free_count; - alloc_count = drm_mem_stats[DRM_MEM_BOUNDAGP].succeed_count; - drm_mem_stats[DRM_MEM_BOUNDAGP].bytes_freed - += handle->page_count << PAGE_SHIFT; - spin_unlock(&drm_mem_lock); - if (free_count > alloc_count) { - DRM_MEM_ERROR(DRM_MEM_BOUNDAGP, - "Excess frees: %d frees, %d allocs\n", - free_count, alloc_count); - } - return retcode; -} -#endif diff --git a/include/drm/drm_mm.h b/include/drm/drm_mm.h index 5662f4278ef3..f8332073d277 100644 --- a/include/drm/drm_mm.h +++ b/include/drm/drm_mm.h @@ -59,13 +59,22 @@ struct drm_mm { /* * Basic range manager support (drm_mm.c) */ - -extern struct drm_mm_node *drm_mm_get_block(struct drm_mm_node *parent, - unsigned long size, - unsigned alignment); -extern struct drm_mm_node *drm_mm_get_block_atomic(struct drm_mm_node *parent, +extern struct drm_mm_node *drm_mm_get_block_generic(struct drm_mm_node *node, + unsigned long size, + unsigned alignment, + int atomic); +static inline struct drm_mm_node *drm_mm_get_block(struct drm_mm_node *parent, unsigned long size, - unsigned alignment); + unsigned alignment) +{ + return drm_mm_get_block_generic(parent, size, alignment, 0); +} +static inline struct drm_mm_node *drm_mm_get_block_atomic(struct drm_mm_node *parent, + unsigned long size, + unsigned alignment) +{ + return drm_mm_get_block_generic(parent, size, alignment, 1); +} extern void drm_mm_put_block(struct drm_mm_node *cur); extern struct drm_mm_node *drm_mm_search_free(const struct drm_mm *mm, unsigned long size, diff --git a/include/linux/agp_backend.h b/include/linux/agp_backend.h index 2b8df8b420fd..76fa794fdac0 100644 --- a/include/linux/agp_backend.h +++ b/include/linux/agp_backend.h @@ -70,7 +70,7 @@ struct agp_memory { struct agp_memory *next; struct agp_memory *prev; struct agp_bridge_data *bridge; - unsigned long *memory; + struct page **pages; size_t page_count; int key; int num_scratch_pages; diff --git a/include/linux/ata.h b/include/linux/ata.h index 915da43edee1..9c75921f0c16 100644 --- a/include/linux/ata.h +++ b/include/linux/ata.h @@ -800,6 +800,20 @@ static inline int ata_id_is_ssd(const u16 *id) return id[ATA_ID_ROT_SPEED] == 0x01; } +static inline int ata_id_pio_need_iordy(const u16 *id, const u8 pio) +{ + /* CF spec. r4.1 Table 22 says no IORDY on PIO5 and PIO6. */ + if (pio > 4 && ata_id_is_cfa(id)) + return 0; + /* For PIO3 and higher it is mandatory. */ + if (pio > 2) + return 1; + /* Turn it on when possible. */ + if (ata_id_has_iordy(id)) + return 1; + return 0; +} + static inline int ata_drive_40wire(const u16 *dev_id) { if (ata_id_is_sata(dev_id)) diff --git a/include/linux/gameport.h b/include/linux/gameport.h index 0cd825f7363a..1bc08541c2b9 100644 --- a/include/linux/gameport.h +++ b/include/linux/gameport.h @@ -11,6 +11,7 @@ #ifdef __KERNEL__ #include <asm/io.h> +#include <linux/types.h> #include <linux/list.h> #include <linux/mutex.h> #include <linux/device.h> @@ -62,7 +63,7 @@ struct gameport_driver { struct device_driver driver; - unsigned int ignore; + bool ignore; }; #define to_gameport_driver(d) container_of(d, struct gameport_driver, driver) diff --git a/include/linux/i2c/lm8323.h b/include/linux/i2c/lm8323.h new file mode 100644 index 000000000000..478d668bc590 --- /dev/null +++ b/include/linux/i2c/lm8323.h @@ -0,0 +1,46 @@ +/* + * lm8323.h - Configuration for LM8323 keypad driver. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation (version 2 of the License only). + * + * 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 + */ + +#ifndef __LINUX_LM8323_H +#define __LINUX_LM8323_H + +#include <linux/types.h> + +/* + * Largest keycode that the chip can send, plus one, + * so keys can be mapped directly at the index of the + * LM8323 keycode instead of subtracting one. + */ +#define LM8323_KEYMAP_SIZE (0x7f + 1) + +#define LM8323_NUM_PWMS 3 + +struct lm8323_platform_data { + int debounce_time; /* Time to watch for key bouncing, in ms. */ + int active_time; /* Idle time until sleep, in ms. */ + + int size_x; + int size_y; + bool repeat; + const unsigned short *keymap; + + const char *pwm_names[LM8323_NUM_PWMS]; + + const char *name; /* Device name. */ +}; + +#endif /* __LINUX_LM8323_H */ diff --git a/include/linux/ide.h b/include/linux/ide.h index a6c6a2fad7c8..95c6e00a72e8 100644 --- a/include/linux/ide.h +++ b/include/linux/ide.h @@ -157,12 +157,6 @@ enum { #define REQ_UNPARK_HEADS 0x23 /* - * Check for an interrupt and acknowledge the interrupt status - */ -struct hwif_s; -typedef int (ide_ack_intr_t)(struct hwif_s *); - -/* * hwif_chipset_t is used to keep track of the specific hardware * chipset used by each IDE interface, if known. */ @@ -185,7 +179,6 @@ struct ide_hw { }; int irq; /* our irq number */ - ide_ack_intr_t *ack_intr; /* acknowledge interrupt */ struct device *dev, *parent; unsigned long config; }; @@ -331,11 +324,6 @@ enum { PC_FLAG_WRITING = (1 << 6), }; -/* - * With each packet command, we allocate a buffer of IDE_PC_BUFFER_SIZE bytes. - * This is used for several packet commands (not for READ/WRITE commands). - */ -#define IDE_PC_BUFFER_SIZE 64 #define ATAPI_WAIT_PC (60 * HZ) struct ide_atapi_pc { @@ -347,12 +335,6 @@ struct ide_atapi_pc { /* bytes to transfer */ int req_xfer; - /* bytes actually transferred */ - int xferred; - - /* data buffer */ - u8 *buf; - int buf_size; /* the corresponding request */ struct request *rq; @@ -363,8 +345,6 @@ struct ide_atapi_pc { * those are more or less driver-specific and some of them are subject * to change/removal later. */ - u8 pc_buf[IDE_PC_BUFFER_SIZE]; - unsigned long timeout; }; @@ -552,7 +532,7 @@ struct ide_drive_s { unsigned int bios_cyl; /* BIOS/fdisk/LILO number of cyls */ unsigned int cyl; /* "real" number of cyls */ - unsigned int drive_data; /* used by set_pio_mode/dev_select() */ + void *drive_data; /* used by set_pio_mode/dev_select() */ unsigned int failures; /* current failure count */ unsigned int max_failures; /* maximum allowed failure count */ u64 probed_capacity;/* initial/native media capacity */ @@ -649,6 +629,7 @@ struct ide_port_ops { void (*maskproc)(ide_drive_t *, int); void (*quirkproc)(ide_drive_t *); void (*clear_irq)(ide_drive_t *); + int (*test_irq)(struct hwif_s *); u8 (*mdma_filter)(ide_drive_t *); u8 (*udma_filter)(ide_drive_t *); @@ -674,6 +655,10 @@ struct ide_dma_ops { u8 (*dma_sff_read_status)(struct hwif_s *); }; +enum { + IDE_PFLAG_PROBING = (1 << 0), +}; + struct ide_host; typedef struct hwif_s { @@ -690,6 +675,8 @@ typedef struct hwif_s { ide_drive_t *devices[MAX_DRIVES + 1]; + unsigned long port_flags; + u8 major; /* our major number */ u8 index; /* 0 for ide0; 1 for ide1; ... */ u8 channel; /* for dual-port chips: 0=primary, 1=secondary */ @@ -708,8 +695,6 @@ typedef struct hwif_s { struct device *dev; - ide_ack_intr_t *ack_intr; - void (*rw_disk)(ide_drive_t *, struct request *); const struct ide_tp_ops *tp_ops; @@ -1130,6 +1115,8 @@ void SELECT_MASK(ide_drive_t *, int); u8 ide_read_error(ide_drive_t *); void ide_read_bcount_and_ireason(ide_drive_t *, u16 *, u8 *); +int ide_check_ireason(ide_drive_t *, struct request *, int, int, int); + int ide_check_atapi_device(ide_drive_t *, const char *); void ide_init_pc(struct ide_atapi_pc *); @@ -1154,7 +1141,8 @@ enum { REQ_IDETAPE_WRITE = (1 << 3), }; -int ide_queue_pc_tail(ide_drive_t *, struct gendisk *, struct ide_atapi_pc *); +int ide_queue_pc_tail(ide_drive_t *, struct gendisk *, struct ide_atapi_pc *, + void *, unsigned int); int ide_do_test_unit_ready(ide_drive_t *, struct gendisk *); int ide_do_start_stop(ide_drive_t *, struct gendisk *, int); @@ -1524,6 +1512,7 @@ int ide_timing_compute(ide_drive_t *, u8, struct ide_timing *, int, int); int ide_scan_pio_blacklist(char *); const char *ide_xfer_verbose(u8); u8 ide_get_best_pio_mode(ide_drive_t *, u8, u8); +int ide_pio_need_iordy(ide_drive_t *, const u8); int ide_set_pio_mode(ide_drive_t *, u8); int ide_set_dma_mode(ide_drive_t *, u8); void ide_set_pio(ide_drive_t *, u8); @@ -1561,6 +1550,16 @@ static inline ide_drive_t *ide_get_pair_dev(ide_drive_t *drive) return (peer->dev_flags & IDE_DFLAG_PRESENT) ? peer : NULL; } +static inline void *ide_get_drivedata(ide_drive_t *drive) +{ + return drive->drive_data; +} + +static inline void ide_set_drivedata(ide_drive_t *drive, void *data) +{ + drive->drive_data = data; +} + #define ide_port_for_each_dev(i, dev, port) \ for ((i) = 0; ((dev) = (port)->devices[i]) || (i) < MAX_DRIVES; (i)++) diff --git a/include/linux/input.h b/include/linux/input.h index 6fed4f6a9c9e..8b3bc3e0d146 100644 --- a/include/linux/input.h +++ b/include/linux/input.h @@ -53,6 +53,7 @@ struct input_absinfo { __s32 maximum; __s32 fuzz; __s32 flat; + __s32 resolution; }; #define EVIOCGVERSION _IOR('E', 0x01, int) /* get driver version */ @@ -1109,6 +1110,7 @@ struct input_dev { int absmin[ABS_MAX + 1]; int absfuzz[ABS_MAX + 1]; int absflat[ABS_MAX + 1]; + int absres[ABS_MAX + 1]; int (*open)(struct input_dev *dev); void (*close)(struct input_dev *dev); diff --git a/include/linux/rotary_encoder.h b/include/linux/rotary_encoder.h index 12d63a30c347..215278b8df2a 100644 --- a/include/linux/rotary_encoder.h +++ b/include/linux/rotary_encoder.h @@ -8,6 +8,8 @@ struct rotary_encoder_platform_data { unsigned int gpio_b; unsigned int inverted_a; unsigned int inverted_b; + bool relative_axis; + bool rollover; }; #endif /* __ROTARY_ENCODER_H__ */ diff --git a/include/linux/serio.h b/include/linux/serio.h index e0417e4d3f15..126d24c9eaa8 100644 --- a/include/linux/serio.h +++ b/include/linux/serio.h @@ -15,6 +15,7 @@ #ifdef __KERNEL__ +#include <linux/types.h> #include <linux/interrupt.h> #include <linux/list.h> #include <linux/spinlock.h> @@ -28,7 +29,10 @@ struct serio { char name[32]; char phys[32]; - unsigned int manual_bind; + bool manual_bind; + bool registered; /* port has been fully registered with driver core */ + bool suspended; /* port is suspended */ + struct serio_device_id id; @@ -47,7 +51,6 @@ struct serio { struct mutex drv_mutex; /* protects serio->drv so attributes can pin driver */ struct device dev; - unsigned int registered; /* port has been fully registered with driver core */ struct list_head node; }; @@ -58,7 +61,7 @@ struct serio_driver { char *description; struct serio_device_id *id_table; - unsigned int manual_bind; + bool manual_bind; void (*write_wakeup)(struct serio *); irqreturn_t (*interrupt)(struct serio *, unsigned char, unsigned int); diff --git a/include/linux/spi/ads7846.h b/include/linux/spi/ads7846.h index 2ea20320c093..51948eb6927a 100644 --- a/include/linux/spi/ads7846.h +++ b/include/linux/spi/ads7846.h @@ -17,6 +17,7 @@ struct ads7846_platform_data { u16 vref_mv; /* external vref value, milliVolts */ bool keep_vref_on; /* set to keep vref on for differential * measurements as well */ + bool swap_xy; /* swap x and y axes */ /* Settling time of the analog signals; a function of Vcc and the * capacitance on the X/Y drivers. If set to non-zero, two samples diff --git a/include/linux/ucb1400.h b/include/linux/ucb1400.h index 970473bf8d5a..ed889f4168f3 100644 --- a/include/linux/ucb1400.h +++ b/include/linux/ucb1400.h @@ -134,28 +134,13 @@ static inline void ucb1400_adc_enable(struct snd_ac97 *ac97) ucb1400_reg_write(ac97, UCB_ADC_CR, UCB_ADC_ENA); } -static unsigned int ucb1400_adc_read(struct snd_ac97 *ac97, u16 adc_channel, - int adcsync) -{ - unsigned int val; - - if (adcsync) - adc_channel |= UCB_ADC_SYNC_ENA; - - ucb1400_reg_write(ac97, UCB_ADC_CR, UCB_ADC_ENA | adc_channel); - ucb1400_reg_write(ac97, UCB_ADC_CR, UCB_ADC_ENA | adc_channel | - UCB_ADC_START); - - while (!((val = ucb1400_reg_read(ac97, UCB_ADC_DATA)) - & UCB_ADC_DAT_VALID)) - schedule_timeout_uninterruptible(1); - - return val & UCB_ADC_DAT_MASK; -} - static inline void ucb1400_adc_disable(struct snd_ac97 *ac97) { ucb1400_reg_write(ac97, UCB_ADC_CR, 0); } + +unsigned int ucb1400_adc_read(struct snd_ac97 *ac97, u16 adc_channel, + int adcsync); + #endif |