diff options
Diffstat (limited to 'drivers/char')
-rw-r--r-- | drivers/char/Kconfig | 2 | ||||
-rw-r--r-- | drivers/char/agp/agp.h | 6 | ||||
-rw-r--r-- | drivers/char/agp/intel-agp.c | 579 | ||||
-rw-r--r-- | drivers/char/cyclades.c | 1 | ||||
-rw-r--r-- | drivers/char/drm/Kconfig | 2 | ||||
-rw-r--r-- | drivers/char/drm/drm_drawable.c | 41 | ||||
-rw-r--r-- | drivers/char/drm/drm_pciids.h | 7 | ||||
-rw-r--r-- | drivers/char/drm/i915_irq.c | 2 | ||||
-rw-r--r-- | drivers/char/n_tty.c | 1 | ||||
-rw-r--r-- | drivers/char/random.c | 67 | ||||
-rw-r--r-- | drivers/char/stallion.c | 81 | ||||
-rw-r--r-- | drivers/char/tty_io.c | 3 | ||||
-rw-r--r-- | drivers/char/watchdog/Kconfig | 7 | ||||
-rw-r--r-- | drivers/char/watchdog/Makefile | 1 | ||||
-rw-r--r-- | drivers/char/watchdog/ixp2000_wdt.c | 2 | ||||
-rw-r--r-- | drivers/char/watchdog/ks8695_wdt.c | 308 |
16 files changed, 714 insertions, 396 deletions
diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig index abcafac64738..ef683ebd367c 100644 --- a/drivers/char/Kconfig +++ b/drivers/char/Kconfig @@ -815,7 +815,7 @@ config SGI_IP27_RTC config GEN_RTC tristate "Generic /dev/rtc emulation" - depends on RTC!=y && !IA64 && !ARM && !M32R && !SPARC && !FRV && !S390 + depends on RTC!=y && !IA64 && !ARM && !M32R && !SPARC && !FRV && !S390 && !SUPERH ---help--- If you say Y here and create a character special file /dev/rtc with major number 10 and minor number 135 using mknod ("man mknod"), you diff --git a/drivers/char/agp/agp.h b/drivers/char/agp/agp.h index fdbca25a3948..35ab1a9f8e8b 100644 --- a/drivers/char/agp/agp.h +++ b/drivers/char/agp/agp.h @@ -176,7 +176,7 @@ struct agp_bridge_data { #define I830_GMCH_MEM_MASK 0x1 #define I830_GMCH_MEM_64M 0x1 #define I830_GMCH_MEM_128M 0 -#define I830_GMCH_GMS_MASK 0x70 +#define I830_GMCH_GMS_MASK 0xF0 #define I830_GMCH_GMS_DISABLED 0x00 #define I830_GMCH_GMS_LOCAL 0x10 #define I830_GMCH_GMS_STOLEN_512 0x20 @@ -231,6 +231,10 @@ struct agp_bridge_data { #define I965_PGETBL_SIZE_512KB (0 << 1) #define I965_PGETBL_SIZE_256KB (1 << 1) #define I965_PGETBL_SIZE_128KB (2 << 1) +#define G33_PGETBL_SIZE_MASK (3 << 8) +#define G33_PGETBL_SIZE_1M (1 << 8) +#define G33_PGETBL_SIZE_2M (2 << 8) + #define I810_DRAM_CTL 0x3000 #define I810_DRAM_ROW_0 0x00000001 #define I810_DRAM_ROW_0_SDRAM 0x00000001 diff --git a/drivers/char/agp/intel-agp.c b/drivers/char/agp/intel-agp.c index 9c69f2e761f5..0439ee951a11 100644 --- a/drivers/char/agp/intel-agp.c +++ b/drivers/char/agp/intel-agp.c @@ -20,6 +20,14 @@ #define PCI_DEVICE_ID_INTEL_82965G_IG 0x29A2 #define PCI_DEVICE_ID_INTEL_82965GM_HB 0x2A00 #define PCI_DEVICE_ID_INTEL_82965GM_IG 0x2A02 +#define PCI_DEVICE_ID_INTEL_82965GME_IG 0x2A12 +#define PCI_DEVICE_ID_INTEL_82945GME_IG 0x27AE +#define PCI_DEVICE_ID_INTEL_G33_HB 0x29C0 +#define PCI_DEVICE_ID_INTEL_G33_IG 0x29C2 +#define PCI_DEVICE_ID_INTEL_Q35_HB 0x29B0 +#define PCI_DEVICE_ID_INTEL_Q35_IG 0x29B2 +#define PCI_DEVICE_ID_INTEL_Q33_HB 0x29D0 +#define PCI_DEVICE_ID_INTEL_Q33_IG 0x29D2 #define IS_I965 (agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82946GZ_HB || \ agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82965G_1_HB || \ @@ -27,6 +35,9 @@ agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82965G_HB || \ agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82965GM_HB) +#define IS_G33 (agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_G33_HB || \ + agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_Q35_HB || \ + agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_Q33_HB) extern int agp_memory_reserved; @@ -53,6 +64,8 @@ extern int agp_memory_reserved; #define I915_PTEADDR 0x1C #define I915_GMCH_GMS_STOLEN_48M (0x6 << 4) #define I915_GMCH_GMS_STOLEN_64M (0x7 << 4) +#define G33_GMCH_GMS_STOLEN_128M (0x8 << 4) +#define G33_GMCH_GMS_STOLEN_256M (0x9 << 4) /* Intel 965G registers */ #define I965_MSAC 0x62 @@ -86,11 +99,18 @@ static struct gatt_mask intel_i810_masks[] = .type = INTEL_AGP_CACHED_MEMORY} }; -static struct _intel_i810_private { - struct pci_dev *i810_dev; /* device one */ - volatile u8 __iomem *registers; +static struct _intel_private { + struct pci_dev *pcidev; /* device one */ + u8 __iomem *registers; + u32 __iomem *gtt; /* I915G */ int num_dcache_entries; -} intel_i810_private; + /* gtt_entries is the number of gtt entries that are already mapped + * to stolen memory. Stolen memory is larger than the memory mapped + * through gtt_entries, as it includes some reserved space for the BIOS + * popup and for the GTT. + */ + int gtt_entries; /* i830+ */ +} intel_private; static int intel_i810_fetch_size(void) { @@ -127,32 +147,32 @@ static int intel_i810_configure(void) current_size = A_SIZE_FIX(agp_bridge->current_size); - if (!intel_i810_private.registers) { - pci_read_config_dword(intel_i810_private.i810_dev, I810_MMADDR, &temp); + if (!intel_private.registers) { + pci_read_config_dword(intel_private.pcidev, I810_MMADDR, &temp); temp &= 0xfff80000; - intel_i810_private.registers = ioremap(temp, 128 * 4096); - if (!intel_i810_private.registers) { + intel_private.registers = ioremap(temp, 128 * 4096); + if (!intel_private.registers) { printk(KERN_ERR PFX "Unable to remap memory.\n"); return -ENOMEM; } } - if ((readl(intel_i810_private.registers+I810_DRAM_CTL) + if ((readl(intel_private.registers+I810_DRAM_CTL) & I810_DRAM_ROW_0) == I810_DRAM_ROW_0_SDRAM) { /* This will need to be dynamically assigned */ printk(KERN_INFO PFX "detected 4MB dedicated video ram.\n"); - intel_i810_private.num_dcache_entries = 1024; + intel_private.num_dcache_entries = 1024; } - pci_read_config_dword(intel_i810_private.i810_dev, I810_GMADDR, &temp); + pci_read_config_dword(intel_private.pcidev, I810_GMADDR, &temp); agp_bridge->gart_bus_addr = (temp & PCI_BASE_ADDRESS_MEM_MASK); - writel(agp_bridge->gatt_bus_addr | I810_PGETBL_ENABLED, intel_i810_private.registers+I810_PGETBL_CTL); - readl(intel_i810_private.registers+I810_PGETBL_CTL); /* PCI Posting. */ + writel(agp_bridge->gatt_bus_addr | I810_PGETBL_ENABLED, intel_private.registers+I810_PGETBL_CTL); + readl(intel_private.registers+I810_PGETBL_CTL); /* PCI Posting. */ if (agp_bridge->driver->needs_scratch_page) { for (i = 0; i < current_size->num_entries; i++) { - writel(agp_bridge->scratch_page, intel_i810_private.registers+I810_PTE_BASE+(i*4)); - readl(intel_i810_private.registers+I810_PTE_BASE+(i*4)); /* PCI posting. */ + writel(agp_bridge->scratch_page, intel_private.registers+I810_PTE_BASE+(i*4)); + readl(intel_private.registers+I810_PTE_BASE+(i*4)); /* PCI posting. */ } } global_cache_flush(); @@ -161,9 +181,9 @@ static int intel_i810_configure(void) static void intel_i810_cleanup(void) { - writel(0, intel_i810_private.registers+I810_PGETBL_CTL); - readl(intel_i810_private.registers); /* PCI Posting. */ - iounmap(intel_i810_private.registers); + writel(0, intel_private.registers+I810_PGETBL_CTL); + readl(intel_private.registers); /* PCI Posting. */ + iounmap(intel_private.registers); } static void intel_i810_tlbflush(struct agp_memory *mem) @@ -261,9 +281,9 @@ static int intel_i810_insert_entries(struct agp_memory *mem, off_t pg_start, global_cache_flush(); for (i = pg_start; i < (pg_start + mem->page_count); i++) { writel((i*4096)|I810_PTE_LOCAL|I810_PTE_VALID, - intel_i810_private.registers+I810_PTE_BASE+(i*4)); + intel_private.registers+I810_PTE_BASE+(i*4)); } - readl(intel_i810_private.registers+I810_PTE_BASE+((i-1)*4)); + readl(intel_private.registers+I810_PTE_BASE+((i-1)*4)); break; case AGP_PHYS_MEMORY: case AGP_NORMAL_MEMORY: @@ -273,9 +293,9 @@ static int intel_i810_insert_entries(struct agp_memory *mem, off_t pg_start, writel(agp_bridge->driver->mask_memory(agp_bridge, mem->memory[i], mask_type), - intel_i810_private.registers+I810_PTE_BASE+(j*4)); + intel_private.registers+I810_PTE_BASE+(j*4)); } - readl(intel_i810_private.registers+I810_PTE_BASE+((j-1)*4)); + readl(intel_private.registers+I810_PTE_BASE+((j-1)*4)); break; default: goto out_err; @@ -298,9 +318,9 @@ static int intel_i810_remove_entries(struct agp_memory *mem, off_t pg_start, return 0; for (i = pg_start; i < (mem->page_count + pg_start); i++) { - writel(agp_bridge->scratch_page, intel_i810_private.registers+I810_PTE_BASE+(i*4)); + writel(agp_bridge->scratch_page, intel_private.registers+I810_PTE_BASE+(i*4)); } - readl(intel_i810_private.registers+I810_PTE_BASE+((i-1)*4)); + readl(intel_private.registers+I810_PTE_BASE+((i-1)*4)); agp_bridge->driver->tlb_flush(mem); return 0; @@ -354,7 +374,7 @@ static struct agp_memory *intel_i810_alloc_by_type(size_t pg_count, int type) struct agp_memory *new; if (type == AGP_DCACHE_MEMORY) { - if (pg_count != intel_i810_private.num_dcache_entries) + if (pg_count != intel_private.num_dcache_entries) return NULL; new = agp_create_memory(1); @@ -404,18 +424,6 @@ static struct aper_size_info_fixed intel_i830_sizes[] = {512, 131072, 7}, }; -static struct _intel_i830_private { - struct pci_dev *i830_dev; /* device one */ - volatile u8 __iomem *registers; - volatile u32 __iomem *gtt; /* I915G */ - /* gtt_entries is the number of gtt entries that are already mapped - * to stolen memory. Stolen memory is larger than the memory mapped - * through gtt_entries, as it includes some reserved space for the BIOS - * popup and for the GTT. - */ - int gtt_entries; -} intel_i830_private; - static void intel_i830_init_gtt_entries(void) { u16 gmch_ctrl; @@ -429,7 +437,7 @@ static void intel_i830_init_gtt_entries(void) if (IS_I965) { u32 pgetbl_ctl; - pgetbl_ctl = readl(intel_i830_private.registers+I810_PGETBL_CTL); + pgetbl_ctl = readl(intel_private.registers+I810_PGETBL_CTL); /* The 965 has a field telling us the size of the GTT, * which may be larger than what is necessary to map the @@ -451,6 +459,22 @@ static void intel_i830_init_gtt_entries(void) size = 512; } size += 4; /* add in BIOS popup space */ + } else if (IS_G33) { + /* G33's GTT size defined in gmch_ctrl */ + switch (gmch_ctrl & G33_PGETBL_SIZE_MASK) { + case G33_PGETBL_SIZE_1M: + size = 1024; + break; + case G33_PGETBL_SIZE_2M: + size = 2048; + break; + default: + printk(KERN_INFO PFX "Unknown page table size 0x%x, " + "assuming 512KB\n", + (gmch_ctrl & G33_PGETBL_SIZE_MASK)); + size = 512; + } + size += 4; } else { /* On previous hardware, the GTT size was just what was * required to map the aperture. @@ -471,7 +495,7 @@ static void intel_i830_init_gtt_entries(void) gtt_entries = MB(8) - KB(size); break; case I830_GMCH_GMS_LOCAL: - rdct = readb(intel_i830_private.registers+I830_RDRAM_CHANNEL_TYPE); + rdct = readb(intel_private.registers+I830_RDRAM_CHANNEL_TYPE); gtt_entries = (I830_RDRAM_ND(rdct) + 1) * MB(ddt[I830_RDRAM_DDT(rdct)]); local = 1; @@ -502,7 +526,8 @@ static void intel_i830_init_gtt_entries(void) if (agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82915G_HB || agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82915GM_HB || agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82945G_HB || - agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82945GM_HB || IS_I965 ) + agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82945GM_HB || + IS_I965 || IS_G33) gtt_entries = MB(48) - KB(size); else gtt_entries = 0; @@ -512,10 +537,24 @@ static void intel_i830_init_gtt_entries(void) if (agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82915G_HB || agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82915GM_HB || agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82945G_HB || - agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82945GM_HB || IS_I965) + agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82945GM_HB || + IS_I965 || IS_G33) gtt_entries = MB(64) - KB(size); else gtt_entries = 0; + break; + case G33_GMCH_GMS_STOLEN_128M: + if (IS_G33) + gtt_entries = MB(128) - KB(size); + else + gtt_entries = 0; + break; + case G33_GMCH_GMS_STOLEN_256M: + if (IS_G33) + gtt_entries = MB(256) - KB(size); + else + gtt_entries = 0; + break; default: gtt_entries = 0; break; @@ -529,7 +568,7 @@ static void intel_i830_init_gtt_entries(void) "No pre-allocated video memory detected.\n"); gtt_entries /= KB(4); - intel_i830_private.gtt_entries = gtt_entries; + intel_private.gtt_entries = gtt_entries; } /* The intel i830 automatically initializes the agp aperture during POST. @@ -547,14 +586,14 @@ static int intel_i830_create_gatt_table(struct agp_bridge_data *bridge) num_entries = size->num_entries; agp_bridge->gatt_table_real = NULL; - pci_read_config_dword(intel_i830_private.i830_dev,I810_MMADDR,&temp); + pci_read_config_dword(intel_private.pcidev,I810_MMADDR,&temp); temp &= 0xfff80000; - intel_i830_private.registers = ioremap(temp,128 * 4096); - if (!intel_i830_private.registers) + intel_private.registers = ioremap(temp,128 * 4096); + if (!intel_private.registers) return -ENOMEM; - temp = readl(intel_i830_private.registers+I810_PGETBL_CTL) & 0xfffff000; + temp = readl(intel_private.registers+I810_PGETBL_CTL) & 0xfffff000; global_cache_flush(); /* FIXME: ?? */ /* we have to call this as early as possible after the MMIO base address is known */ @@ -614,20 +653,20 @@ static int intel_i830_configure(void) current_size = A_SIZE_FIX(agp_bridge->current_size); - pci_read_config_dword(intel_i830_private.i830_dev,I810_GMADDR,&temp); + pci_read_config_dword(intel_private.pcidev,I810_GMADDR,&temp); agp_bridge->gart_bus_addr = (temp & PCI_BASE_ADDRESS_MEM_MASK); pci_read_config_word(agp_bridge->dev,I830_GMCH_CTRL,&gmch_ctrl); gmch_ctrl |= I830_GMCH_ENABLED; pci_write_config_word(agp_bridge->dev,I830_GMCH_CTRL,gmch_ctrl); - writel(agp_bridge->gatt_bus_addr|I810_PGETBL_ENABLED, intel_i830_private.registers+I810_PGETBL_CTL); - readl(intel_i830_private.registers+I810_PGETBL_CTL); /* PCI Posting. */ + writel(agp_bridge->gatt_bus_addr|I810_PGETBL_ENABLED, intel_private.registers+I810_PGETBL_CTL); + readl(intel_private.registers+I810_PGETBL_CTL); /* PCI Posting. */ if (agp_bridge->driver->needs_scratch_page) { - for (i = intel_i830_private.gtt_entries; i < current_size->num_entries; i++) { - writel(agp_bridge->scratch_page, intel_i830_private.registers+I810_PTE_BASE+(i*4)); - readl(intel_i830_private.registers+I810_PTE_BASE+(i*4)); /* PCI Posting. */ + for (i = intel_private.gtt_entries; i < current_size->num_entries; i++) { + writel(agp_bridge->scratch_page, intel_private.registers+I810_PTE_BASE+(i*4)); + readl(intel_private.registers+I810_PTE_BASE+(i*4)); /* PCI Posting. */ } } @@ -637,7 +676,7 @@ static int intel_i830_configure(void) static void intel_i830_cleanup(void) { - iounmap(intel_i830_private.registers); + iounmap(intel_private.registers); } static int intel_i830_insert_entries(struct agp_memory *mem,off_t pg_start, int type) @@ -653,9 +692,9 @@ static int intel_i830_insert_entries(struct agp_memory *mem,off_t pg_start, int temp = agp_bridge->current_size; num_entries = A_SIZE_FIX(temp)->num_entries; - if (pg_start < intel_i830_private.gtt_entries) { - printk (KERN_DEBUG PFX "pg_start == 0x%.8lx,intel_i830_private.gtt_entries == 0x%.8x\n", - pg_start,intel_i830_private.gtt_entries); + if (pg_start < intel_private.gtt_entries) { + printk (KERN_DEBUG PFX "pg_start == 0x%.8lx,intel_private.gtt_entries == 0x%.8x\n", + pg_start,intel_private.gtt_entries); printk (KERN_INFO PFX "Trying to insert into local/stolen memory\n"); goto out_err; @@ -683,9 +722,9 @@ static int intel_i830_insert_entries(struct agp_memory *mem,off_t pg_start, int 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_i830_private.registers+I810_PTE_BASE+(j*4)); + intel_private.registers+I810_PTE_BASE+(j*4)); } - readl(intel_i830_private.registers+I810_PTE_BASE+((j-1)*4)); + readl(intel_private.registers+I810_PTE_BASE+((j-1)*4)); agp_bridge->driver->tlb_flush(mem); out: @@ -703,15 +742,15 @@ static int intel_i830_remove_entries(struct agp_memory *mem,off_t pg_start, if (mem->page_count == 0) return 0; - if (pg_start < intel_i830_private.gtt_entries) { + if (pg_start < intel_private.gtt_entries) { printk (KERN_INFO PFX "Trying to disable local/stolen memory\n"); return -EINVAL; } for (i = pg_start; i < (mem->page_count + pg_start); i++) { - writel(agp_bridge->scratch_page, intel_i830_private.registers+I810_PTE_BASE+(i*4)); + writel(agp_bridge->scratch_page, intel_private.registers+I810_PTE_BASE+(i*4)); } - readl(intel_i830_private.registers+I810_PTE_BASE+((i-1)*4)); + readl(intel_private.registers+I810_PTE_BASE+((i-1)*4)); agp_bridge->driver->tlb_flush(mem); return 0; @@ -734,7 +773,7 @@ static int intel_i915_configure(void) current_size = A_SIZE_FIX(agp_bridge->current_size); - pci_read_config_dword(intel_i830_private.i830_dev, I915_GMADDR, &temp); + pci_read_config_dword(intel_private.pcidev, I915_GMADDR, &temp); agp_bridge->gart_bus_addr = (temp & PCI_BASE_ADDRESS_MEM_MASK); @@ -742,13 +781,13 @@ static int intel_i915_configure(void) gmch_ctrl |= I830_GMCH_ENABLED; pci_write_config_word(agp_bridge->dev,I830_GMCH_CTRL,gmch_ctrl); - writel(agp_bridge->gatt_bus_addr|I810_PGETBL_ENABLED, intel_i830_private.registers+I810_PGETBL_CTL); - readl(intel_i830_private.registers+I810_PGETBL_CTL); /* PCI Posting. */ + writel(agp_bridge->gatt_bus_addr|I810_PGETBL_ENABLED, intel_private.registers+I810_PGETBL_CTL); + readl(intel_private.registers+I810_PGETBL_CTL); /* PCI Posting. */ if (agp_bridge->driver->needs_scratch_page) { - for (i = intel_i830_private.gtt_entries; i < current_size->num_entries; i++) { - writel(agp_bridge->scratch_page, intel_i830_private.gtt+i); - readl(intel_i830_private.gtt+i); /* PCI Posting. */ + for (i = intel_private.gtt_entries; i < current_size->num_entries; i++) { + writel(agp_bridge->scratch_page, intel_private.gtt+i); + readl(intel_private.gtt+i); /* PCI Posting. */ } } @@ -758,8 +797,8 @@ static int intel_i915_configure(void) static void intel_i915_cleanup(void) { - iounmap(intel_i830_private.gtt); - iounmap(intel_i830_private.registers); + iounmap(intel_private.gtt); + iounmap(intel_private.registers); } static int intel_i915_insert_entries(struct agp_memory *mem,off_t pg_start, @@ -776,9 +815,9 @@ static int intel_i915_insert_entries(struct agp_memory *mem,off_t pg_start, temp = agp_bridge->current_size; num_entries = A_SIZE_FIX(temp)->num_entries; - if (pg_start < intel_i830_private.gtt_entries) { - printk (KERN_DEBUG PFX "pg_start == 0x%.8lx,intel_i830_private.gtt_entries == 0x%.8x\n", - pg_start,intel_i830_private.gtt_entries); + if (pg_start < intel_private.gtt_entries) { + printk (KERN_DEBUG PFX "pg_start == 0x%.8lx,intel_private.gtt_entries == 0x%.8x\n", + pg_start,intel_private.gtt_entries); printk (KERN_INFO PFX "Trying to insert into local/stolen memory\n"); goto out_err; @@ -805,10 +844,10 @@ 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_i830_private.gtt+j); + mem->memory[i], mask_type), intel_private.gtt+j); } - readl(intel_i830_private.gtt+j-1); + readl(intel_private.gtt+j-1); agp_bridge->driver->tlb_flush(mem); out: @@ -826,15 +865,15 @@ static int intel_i915_remove_entries(struct agp_memory *mem,off_t pg_start, if (mem->page_count == 0) return 0; - if (pg_start < intel_i830_private.gtt_entries) { + if (pg_start < intel_private.gtt_entries) { printk (KERN_INFO PFX "Trying to disable local/stolen memory\n"); return -EINVAL; } for (i = pg_start; i < (mem->page_count + pg_start); i++) { - writel(agp_bridge->scratch_page, intel_i830_private.gtt+i); + writel(agp_bridge->scratch_page, intel_private.gtt+i); } - readl(intel_i830_private.gtt+i-1); + readl(intel_private.gtt+i-1); agp_bridge->driver->tlb_flush(mem); return 0; @@ -850,7 +889,7 @@ static int intel_i9xx_fetch_size(void) int aper_size; /* size in megabytes */ int i; - aper_size = pci_resource_len(intel_i830_private.i830_dev, 2) / MB(1); + aper_size = pci_resource_len(intel_private.pcidev, 2) / MB(1); for (i = 0; i < num_sizes; i++) { if (aper_size == intel_i830_sizes[i].size) { @@ -878,20 +917,20 @@ static int intel_i915_create_gatt_table(struct agp_bridge_data *bridge) num_entries = size->num_entries; agp_bridge->gatt_table_real = NULL; - pci_read_config_dword(intel_i830_private.i830_dev, I915_MMADDR, &temp); - pci_read_config_dword(intel_i830_private.i830_dev, I915_PTEADDR,&temp2); + pci_read_config_dword(intel_private.pcidev, I915_MMADDR, &temp); + pci_read_config_dword(intel_private.pcidev, I915_PTEADDR,&temp2); - intel_i830_private.gtt = ioremap(temp2, 256 * 1024); - if (!intel_i830_private.gtt) + intel_private.gtt = ioremap(temp2, 256 * 1024); + if (!intel_private.gtt) return -ENOMEM; temp &= 0xfff80000; - intel_i830_private.registers = ioremap(temp,128 * 4096); - if (!intel_i830_private.registers) + intel_private.registers = ioremap(temp,128 * 4096); + if (!intel_private.registers) return -ENOMEM; - temp = readl(intel_i830_private.registers+I810_PGETBL_CTL) & 0xfffff000; + temp = readl(intel_private.registers+I810_PGETBL_CTL) & 0xfffff000; global_cache_flush(); /* FIXME: ? */ /* we have to call this as early as possible after the MMIO base address is known */ @@ -938,20 +977,20 @@ static int intel_i965_create_gatt_table(struct agp_bridge_data *bridge) num_entries = size->num_entries; agp_bridge->gatt_table_real = NULL; - pci_read_config_dword(intel_i830_private.i830_dev, I915_MMADDR, &temp); + pci_read_config_dword(intel_private.pcidev, I915_MMADDR, &temp); temp &= 0xfff00000; - intel_i830_private.gtt = ioremap((temp + (512 * 1024)) , 512 * 1024); + intel_private.gtt = ioremap((temp + (512 * 1024)) , 512 * 1024); - if (!intel_i830_private.gtt) + if (!intel_private.gtt) return -ENOMEM; - intel_i830_private.registers = ioremap(temp,128 * 4096); - if (!intel_i830_private.registers) + intel_private.registers = ioremap(temp,128 * 4096); + if (!intel_private.registers) return -ENOMEM; - temp = readl(intel_i830_private.registers+I810_PGETBL_CTL) & 0xfffff000; + temp = readl(intel_private.registers+I810_PGETBL_CTL) & 0xfffff000; global_cache_flush(); /* FIXME: ? */ /* we have to call this as early as possible after the MMIO base address is known */ @@ -1722,41 +1761,127 @@ static const struct agp_bridge_driver intel_7505_driver = { .agp_type_to_mask_type = agp_generic_type_to_mask_type, }; -static int find_i810(u16 device) -{ - struct pci_dev *i810_dev; - - i810_dev = pci_get_device(PCI_VENDOR_ID_INTEL, device, NULL); - if (!i810_dev) - return 0; - intel_i810_private.i810_dev = i810_dev; - return 1; -} +static const struct agp_bridge_driver intel_g33_driver = { + .owner = THIS_MODULE, + .aperture_sizes = intel_i830_sizes, + .size_type = FIXED_APER_SIZE, + .num_aperture_sizes = 4, + .needs_scratch_page = TRUE, + .configure = intel_i915_configure, + .fetch_size = intel_i9xx_fetch_size, + .cleanup = intel_i915_cleanup, + .tlb_flush = intel_i810_tlbflush, + .mask_memory = intel_i965_mask_memory, + .masks = intel_i810_masks, + .agp_enable = intel_i810_agp_enable, + .cache_flush = global_cache_flush, + .create_gatt_table = intel_i915_create_gatt_table, + .free_gatt_table = intel_i830_free_gatt_table, + .insert_memory = intel_i915_insert_entries, + .remove_memory = intel_i915_remove_entries, + .alloc_by_type = intel_i830_alloc_by_type, + .free_by_type = intel_i810_free_by_type, + .agp_alloc_page = agp_generic_alloc_page, + .agp_destroy_page = agp_generic_destroy_page, + .agp_type_to_mask_type = intel_i830_type_to_mask_type, +}; -static int find_i830(u16 device) +static int find_gmch(u16 device) { - struct pci_dev *i830_dev; + struct pci_dev *gmch_device; - i830_dev = pci_get_device(PCI_VENDOR_ID_INTEL, device, NULL); - if (i830_dev && PCI_FUNC(i830_dev->devfn) != 0) { - i830_dev = pci_get_device(PCI_VENDOR_ID_INTEL, - device, i830_dev); + gmch_device = pci_get_device(PCI_VENDOR_ID_INTEL, device, NULL); + if (gmch_device && PCI_FUNC(gmch_device->devfn) != 0) { + gmch_device = pci_get_device(PCI_VENDOR_ID_INTEL, + device, gmch_device); } - if (!i830_dev) + if (!gmch_device) return 0; - intel_i830_private.i830_dev = i830_dev; + intel_private.pcidev = gmch_device; return 1; } +/* Table to describe Intel GMCH and AGP/PCIE GART drivers. At least one of + * driver and gmch_driver must be non-null, and find_gmch will determine + * which one should be used if a gmch_chip_id is present. + */ +static const struct intel_driver_description { + unsigned int chip_id; + unsigned int gmch_chip_id; + unsigned int multi_gmch_chip; /* if we have more gfx chip type on this HB. */ + char *name; + const struct agp_bridge_driver *driver; + const struct agp_bridge_driver *gmch_driver; +} intel_agp_chipsets[] = { + { PCI_DEVICE_ID_INTEL_82443LX_0, 0, 0, "440LX", &intel_generic_driver, NULL }, + { PCI_DEVICE_ID_INTEL_82443BX_0, 0, 0, "440BX", &intel_generic_driver, NULL }, + { PCI_DEVICE_ID_INTEL_82443GX_0, 0, 0, "440GX", &intel_generic_driver, NULL }, + { PCI_DEVICE_ID_INTEL_82810_MC1, PCI_DEVICE_ID_INTEL_82810_IG1, 0, "i810", + NULL, &intel_810_driver }, + { PCI_DEVICE_ID_INTEL_82810_MC3, PCI_DEVICE_ID_INTEL_82810_IG3, 0, "i810", + NULL, &intel_810_driver }, + { PCI_DEVICE_ID_INTEL_82810E_MC, PCI_DEVICE_ID_INTEL_82810E_IG, 0, "i810", + NULL, &intel_810_driver }, + { PCI_DEVICE_ID_INTEL_82815_MC, PCI_DEVICE_ID_INTEL_82815_CGC, 0, "i815", + &intel_815_driver, &intel_810_driver }, + { PCI_DEVICE_ID_INTEL_82820_HB, 0, 0, "i820", &intel_820_driver, NULL }, + { PCI_DEVICE_ID_INTEL_82820_UP_HB, 0, 0, "i820", &intel_820_driver, NULL }, + { PCI_DEVICE_ID_INTEL_82830_HB, PCI_DEVICE_ID_INTEL_82830_CGC, 0, "830M", + &intel_830mp_driver, &intel_830_driver }, + { PCI_DEVICE_ID_INTEL_82840_HB, 0, 0, "i840", &intel_840_driver, NULL }, + { PCI_DEVICE_ID_INTEL_82845_HB, 0, 0, "845G", &intel_845_driver, NULL }, + { PCI_DEVICE_ID_INTEL_82845G_HB, PCI_DEVICE_ID_INTEL_82845G_IG, 0, "830M", + &intel_845_driver, &intel_830_driver }, + { PCI_DEVICE_ID_INTEL_82850_HB, 0, 0, "i850", &intel_850_driver, NULL }, + { PCI_DEVICE_ID_INTEL_82855PM_HB, 0, 0, "855PM", &intel_845_driver, NULL }, + { PCI_DEVICE_ID_INTEL_82855GM_HB, PCI_DEVICE_ID_INTEL_82855GM_IG, 0, "855GM", + &intel_845_driver, &intel_830_driver }, + { PCI_DEVICE_ID_INTEL_82860_HB, 0, 0, "i860", &intel_860_driver, NULL }, + { PCI_DEVICE_ID_INTEL_82865_HB, PCI_DEVICE_ID_INTEL_82865_IG, 0, "865", + &intel_845_driver, &intel_830_driver }, + { PCI_DEVICE_ID_INTEL_82875_HB, 0, 0, "i875", &intel_845_driver, NULL }, + { PCI_DEVICE_ID_INTEL_82915G_HB, PCI_DEVICE_ID_INTEL_82915G_IG, 0, "915G", + &intel_845_driver, &intel_915_driver }, + { PCI_DEVICE_ID_INTEL_82915GM_HB, PCI_DEVICE_ID_INTEL_82915GM_IG, 0, "915GM", + &intel_845_driver, &intel_915_driver }, + { PCI_DEVICE_ID_INTEL_82945G_HB, PCI_DEVICE_ID_INTEL_82945G_IG, 0, "945G", + &intel_845_driver, &intel_915_driver }, + { PCI_DEVICE_ID_INTEL_82945GM_HB, PCI_DEVICE_ID_INTEL_82945GM_IG, 1, "945GM", + &intel_845_driver, &intel_915_driver }, + { PCI_DEVICE_ID_INTEL_82945GM_HB, PCI_DEVICE_ID_INTEL_82945GME_IG, 0, "945GME", + &intel_845_driver, &intel_915_driver }, + { PCI_DEVICE_ID_INTEL_82946GZ_HB, PCI_DEVICE_ID_INTEL_82946GZ_IG, 0, "946GZ", + &intel_845_driver, &intel_i965_driver }, + { PCI_DEVICE_ID_INTEL_82965G_1_HB, PCI_DEVICE_ID_INTEL_82965G_1_IG, 0, "965G", + &intel_845_driver, &intel_i965_driver }, + { PCI_DEVICE_ID_INTEL_82965Q_HB, PCI_DEVICE_ID_INTEL_82965Q_IG, 0, "965Q", + &intel_845_driver, &intel_i965_driver }, + { PCI_DEVICE_ID_INTEL_82965G_HB, PCI_DEVICE_ID_INTEL_82965G_IG, 0, "965G", + &intel_845_driver, &intel_i965_driver }, + { PCI_DEVICE_ID_INTEL_82965GM_HB, PCI_DEVICE_ID_INTEL_82965GM_IG, 1, "965GM", + &intel_845_driver, &intel_i965_driver }, + { PCI_DEVICE_ID_INTEL_82965GM_HB, PCI_DEVICE_ID_INTEL_82965GME_IG, 0, "965GME/GLE", + &intel_845_driver, &intel_i965_driver }, + { PCI_DEVICE_ID_INTEL_7505_0, 0, 0, "E7505", &intel_7505_driver, NULL }, + { PCI_DEVICE_ID_INTEL_7205_0, 0, 0, "E7205", &intel_7505_driver, NULL }, + { PCI_DEVICE_ID_INTEL_G33_HB, PCI_DEVICE_ID_INTEL_G33_IG, 0, "G33", + &intel_845_driver, &intel_g33_driver }, + { PCI_DEVICE_ID_INTEL_Q35_HB, PCI_DEVICE_ID_INTEL_Q35_IG, 0, "Q35", + &intel_845_driver, &intel_g33_driver }, + { PCI_DEVICE_ID_INTEL_Q33_HB, PCI_DEVICE_ID_INTEL_Q33_IG, 0, "Q33", + &intel_845_driver, &intel_g33_driver }, + { 0, 0, 0, NULL, NULL, NULL } +}; + static int __devinit agp_intel_probe(struct pci_dev *pdev, const struct pci_device_id *ent) { struct agp_bridge_data *bridge; - char *name = "(unknown)"; u8 cap_ptr = 0; struct resource *r; + int i; cap_ptr = pci_find_capability(pdev, PCI_CAP_ID_AGP); @@ -1764,195 +1889,46 @@ static int __devinit agp_intel_probe(struct pci_dev *pdev, if (!bridge) return -ENOMEM; - switch (pdev->device) { - case PCI_DEVICE_ID_INTEL_82443LX_0: - bridge->driver = &intel_generic_driver; - name = "440LX"; - break; - case PCI_DEVICE_ID_INTEL_82443BX_0: - bridge->driver = &intel_generic_driver; - name = "440BX"; - break; - case PCI_DEVICE_ID_INTEL_82443GX_0: - bridge->driver = &intel_generic_driver; - name = "440GX"; - break; - case PCI_DEVICE_ID_INTEL_82810_MC1: - name = "i810"; - if (!find_i810(PCI_DEVICE_ID_INTEL_82810_IG1)) - goto fail; - bridge->driver = &intel_810_driver; - break; - case PCI_DEVICE_ID_INTEL_82810_MC3: - name = "i810 DC100"; - if (!find_i810(PCI_DEVICE_ID_INTEL_82810_IG3)) - goto fail; - bridge->driver = &intel_810_driver; - break; - case PCI_DEVICE_ID_INTEL_82810E_MC: - name = "i810 E"; - if (!find_i810(PCI_DEVICE_ID_INTEL_82810E_IG)) - goto fail; - bridge->driver = &intel_810_driver; - break; - case PCI_DEVICE_ID_INTEL_82815_MC: - /* - * The i815 can operate either as an i810 style - * integrated device, or as an AGP4X motherboard. - */ - if (find_i810(PCI_DEVICE_ID_INTEL_82815_CGC)) - bridge->driver = &intel_810_driver; - else - bridge->driver = &intel_815_driver; - name = "i815"; - break; - case PCI_DEVICE_ID_INTEL_82820_HB: - case PCI_DEVICE_ID_INTEL_82820_UP_HB: - bridge->driver = &intel_820_driver; - name = "i820"; - break; - case PCI_DEVICE_ID_INTEL_82830_HB: - if (find_i830(PCI_DEVICE_ID_INTEL_82830_CGC)) - bridge->driver = &intel_830_driver; - else - bridge->driver = &intel_830mp_driver; - name = "830M"; - break; - case PCI_DEVICE_ID_INTEL_82840_HB: - bridge->driver = &intel_840_driver; - name = "i840"; - break; - case PCI_DEVICE_ID_INTEL_82845_HB: - bridge->driver = &intel_845_driver; - name = "i845"; - break; - case PCI_DEVICE_ID_INTEL_82845G_HB: - if (find_i830(PCI_DEVICE_ID_INTEL_82845G_IG)) - bridge->driver = &intel_830_driver; - else - bridge->driver = &intel_845_driver; - name = "845G"; - break; - case PCI_DEVICE_ID_INTEL_82850_HB: - bridge->driver = &intel_850_driver; - name = "i850"; - break; - case PCI_DEVICE_ID_INTEL_82855PM_HB: - bridge->driver = &intel_845_driver; - name = "855PM"; - break; - case PCI_DEVICE_ID_INTEL_82855GM_HB: - if (find_i830(PCI_DEVICE_ID_INTEL_82855GM_IG)) { - bridge->driver = &intel_830_driver; - name = "855"; - } else { - bridge->driver = &intel_845_driver; - name = "855GM"; + for (i = 0; intel_agp_chipsets[i].name != NULL; i++) { + /* In case that multiple models of gfx chip may + stand on same host bridge type, this can be + sure we detect the right IGD. */ + if (pdev->device == intel_agp_chipsets[i].chip_id) { + if ((intel_agp_chipsets[i].gmch_chip_id != 0) && + find_gmch(intel_agp_chipsets[i].gmch_chip_id)) { + bridge->driver = + intel_agp_chipsets[i].gmch_driver; + break; + } else if (intel_agp_chipsets[i].multi_gmch_chip) { + continue; + } else { + bridge->driver = intel_agp_chipsets[i].driver; + break; + } } - break; - case PCI_DEVICE_ID_INTEL_82860_HB: - bridge->driver = &intel_860_driver; - name = "i860"; - break; - case PCI_DEVICE_ID_INTEL_82865_HB: - if (find_i830(PCI_DEVICE_ID_INTEL_82865_IG)) - bridge->driver = &intel_830_driver; - else - bridge->driver = &intel_845_driver; - name = "865"; - break; - case PCI_DEVICE_ID_INTEL_82875_HB: - bridge->driver = &intel_845_driver; - name = "i875"; - break; - case PCI_DEVICE_ID_INTEL_82915G_HB: - if (find_i830(PCI_DEVICE_ID_INTEL_82915G_IG)) - bridge->driver = &intel_915_driver; - else - bridge->driver = &intel_845_driver; - name = "915G"; - break; - case PCI_DEVICE_ID_INTEL_82915GM_HB: - if (find_i830(PCI_DEVICE_ID_INTEL_82915GM_IG)) - bridge->driver = &intel_915_driver; - else - bridge->driver = &intel_845_driver; - name = "915GM"; - break; - case PCI_DEVICE_ID_INTEL_82945G_HB: - if (find_i830(PCI_DEVICE_ID_INTEL_82945G_IG)) - bridge->driver = &intel_915_driver; - else - bridge->driver = &intel_845_driver; - name = "945G"; - break; - case PCI_DEVICE_ID_INTEL_82945GM_HB: - if (find_i830(PCI_DEVICE_ID_INTEL_82945GM_IG)) - bridge->driver = &intel_915_driver; - else - bridge->driver = &intel_845_driver; - name = "945GM"; - break; - case PCI_DEVICE_ID_INTEL_82946GZ_HB: - if (find_i830(PCI_DEVICE_ID_INTEL_82946GZ_IG)) - bridge->driver = &intel_i965_driver; - else - bridge->driver = &intel_845_driver; - name = "946GZ"; - break; - case PCI_DEVICE_ID_INTEL_82965G_1_HB: - if (find_i830(PCI_DEVICE_ID_INTEL_82965G_1_IG)) - bridge->driver = &intel_i965_driver; - else - bridge->driver = &intel_845_driver; - name = "965G"; - break; - case PCI_DEVICE_ID_INTEL_82965Q_HB: - if (find_i830(PCI_DEVICE_ID_INTEL_82965Q_IG)) - bridge->driver = &intel_i965_driver; - else - bridge->driver = &intel_845_driver; - name = "965Q"; - break; - case PCI_DEVICE_ID_INTEL_82965G_HB: - if (find_i830(PCI_DEVICE_ID_INTEL_82965G_IG)) - bridge->driver = &intel_i965_driver; - else - bridge->driver = &intel_845_driver; - name = "965G"; - break; - case PCI_DEVICE_ID_INTEL_82965GM_HB: - if (find_i830(PCI_DEVICE_ID_INTEL_82965GM_IG)) - bridge->driver = &intel_i965_driver; - else - bridge->driver = &intel_845_driver; - name = "965GM"; - break; - case PCI_DEVICE_ID_INTEL_7505_0: - bridge->driver = &intel_7505_driver; - name = "E7505"; - break; - case PCI_DEVICE_ID_INTEL_7205_0: - bridge->driver = &intel_7505_driver; - name = "E7205"; - break; - default: + } + + if (intel_agp_chipsets[i].name == NULL) { if (cap_ptr) - printk(KERN_WARNING PFX "Unsupported Intel chipset (device id: %04x)\n", - pdev->device); + printk(KERN_WARNING PFX "Unsupported Intel chipset" + "(device id: %04x)\n", pdev->device); + agp_put_bridge(bridge); + return -ENODEV; + } + + if (bridge->driver == NULL) { + printk(KERN_WARNING PFX "Failed to find bridge device " + "(chip_id: %04x)\n", intel_agp_chipsets[i].gmch_chip_id); agp_put_bridge(bridge); return -ENODEV; - }; + } bridge->dev = pdev; bridge->capndx = cap_ptr; + bridge->dev_private_data = &intel_private; - if (bridge->driver == &intel_810_driver) - bridge->dev_private_data = &intel_i810_private; - else if (bridge->driver == &intel_830_driver) - bridge->dev_private_data = &intel_i830_private; - - printk(KERN_INFO PFX "Detected an Intel %s Chipset.\n", name); + printk(KERN_INFO PFX "Detected an Intel %s Chipset.\n", + intel_agp_chipsets[i].name); /* * The following fixes the case where the BIOS has "forgotten" to @@ -1988,12 +1964,6 @@ static int __devinit agp_intel_probe(struct pci_dev *pdev, pci_set_drvdata(pdev, bridge); return agp_add_bridge(bridge); - -fail: - printk(KERN_ERR PFX "Detected an Intel %s chipset, " - "but could not find the secondary device.\n", name); - agp_put_bridge(bridge); - return -ENODEV; } static void __devexit agp_intel_remove(struct pci_dev *pdev) @@ -2002,10 +1972,8 @@ static void __devexit agp_intel_remove(struct pci_dev *pdev) agp_remove_bridge(bridge); - if (intel_i810_private.i810_dev) - pci_dev_put(intel_i810_private.i810_dev); - if (intel_i830_private.i830_dev) - pci_dev_put(intel_i830_private.i830_dev); + if (intel_private.pcidev) + pci_dev_put(intel_private.pcidev); agp_put_bridge(bridge); } @@ -2021,10 +1989,8 @@ static int agp_intel_resume(struct pci_dev *pdev) * as host bridge (00:00) resumes before graphics device (02:00), * then our access to its pci space can work right. */ - if (intel_i810_private.i810_dev) - pci_restore_state(intel_i810_private.i810_dev); - if (intel_i830_private.i830_dev) - pci_restore_state(intel_i830_private.i830_dev); + if (intel_private.pcidev) + pci_restore_state(intel_private.pcidev); if (bridge->driver == &intel_generic_driver) intel_configure(); @@ -2087,6 +2053,9 @@ static struct pci_device_id agp_intel_pci_table[] = { ID(PCI_DEVICE_ID_INTEL_82965Q_HB), ID(PCI_DEVICE_ID_INTEL_82965G_HB), ID(PCI_DEVICE_ID_INTEL_82965GM_HB), + ID(PCI_DEVICE_ID_INTEL_G33_HB), + ID(PCI_DEVICE_ID_INTEL_Q35_HB), + ID(PCI_DEVICE_ID_INTEL_Q33_HB), { } }; diff --git a/drivers/char/cyclades.c b/drivers/char/cyclades.c index c72ee97d3892..ca376b92162c 100644 --- a/drivers/char/cyclades.c +++ b/drivers/char/cyclades.c @@ -1061,6 +1061,7 @@ static void cyy_intr_chip(struct cyclades_card *cinfo, int chip, if (data & info->ignore_status_mask) { info->icount.rx++; + spin_unlock(&cinfo->card_lock); return; } if (tty_buffer_request_room(tty, 1)) { diff --git a/drivers/char/drm/Kconfig b/drivers/char/drm/Kconfig index ef833a1c27eb..0b7ffa5191c6 100644 --- a/drivers/char/drm/Kconfig +++ b/drivers/char/drm/Kconfig @@ -6,7 +6,7 @@ # config DRM tristate "Direct Rendering Manager (XFree86 4.1.0 and higher DRI support)" - depends on (AGP || AGP=n) && PCI + depends on (AGP || AGP=n) && PCI && !EMULATED_CMPXCHG help Kernel-level support for the Direct Rendering Infrastructure (DRI) introduced in XFree86 4.0. If you say Y here, you need to select diff --git a/drivers/char/drm/drm_drawable.c b/drivers/char/drm/drm_drawable.c index de37d5f74563..b33313be2547 100644 --- a/drivers/char/drm/drm_drawable.c +++ b/drivers/char/drm/drm_drawable.c @@ -172,38 +172,49 @@ int drm_rmdraw(DRM_IOCTL_ARGS) bitfield_length = idx + 1; - if (idx != id / (8 * sizeof(*bitfield))) - bitfield = drm_alloc(bitfield_length * - sizeof(*bitfield), DRM_MEM_BUFS); + bitfield = NULL; - if (!bitfield && bitfield_length) { - bitfield = dev->drw_bitfield; - bitfield_length = dev->drw_bitfield_length; + if (bitfield_length) { + if (bitfield_length != dev->drw_bitfield_length) + bitfield = drm_alloc(bitfield_length * + sizeof(*bitfield), + DRM_MEM_BUFS); + + if (!bitfield) { + bitfield = dev->drw_bitfield; + bitfield_length = dev->drw_bitfield_length; + } } } if (bitfield != dev->drw_bitfield) { info_length = 8 * sizeof(*bitfield) * bitfield_length; - info = drm_alloc(info_length * sizeof(*info), DRM_MEM_BUFS); + if (info_length) { + info = drm_alloc(info_length * sizeof(*info), + DRM_MEM_BUFS); - if (!info && info_length) { - info = dev->drw_info; - info_length = dev->drw_info_length; - } + if (!info) { + info = dev->drw_info; + info_length = dev->drw_info_length; + } + } else + info = NULL; spin_lock_irqsave(&dev->drw_lock, irqflags); - memcpy(bitfield, dev->drw_bitfield, bitfield_length * - sizeof(*bitfield)); + if (bitfield) + memcpy(bitfield, dev->drw_bitfield, bitfield_length * + sizeof(*bitfield)); drm_free(dev->drw_bitfield, sizeof(*bitfield) * dev->drw_bitfield_length, DRM_MEM_BUFS); dev->drw_bitfield = bitfield; dev->drw_bitfield_length = bitfield_length; if (info != dev->drw_info) { - memcpy(info, dev->drw_info, info_length * - sizeof(*info)); + if (info) + memcpy(info, dev->drw_info, info_length * + sizeof(*info)); drm_free(dev->drw_info, sizeof(*info) * dev->drw_info_length, DRM_MEM_BUFS); dev->drw_info = info; diff --git a/drivers/char/drm/drm_pciids.h b/drivers/char/drm/drm_pciids.h index 31cdde83713b..177ccc07f968 100644 --- a/drivers/char/drm/drm_pciids.h +++ b/drivers/char/drm/drm_pciids.h @@ -102,13 +102,20 @@ {0x1002, 0x5653, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV410|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ {0x1002, 0x5834, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS300|RADEON_IS_IGP}, \ {0x1002, 0x5835, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS300|RADEON_IS_IGP|RADEON_IS_MOBILITY}, \ + {0x1002, 0x5954, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS400|RADEON_IS_IGP|RADEON_IS_MOBILITY|RADEON_IS_IGPGART}, \ {0x1002, 0x5955, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS400|RADEON_IS_IGP|RADEON_IS_MOBILITY|RADEON_IS_IGPGART}, \ + {0x1002, 0x5974, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS400|RADEON_IS_IGP|RADEON_IS_MOBILITY|RADEON_IS_IGPGART}, \ + {0x1002, 0x5975, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS400|RADEON_IS_IGP|RADEON_IS_MOBILITY|RADEON_IS_IGPGART}, \ {0x1002, 0x5960, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV280}, \ {0x1002, 0x5961, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV280}, \ {0x1002, 0x5962, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV280}, \ {0x1002, 0x5964, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV280}, \ {0x1002, 0x5965, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV280}, \ {0x1002, 0x5969, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV100}, \ + {0x1002, 0x5a41, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS400|RADEON_IS_IGP|RADEON_IS_MOBILITY|RADEON_IS_IGPGART}, \ + {0x1002, 0x5a42, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS400|RADEON_IS_IGP|RADEON_IS_MOBILITY|RADEON_IS_IGPGART}, \ + {0x1002, 0x5a61, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS400|RADEON_IS_IGP|RADEON_IS_MOBILITY|RADEON_IS_IGPGART}, \ + {0x1002, 0x5a62, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS400|RADEON_IS_IGP|RADEON_IS_MOBILITY|RADEON_IS_IGPGART}, \ {0x1002, 0x5b60, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|RADEON_NEW_MEMMAP}, \ {0x1002, 0x5b62, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|RADEON_NEW_MEMMAP}, \ {0x1002, 0x5b63, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|RADEON_NEW_MEMMAP}, \ diff --git a/drivers/char/drm/i915_irq.c b/drivers/char/drm/i915_irq.c index 78c1ae28f17c..b92062a239f1 100644 --- a/drivers/char/drm/i915_irq.c +++ b/drivers/char/drm/i915_irq.c @@ -582,7 +582,7 @@ void i915_driver_irq_postinstall(drm_device_t * dev) { drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private; - dev_priv->swaps_lock = SPIN_LOCK_UNLOCKED; + spin_lock_init(&dev_priv->swaps_lock); INIT_LIST_HEAD(&dev_priv->vbl_swaps.head); dev_priv->swaps_pending = 0; diff --git a/drivers/char/n_tty.c b/drivers/char/n_tty.c index b3d4ccc33a47..154f42203b05 100644 --- a/drivers/char/n_tty.c +++ b/drivers/char/n_tty.c @@ -1191,6 +1191,7 @@ static int job_control(struct tty_struct *tty, struct file *file) is_current_pgrp_orphaned()) return -EIO; kill_pgrp(task_pgrp(current), SIGTTIN, 1); + set_thread_flag(TIF_SIGPENDING); return -ERESTARTSYS; } } diff --git a/drivers/char/random.c b/drivers/char/random.c index 46c1b97748b6..0474cac4a84e 100644 --- a/drivers/char/random.c +++ b/drivers/char/random.c @@ -760,7 +760,7 @@ static size_t account(struct entropy_store *r, size_t nbytes, int min, static void extract_buf(struct entropy_store *r, __u8 *out) { - int i, x; + int i; __u32 data[16], buf[5 + SHA_WORKSPACE_WORDS]; sha_init(buf); @@ -772,9 +772,11 @@ static void extract_buf(struct entropy_store *r, __u8 *out) * attempts to find previous ouputs), unless the hash * function can be inverted. */ - for (i = 0, x = 0; i < r->poolinfo->poolwords; i += 16, x+=2) { - sha_transform(buf, (__u8 *)r->pool+i, buf + 5); - add_entropy_words(r, &buf[x % 5], 1); + for (i = 0; i < r->poolinfo->poolwords; i += 16) { + /* hash blocks of 16 words = 512 bits */ + sha_transform(buf, (__u8 *)(r->pool + i), buf + 5); + /* feed back portion of the resulting hash */ + add_entropy_words(r, &buf[i % 5], 1); } /* @@ -782,7 +784,7 @@ static void extract_buf(struct entropy_store *r, __u8 *out) * portion of the pool while mixing, and hash one * final time. */ - __add_entropy_words(r, &buf[x % 5], 1, data); + __add_entropy_words(r, &buf[i % 5], 1, data); sha_transform(buf, (__u8 *)data, buf + 5); /* @@ -1018,37 +1020,44 @@ random_poll(struct file *file, poll_table * wait) return mask; } -static ssize_t -random_write(struct file * file, const char __user * buffer, - size_t count, loff_t *ppos) +static int +write_pool(struct entropy_store *r, const char __user *buffer, size_t count) { - int ret = 0; size_t bytes; __u32 buf[16]; const char __user *p = buffer; - size_t c = count; - while (c > 0) { - bytes = min(c, sizeof(buf)); + while (count > 0) { + bytes = min(count, sizeof(buf)); + if (copy_from_user(&buf, p, bytes)) + return -EFAULT; - bytes -= copy_from_user(&buf, p, bytes); - if (!bytes) { - ret = -EFAULT; - break; - } - c -= bytes; + count -= bytes; p += bytes; - add_entropy_words(&input_pool, buf, (bytes + 3) / 4); - } - if (p == buffer) { - return (ssize_t)ret; - } else { - struct inode *inode = file->f_path.dentry->d_inode; - inode->i_mtime = current_fs_time(inode->i_sb); - mark_inode_dirty(inode); - return (ssize_t)(p - buffer); + add_entropy_words(r, buf, (bytes + 3) / 4); } + + return 0; +} + +static ssize_t +random_write(struct file * file, const char __user * buffer, + size_t count, loff_t *ppos) +{ + size_t ret; + struct inode *inode = file->f_path.dentry->d_inode; + + ret = write_pool(&blocking_pool, buffer, count); + if (ret) + return ret; + ret = write_pool(&nonblocking_pool, buffer, count); + if (ret) + return ret; + + inode->i_mtime = current_fs_time(inode->i_sb); + mark_inode_dirty(inode); + return (ssize_t)count; } static int @@ -1087,8 +1096,8 @@ random_ioctl(struct inode * inode, struct file * file, return -EINVAL; if (get_user(size, p++)) return -EFAULT; - retval = random_write(file, (const char __user *) p, - size, &file->f_pos); + retval = write_pool(&input_pool, (const char __user *)p, + size); if (retval < 0) return retval; credit_entropy_store(&input_pool, ent_count); diff --git a/drivers/char/stallion.c b/drivers/char/stallion.c index e45113a7a472..45bf2a262a85 100644 --- a/drivers/char/stallion.c +++ b/drivers/char/stallion.c @@ -2172,11 +2172,12 @@ static int __devinit stl_initech(struct stlbrd *brdp) } status = inb(ioaddr + ECH_PNLSTATUS); if ((status & ECH_PNLIDMASK) != nxtid) - goto err_fr; + break; panelp = kzalloc(sizeof(struct stlpanel), GFP_KERNEL); if (!panelp) { printk("STALLION: failed to allocate memory " "(size=%Zd)\n", sizeof(struct stlpanel)); + retval = -ENOMEM; goto err_fr; } panelp->magic = STL_PANELMAGIC; @@ -2223,8 +2224,10 @@ static int __devinit stl_initech(struct stlbrd *brdp) brdp->nrports += panelp->nrports; brdp->panels[panelnr++] = panelp; if ((brdp->brdtype != BRD_ECHPCI) && - (ioaddr >= (brdp->ioaddr2 + brdp->iosize2))) + (ioaddr >= (brdp->ioaddr2 + brdp->iosize2))) { + retval = -EINVAL; goto err_fr; + } } brdp->nrpanels = panelnr; @@ -2371,6 +2374,7 @@ static int __devinit stl_pciprobe(struct pci_dev *pdev, dev_err(&pdev->dev, "too many boards found, " "maximum supported %d\n", STL_MAXBRDS); mutex_unlock(&stl_brdslock); + retval = -ENODEV; goto err_fr; } brdp->brdnr = (unsigned int)brdnr; @@ -4710,6 +4714,29 @@ static int __init stallion_module_init(void) spin_lock_init(&stallion_lock); spin_lock_init(&brd_lock); + stl_serial = alloc_tty_driver(STL_MAXBRDS * STL_MAXPORTS); + if (!stl_serial) { + retval = -ENOMEM; + goto err; + } + + stl_serial->owner = THIS_MODULE; + stl_serial->driver_name = stl_drvname; + stl_serial->name = "ttyE"; + stl_serial->major = STL_SERIALMAJOR; + stl_serial->minor_start = 0; + stl_serial->type = TTY_DRIVER_TYPE_SERIAL; + stl_serial->subtype = SERIAL_TYPE_NORMAL; + stl_serial->init_termios = stl_deftermios; + stl_serial->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV; + tty_set_operations(stl_serial, &stl_ops); + + retval = tty_register_driver(stl_serial); + if (retval) { + printk("STALLION: failed to register serial driver\n"); + goto err_frtty; + } + /* * Find any dynamically supported boards. That is via module load * line options. @@ -4739,13 +4766,9 @@ static int __init stallion_module_init(void) /* this has to be _after_ isa finding because of locking */ retval = pci_register_driver(&stl_pcidriver); - if (retval && stl_nrbrds == 0) - goto err; - - stl_serial = alloc_tty_driver(STL_MAXBRDS * STL_MAXPORTS); - if (!stl_serial) { - retval = -ENOMEM; - goto err_pcidr; + if (retval && stl_nrbrds == 0) { + printk(KERN_ERR "STALLION: can't register pci driver\n"); + goto err_unrtty; } /* @@ -4756,43 +4779,18 @@ static int __init stallion_module_init(void) printk("STALLION: failed to register serial board device\n"); stallion_class = class_create(THIS_MODULE, "staliomem"); - if (IS_ERR(stallion_class)) { - retval = PTR_ERR(stallion_class); - goto err_reg; - } + if (IS_ERR(stallion_class)) + printk("STALLION: failed to create class\n"); for (i = 0; i < 4; i++) class_device_create(stallion_class, NULL, MKDEV(STL_SIOMEMMAJOR, i), NULL, "staliomem%d", i); - stl_serial->owner = THIS_MODULE; - stl_serial->driver_name = stl_drvname; - stl_serial->name = "ttyE"; - stl_serial->major = STL_SERIALMAJOR; - stl_serial->minor_start = 0; - stl_serial->type = TTY_DRIVER_TYPE_SERIAL; - stl_serial->subtype = SERIAL_TYPE_NORMAL; - stl_serial->init_termios = stl_deftermios; - stl_serial->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV; - tty_set_operations(stl_serial, &stl_ops); - - retval = tty_register_driver(stl_serial); - if (retval) { - printk("STALLION: failed to register serial driver\n"); - goto err_clsdev; - } - return 0; -err_clsdev: - for (i = 0; i < 4; i++) - class_device_destroy(stallion_class, MKDEV(STL_SIOMEMMAJOR, i)); - class_destroy(stallion_class); -err_reg: - unregister_chrdev(STL_SIOMEMMAJOR, "staliomem"); +err_unrtty: + tty_unregister_driver(stl_serial); +err_frtty: put_tty_driver(stl_serial); -err_pcidr: - pci_unregister_driver(&stl_pcidriver); - stl_free_isabrds(); err: return retval; } @@ -4821,8 +4819,6 @@ static void __exit stallion_module_exit(void) tty_unregister_device(stl_serial, brdp->brdnr * STL_MAXPORTS + j); } - tty_unregister_driver(stl_serial); - put_tty_driver(stl_serial); for (i = 0; i < 4; i++) class_device_destroy(stallion_class, MKDEV(STL_SIOMEMMAJOR, i)); @@ -4834,6 +4830,9 @@ static void __exit stallion_module_exit(void) pci_unregister_driver(&stl_pcidriver); stl_free_isabrds(); + + tty_unregister_driver(stl_serial); + put_tty_driver(stl_serial); } module_init(stallion_module_init); diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c index 75d2a46e106f..3752edc30c36 100644 --- a/drivers/char/tty_io.c +++ b/drivers/char/tty_io.c @@ -1148,7 +1148,8 @@ int tty_check_change(struct tty_struct * tty) return 0; if (is_current_pgrp_orphaned()) return -EIO; - (void) kill_pgrp(task_pgrp(current), SIGTTOU, 1); + kill_pgrp(task_pgrp(current), SIGTTOU, 1); + set_thread_flag(TIF_SIGPENDING); return -ERESTARTSYS; } diff --git a/drivers/char/watchdog/Kconfig b/drivers/char/watchdog/Kconfig index 1cad32c62ed3..53f5538c0c05 100644 --- a/drivers/char/watchdog/Kconfig +++ b/drivers/char/watchdog/Kconfig @@ -115,6 +115,13 @@ config IXP4XX_WATCHDOG Say N if you are unsure. +config KS8695_WATCHDOG + tristate "KS8695 watchdog" + depends on ARCH_KS8695 + help + Watchdog timer embedded into KS8695 processor. This will reboot your + system when the timeout is reached. + config S3C2410_WATCHDOG tristate "S3C2410 Watchdog" depends on ARCH_S3C2410 diff --git a/drivers/char/watchdog/Makefile b/drivers/char/watchdog/Makefile index 8bfc00cc7c2b..d90f649038c2 100644 --- a/drivers/char/watchdog/Makefile +++ b/drivers/char/watchdog/Makefile @@ -29,6 +29,7 @@ obj-$(CONFIG_21285_WATCHDOG) += wdt285.o obj-$(CONFIG_977_WATCHDOG) += wdt977.o obj-$(CONFIG_IXP2000_WATCHDOG) += ixp2000_wdt.o obj-$(CONFIG_IXP4XX_WATCHDOG) += ixp4xx_wdt.o +obj-$(CONFIG_KS8695_WATCHDOG) += ks8695_wdt.o obj-$(CONFIG_S3C2410_WATCHDOG) += s3c2410_wdt.o obj-$(CONFIG_SA1100_WATCHDOG) += sa1100_wdt.o obj-$(CONFIG_MPCORE_WATCHDOG) += mpcore_wdt.o diff --git a/drivers/char/watchdog/ixp2000_wdt.c b/drivers/char/watchdog/ixp2000_wdt.c index fd955dbd588c..dc7548dcaf35 100644 --- a/drivers/char/watchdog/ixp2000_wdt.c +++ b/drivers/char/watchdog/ixp2000_wdt.c @@ -205,7 +205,7 @@ static void __exit ixp2000_wdt_exit(void) module_init(ixp2000_wdt_init); module_exit(ixp2000_wdt_exit); -MODULE_AUTHOR("Deepak Saxena <dsaxena@plexity.net">); +MODULE_AUTHOR("Deepak Saxena <dsaxena@plexity.net>"); MODULE_DESCRIPTION("IXP2000 Network Processor Watchdog"); module_param(heartbeat, int, 0); diff --git a/drivers/char/watchdog/ks8695_wdt.c b/drivers/char/watchdog/ks8695_wdt.c new file mode 100644 index 000000000000..7150fb945eaf --- /dev/null +++ b/drivers/char/watchdog/ks8695_wdt.c @@ -0,0 +1,308 @@ +/* + * Watchdog driver for Kendin/Micrel KS8695. + * + * (C) 2007 Andrew Victor + * + * 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/errno.h> +#include <linux/fs.h> +#include <linux/init.h> +#include <linux/kernel.h> +#include <linux/miscdevice.h> +#include <linux/module.h> +#include <linux/moduleparam.h> +#include <linux/platform_device.h> +#include <linux/types.h> +#include <linux/watchdog.h> +#include <asm/bitops.h> +#include <asm/io.h> +#include <asm/uaccess.h> +#include <asm/arch/regs-timer.h> + + +#define WDT_DEFAULT_TIME 5 /* seconds */ +#define WDT_MAX_TIME 171 /* seconds */ + +static int wdt_time = WDT_DEFAULT_TIME; +static int nowayout = WATCHDOG_NOWAYOUT; + +module_param(wdt_time, int, 0); +MODULE_PARM_DESC(wdt_time, "Watchdog time in seconds. (default="__MODULE_STRING(WDT_DEFAULT_TIME) ")"); + +#ifdef CONFIG_WATCHDOG_NOWAYOUT +module_param(nowayout, int, 0); +MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); +#endif + + +static unsigned long ks8695wdt_busy; + +/* ......................................................................... */ + +/* + * Disable the watchdog. + */ +static void inline ks8695_wdt_stop(void) +{ + unsigned long tmcon; + + /* disable timer0 */ + tmcon = __raw_readl(KS8695_TMR_VA + KS8695_TMCON); + __raw_writel(tmcon & ~TMCON_T0EN, KS8695_TMR_VA + KS8695_TMCON); +} + +/* + * Enable and reset the watchdog. + */ +static void inline ks8695_wdt_start(void) +{ + unsigned long tmcon; + unsigned long tval = wdt_time * CLOCK_TICK_RATE; + + /* disable timer0 */ + tmcon = __raw_readl(KS8695_TMR_VA + KS8695_TMCON); + __raw_writel(tmcon & ~TMCON_T0EN, KS8695_TMR_VA + KS8695_TMCON); + + /* program timer0 */ + __raw_writel(tval | T0TC_WATCHDOG, KS8695_TMR_VA + KS8695_T0TC); + + /* re-enable timer0 */ + tmcon = __raw_readl(KS8695_TMR_VA + KS8695_TMCON); + __raw_writel(tmcon | TMCON_T0EN, KS8695_TMR_VA + KS8695_TMCON); +} + +/* + * Reload the watchdog timer. (ie, pat the watchdog) + */ +static void inline ks8695_wdt_reload(void) +{ + unsigned long tmcon; + + /* disable, then re-enable timer0 */ + tmcon = __raw_readl(KS8695_TMR_VA + KS8695_TMCON); + __raw_writel(tmcon & ~TMCON_T0EN, KS8695_TMR_VA + KS8695_TMCON); + __raw_writel(tmcon | TMCON_T0EN, KS8695_TMR_VA + KS8695_TMCON); +} + +/* + * Change the watchdog time interval. + */ +static int ks8695_wdt_settimeout(int new_time) +{ + /* + * All counting occurs at SLOW_CLOCK / 128 = 0.256 Hz + * + * Since WDV is a 16-bit counter, the maximum period is + * 65536 / 0.256 = 256 seconds. + */ + if ((new_time <= 0) || (new_time > WDT_MAX_TIME)) + return -EINVAL; + + /* Set new watchdog time. It will be used when ks8695_wdt_start() is called. */ + wdt_time = new_time; + return 0; +} + +/* ......................................................................... */ + +/* + * Watchdog device is opened, and watchdog starts running. + */ +static int ks8695_wdt_open(struct inode *inode, struct file *file) +{ + if (test_and_set_bit(0, &ks8695wdt_busy)) + return -EBUSY; + + ks8695_wdt_start(); + return nonseekable_open(inode, file); +} + +/* + * Close the watchdog device. + * If CONFIG_WATCHDOG_NOWAYOUT is NOT defined then the watchdog is also + * disabled. + */ +static int ks8695_wdt_close(struct inode *inode, struct file *file) +{ + if (!nowayout) + ks8695_wdt_stop(); /* Disable the watchdog when file is closed */ + + clear_bit(0, &ks8695wdt_busy); + return 0; +} + +static struct watchdog_info ks8695_wdt_info = { + .identity = "ks8695 watchdog", + .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING, +}; + +/* + * Handle commands from user-space. + */ +static int ks8695_wdt_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg) +{ + void __user *argp = (void __user *)arg; + int __user *p = argp; + int new_value; + + switch(cmd) { + case WDIOC_KEEPALIVE: + ks8695_wdt_reload(); /* pat the watchdog */ + return 0; + + case WDIOC_GETSUPPORT: + return copy_to_user(argp, &ks8695_wdt_info, sizeof(ks8695_wdt_info)) ? -EFAULT : 0; + + case WDIOC_SETTIMEOUT: + if (get_user(new_value, p)) + return -EFAULT; + + if (ks8695_wdt_settimeout(new_value)) + return -EINVAL; + + /* Enable new time value */ + ks8695_wdt_start(); + + /* Return current value */ + return put_user(wdt_time, p); + + case WDIOC_GETTIMEOUT: + return put_user(wdt_time, p); + + case WDIOC_GETSTATUS: + case WDIOC_GETBOOTSTATUS: + return put_user(0, p); + + case WDIOC_SETOPTIONS: + if (get_user(new_value, p)) + return -EFAULT; + + if (new_value & WDIOS_DISABLECARD) + ks8695_wdt_stop(); + if (new_value & WDIOS_ENABLECARD) + ks8695_wdt_start(); + return 0; + + default: + return -ENOTTY; + } +} + +/* + * Pat the watchdog whenever device is written to. + */ +static ssize_t ks8695_wdt_write(struct file *file, const char *data, size_t len, loff_t *ppos) +{ + ks8695_wdt_reload(); /* pat the watchdog */ + return len; +} + +/* ......................................................................... */ + +static const struct file_operations ks8695wdt_fops = { + .owner = THIS_MODULE, + .llseek = no_llseek, + .ioctl = ks8695_wdt_ioctl, + .open = ks8695_wdt_open, + .release = ks8695_wdt_close, + .write = ks8695_wdt_write, +}; + +static struct miscdevice ks8695wdt_miscdev = { + .minor = WATCHDOG_MINOR, + .name = "watchdog", + .fops = &ks8695wdt_fops, +}; + +static int __init ks8695wdt_probe(struct platform_device *pdev) +{ + int res; + + if (ks8695wdt_miscdev.parent) + return -EBUSY; + ks8695wdt_miscdev.parent = &pdev->dev; + + res = misc_register(&ks8695wdt_miscdev); + if (res) + return res; + + printk("KS8695 Watchdog Timer enabled (%d seconds%s)\n", wdt_time, nowayout ? ", nowayout" : ""); + return 0; +} + +static int __exit ks8695wdt_remove(struct platform_device *pdev) +{ + int res; + + res = misc_deregister(&ks8695wdt_miscdev); + if (!res) + ks8695wdt_miscdev.parent = NULL; + + return res; +} + +static void ks8695wdt_shutdown(struct platform_device *pdev) +{ + ks8695_wdt_stop(); +} + +#ifdef CONFIG_PM + +static int ks8695wdt_suspend(struct platform_device *pdev, pm_message_t message) +{ + ks8695_wdt_stop(); + return 0; +} + +static int ks8695wdt_resume(struct platform_device *pdev) +{ + if (ks8695wdt_busy) + ks8695_wdt_start(); + return 0; +} + +#else +#define ks8695wdt_suspend NULL +#define ks8695wdt_resume NULL +#endif + +static struct platform_driver ks8695wdt_driver = { + .probe = ks8695wdt_probe, + .remove = __exit_p(ks8695wdt_remove), + .shutdown = ks8695wdt_shutdown, + .suspend = ks8695wdt_suspend, + .resume = ks8695wdt_resume, + .driver = { + .name = "ks8695_wdt", + .owner = THIS_MODULE, + }, +}; + +static int __init ks8695_wdt_init(void) +{ + /* Check that the heartbeat value is within range; if not reset to the default */ + if (ks8695_wdt_settimeout(wdt_time)) { + ks8695_wdt_settimeout(WDT_DEFAULT_TIME); + pr_info("ks8695_wdt: wdt_time value must be 1 <= wdt_time <= %i, using %d\n", wdt_time, WDT_MAX_TIME); + } + + return platform_driver_register(&ks8695wdt_driver); +} + +static void __exit ks8695_wdt_exit(void) +{ + platform_driver_unregister(&ks8695wdt_driver); +} + +module_init(ks8695_wdt_init); +module_exit(ks8695_wdt_exit); + +MODULE_AUTHOR("Andrew Victor"); +MODULE_DESCRIPTION("Watchdog driver for KS8695"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR); |