diff options
author | Thomas Gleixner <tglx@tglx.tec.linutronix.de> | 2005-06-26 23:20:36 +0200 |
---|---|---|
committer | Thomas Gleixner <tglx@mtd.linutronix.de> | 2005-06-26 23:20:36 +0200 |
commit | 7ca6448dbfb398bba36eda3c01bc14b86c3675be (patch) | |
tree | 82d934ebf07f22a2c64c3b6d82ec24082878b43a /drivers/char | |
parent | f1f67a9874f1a4bba1adff6d694aa52e5f52ff1a (diff) | |
parent | 7d681b23d6cc14a8c026ea6756242cb522cbbcae (diff) |
Merge with rsync://fileserver/linux
Update to Linus latest
Diffstat (limited to 'drivers/char')
73 files changed, 2949 insertions, 1490 deletions
diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig index 5ed6515ae01..43d0cb19ef6 100644 --- a/drivers/char/Kconfig +++ b/drivers/char/Kconfig @@ -929,6 +929,10 @@ config SCx200_GPIO If compiled as a module, it will be called scx200_gpio. +config GPIO_VR41XX + tristate "NEC VR4100 series General-purpose I/O Unit support" + depends on CPU_VR41XX + config RAW_DRIVER tristate "RAW driver (/dev/raw/rawN) (OBSOLETE)" help @@ -936,8 +940,8 @@ config RAW_DRIVER Once bound, I/O against /dev/raw/rawN uses efficient zero-copy I/O. See the raw(8) manpage for more details. - The raw driver is deprecated and may be removed from 2.7 - kernels. Applications should simply open the device (eg /dev/hda1) + The raw driver is deprecated and will be removed soon. + Applications should simply open the device (eg /dev/hda1) with the O_DIRECT flag. config HPET diff --git a/drivers/char/Makefile b/drivers/char/Makefile index e3f5c32aac5..1aff819f383 100644 --- a/drivers/char/Makefile +++ b/drivers/char/Makefile @@ -80,6 +80,7 @@ obj-$(CONFIG_PPDEV) += ppdev.o obj-$(CONFIG_NWBUTTON) += nwbutton.o obj-$(CONFIG_NWFLASH) += nwflash.o obj-$(CONFIG_SCx200_GPIO) += scx200_gpio.o +obj-$(CONFIG_GPIO_VR41XX) += vr41xx_giu.o obj-$(CONFIG_TANBAC_TB0219) += tb0219.o obj-$(CONFIG_WATCHDOG) += watchdog/ diff --git a/drivers/char/agp/agp.h b/drivers/char/agp/agp.h index ad9c11391d8..c1fe013c64f 100644 --- a/drivers/char/agp/agp.h +++ b/drivers/char/agp/agp.h @@ -278,6 +278,8 @@ void agp3_generic_cleanup(void); #define AGP_GENERIC_SIZES_ENTRIES 11 extern struct aper_size_info_16 agp3_generic_sizes[]; +#define virt_to_gart(x) (phys_to_gart(virt_to_phys(x))) +#define gart_to_virt(x) (phys_to_virt(gart_to_phys(x))) extern int agp_off; extern int agp_try_unsupported_boot; diff --git a/drivers/char/agp/ali-agp.c b/drivers/char/agp/ali-agp.c index 0212febda65..9c9c9c2247c 100644 --- a/drivers/char/agp/ali-agp.c +++ b/drivers/char/agp/ali-agp.c @@ -150,7 +150,7 @@ static void *m1541_alloc_page(struct agp_bridge_data *bridge) 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_phys(addr)) | ALI_CACHE_FLUSH_EN )); + virt_to_gart(addr)) | ALI_CACHE_FLUSH_EN )); return addr; } @@ -174,7 +174,7 @@ static void m1541_destroy_page(void * addr) 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_phys(addr)) | ALI_CACHE_FLUSH_EN)); + virt_to_gart(addr)) | ALI_CACHE_FLUSH_EN)); agp_generic_destroy_page(addr); } diff --git a/drivers/char/agp/amd-k7-agp.c b/drivers/char/agp/amd-k7-agp.c index e62a3c2c44a..3a41672e4d6 100644 --- a/drivers/char/agp/amd-k7-agp.c +++ b/drivers/char/agp/amd-k7-agp.c @@ -43,7 +43,7 @@ static int amd_create_page_map(struct amd_page_map *page_map) SetPageReserved(virt_to_page(page_map->real)); global_cache_flush(); - page_map->remapped = ioremap_nocache(virt_to_phys(page_map->real), + page_map->remapped = ioremap_nocache(virt_to_gart(page_map->real), PAGE_SIZE); if (page_map->remapped == NULL) { ClearPageReserved(virt_to_page(page_map->real)); @@ -154,7 +154,7 @@ static int amd_create_gatt_table(struct agp_bridge_data *bridge) agp_bridge->gatt_table_real = (u32 *)page_dir.real; agp_bridge->gatt_table = (u32 __iomem *)page_dir.remapped; - agp_bridge->gatt_bus_addr = virt_to_phys(page_dir.real); + agp_bridge->gatt_bus_addr = virt_to_gart(page_dir.real); /* Get the address for the gart region. * This is a bus address even on the alpha, b/c its @@ -167,7 +167,7 @@ static int amd_create_gatt_table(struct agp_bridge_data *bridge) /* Calculate the agp offset */ for (i = 0; i < value->num_entries / 1024; i++, addr += 0x00400000) { - writel(virt_to_phys(amd_irongate_private.gatt_pages[i]->real) | 1, + writel(virt_to_gart(amd_irongate_private.gatt_pages[i]->real) | 1, page_dir.remapped+GET_PAGE_DIR_OFF(addr)); readl(page_dir.remapped+GET_PAGE_DIR_OFF(addr)); /* PCI Posting. */ } diff --git a/drivers/char/agp/amd64-agp.c b/drivers/char/agp/amd64-agp.c index 399c042f68f..1407945a589 100644 --- a/drivers/char/agp/amd64-agp.c +++ b/drivers/char/agp/amd64-agp.c @@ -219,7 +219,7 @@ static struct aper_size_info_32 amd_8151_sizes[7] = static int amd_8151_configure(void) { - unsigned long gatt_bus = virt_to_phys(agp_bridge->gatt_table_real); + unsigned long gatt_bus = virt_to_gart(agp_bridge->gatt_table_real); /* Configure AGP regs in each x86-64 host bridge. */ for_each_nb() { @@ -591,7 +591,7 @@ static void __devexit agp_amd64_remove(struct pci_dev *pdev) { struct agp_bridge_data *bridge = pci_get_drvdata(pdev); - release_mem_region(virt_to_phys(bridge->gatt_table_real), + release_mem_region(virt_to_gart(bridge->gatt_table_real), amd64_aperture_sizes[bridge->aperture_size_idx].size); agp_remove_bridge(bridge); agp_put_bridge(bridge); diff --git a/drivers/char/agp/ati-agp.c b/drivers/char/agp/ati-agp.c index a65f8827c28..e572ced9100 100644 --- a/drivers/char/agp/ati-agp.c +++ b/drivers/char/agp/ati-agp.c @@ -61,7 +61,7 @@ static int ati_create_page_map(ati_page_map *page_map) SetPageReserved(virt_to_page(page_map->real)); err = map_page_into_agp(virt_to_page(page_map->real)); - page_map->remapped = ioremap_nocache(virt_to_phys(page_map->real), + page_map->remapped = ioremap_nocache(virt_to_gart(page_map->real), PAGE_SIZE); if (page_map->remapped == NULL || err) { ClearPageReserved(virt_to_page(page_map->real)); @@ -343,7 +343,7 @@ static int ati_create_gatt_table(struct agp_bridge_data *bridge) agp_bridge->gatt_table_real = (u32 *)page_dir.real; agp_bridge->gatt_table = (u32 __iomem *) page_dir.remapped; - agp_bridge->gatt_bus_addr = virt_to_bus(page_dir.real); + agp_bridge->gatt_bus_addr = virt_to_gart(page_dir.real); /* Write out the size register */ current_size = A_SIZE_LVL2(agp_bridge->current_size); @@ -373,7 +373,7 @@ static int ati_create_gatt_table(struct agp_bridge_data *bridge) /* Calculate the agp offset */ for(i = 0; i < value->num_entries / 1024; i++, addr += 0x00400000) { - writel(virt_to_bus(ati_generic_private.gatt_pages[i]->real) | 1, + writel(virt_to_gart(ati_generic_private.gatt_pages[i]->real) | 1, page_dir.remapped+GET_PAGE_DIR_OFF(addr)); readl(page_dir.remapped+GET_PAGE_DIR_OFF(addr)); /* PCI Posting. */ } diff --git a/drivers/char/agp/backend.c b/drivers/char/agp/backend.c index 2f3dfb63bdc..4d4e602fdc7 100644 --- a/drivers/char/agp/backend.c +++ b/drivers/char/agp/backend.c @@ -148,7 +148,7 @@ static int agp_backend_initialize(struct agp_bridge_data *bridge) return -ENOMEM; } - bridge->scratch_page_real = virt_to_phys(addr); + bridge->scratch_page_real = virt_to_gart(addr); bridge->scratch_page = bridge->driver->mask_memory(bridge, bridge->scratch_page_real, 0); } @@ -189,7 +189,7 @@ static int agp_backend_initialize(struct agp_bridge_data *bridge) err_out: if (bridge->driver->needs_scratch_page) bridge->driver->agp_destroy_page( - phys_to_virt(bridge->scratch_page_real)); + gart_to_virt(bridge->scratch_page_real)); if (got_gatt) bridge->driver->free_gatt_table(bridge); if (got_keylist) { @@ -214,7 +214,7 @@ static void agp_backend_cleanup(struct agp_bridge_data *bridge) if (bridge->driver->agp_destroy_page && bridge->driver->needs_scratch_page) bridge->driver->agp_destroy_page( - phys_to_virt(bridge->scratch_page_real)); + gart_to_virt(bridge->scratch_page_real)); } /* When we remove the global variable agp_bridge from all drivers diff --git a/drivers/char/agp/efficeon-agp.c b/drivers/char/agp/efficeon-agp.c index 1383c3165ea..ac19fdcd21c 100644 --- a/drivers/char/agp/efficeon-agp.c +++ b/drivers/char/agp/efficeon-agp.c @@ -219,7 +219,7 @@ static int efficeon_create_gatt_table(struct agp_bridge_data *bridge) efficeon_private.l1_table[index] = page; - value = __pa(page) | pati | present | index; + value = virt_to_gart(page) | pati | present | index; pci_write_config_dword(agp_bridge->dev, EFFICEON_ATTPAGE, value); diff --git a/drivers/char/agp/generic.c b/drivers/char/agp/generic.c index c321a924e38..f0079e991bd 100644 --- a/drivers/char/agp/generic.c +++ b/drivers/char/agp/generic.c @@ -153,7 +153,7 @@ void agp_free_memory(struct agp_memory *curr) } if (curr->page_count != 0) { for (i = 0; i < curr->page_count; i++) { - curr->bridge->driver->agp_destroy_page(phys_to_virt(curr->memory[i])); + curr->bridge->driver->agp_destroy_page(gart_to_virt(curr->memory[i])); } } agp_free_key(curr->key); @@ -209,7 +209,7 @@ struct agp_memory *agp_allocate_memory(struct agp_bridge_data *bridge, agp_free_memory(new); return NULL; } - new->memory[i] = virt_to_phys(addr); + new->memory[i] = virt_to_gart(addr); new->page_count++; } new->bridge = bridge; @@ -295,19 +295,6 @@ int agp_num_entries(void) EXPORT_SYMBOL_GPL(agp_num_entries); -static int check_bridge_mode(struct pci_dev *dev) -{ - u32 agp3; - u8 cap_ptr; - - cap_ptr = pci_find_capability(dev, PCI_CAP_ID_AGP); - pci_read_config_dword(dev, cap_ptr+AGPSTAT, &agp3); - if (agp3 & AGPSTAT_MODE_3_0) - return 1; - return 0; -} - - /** * agp_copy_info - copy bridge state information * @@ -328,7 +315,7 @@ int agp_copy_info(struct agp_bridge_data *bridge, struct agp_kern_info *info) info->version.minor = bridge->version->minor; info->chipset = SUPPORTED; info->device = bridge->dev; - if (check_bridge_mode(bridge->dev)) + if (bridge->mode & AGPSTAT_MODE_3_0) info->mode = bridge->mode & ~AGP3_RESERVED_MASK; else info->mode = bridge->mode & ~AGP2_RESERVED_MASK; @@ -661,7 +648,7 @@ u32 agp_collect_device_status(struct agp_bridge_data *bridge, u32 requested_mode bridge_agpstat &= ~AGPSTAT_FW; /* Check to see if we are operating in 3.0 mode */ - if (check_bridge_mode(agp_bridge->dev)) + if (agp_bridge->mode & AGPSTAT_MODE_3_0) agp_v3_parse_one(&requested_mode, &bridge_agpstat, &vga_agpstat); else agp_v2_parse_one(&requested_mode, &bridge_agpstat, &vga_agpstat); @@ -732,7 +719,7 @@ void agp_generic_enable(struct agp_bridge_data *bridge, u32 requested_mode) /* Do AGP version specific frobbing. */ if (bridge->major_version >= 3) { - if (check_bridge_mode(bridge->dev)) { + if (bridge->mode & AGPSTAT_MODE_3_0) { /* If we have 3.5, we can do the isoch stuff. */ if (bridge->minor_version >= 5) agp_3_5_enable(bridge); @@ -806,8 +793,7 @@ int agp_generic_create_gatt_table(struct agp_bridge_data *bridge) break; } - table = (char *) __get_free_pages(GFP_KERNEL, - page_order); + table = alloc_gatt_pages(page_order); if (table == NULL) { i++; @@ -838,7 +824,7 @@ int agp_generic_create_gatt_table(struct agp_bridge_data *bridge) size = ((struct aper_size_info_fixed *) temp)->size; page_order = ((struct aper_size_info_fixed *) temp)->page_order; num_entries = ((struct aper_size_info_fixed *) temp)->num_entries; - table = (char *) __get_free_pages(GFP_KERNEL, page_order); + table = alloc_gatt_pages(page_order); } if (table == NULL) @@ -853,7 +839,7 @@ int agp_generic_create_gatt_table(struct agp_bridge_data *bridge) agp_gatt_table = (void *)table; bridge->driver->cache_flush(); - bridge->gatt_table = ioremap_nocache(virt_to_phys(table), + bridge->gatt_table = ioremap_nocache(virt_to_gart(table), (PAGE_SIZE * (1 << page_order))); bridge->driver->cache_flush(); @@ -861,11 +847,11 @@ int agp_generic_create_gatt_table(struct agp_bridge_data *bridge) for (page = virt_to_page(table); page <= virt_to_page(table_end); page++) ClearPageReserved(page); - free_pages((unsigned long) table, page_order); + free_gatt_pages(table, page_order); return -ENOMEM; } - bridge->gatt_bus_addr = virt_to_phys(bridge->gatt_table_real); + bridge->gatt_bus_addr = virt_to_gart(bridge->gatt_table_real); /* AK: bogus, should encode addresses > 4GB */ for (i = 0; i < num_entries; i++) { @@ -919,7 +905,7 @@ int agp_generic_free_gatt_table(struct agp_bridge_data *bridge) for (page = virt_to_page(table); page <= virt_to_page(table_end); page++) ClearPageReserved(page); - free_pages((unsigned long) bridge->gatt_table_real, page_order); + free_gatt_pages(bridge->gatt_table_real, page_order); agp_gatt_table = NULL; bridge->gatt_table = NULL; diff --git a/drivers/char/agp/hp-agp.c b/drivers/char/agp/hp-agp.c index 6052bfa04c7..99762b6c19a 100644 --- a/drivers/char/agp/hp-agp.c +++ b/drivers/char/agp/hp-agp.c @@ -110,7 +110,7 @@ static int __init hp_zx1_ioc_shared(void) hp->gart_size = HP_ZX1_GART_SIZE; hp->gatt_entries = hp->gart_size / hp->io_page_size; - hp->io_pdir = phys_to_virt(readq(hp->ioc_regs+HP_ZX1_PDIR_BASE)); + hp->io_pdir = gart_to_virt(readq(hp->ioc_regs+HP_ZX1_PDIR_BASE)); hp->gatt = &hp->io_pdir[HP_ZX1_IOVA_TO_PDIR(hp->gart_base)]; if (hp->gatt[0] != HP_ZX1_SBA_IOMMU_COOKIE) { @@ -248,7 +248,7 @@ hp_zx1_configure (void) agp_bridge->mode = readl(hp->lba_regs+hp->lba_cap_offset+PCI_AGP_STATUS); if (hp->io_pdir_owner) { - writel(virt_to_phys(hp->io_pdir), hp->ioc_regs+HP_ZX1_PDIR_BASE); + writel(virt_to_gart(hp->io_pdir), hp->ioc_regs+HP_ZX1_PDIR_BASE); readl(hp->ioc_regs+HP_ZX1_PDIR_BASE); writel(hp->io_tlb_ps, hp->ioc_regs+HP_ZX1_TCNFG); readl(hp->ioc_regs+HP_ZX1_TCNFG); diff --git a/drivers/char/agp/i460-agp.c b/drivers/char/agp/i460-agp.c index adbea896c0d..94943298c03 100644 --- a/drivers/char/agp/i460-agp.c +++ b/drivers/char/agp/i460-agp.c @@ -372,7 +372,7 @@ static int i460_alloc_large_page (struct lp_desc *lp) } memset(lp->alloced_map, 0, map_size); - lp->paddr = virt_to_phys(lpage); + lp->paddr = virt_to_gart(lpage); lp->refcount = 0; atomic_add(I460_KPAGES_PER_IOPAGE, &agp_bridge->current_memory_agp); return 0; @@ -383,7 +383,7 @@ static void i460_free_large_page (struct lp_desc *lp) kfree(lp->alloced_map); lp->alloced_map = NULL; - free_pages((unsigned long) phys_to_virt(lp->paddr), I460_IO_PAGE_SHIFT - PAGE_SHIFT); + free_pages((unsigned long) gart_to_virt(lp->paddr), I460_IO_PAGE_SHIFT - PAGE_SHIFT); atomic_sub(I460_KPAGES_PER_IOPAGE, &agp_bridge->current_memory_agp); } diff --git a/drivers/char/agp/intel-agp.c b/drivers/char/agp/intel-agp.c index 8c7d727432b..51266d6b4d7 100644 --- a/drivers/char/agp/intel-agp.c +++ b/drivers/char/agp/intel-agp.c @@ -286,7 +286,7 @@ static struct agp_memory *alloc_agpphysmem_i8xx(size_t pg_count, int type) if (new == NULL) return NULL; - new->memory[0] = virt_to_phys(addr); + new->memory[0] = virt_to_gart(addr); if (pg_count == 4) { /* kludge to get 4 physical pages for ARGB cursor */ new->memory[1] = new->memory[0] + PAGE_SIZE; @@ -329,10 +329,10 @@ 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(phys_to_virt(curr->memory[0])); + i8xx_destroy_pages(gart_to_virt(curr->memory[0])); else agp_bridge->driver->agp_destroy_page( - phys_to_virt(curr->memory[0])); + gart_to_virt(curr->memory[0])); vfree(curr->memory); } kfree(curr); @@ -418,7 +418,8 @@ static void intel_i830_init_gtt_entries(void) case I915_GMCH_GMS_STOLEN_48M: /* Check it's really I915G */ 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_82915GM_HB || + agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82945G_HB) gtt_entries = MB(48) - KB(size); else gtt_entries = 0; @@ -426,7 +427,8 @@ static void intel_i830_init_gtt_entries(void) case I915_GMCH_GMS_STOLEN_64M: /* Check it's really I915G */ 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_82915GM_HB || + agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82945G_HB) gtt_entries = MB(64) - KB(size); else gtt_entries = 0; @@ -1662,6 +1664,14 @@ static int __devinit agp_intel_probe(struct pci_dev *pdev, } 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_7505_0: bridge->driver = &intel_7505_driver; name = "E7505"; @@ -1801,6 +1811,7 @@ static struct pci_device_id agp_intel_pci_table[] = { ID(PCI_DEVICE_ID_INTEL_7205_0), ID(PCI_DEVICE_ID_INTEL_82915G_HB), ID(PCI_DEVICE_ID_INTEL_82915GM_HB), + ID(PCI_DEVICE_ID_INTEL_82945G_HB), { } }; diff --git a/drivers/char/agp/sgi-agp.c b/drivers/char/agp/sgi-agp.c index 4b3eda26797..d3aa159c9de 100644 --- a/drivers/char/agp/sgi-agp.c +++ b/drivers/char/agp/sgi-agp.c @@ -133,11 +133,14 @@ static int sgi_tioca_insert_memory(struct agp_memory *mem, off_t pg_start, off_t j; void *temp; struct agp_bridge_data *bridge; + u64 *table; bridge = mem->bridge; if (!bridge) return -EINVAL; + table = (u64 *)bridge->gatt_table; + temp = bridge->current_size; switch (bridge->driver->size_type) { @@ -175,7 +178,7 @@ static int sgi_tioca_insert_memory(struct agp_memory *mem, off_t pg_start, j = pg_start; while (j < (pg_start + mem->page_count)) { - if (*(bridge->gatt_table + j)) + if (table[j]) return -EBUSY; j++; } @@ -186,7 +189,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++) { - *(bridge->gatt_table + j) = + table[j] = bridge->driver->mask_memory(bridge, mem->memory[i], mem->type); } @@ -200,6 +203,7 @@ static int sgi_tioca_remove_memory(struct agp_memory *mem, off_t pg_start, { size_t i; struct agp_bridge_data *bridge; + u64 *table; bridge = mem->bridge; if (!bridge) @@ -209,8 +213,10 @@ static int sgi_tioca_remove_memory(struct agp_memory *mem, off_t pg_start, return -EINVAL; } + table = (u64 *)bridge->gatt_table; + for (i = pg_start; i < (mem->page_count + pg_start); i++) { - *(bridge->gatt_table + i) = 0; + table[i] = 0; } bridge->driver->tlb_flush(mem); diff --git a/drivers/char/agp/sworks-agp.c b/drivers/char/agp/sworks-agp.c index 10c23302dd8..a9fb12c20eb 100644 --- a/drivers/char/agp/sworks-agp.c +++ b/drivers/char/agp/sworks-agp.c @@ -51,7 +51,7 @@ static int serverworks_create_page_map(struct serverworks_page_map *page_map) } SetPageReserved(virt_to_page(page_map->real)); global_cache_flush(); - page_map->remapped = ioremap_nocache(virt_to_phys(page_map->real), + page_map->remapped = ioremap_nocache(virt_to_gart(page_map->real), PAGE_SIZE); if (page_map->remapped == NULL) { ClearPageReserved(virt_to_page(page_map->real)); @@ -162,7 +162,7 @@ static int serverworks_create_gatt_table(struct agp_bridge_data *bridge) /* Create a fake scratch directory */ for(i = 0; i < 1024; i++) { writel(agp_bridge->scratch_page, serverworks_private.scratch_dir.remapped+i); - writel(virt_to_phys(serverworks_private.scratch_dir.real) | 1, page_dir.remapped+i); + writel(virt_to_gart(serverworks_private.scratch_dir.real) | 1, page_dir.remapped+i); } retval = serverworks_create_gatt_pages(value->num_entries / 1024); @@ -174,7 +174,7 @@ static int serverworks_create_gatt_table(struct agp_bridge_data *bridge) agp_bridge->gatt_table_real = (u32 *)page_dir.real; agp_bridge->gatt_table = (u32 __iomem *)page_dir.remapped; - agp_bridge->gatt_bus_addr = virt_to_phys(page_dir.real); + agp_bridge->gatt_bus_addr = virt_to_gart(page_dir.real); /* Get the address for the gart region. * This is a bus address even on the alpha, b/c its @@ -187,7 +187,7 @@ static int serverworks_create_gatt_table(struct agp_bridge_data *bridge) /* Calculate the agp offset */ for(i = 0; i < value->num_entries / 1024; i++) - writel(virt_to_phys(serverworks_private.gatt_pages[i]->real)|1, page_dir.remapped+i); + writel(virt_to_gart(serverworks_private.gatt_pages[i]->real)|1, page_dir.remapped+i); return 0; } diff --git a/drivers/char/agp/uninorth-agp.c b/drivers/char/agp/uninorth-agp.c index a673971f2a9..c8255312b8c 100644 --- a/drivers/char/agp/uninorth-agp.c +++ b/drivers/char/agp/uninorth-agp.c @@ -407,7 +407,7 @@ static int uninorth_create_gatt_table(struct agp_bridge_data *bridge) bridge->gatt_table_real = (u32 *) table; bridge->gatt_table = (u32 *)table; - bridge->gatt_bus_addr = virt_to_phys(table); + bridge->gatt_bus_addr = virt_to_gart(table); for (i = 0; i < num_entries; i++) bridge->gatt_table[i] = 0; diff --git a/drivers/char/amiserial.c b/drivers/char/amiserial.c index 1dc4259213a..2a36561eec6 100644 --- a/drivers/char/amiserial.c +++ b/drivers/char/amiserial.c @@ -861,13 +861,18 @@ static void change_speed(struct async_struct *info, static void rs_put_char(struct tty_struct *tty, unsigned char ch) { - struct async_struct *info = (struct async_struct *)tty->driver_data; + struct async_struct *info; unsigned long flags; + if (!tty) + return; + + info = tty->driver_data; + if (serial_paranoia_check(info, tty->name, "rs_put_char")) return; - if (!tty || !info->xmit.buf) + if (!info->xmit.buf) return; local_irq_save(flags); @@ -910,13 +915,18 @@ static void rs_flush_chars(struct tty_struct *tty) static int rs_write(struct tty_struct * tty, const unsigned char *buf, int count) { int c, ret = 0; - struct async_struct *info = (struct async_struct *)tty->driver_data; + struct async_struct *info; unsigned long flags; + if (!tty) + return 0; + + info = tty->driver_data; + if (serial_paranoia_check(info, tty->name, "rs_write")) return 0; - if (!tty || !info->xmit.buf || !tmp_buf) + if (!info->xmit.buf || !tmp_buf) return 0; local_save_flags(flags); @@ -1963,10 +1973,6 @@ static _INLINE_ void show_serial_version(void) } -int register_serial(struct serial_struct *req); -void unregister_serial(int line); - - static struct tty_operations serial_ops = { .open = rs_open, .close = rs_close, diff --git a/drivers/char/applicom.c b/drivers/char/applicom.c index 6bf2e27dc23..11f9ee58112 100644 --- a/drivers/char/applicom.c +++ b/drivers/char/applicom.c @@ -599,7 +599,7 @@ static ssize_t ac_read (struct file *filp, char __user *buf, size_t count, loff_ #ifdef DEBUG if (loopcount++ > 2) { - printk("Looping in ac_read. loopcount %d\n", loopcount); + printk(KERN_DEBUG "Looping in ac_read. loopcount %d\n", loopcount); } #endif } diff --git a/drivers/char/drm/drm_pciids.h b/drivers/char/drm/drm_pciids.h index 54a2914e3a3..11c6950158b 100644 --- a/drivers/char/drm/drm_pciids.h +++ b/drivers/char/drm/drm_pciids.h @@ -220,5 +220,6 @@ {0x8086, 0x2572, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ {0x8086, 0x2582, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ {0x8086, 0x2592, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ + {0x8086, 0x2772, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ {0, 0, 0} diff --git a/drivers/char/drm/radeon_irq.c b/drivers/char/drm/radeon_irq.c index 5b18bee6492..cd25f28e26a 100644 --- a/drivers/char/drm/radeon_irq.c +++ b/drivers/char/drm/radeon_irq.c @@ -123,11 +123,6 @@ static int radeon_wait_irq(drm_device_t *dev, int swi_nr) dev_priv->stats.boxes |= RADEON_BOX_WAIT_IDLE; - /* This is a hack to work around mysterious freezes on certain - * systems: - */ - radeon_acknowledge_irqs( dev_priv ); - DRM_WAIT_ON( ret, dev_priv->swi_queue, 3 * DRM_HZ, RADEON_READ( RADEON_LAST_SWI_REG ) >= swi_nr ); diff --git a/drivers/char/ds1620.c b/drivers/char/ds1620.c index 7def6ad5179..62cda25724e 100644 --- a/drivers/char/ds1620.c +++ b/drivers/char/ds1620.c @@ -163,8 +163,7 @@ static void ds1620_out(int cmd, int bits, int value) netwinder_ds1620_reset(); netwinder_unlock(&flags); - set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(2); + msleep(20); } static unsigned int ds1620_in(int cmd, int bits) diff --git a/drivers/char/dsp56k.c b/drivers/char/dsp56k.c index 37d6649011a..26271e3ca82 100644 --- a/drivers/char/dsp56k.c +++ b/drivers/char/dsp56k.c @@ -144,7 +144,7 @@ static struct dsp56k_device { int tx_wsize, rx_wsize; } dsp56k; -static struct class_simple *dsp56k_class; +static struct class *dsp56k_class; static int dsp56k_reset(void) { @@ -510,12 +510,12 @@ static int __init dsp56k_init_driver(void) printk("DSP56k driver: Unable to register driver\n"); return -ENODEV; } - dsp56k_class = class_simple_create(THIS_MODULE, "dsp56k"); + dsp56k_class = class_create(THIS_MODULE, "dsp56k"); if (IS_ERR(dsp56k_class)) { err = PTR_ERR(dsp56k_class); goto out_chrdev; } - class_simple_device_add(dsp56k_class, MKDEV(DSP56K_MAJOR, 0), NULL, "dsp56k"); + class_device_create(dsp56k_class, MKDEV(DSP56K_MAJOR, 0), NULL, "dsp56k"); err = devfs_mk_cdev(MKDEV(DSP56K_MAJOR, 0), S_IFCHR | S_IRUSR | S_IWUSR, "dsp56k"); @@ -526,8 +526,8 @@ static int __init dsp56k_init_driver(void) goto out; out_class: - class_simple_device_remove(MKDEV(DSP56K_MAJOR, 0)); - class_simple_destroy(dsp56k_class); + class_device_destroy(dsp56k_class, MKDEV(DSP56K_MAJOR, 0)); + class_destroy(dsp56k_class); out_chrdev: unregister_chrdev(DSP56K_MAJOR, "dsp56k"); out: @@ -537,8 +537,8 @@ module_init(dsp56k_init_driver); static void __exit dsp56k_cleanup_driver(void) { - class_simple_device_remove(MKDEV(DSP56K_MAJOR, 0)); - class_simple_destroy(dsp56k_class); + class_device_destroy(dsp56k_class, MKDEV(DSP56K_MAJOR, 0)); + class_destroy(dsp56k_class); unregister_chrdev(DSP56K_MAJOR, "dsp56k"); devfs_remove("dsp56k"); } diff --git a/drivers/char/ftape/compressor/zftape-compress.c b/drivers/char/ftape/compressor/zftape-compress.c index 220a227e606..65ffc0be3df 100644 --- a/drivers/char/ftape/compressor/zftape-compress.c +++ b/drivers/char/ftape/compressor/zftape-compress.c @@ -1176,8 +1176,8 @@ KERN_INFO "Compressor for zftape (lzrw3 algorithm)\n"); } #else /* !MODULE */ /* print a short no-nonsense boot message */ - printk("zftape compressor v1.00a 970514\n"); - printk("For use with " FTAPE_VERSION "\n"); + printk(KERN_INFO "zftape compressor v1.00a 970514\n"); + printk(KERN_INFO "For use with " FTAPE_VERSION "\n"); #endif /* MODULE */ TRACE(ft_t_info, "zft_compressor_init @ 0x%p", zft_compressor_init); TRACE(ft_t_info, "installing compressor for zftape ..."); diff --git a/drivers/char/ftape/zftape/zftape-init.c b/drivers/char/ftape/zftape/zftape-init.c index dbac7e54e8e..5745b74044e 100644 --- a/drivers/char/ftape/zftape/zftape-init.c +++ b/drivers/char/ftape/zftape/zftape-init.c @@ -99,7 +99,7 @@ static struct file_operations zft_cdev = .release = zft_close, }; -static struct class_simple *zft_class; +static struct class *zft_class; /* Open floppy tape device */ @@ -329,29 +329,29 @@ KERN_INFO "installing zftape VFS interface for ftape driver ..."); TRACE_CATCH(register_chrdev(QIC117_TAPE_MAJOR, "zft", &zft_cdev),); - zft_class = class_simple_create(THIS_MODULE, "zft"); + zft_class = class_create(THIS_MODULE, "zft"); for (i = 0; i < 4; i++) { - class_simple_device_add(zft_class, MKDEV(QIC117_TAPE_MAJOR, i), NULL, "qft%i", i); + class_device_create(zft_class, MKDEV(QIC117_TAPE_MAJOR, i), NULL, "qft%i", i); devfs_mk_cdev(MKDEV(QIC117_TAPE_MAJOR, i), S_IFCHR | S_IRUSR | S_IWUSR, "qft%i", i); - class_simple_device_add(zft_class, MKDEV(QIC117_TAPE_MAJOR, i + 4), NULL, "nqft%i", i); + class_device_create(zft_class, MKDEV(QIC117_TAPE_MAJOR, i + 4), NULL, "nqft%i", i); devfs_mk_cdev(MKDEV(QIC117_TAPE_MAJOR, i + 4), S_IFCHR | S_IRUSR | S_IWUSR, "nqft%i", i); - class_simple_device_add(zft_class, MKDEV(QIC117_TAPE_MAJOR, i + 16), NULL, "zqft%i", i); + class_device_create(zft_class, MKDEV(QIC117_TAPE_MAJOR, i + 16), NULL, "zqft%i", i); devfs_mk_cdev(MKDEV(QIC117_TAPE_MAJOR, i + 16), S_IFCHR | S_IRUSR | S_IWUSR, "zqft%i", i); - class_simple_device_add(zft_class, MKDEV(QIC117_TAPE_MAJOR, i + 20), NULL, "nzqft%i", i); + class_device_create(zft_class, MKDEV(QIC117_TAPE_MAJOR, i + 20), NULL, "nzqft%i", i); devfs_mk_cdev(MKDEV(QIC117_TAPE_MAJOR, i + 20), S_IFCHR | S_IRUSR | S_IWUSR, "nzqft%i", i); - class_simple_device_add(zft_class, MKDEV(QIC117_TAPE_MAJOR, i + 32), NULL, "rawqft%i", i); + class_device_create(zft_class, MKDEV(QIC117_TAPE_MAJOR, i + 32), NULL, "rawqft%i", i); devfs_mk_cdev(MKDEV(QIC117_TAPE_MAJOR, i + 32), S_IFCHR | S_IRUSR | S_IWUSR, "rawqft%i", i); - class_simple_device_add(zft_class, MKDEV(QIC117_TAPE_MAJOR, i + 36), NULL, "nrawrawqft%i", i); + class_device_create(zft_class, MKDEV(QIC117_TAPE_MAJOR, i + 36), NULL, "nrawrawqft%i", i); devfs_mk_cdev(MKDEV(QIC117_TAPE_MAJOR, i + 36), S_IFCHR | S_IRUSR | S_IWUSR, "nrawqft%i", i); @@ -381,19 +381,19 @@ static void zft_exit(void) } for (i = 0; i < 4; i++) { devfs_remove("qft%i", i); - class_simple_device_remove(MKDEV(QIC117_TAPE_MAJOR, i)); + class_device_destroy(zft_class, MKDEV(QIC117_TAPE_MAJOR, i)); devfs_remove("nqft%i", i); - class_simple_device_remove(MKDEV(QIC117_TAPE_MAJOR, i + 4)); + class_device_destroy(zft_class, MKDEV(QIC117_TAPE_MAJOR, i + 4)); devfs_remove("zqft%i", i); - class_simple_device_remove(MKDEV(QIC117_TAPE_MAJOR, i + 16)); + class_device_destroy(zft_class, MKDEV(QIC117_TAPE_MAJOR, i + 16)); devfs_remove("nzqft%i", i); - class_simple_device_remove(MKDEV(QIC117_TAPE_MAJOR, i + 20)); + class_device_destroy(zft_class, MKDEV(QIC117_TAPE_MAJOR, i + 20)); devfs_remove("rawqft%i", i); - class_simple_device_remove(MKDEV(QIC117_TAPE_MAJOR, i + 32)); + class_device_destroy(zft_class, MKDEV(QIC117_TAPE_MAJOR, i + 32)); devfs_remove("nrawqft%i", i); - class_simple_device_remove(MKDEV(QIC117_TAPE_MAJOR, i + 36)); + class_device_destroy(zft_class, MKDEV(QIC117_TAPE_MAJOR, i + 36)); } - class_simple_destroy(zft_class); + class_destroy(zft_class); zft_uninit_mem(); /* release remaining memory, if any */ printk(KERN_INFO "zftape successfully unloaded.\n"); TRACE_EXIT; diff --git a/drivers/char/hpet.c b/drivers/char/hpet.c index 5ec732e6ca9..762fa430fb5 100644 --- a/drivers/char/hpet.c +++ b/drivers/char/hpet.c @@ -834,7 +834,7 @@ int hpet_alloc(struct hpet_data *hdp) printk("\n"); ns = hpetp->hp_period; /* femptoseconds, 10^-15 */ - do_div(ns, 1000000); /* convert to nanoseconds, 10^-9 */ + ns /= 1000000; /* convert to nanoseconds, 10^-9 */ printk(KERN_INFO "hpet%d: %ldns tick, %d %d-bit timers\n", hpetp->hp_which, ns, hpetp->hp_ntimer, cap & HPET_COUNTER_SIZE_MASK ? 64 : 32); diff --git a/drivers/char/hvcs.c b/drivers/char/hvcs.c index abfbdcfd4e7..3236d240490 100644 --- a/drivers/char/hvcs.c +++ b/drivers/char/hvcs.c @@ -1466,7 +1466,7 @@ static inline struct hvcs_struct *from_vio_dev(struct vio_dev *viod) } /* The sysfs interface for the driver and devices */ -static ssize_t hvcs_partner_vtys_show(struct device *dev, char *buf) +static ssize_t hvcs_partner_vtys_show(struct device *dev, struct device_attribute *attr, char *buf) { struct vio_dev *viod = to_vio_dev(dev); struct hvcs_struct *hvcsd = from_vio_dev(viod); @@ -1480,7 +1480,7 @@ static ssize_t hvcs_partner_vtys_show(struct device *dev, char *buf) } static DEVICE_ATTR(partner_vtys, S_IRUGO, hvcs_partner_vtys_show, NULL); -static ssize_t hvcs_partner_clcs_show(struct device *dev, char *buf) +static ssize_t hvcs_partner_clcs_show(struct device *dev, struct device_attribute *attr, char *buf) { struct vio_dev *viod = to_vio_dev(dev); struct hvcs_struct *hvcsd = from_vio_dev(viod); @@ -1494,7 +1494,7 @@ static ssize_t hvcs_partner_clcs_show(struct device *dev, char *buf) } static DEVICE_ATTR(partner_clcs, S_IRUGO, hvcs_partner_clcs_show, NULL); -static ssize_t hvcs_current_vty_store(struct device *dev, const char * buf, +static ssize_t hvcs_current_vty_store(struct device *dev, struct device_attribute *attr, const char * buf, size_t count) { /* @@ -1505,7 +1505,7 @@ static ssize_t hvcs_current_vty_store(struct device *dev, const char * buf, return -EPERM; } -static ssize_t hvcs_current_vty_show(struct device *dev, char *buf) +static ssize_t hvcs_current_vty_show(struct device *dev, struct device_attribute *attr, char *buf) { struct vio_dev *viod = to_vio_dev(dev); struct hvcs_struct *hvcsd = from_vio_dev(viod); @@ -1521,7 +1521,7 @@ static ssize_t hvcs_current_vty_show(struct device *dev, char *buf) static DEVICE_ATTR(current_vty, S_IRUGO | S_IWUSR, hvcs_current_vty_show, hvcs_current_vty_store); -static ssize_t hvcs_vterm_state_store(struct device *dev, const char *buf, +static ssize_t hvcs_vterm_state_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct vio_dev *viod = to_vio_dev(dev); @@ -1559,7 +1559,7 @@ static ssize_t hvcs_vterm_state_store(struct device *dev, const char *buf, return count; } -static ssize_t hvcs_vterm_state_show(struct device *dev, char *buf) +static ssize_t hvcs_vterm_state_show(struct device *dev, struct device_attribute *attr, char *buf) { struct vio_dev *viod = to_vio_dev(dev); struct hvcs_struct *hvcsd = from_vio_dev(viod); @@ -1574,7 +1574,7 @@ static ssize_t hvcs_vterm_state_show(struct device *dev, char *buf) static DEVICE_ATTR(vterm_state, S_IRUGO | S_IWUSR, hvcs_vterm_state_show, hvcs_vterm_state_store); -static ssize_t hvcs_index_show(struct device *dev, char *buf) +static ssize_t hvcs_index_show(struct device *dev, struct device_attribute *attr, char *buf) { struct vio_dev *viod = to_vio_dev(dev); struct hvcs_struct *hvcsd = from_vio_dev(viod); diff --git a/drivers/char/i8k.c b/drivers/char/i8k.c index a8119764028..6c4b3f986d0 100644 --- a/drivers/char/i8k.c +++ b/drivers/char/i8k.c @@ -20,13 +20,14 @@ #include <linux/types.h> #include <linux/init.h> #include <linux/proc_fs.h> -#include <linux/apm_bios.h> +#include <linux/seq_file.h> +#include <linux/dmi.h> #include <asm/uaccess.h> #include <asm/io.h> #include <linux/i8k.h> -#define I8K_VERSION "1.13 14/05/2002" +#define I8K_VERSION "1.14 21/02/2005" #define I8K_SMM_FN_STATUS 0x0025 #define I8K_SMM_POWER_STATUS 0x0069 @@ -34,7 +35,8 @@ #define I8K_SMM_GET_FAN 0x00a3 #define I8K_SMM_GET_SPEED 0x02a3 #define I8K_SMM_GET_TEMP 0x10a3 -#define I8K_SMM_GET_DELL_SIG 0xffa3 +#define I8K_SMM_GET_DELL_SIG1 0xfea3 +#define I8K_SMM_GET_DELL_SIG2 0xffa3 #define I8K_SMM_BIOS_VERSION 0x00a6 #define I8K_FAN_MULT 30 @@ -52,18 +54,7 @@ #define I8K_TEMPERATURE_BUG 1 -#define DELL_SIGNATURE "Dell Computer" - -static char *supported_models[] = { - "Inspiron", - "Latitude", - NULL -}; - -static char system_vendor[48] = "?"; -static char product_name [48] = "?"; -static char bios_version [4] = "?"; -static char serial_number[16] = "?"; +static char bios_version[4]; MODULE_AUTHOR("Massimo Dal Zotto (dz@debian.org)"); MODULE_DESCRIPTION("Driver for accessing SMM BIOS on Dell laptops"); @@ -73,6 +64,10 @@ static int force; module_param(force, bool, 0); MODULE_PARM_DESC(force, "Force loading without checking for supported models"); +static int ignore_dmi; +module_param(ignore_dmi, bool, 0); +MODULE_PARM_DESC(ignore_dmi, "Continue probing hardware even if DMI data does not match"); + static int restricted; module_param(restricted, bool, 0); MODULE_PARM_DESC(restricted, "Allow fan control if SYS_ADMIN capability set"); @@ -81,69 +76,69 @@ static int power_status; module_param(power_status, bool, 0600); MODULE_PARM_DESC(power_status, "Report power status in /proc/i8k"); -static ssize_t i8k_read(struct file *, char __user *, size_t, loff_t *); +static int i8k_open_fs(struct inode *inode, struct file *file); static int i8k_ioctl(struct inode *, struct file *, unsigned int, unsigned long); static struct file_operations i8k_fops = { - .read = i8k_read, - .ioctl = i8k_ioctl, + .open = i8k_open_fs, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, + .ioctl = i8k_ioctl, +}; + +struct smm_regs { + unsigned int eax; + unsigned int ebx __attribute__ ((packed)); + unsigned int ecx __attribute__ ((packed)); + unsigned int edx __attribute__ ((packed)); + unsigned int esi __attribute__ ((packed)); + unsigned int edi __attribute__ ((packed)); }; -typedef struct { - unsigned int eax; - unsigned int ebx __attribute__ ((packed)); - unsigned int ecx __attribute__ ((packed)); - unsigned int edx __attribute__ ((packed)); - unsigned int esi __attribute__ ((packed)); - unsigned int edi __attribute__ ((packed)); -} SMMRegisters; - -typedef struct { - u8 type; - u8 length; - u16 handle; -} DMIHeader; +static inline char *i8k_get_dmi_data(int field) +{ + return dmi_get_system_info(field) ? : "N/A"; +} /* * Call the System Management Mode BIOS. Code provided by Jonathan Buzzard. */ -static int i8k_smm(SMMRegisters *regs) +static int i8k_smm(struct smm_regs *regs) { - int rc; - int eax = regs->eax; - - asm("pushl %%eax\n\t" \ - "movl 0(%%eax),%%edx\n\t" \ - "push %%edx\n\t" \ - "movl 4(%%eax),%%ebx\n\t" \ - "movl 8(%%eax),%%ecx\n\t" \ - "movl 12(%%eax),%%edx\n\t" \ - "movl 16(%%eax),%%esi\n\t" \ - "movl 20(%%eax),%%edi\n\t" \ - "popl %%eax\n\t" \ - "out %%al,$0xb2\n\t" \ - "out %%al,$0x84\n\t" \ - "xchgl %%eax,(%%esp)\n\t" - "movl %%ebx,4(%%eax)\n\t" \ - "movl %%ecx,8(%%eax)\n\t" \ - "movl %%edx,12(%%eax)\n\t" \ - "movl %%esi,16(%%eax)\n\t" \ - "movl %%edi,20(%%eax)\n\t" \ - "popl %%edx\n\t" \ - "movl %%edx,0(%%eax)\n\t" \ - "lahf\n\t" \ - "shrl $8,%%eax\n\t" \ - "andl $1,%%eax\n" \ - : "=a" (rc) - : "a" (regs) - : "%ebx", "%ecx", "%edx", "%esi", "%edi", "memory"); - - if ((rc != 0) || ((regs->eax & 0xffff) == 0xffff) || (regs->eax == eax)) { - return -EINVAL; - } - - return 0; + int rc; + int eax = regs->eax; + + asm("pushl %%eax\n\t" + "movl 0(%%eax),%%edx\n\t" + "push %%edx\n\t" + "movl 4(%%eax),%%ebx\n\t" + "movl 8(%%eax),%%ecx\n\t" + "movl 12(%%eax),%%edx\n\t" + "movl 16(%%eax),%%esi\n\t" + "movl 20(%%eax),%%edi\n\t" + "popl %%eax\n\t" + "out %%al,$0xb2\n\t" + "out %%al,$0x84\n\t" + "xchgl %%eax,(%%esp)\n\t" + "movl %%ebx,4(%%eax)\n\t" + "movl %%ecx,8(%%eax)\n\t" + "movl %%edx,12(%%eax)\n\t" + "movl %%esi,16(%%eax)\n\t" + "movl %%edi,20(%%eax)\n\t" + "popl %%edx\n\t" + "movl %%edx,0(%%eax)\n\t" + "lahf\n\t" + "shrl $8,%%eax\n\t" + "andl $1,%%eax\n":"=a"(rc) + : "a"(regs) + : "%ebx", "%ecx", "%edx", "%esi", "%edi", "memory"); + + if (rc != 0 || (regs->eax & 0xffff) == 0xffff || regs->eax == eax) + return -EINVAL; + + return 0; } /* @@ -152,24 +147,9 @@ static int i8k_smm(SMMRegisters *regs) */ static int i8k_get_bios_version(void) { - SMMRegisters regs = { 0, 0, 0, 0, 0, 0 }; - int rc; - - regs.eax = I8K_SMM_BIOS_VERSION; - if ((rc=i8k_smm(®s)) < 0) { - return rc; - } - - return regs.eax; -} + struct smm_regs regs = { .eax = I8K_SMM_BIOS_VERSION, }; -/* - * Read the machine id. - */ -static int i8k_get_serial_number(unsigned char *buff) -{ - strlcpy(buff, serial_number, sizeof(serial_number)); - return 0; + return i8k_smm(®s) ? : regs.eax; } /* @@ -177,24 +157,22 @@ static int i8k_get_serial_number(unsigned char *buff) */ static int i8k_get_fn_status(void) { - SMMRegisters regs = { 0, 0, 0, 0, 0, 0 }; - int rc; - - regs.eax = I8K_SMM_FN_STATUS; - if ((rc=i8k_smm(®s)) < 0) { - return rc; - } - - switch ((regs.eax >> I8K_FN_SHIFT) & I8K_FN_MASK) { - case I8K_FN_UP: - return I8K_VOL_UP; - case I8K_FN_DOWN: - return I8K_VOL_DOWN; - case I8K_FN_MUTE: - return I8K_VOL_MUTE; - default: - return 0; - } + struct smm_regs regs = { .eax = I8K_SMM_FN_STATUS, }; + int rc; + + if ((rc = i8k_smm(®s)) < 0) + return rc; + + switch ((regs.eax >> I8K_FN_SHIFT) & I8K_FN_MASK) { + case I8K_FN_UP: + return I8K_VOL_UP; + case I8K_FN_DOWN: + return I8K_VOL_DOWN; + case I8K_FN_MUTE: + return I8K_VOL_MUTE; + default: + return 0; + } } /* @@ -202,20 +180,13 @@ static int i8k_get_fn_status(void) */ static int i8k_get_power_status(void) { - SMMRegisters regs = { 0, 0, 0, 0, 0, 0 }; - int rc; - - regs.eax = I8K_SMM_POWER_STATUS; - if ((rc=i8k_smm(®s)) < 0) { - return rc; - } - - switch (regs.eax & 0xff) { - case I8K_POWER_AC: - return I8K_AC; - default: - return I8K_BATTERY; - } + struct smm_regs regs = { .eax = I8K_SMM_POWER_STATUS, }; + int rc; + + if ((rc = i8k_smm(®s)) < 0) + return rc; + + return (regs.eax & 0xff) == I8K_POWER_AC ? I8K_AC : I8K_BATTERY; } /* @@ -223,16 +194,10 @@ static int i8k_get_power_status(void) */ static int i8k_get_fan_status(int fan) { - SMMRegisters regs = { 0, 0, 0, 0, 0, 0 }; - int rc; - - regs.eax = I8K_SMM_GET_FAN; - regs.ebx = fan & 0xff; - if ((rc=i8k_smm(®s)) < 0) { - return rc; - } + struct smm_regs regs = { .eax = I8K_SMM_GET_FAN, }; - return (regs.eax & 0xff); + regs.ebx = fan & 0xff; + return i8k_smm(®s) ? : regs.eax & 0xff; } /* @@ -240,16 +205,10 @@ static int i8k_get_fan_status(int fan) */ static int i8k_get_fan_speed(int fan) { - SMMRegisters regs = { 0, 0, 0, 0, 0, 0 }; - int rc; + struct smm_regs regs = { .eax = I8K_SMM_GET_SPEED, }; - regs.eax = I8K_SMM_GET_SPEED; - regs.ebx = fan & 0xff; - if ((rc=i8k_smm(®s)) < 0) { - return rc; - } - - return (regs.eax & 0xffff) * I8K_FAN_MULT; + regs.ebx = fan & 0xff; + return i8k_smm(®s) ? : (regs.eax & 0xffff) * I8K_FAN_MULT; } /* @@ -257,532 +216,318 @@ static int i8k_get_fan_speed(int fan) */ static int i8k_set_fan(int fan, int speed) { - SMMRegisters regs = { 0, 0, 0, 0, 0, 0 }; - int rc; - - speed = (speed < 0) ? 0 : ((speed > I8K_FAN_MAX) ? I8K_FAN_MAX : speed); + struct smm_regs regs = { .eax = I8K_SMM_SET_FAN, }; - regs.eax = I8K_SMM_SET_FAN; - regs.ebx = (fan & 0xff) | (speed << 8); - if ((rc=i8k_smm(®s)) < 0) { - return rc; - } + speed = (speed < 0) ? 0 : ((speed > I8K_FAN_MAX) ? I8K_FAN_MAX : speed); + regs.ebx = (fan & 0xff) | (speed << 8); - return (i8k_get_fan_status(fan)); + return i8k_smm(®s) ? : i8k_get_fan_status(fan); } /* * Read the cpu temperature. */ -static int i8k_get_cpu_temp(void) +static int i8k_get_temp(int sensor) { - SMMRegisters regs = { 0, 0, 0, 0, 0, 0 }; - int rc; - int temp; + struct smm_regs regs = { .eax = I8K_SMM_GET_TEMP, }; + int rc; + int temp; #ifdef I8K_TEMPERATURE_BUG - static int prev = 0; + static int prev; #endif + regs.ebx = sensor & 0xff; + if ((rc = i8k_smm(®s)) < 0) + return rc; - regs.eax = I8K_SMM_GET_TEMP; - if ((rc=i8k_smm(®s)) < 0) { - return rc; - } - temp = regs.eax & 0xff; + temp = regs.eax & 0xff; #ifdef I8K_TEMPERATURE_BUG - /* - * Sometimes the temperature sensor returns 0x99, which is out of range. - * In this case we return (once) the previous cached value. For example: - # 1003655137 00000058 00005a4b - # 1003655138 00000099 00003a80 <--- 0x99 = 153 degrees - # 1003655139 00000054 00005c52 - */ - if (temp > I8K_MAX_TEMP) { - temp = prev; - prev = I8K_MAX_TEMP; - } else { - prev = temp; - } + /* + * Sometimes the temperature sensor returns 0x99, which is out of range. + * In this case we return (once) the previous cached value. For example: + # 1003655137 00000058 00005a4b + # 1003655138 00000099 00003a80 <--- 0x99 = 153 degrees + # 1003655139 00000054 00005c52 + */ + if (temp > I8K_MAX_TEMP) { + temp = prev; + prev = I8K_MAX_TEMP; + } else { + prev = temp; + } #endif - return temp; + return temp; } -static int i8k_get_dell_signature(void) +static int i8k_get_dell_signature(int req_fn) { - SMMRegisters regs = { 0, 0, 0, 0, 0, 0 }; - int rc; + struct smm_regs regs = { .eax = req_fn, }; + int rc; - regs.eax = I8K_SMM_GET_DELL_SIG; - if ((rc=i8k_smm(®s)) < 0) { - return rc; - } + if ((rc = i8k_smm(®s)) < 0) + return rc; - if ((regs.eax == 1145651527) && (regs.edx == 1145392204)) { - return 0; - } else { - return -1; - } + return regs.eax == 1145651527 && regs.edx == 1145392204 ? 0 : -1; } static int i8k_ioctl(struct inode *ip, struct file *fp, unsigned int cmd, unsigned long arg) { - int val; - int speed; - unsigned char buff[16]; - int __user *argp = (int __user *)arg; - - if (!argp) - return -EINVAL; - - switch (cmd) { - case I8K_BIOS_VERSION: - val = i8k_get_bios_version(); - break; - - case I8K_MACHINE_ID: - memset(buff, 0, 16); - val = i8k_get_serial_number(buff); - break; - - case I8K_FN_STATUS: - val = i8k_get_fn_status(); - break; - - case I8K_POWER_STATUS: - val = i8k_get_power_status(); - break; - - case I8K_GET_TEMP: - val = i8k_get_cpu_temp(); - break; - - case I8K_GET_SPEED: - if (copy_from_user(&val, argp, sizeof(int))) { - return -EFAULT; - } - val = i8k_get_fan_speed(val); - break; - - case I8K_GET_FAN: - if (copy_from_user(&val, argp, sizeof(int))) { - return -EFAULT; - } - val = i8k_get_fan_status(val); - break; + int val = 0; + int speed; + unsigned char buff[16]; + int __user *argp = (int __user *)arg; - case I8K_SET_FAN: - if (restricted && !capable(CAP_SYS_ADMIN)) { - return -EPERM; - } - if (copy_from_user(&val, argp, sizeof(int))) { - return -EFAULT; - } - if (copy_from_user(&speed, argp+1, sizeof(int))) { - return -EFAULT; - } - val = i8k_set_fan(val, speed); - break; + if (!argp) + return -EINVAL; - default: - return -EINVAL; - } + switch (cmd) { + case I8K_BIOS_VERSION: + val = i8k_get_bios_version(); + break; - if (val < 0) { - return val; - } + case I8K_MACHINE_ID: + memset(buff, 0, 16); + strlcpy(buff, i8k_get_dmi_data(DMI_PRODUCT_SERIAL), sizeof(buff)); + break; - switch (cmd) { - case I8K_BIOS_VERSION: - if (copy_to_user(argp, &val, 4)) { - return -EFAULT; - } - break; - case I8K_MACHINE_ID: - if (copy_to_user(argp, buff, 16)) { - return -EFAULT; - } - break; - default: - if (copy_to_user(argp, &val, sizeof(int))) { - return -EFAULT; - } - break; - } + case I8K_FN_STATUS: + val = i8k_get_fn_status(); + break; - return 0; -} + case I8K_POWER_STATUS: + val = i8k_get_power_status(); + break; -/* - * Print the information for /proc/i8k. - */ -static int i8k_get_info(char *buffer, char **start, off_t fpos, int length) -{ - int n, fn_key, cpu_temp, ac_power; - int left_fan, right_fan, left_speed, right_speed; - - cpu_temp = i8k_get_cpu_temp(); /* 11100 µs */ - left_fan = i8k_get_fan_status(I8K_FAN_LEFT); /* 580 µs */ - right_fan = i8k_get_fan_status(I8K_FAN_RIGHT); /* 580 µs */ - left_speed = i8k_get_fan_speed(I8K_FAN_LEFT); /* 580 µs */ - right_speed = i8k_get_fan_speed(I8K_FAN_RIGHT); /* 580 µs */ - fn_key = i8k_get_fn_status(); /* 750 µs */ - if (power_status) { - ac_power = i8k_get_power_status(); /* 14700 µs */ - } else { - ac_power = -1; - } - - /* - * Info: - * - * 1) Format version (this will change if format changes) - * 2) BIOS version - * 3) BIOS machine ID - * 4) Cpu temperature - * 5) Left fan status - * 6) Right fan status - * 7) Left fan speed - * 8) Right fan speed - * 9) AC power - * 10) Fn Key status - */ - n = sprintf(buffer, "%s %s %s %d %d %d %d %d %d %d\n", - I8K_PROC_FMT, - bios_version, - serial_number, - cpu_temp, - left_fan, - right_fan, - left_speed, - right_speed, - ac_power, - fn_key); - - return n; -} + case I8K_GET_TEMP: + val = i8k_get_temp(0); + break; -static ssize_t i8k_read(struct file *f, char __user *buffer, size_t len, loff_t *fpos) -{ - int n; - char info[128]; + case I8K_GET_SPEED: + if (copy_from_user(&val, argp, sizeof(int))) + return -EFAULT; - n = i8k_get_info(info, NULL, 0, 128); - if (n <= 0) { - return n; - } + val = i8k_get_fan_speed(val); + break; - if (*fpos >= n) { - return 0; - } + case I8K_GET_FAN: + if (copy_from_user(&val, argp, sizeof(int))) + return -EFAULT; - if ((*fpos + len) >= n) { - len = n - *fpos; - } + val = i8k_get_fan_status(val); + break; - if (copy_to_user(buffer, info, len) != 0) { - return -EFAULT; - } + case I8K_SET_FAN: + if (restricted && !capable(CAP_SYS_ADMIN)) + return -EPERM; - *fpos += len; - return len; -} + if (copy_from_user(&val, argp, sizeof(int))) + return -EFAULT; -static char* __init string_trim(char *s, int size) -{ - int len; - char *p; + if (copy_from_user(&speed, argp + 1, sizeof(int))) + return -EFAULT; - if ((len = strlen(s)) > size) { - len = size; - } + val = i8k_set_fan(val, speed); + break; - for (p=s+len-1; len && (*p==' '); len--,p--) { - *p = '\0'; - } + default: + return -EINVAL; + } - return s; -} + if (val < 0) + return val; -/* DMI code, stolen from arch/i386/kernel/dmi_scan.c */ + switch (cmd) { + case I8K_BIOS_VERSION: + if (copy_to_user(argp, &val, 4)) + return -EFAULT; -/* - * |<-- dmi->length -->| - * | | - * |dmi header s=N | string1,\0, ..., stringN,\0, ..., \0 - * | | - * +-----------------------+ - */ -static char* __init dmi_string(DMIHeader *dmi, u8 s) -{ - u8 *p; + break; + case I8K_MACHINE_ID: + if (copy_to_user(argp, buff, 16)) + return -EFAULT; - if (!s) { - return ""; - } - s--; + break; + default: + if (copy_to_user(argp, &val, sizeof(int))) + return -EFAULT; - p = (u8 *)dmi + dmi->length; - while (s > 0) { - p += strlen(p); - p++; - s--; - } + break; + } - return p; + return 0; } -static void __init dmi_decode(DMIHeader *dmi) +/* + * Print the information for /proc/i8k. + */ +static int i8k_proc_show(struct seq_file *seq, void *offset) { - u8 *data = (u8 *) dmi; - char *p; - -#ifdef I8K_DEBUG - int i; - printk("%08x ", (int)data); - for (i=0; i<data[1] && i<64; i++) { - printk("%02x ", data[i]); - } - printk("\n"); -#endif - - switch (dmi->type) { - case 0: /* BIOS Information */ - p = dmi_string(dmi,data[5]); - if (*p) { - strlcpy(bios_version, p, sizeof(bios_version)); - string_trim(bios_version, sizeof(bios_version)); - } - break; - case 1: /* System Information */ - p = dmi_string(dmi,data[4]); - if (*p) { - strlcpy(system_vendor, p, sizeof(system_vendor)); - string_trim(system_vendor, sizeof(system_vendor)); - } - p = dmi_string(dmi,data[5]); - if (*p) { - strlcpy(product_name, p, sizeof(product_name)); - string_trim(product_name, sizeof(product_name)); - } - p = dmi_string(dmi,data[7]); - if (*p) { - strlcpy(serial_number, p, sizeof(serial_number)); - string_trim(serial_number, sizeof(serial_number)); - } - break; - } -} + int fn_key, cpu_temp, ac_power; + int left_fan, right_fan, left_speed, right_speed; + + cpu_temp = i8k_get_temp(0); /* 11100 µs */ + left_fan = i8k_get_fan_status(I8K_FAN_LEFT); /* 580 µs */ + right_fan = i8k_get_fan_status(I8K_FAN_RIGHT); /* 580 µs */ + left_speed = i8k_get_fan_speed(I8K_FAN_LEFT); /* 580 µs */ + right_speed = i8k_get_fan_speed(I8K_FAN_RIGHT); /* 580 µs */ + fn_key = i8k_get_fn_status(); /* 750 µs */ + if (power_status) + ac_power = i8k_get_power_status(); /* 14700 µs */ + else + ac_power = -1; -static int __init dmi_table(u32 base, int len, int num, void (*fn)(DMIHeader*)) -{ - u8 *buf; - u8 *data; - DMIHeader *dmi; - int i = 1; - - buf = ioremap(base, len); - if (buf == NULL) { - return -1; - } - data = buf; - - /* - * Stop when we see al the items the table claimed to have - * or we run off the end of the table (also happens) - */ - while ((i<num) && ((data-buf) < len)) { - dmi = (DMIHeader *)data; - /* - * Avoid misparsing crud if the length of the last - * record is crap - */ - if ((data-buf+dmi->length) >= len) { - break; - } - fn(dmi); - data += dmi->length; /* - * Don't go off the end of the data if there is - * stuff looking like string fill past the end + * Info: + * + * 1) Format version (this will change if format changes) + * 2) BIOS version + * 3) BIOS machine ID + * 4) Cpu temperature + * 5) Left fan status + * 6) Right fan status + * 7) Left fan speed + * 8) Right fan speed + * 9) AC power + * 10) Fn Key status */ - while (((data-buf) < len) && (*data || data[1])) { - data++; - } - data += 2; - i++; - } - iounmap(buf); - - return 0; + return seq_printf(seq, "%s %s %s %d %d %d %d %d %d %d\n", + I8K_PROC_FMT, + bios_version, + dmi_get_system_info(DMI_PRODUCT_SERIAL) ? : "N/A", + cpu_temp, + left_fan, right_fan, left_speed, right_speed, + ac_power, fn_key); } -static int __init dmi_iterate(void (*decode)(DMIHeader *)) +static int i8k_open_fs(struct inode *inode, struct file *file) { - unsigned char buf[20]; - void __iomem *p = ioremap(0xe0000, 0x20000), *q; - - if (!p) - return -1; - - for (q = p; q < p + 0x20000; q += 16) { - memcpy_fromio(buf, q, 20); - if (memcmp(buf, "_DMI_", 5)==0) { - u16 num = buf[13]<<8 | buf[12]; - u16 len = buf [7]<<8 | buf [6]; - u32 base = buf[11]<<24 | buf[10]<<16 | buf[9]<<8 | buf[8]; -#ifdef I8K_DEBUG - printk(KERN_INFO "DMI %d.%d present.\n", - buf[14]>>4, buf[14]&0x0F); - printk(KERN_INFO "%d structures occupying %d bytes.\n", - buf[13]<<8 | buf[12], - buf [7]<<8 | buf[6]); - printk(KERN_INFO "DMI table at 0x%08X.\n", - buf[11]<<24 | buf[10]<<16 | buf[9]<<8 | buf[8]); -#endif - if (dmi_table(base, len, num, decode)==0) { - iounmap(p); - return 0; - } - } - } - iounmap(p); - return -1; + return single_open(file, i8k_proc_show, NULL); } -/* end of DMI code */ - -/* - * Get DMI information. - */ -static int __init i8k_dmi_probe(void) -{ - char **p; - - if (dmi_iterate(dmi_decode) != 0) { - printk(KERN_INFO "i8k: unable to get DMI information\n"); - return -ENODEV; - } - - if (strncmp(system_vendor,DELL_SIGNATURE,strlen(DELL_SIGNATURE)) != 0) { - printk(KERN_INFO "i8k: not running on a Dell system\n"); - return -ENODEV; - } - - for (p=supported_models; ; p++) { - if (!*p) { - printk(KERN_INFO "i8k: unsupported model: %s\n", product_name); - return -ENODEV; - } - if (strncmp(product_name,*p,strlen(*p)) == 0) { - break; - } - } - return 0; -} +static struct dmi_system_id __initdata i8k_dmi_table[] = { + { + .ident = "Dell Inspiron", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell Computer"), + DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron"), + }, + }, + { + .ident = "Dell Latitude", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell Computer"), + DMI_MATCH(DMI_PRODUCT_NAME, "Latitude"), + }, + }, + { + .ident = "Dell Inspiron 2", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), + DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron"), + }, + }, + { + .ident = "Dell Latitude 2", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), + DMI_MATCH(DMI_PRODUCT_NAME, "Latitude"), + }, + }, + { } +}; /* * Probe for the presence of a supported laptop. */ static int __init i8k_probe(void) { - char buff[4]; - int version; - int smm_found = 0; - - /* - * Get DMI information - */ - if (i8k_dmi_probe() != 0) { - printk(KERN_INFO "i8k: vendor=%s, model=%s, version=%s\n", - system_vendor, product_name, bios_version); - } - - /* - * Get SMM Dell signature - */ - if (i8k_get_dell_signature() != 0) { - printk(KERN_INFO "i8k: unable to get SMM Dell signature\n"); - } else { - smm_found = 1; - } - - /* - * Get SMM BIOS version. - */ - version = i8k_get_bios_version(); - if (version <= 0) { - printk(KERN_INFO "i8k: unable to get SMM BIOS version\n"); - } else { - smm_found = 1; - buff[0] = (version >> 16) & 0xff; - buff[1] = (version >> 8) & 0xff; - buff[2] = (version) & 0xff; - buff[3] = '\0'; + char buff[4]; + int version; + /* - * If DMI BIOS version is unknown use SMM BIOS version. + * Get DMI information */ - if (bios_version[0] == '?') { - strcpy(bios_version, buff); + if (!dmi_check_system(i8k_dmi_table)) { + if (!ignore_dmi && !force) + return -ENODEV; + + printk(KERN_INFO "i8k: not running on a supported Dell system.\n"); + printk(KERN_INFO "i8k: vendor=%s, model=%s, version=%s\n", + i8k_get_dmi_data(DMI_SYS_VENDOR), + i8k_get_dmi_data(DMI_PRODUCT_NAME), + i8k_get_dmi_data(DMI_BIOS_VERSION)); } + + strlcpy(bios_version, i8k_get_dmi_data(DMI_BIOS_VERSION), sizeof(bios_version)); + /* - * Check if the two versions match. + * Get SMM Dell signature */ - if (strncmp(buff,bios_version,sizeof(bios_version)) != 0) { - printk(KERN_INFO "i8k: BIOS version mismatch: %s != %s\n", - buff, bios_version); + if (i8k_get_dell_signature(I8K_SMM_GET_DELL_SIG1) && + i8k_get_dell_signature(I8K_SMM_GET_DELL_SIG2)) { + printk(KERN_ERR "i8k: unable to get SMM Dell signature\n"); + if (!force) + return -ENODEV; } - } - if (!smm_found && !force) { - return -ENODEV; - } + /* + * Get SMM BIOS version. + */ + version = i8k_get_bios_version(); + if (version <= 0) { + printk(KERN_WARNING "i8k: unable to get SMM BIOS version\n"); + } else { + buff[0] = (version >> 16) & 0xff; + buff[1] = (version >> 8) & 0xff; + buff[2] = (version) & 0xff; + buff[3] = '\0'; + /* + * If DMI BIOS version is unknown use SMM BIOS version. + */ + if (!dmi_get_system_info(DMI_BIOS_VERSION)) + strlcpy(bios_version, buff, sizeof(bios_version)); + + /* + * Check if the two versions match. + */ + if (strncmp(buff, bios_version, sizeof(bios_version)) != 0) + printk(KERN_WARNING "i8k: BIOS version mismatch: %s != %s\n", + buff, bios_version); + } - return 0; + return 0; } -#ifdef MODULE -static -#endif -int __init i8k_init(void) +static int __init i8k_init(void) { - struct proc_dir_entry *proc_i8k; - - /* Are we running on an supported laptop? */ - if (i8k_probe() != 0) { - return -ENODEV; - } - - /* Register the proc entry */ - proc_i8k = create_proc_info_entry("i8k", 0, NULL, i8k_get_info); - if (!proc_i8k) { - return -ENOENT; - } - proc_i8k->proc_fops = &i8k_fops; - proc_i8k->owner = THIS_MODULE; - - printk(KERN_INFO - "Dell laptop SMM driver v%s Massimo Dal Zotto (dz@debian.org)\n", - I8K_VERSION); - - return 0; -} + struct proc_dir_entry *proc_i8k; -#ifdef MODULE -int init_module(void) -{ - return i8k_init(); + /* Are we running on an supported laptop? */ + if (i8k_probe()) + return -ENODEV; + + /* Register the proc entry */ + proc_i8k = create_proc_entry("i8k", 0, NULL); + if (!proc_i8k) + return -ENOENT; + + proc_i8k->proc_fops = &i8k_fops; + proc_i8k->owner = THIS_MODULE; + + printk(KERN_INFO + "Dell laptop SMM driver v%s Massimo Dal Zotto (dz@debian.org)\n", + I8K_VERSION); + + return 0; } -void cleanup_module(void) +static void __exit i8k_exit(void) { - /* Remove the proc entry */ - remove_proc_entry("i8k", NULL); - - printk(KERN_INFO "i8k: module unloaded\n"); + remove_proc_entry("i8k", NULL); } -#endif -/* end of file */ +module_init(i8k_init); +module_exit(i8k_exit); diff --git a/drivers/char/ip2/i2cmd.c b/drivers/char/ip2/i2cmd.c index fd299d6c42a..cb8f4198e9a 100644 --- a/drivers/char/ip2/i2cmd.c +++ b/drivers/char/ip2/i2cmd.c @@ -97,7 +97,7 @@ static UCHAR ct41[] = { 1, BYP, 0x29 }; // RESUME //static UCHAR ct44[]={ 2, BTH, 0x2C,0 }; // MS PING //static UCHAR ct45[]={ 1, BTH, 0x2D }; // HOTENAB //static UCHAR ct46[]={ 1, BTH, 0x2E }; // HOTDSAB -static UCHAR ct47[] = { 7, BTH, 0x2F,0,0,0,0,0,0 }; // UNIX FLAGS +//static UCHAR ct47[]={ 7, BTH, 0x2F,0,0,0,0,0,0 }; // UNIX FLAGS //static UCHAR ct48[]={ 1, BTH, 0x30 }; // DSRFLOWENAB //static UCHAR ct49[]={ 1, BTH, 0x31 }; // DSRFLOWDSAB //static UCHAR ct50[]={ 1, BTH, 0x32 }; // DTRFLOWENAB @@ -162,6 +162,7 @@ static UCHAR ct89[]={ 1, BYP, 0x59 }; // DSS_NOW // This routine sets the parameters of command 47 and returns a pointer to the // appropriate structure. //****************************************************************************** +#if 0 cmdSyntaxPtr i2cmdUnixFlags(unsigned short iflag,unsigned short cflag,unsigned short lflag) { @@ -175,6 +176,7 @@ i2cmdUnixFlags(unsigned short iflag,unsigned short cflag,unsigned short lflag) pCM->cmd[6] = (unsigned char) (lflag >> 8); return pCM; } +#endif /* 0 */ //****************************************************************************** // Function: i2cmdBaudDef(which, rate) @@ -187,7 +189,7 @@ i2cmdUnixFlags(unsigned short iflag,unsigned short cflag,unsigned short lflag) // This routine sets the parameters of commands 54 or 55 (according to the // argument which), and returns a pointer to the appropriate structure. //****************************************************************************** -cmdSyntaxPtr +static cmdSyntaxPtr i2cmdBaudDef(int which, unsigned short rate) { cmdSyntaxPtr pCM; diff --git a/drivers/char/ip2/i2cmd.h b/drivers/char/ip2/i2cmd.h index c41728a8571..baa4e721b75 100644 --- a/drivers/char/ip2/i2cmd.h +++ b/drivers/char/ip2/i2cmd.h @@ -64,16 +64,6 @@ typedef struct _cmdSyntax // directly from user-level #define VAR 0x10 // This command is of variable length! -//----------------------------------- -// External declarations for i2cmd.c -//----------------------------------- -// Routine to set up parameters for the "define hot-key sequence" command. Since -// there is more than one parameter to assign, we must use a function rather -// than a macro (used usually). -// -extern cmdSyntaxPtr i2cmdUnixFlags(USHORT iflag,USHORT cflag,USHORT lflag); -extern cmdSyntaxPtr i2cmdBaudDef(int which, USHORT rate); - // Declarations for the global arrays used to bear the commands and their // arguments. // @@ -433,6 +423,7 @@ static UCHAR cc02[]; #define CMD_HOT_ENAB (cmdSyntaxPtr)(ct45) // Enable Hot-key checking #define CMD_HOT_DSAB (cmdSyntaxPtr)(ct46) // Disable Hot-key checking +#if 0 // COMMAND 47: Send Protocol info via Unix flags: // iflag = Unix tty t_iflag // cflag = Unix tty t_cflag @@ -441,6 +432,7 @@ static UCHAR cc02[]; // within these flags // #define CMD_UNIX_FLAGS(iflag,cflag,lflag) i2cmdUnixFlags(iflag,cflag,lflag) +#endif /* 0 */ #define CMD_DSRFL_ENAB (cmdSyntaxPtr)(ct48) // Enable DSR receiver ctrl #define CMD_DSRFL_DSAB (cmdSyntaxPtr)(ct49) // Disable DSR receiver ctrl diff --git a/drivers/char/ip2main.c b/drivers/char/ip2main.c index fca9a978fb7..cf0cd58d630 100644 --- a/drivers/char/ip2main.c +++ b/drivers/char/ip2main.c @@ -302,7 +302,7 @@ static char rirqs[IP2_MAX_BOARDS]; static int Valid_Irqs[] = { 3, 4, 5, 7, 10, 11, 12, 15, 0}; /* for sysfs class support */ -static struct class_simple *ip2_class; +static struct class *ip2_class; // Some functions to keep track of what irq's we have @@ -414,9 +414,9 @@ cleanup_module(void) iiResetDelay( i2BoardPtrTable[i] ); /* free io addresses and Tibet */ release_region( ip2config.addr[i], 8 ); - class_simple_device_remove(MKDEV(IP2_IPL_MAJOR, 4 * i)); + class_device_destroy(ip2_class, MKDEV(IP2_IPL_MAJOR, 4 * i)); devfs_remove("ip2/ipl%d", i); - class_simple_device_remove(MKDEV(IP2_IPL_MAJOR, 4 * i + 1)); + class_device_destroy(ip2_class, MKDEV(IP2_IPL_MAJOR, 4 * i + 1)); devfs_remove("ip2/stat%d", i); } /* Disable and remove interrupt handler. */ @@ -425,7 +425,7 @@ cleanup_module(void) clear_requested_irq( ip2config.irq[i]); } } - class_simple_destroy(ip2_class); + class_destroy(ip2_class); devfs_remove("ip2"); if ( ( err = tty_unregister_driver ( ip2_tty_driver ) ) ) { printk(KERN_ERR "IP2: failed to unregister tty driver (%d)\n", err); @@ -700,7 +700,7 @@ ip2_loadmain(int *iop, int *irqp, unsigned char *firmware, int firmsize) printk(KERN_ERR "IP2: failed to register IPL device (%d)\n", err ); } else { /* create the sysfs class */ - ip2_class = class_simple_create(THIS_MODULE, "ip2"); + ip2_class = class_create(THIS_MODULE, "ip2"); if (IS_ERR(ip2_class)) { err = PTR_ERR(ip2_class); goto out_chrdev; @@ -722,25 +722,25 @@ ip2_loadmain(int *iop, int *irqp, unsigned char *firmware, int firmsize) } if ( NULL != ( pB = i2BoardPtrTable[i] ) ) { - class_simple_device_add(ip2_class, MKDEV(IP2_IPL_MAJOR, + class_device_create(ip2_class, MKDEV(IP2_IPL_MAJOR, 4 * i), NULL, "ipl%d", i); err = devfs_mk_cdev(MKDEV(IP2_IPL_MAJOR, 4 * i), S_IRUSR | S_IWUSR | S_IRGRP | S_IFCHR, "ip2/ipl%d", i); if (err) { - class_simple_device_remove(MKDEV(IP2_IPL_MAJOR, - 4 * i)); + class_device_destroy(ip2_class, + MKDEV(IP2_IPL_MAJOR, 4 * i)); goto out_class; } - class_simple_device_add(ip2_class, MKDEV(IP2_IPL_MAJOR, + class_device_create(ip2_class, MKDEV(IP2_IPL_MAJOR, 4 * i + 1), NULL, "stat%d", i); err = devfs_mk_cdev(MKDEV(IP2_IPL_MAJOR, 4 * i + 1), S_IRUSR | S_IWUSR | S_IRGRP | S_IFCHR, "ip2/stat%d", i); if (err) { - class_simple_device_remove(MKDEV(IP2_IPL_MAJOR, - 4 * i + 1)); + class_device_destroy(ip2_class, + MKDEV(IP2_IPL_MAJOR, 4 * i + 1)); goto out_class; } @@ -798,7 +798,7 @@ retry: goto out; out_class: - class_simple_destroy(ip2_class); + class_destroy(ip2_class); out_chrdev: unregister_chrdev(IP2_IPL_MAJOR, "ip2"); out: @@ -2691,16 +2691,6 @@ no_xon: pCh->flags |= ASYNC_CHECK_CD; } -#ifdef XXX -do_flags_thing: // This is a test, we don't do the flags thing - - if ( (cflag & CRTSCTS) ) { - cflag |= 014000000000; - } - i2QueueCommands(PTYPE_BYPASS, pCh, 100, 1, - CMD_UNIX_FLAGS(iflag,cflag,lflag)); -#endif - service_it: i2DrainOutput( pCh, 100 ); } diff --git a/drivers/char/ipmi/ipmi_devintf.c b/drivers/char/ipmi/ipmi_devintf.c index 4bb9af736fb..e0a53570fea 100644 --- a/drivers/char/ipmi/ipmi_devintf.c +++ b/drivers/char/ipmi/ipmi_devintf.c @@ -45,6 +45,7 @@ #include <asm/semaphore.h> #include <linux/init.h> #include <linux/device.h> +#include <linux/compat.h> #define IPMI_DEVINTF_VERSION "v33" @@ -500,10 +501,205 @@ static int ipmi_ioctl(struct inode *inode, return rv; } +#ifdef CONFIG_COMPAT + +/* + * The following code contains code for supporting 32-bit compatible + * ioctls on 64-bit kernels. This allows running 32-bit apps on the + * 64-bit kernel + */ +#define COMPAT_IPMICTL_SEND_COMMAND \ + _IOR(IPMI_IOC_MAGIC, 13, struct compat_ipmi_req) +#define COMPAT_IPMICTL_SEND_COMMAND_SETTIME \ + _IOR(IPMI_IOC_MAGIC, 21, struct compat_ipmi_req_settime) +#define COMPAT_IPMICTL_RECEIVE_MSG \ + _IOWR(IPMI_IOC_MAGIC, 12, struct compat_ipmi_recv) +#define COMPAT_IPMICTL_RECEIVE_MSG_TRUNC \ + _IOWR(IPMI_IOC_MAGIC, 11, struct compat_ipmi_recv) + +struct compat_ipmi_msg { + u8 netfn; + u8 cmd; + u16 data_len; + compat_uptr_t data; +}; + +struct compat_ipmi_req { + compat_uptr_t addr; + compat_uint_t addr_len; + compat_long_t msgid; + struct compat_ipmi_msg msg; +}; + +struct compat_ipmi_recv { + compat_int_t recv_type; + compat_uptr_t addr; + compat_uint_t addr_len; + compat_long_t msgid; + struct compat_ipmi_msg msg; +}; + +struct compat_ipmi_req_settime { + struct compat_ipmi_req req; + compat_int_t retries; + compat_uint_t retry_time_ms; +}; + +/* + * Define some helper functions for copying IPMI data + */ +static long get_compat_ipmi_msg(struct ipmi_msg *p64, + struct compat_ipmi_msg __user *p32) +{ + compat_uptr_t tmp; + + if (!access_ok(VERIFY_READ, p32, sizeof(*p32)) || + __get_user(p64->netfn, &p32->netfn) || + __get_user(p64->cmd, &p32->cmd) || + __get_user(p64->data_len, &p32->data_len) || + __get_user(tmp, &p32->data)) + return -EFAULT; + p64->data = compat_ptr(tmp); + return 0; +} + +static long put_compat_ipmi_msg(struct ipmi_msg *p64, + struct compat_ipmi_msg __user *p32) +{ + if (!access_ok(VERIFY_WRITE, p32, sizeof(*p32)) || + __put_user(p64->netfn, &p32->netfn) || + __put_user(p64->cmd, &p32->cmd) || + __put_user(p64->data_len, &p32->data_len)) + return -EFAULT; + return 0; +} + +static long get_compat_ipmi_req(struct ipmi_req *p64, + struct compat_ipmi_req __user *p32) +{ + + compat_uptr_t tmp; + + if (!access_ok(VERIFY_READ, p32, sizeof(*p32)) || + __get_user(tmp, &p32->addr) || + __get_user(p64->addr_len, &p32->addr_len) || + __get_user(p64->msgid, &p32->msgid) || + get_compat_ipmi_msg(&p64->msg, &p32->msg)) + return -EFAULT; + p64->addr = compat_ptr(tmp); + return 0; +} + +static long get_compat_ipmi_req_settime(struct ipmi_req_settime *p64, + struct compat_ipmi_req_settime __user *p32) +{ + if (!access_ok(VERIFY_READ, p32, sizeof(*p32)) || + get_compat_ipmi_req(&p64->req, &p32->req) || + __get_user(p64->retries, &p32->retries) || + __get_user(p64->retry_time_ms, &p32->retry_time_ms)) + return -EFAULT; + return 0; +} + +static long get_compat_ipmi_recv(struct ipmi_recv *p64, + struct compat_ipmi_recv __user *p32) +{ + compat_uptr_t tmp; + + if (!access_ok(VERIFY_READ, p32, sizeof(*p32)) || + __get_user(p64->recv_type, &p32->recv_type) || + __get_user(tmp, &p32->addr) || + __get_user(p64->addr_len, &p32->addr_len) || + __get_user(p64->msgid, &p32->msgid) || + get_compat_ipmi_msg(&p64->msg, &p32->msg)) + return -EFAULT; + p64->addr = compat_ptr(tmp); + return 0; +} + +static long put_compat_ipmi_recv(struct ipmi_recv *p64, + struct compat_ipmi_recv __user *p32) +{ + if (!access_ok(VERIFY_WRITE, p32, sizeof(*p32)) || + __put_user(p64->recv_type, &p32->recv_type) || + __put_user(p64->addr_len, &p32->addr_len) || + __put_user(p64->msgid, &p32->msgid) || + put_compat_ipmi_msg(&p64->msg, &p32->msg)) + return -EFAULT; + return 0; +} + +/* + * Handle compatibility ioctls + */ +static long compat_ipmi_ioctl(struct file *filep, unsigned int cmd, + unsigned long arg) +{ + int rc; + struct ipmi_file_private *priv = filep->private_data; + + switch(cmd) { + case COMPAT_IPMICTL_SEND_COMMAND: + { + struct ipmi_req rp; + + if (get_compat_ipmi_req(&rp, compat_ptr(arg))) + return -EFAULT; + + return handle_send_req(priv->user, &rp, + priv->default_retries, + priv->default_retry_time_ms); + } + case COMPAT_IPMICTL_SEND_COMMAND_SETTIME: + { + struct ipmi_req_settime sp; + + if (get_compat_ipmi_req_settime(&sp, compat_ptr(arg))) + return -EFAULT; + + return handle_send_req(priv->user, &sp.req, + sp.retries, sp.retry_time_ms); + } + case COMPAT_IPMICTL_RECEIVE_MSG: + case COMPAT_IPMICTL_RECEIVE_MSG_TRUNC: + { + struct ipmi_recv *precv64, recv64; + + if (get_compat_ipmi_recv(&recv64, compat_ptr(arg))) + return -EFAULT; + + precv64 = compat_alloc_user_space(sizeof(recv64)); + if (copy_to_user(precv64, &recv64, sizeof(recv64))) + return -EFAULT; + + rc = ipmi_ioctl(filep->f_dentry->d_inode, filep, + ((cmd == COMPAT_IPMICTL_RECEIVE_MSG) + ? IPMICTL_RECEIVE_MSG + : IPMICTL_RECEIVE_MSG_TRUNC), + (long) precv64); + if (rc != 0) + return rc; + + if (copy_from_user(&recv64, precv64, sizeof(recv64))) + return -EFAULT; + + if (put_compat_ipmi_recv(&recv64, compat_ptr(arg))) + return -EFAULT; + + return rc; + } + default: + return ipmi_ioctl(filep->f_dentry->d_inode, filep, cmd, arg); + } +} +#endif static struct file_operations ipmi_fops = { .owner = THIS_MODULE, .ioctl = ipmi_ioctl, +#ifdef CONFIG_COMPAT + .compat_ioctl = compat_ipmi_ioctl, +#endif .open = ipmi_open, .release = ipmi_release, .fasync = ipmi_fasync, @@ -529,12 +725,12 @@ static void ipmi_new_smi(int if_num) devfs_mk_cdev(dev, S_IFCHR | S_IRUSR | S_IWUSR, "ipmidev/%d", if_num); - class_simple_device_add(ipmi_class, dev, NULL, "ipmi%d", if_num); + class_device_create(ipmi_class, dev, NULL, "ipmi%d", if_num); } static void ipmi_smi_gone(int if_num) { - class_simple_device_remove(ipmi_class, MKDEV(ipmi_major, if_num)); + class_device_destroy(ipmi_class, MKDEV(ipmi_major, if_num)); devfs_remove("ipmidev/%d", if_num); } @@ -555,7 +751,7 @@ static __init int init_ipmi_devintf(void) printk(KERN_INFO "ipmi device interface version " IPMI_DEVINTF_VERSION "\n"); - ipmi_class = class_simple_create(THIS_MODULE, "ipmi"); + ipmi_class = class_create(THIS_MODULE, "ipmi"); if (IS_ERR(ipmi_class)) { printk(KERN_ERR "ipmi: can't register device class\n"); return PTR_ERR(ipmi_class); @@ -563,7 +759,7 @@ static __init int init_ipmi_devintf(void) rv = register_chrdev(ipmi_major, DEVICE_NAME, &ipmi_fops); if (rv < 0) { - class_simple_destroy(ipmi_class); + class_destroy(ipmi_class); printk(KERN_ERR "ipmi: can't get major %d\n", ipmi_major); return rv; } @@ -577,7 +773,7 @@ static __init int init_ipmi_devintf(void) rv = ipmi_smi_watcher_register(&smi_watcher); if (rv) { unregister_chrdev(ipmi_major, DEVICE_NAME); - class_simple_destroy(ipmi_class); + class_destroy(ipmi_class); printk(KERN_WARNING "ipmi: can't register smi watcher\n"); return rv; } @@ -588,7 +784,7 @@ module_init(init_ipmi_devintf); static __exit void cleanup_ipmi(void) { - class_simple_destroy(ipmi_class); + class_destroy(ipmi_class); ipmi_smi_watcher_unregister(&smi_watcher); devfs_remove(DEVICE_NAME); unregister_chrdev(ipmi_major, DEVICE_NAME); diff --git a/drivers/char/ipmi/ipmi_msghandler.c b/drivers/char/ipmi/ipmi_msghandler.c index d7fb452af7f..1813d0d198f 100644 --- a/drivers/char/ipmi/ipmi_msghandler.c +++ b/drivers/char/ipmi/ipmi_msghandler.c @@ -54,7 +54,9 @@ static int ipmi_init_msghandler(void); static int initialized = 0; -static struct proc_dir_entry *proc_ipmi_root = NULL; +#ifdef CONFIG_PROC_FS +struct proc_dir_entry *proc_ipmi_root = NULL; +#endif /* CONFIG_PROC_FS */ #define MAX_EVENTS_IN_QUEUE 25 @@ -124,11 +126,13 @@ struct ipmi_channel unsigned char protocol; }; +#ifdef CONFIG_PROC_FS struct ipmi_proc_entry { char *name; struct ipmi_proc_entry *next; }; +#endif #define IPMI_IPMB_NUM_SEQ 64 #define IPMI_MAX_CHANNELS 8 @@ -156,10 +160,13 @@ struct ipmi_smi struct ipmi_smi_handlers *handlers; void *send_info; +#ifdef CONFIG_PROC_FS /* A list of proc entries for this interface. This does not need a lock, only one thread creates it and only one thread destroys it. */ + spinlock_t proc_entry_lock; struct ipmi_proc_entry *proc_entries; +#endif /* A table of sequence numbers for this interface. We use the sequence numbers for IPMB messages that go out of the @@ -641,7 +648,7 @@ int ipmi_create_user(unsigned int if_num, return -ENOMEM; down_read(&interfaces_sem); - if ((if_num > MAX_IPMI_INTERFACES) || ipmi_interfaces[if_num] == NULL) + if ((if_num >= MAX_IPMI_INTERFACES) || ipmi_interfaces[if_num] == NULL) { rv = -EINVAL; goto out_unlock; @@ -1470,8 +1477,9 @@ int ipmi_smi_add_proc_entry(ipmi_smi_t smi, char *name, read_proc_t *read_proc, write_proc_t *write_proc, void *data, struct module *owner) { - struct proc_dir_entry *file; int rv = 0; +#ifdef CONFIG_PROC_FS + struct proc_dir_entry *file; struct ipmi_proc_entry *entry; /* Create a list element. */ @@ -1497,10 +1505,13 @@ int ipmi_smi_add_proc_entry(ipmi_smi_t smi, char *name, file->write_proc = write_proc; file->owner = owner; + spin_lock(&smi->proc_entry_lock); /* Stick it on the list. */ entry->next = smi->proc_entries; smi->proc_entries = entry; + spin_unlock(&smi->proc_entry_lock); } +#endif /* CONFIG_PROC_FS */ return rv; } @@ -1509,6 +1520,7 @@ static int add_proc_entries(ipmi_smi_t smi, int num) { int rv = 0; +#ifdef CONFIG_PROC_FS sprintf(smi->proc_dir_name, "%d", num); smi->proc_dir = proc_mkdir(smi->proc_dir_name, proc_ipmi_root); if (!smi->proc_dir) @@ -1531,14 +1543,17 @@ static int add_proc_entries(ipmi_smi_t smi, int num) rv = ipmi_smi_add_proc_entry(smi, "version", version_file_read_proc, NULL, smi, THIS_MODULE); +#endif /* CONFIG_PROC_FS */ return rv; } static void remove_proc_entries(ipmi_smi_t smi) { +#ifdef CONFIG_PROC_FS struct ipmi_proc_entry *entry; + spin_lock(&smi->proc_entry_lock); while (smi->proc_entries) { entry = smi->proc_entries; smi->proc_entries = entry->next; @@ -1547,7 +1562,9 @@ static void remove_proc_entries(ipmi_smi_t smi) kfree(entry->name); kfree(entry); } + spin_unlock(&smi->proc_entry_lock); remove_proc_entry(smi->proc_dir_name, proc_ipmi_root); +#endif /* CONFIG_PROC_FS */ } static int @@ -1694,6 +1711,9 @@ int ipmi_register_smi(struct ipmi_smi_handlers *handlers, new_intf->seq_table[j].seqid = 0; } new_intf->curr_seq = 0; +#ifdef CONFIG_PROC_FS + spin_lock_init(&(new_intf->proc_entry_lock)); +#endif spin_lock_init(&(new_intf->waiting_msgs_lock)); INIT_LIST_HEAD(&(new_intf->waiting_msgs)); spin_lock_init(&(new_intf->events_lock)); @@ -2747,16 +2767,13 @@ static struct timer_list ipmi_timer; the queue and this silliness can go away. */ #define IPMI_REQUEST_EV_TIME (1000 / (IPMI_TIMEOUT_TIME)) -static volatile int stop_operation = 0; -static volatile int timer_stopped = 0; +static atomic_t stop_operation; static unsigned int ticks_to_req_ev = IPMI_REQUEST_EV_TIME; static void ipmi_timeout(unsigned long data) { - if (stop_operation) { - timer_stopped = 1; + if (atomic_read(&stop_operation)) return; - } ticks_to_req_ev--; if (ticks_to_req_ev == 0) { @@ -2766,8 +2783,7 @@ static void ipmi_timeout(unsigned long data) ipmi_timeout_handler(IPMI_TIMEOUT_TIME); - ipmi_timer.expires += IPMI_TIMEOUT_JIFFIES; - add_timer(&ipmi_timer); + mod_timer(&ipmi_timer, jiffies + IPMI_TIMEOUT_JIFFIES); } @@ -3089,6 +3105,7 @@ static int ipmi_init_msghandler(void) ipmi_interfaces[i] = NULL; } +#ifdef CONFIG_PROC_FS proc_ipmi_root = proc_mkdir("ipmi", NULL); if (!proc_ipmi_root) { printk(KERN_ERR PFX "Unable to create IPMI proc dir"); @@ -3096,6 +3113,7 @@ static int ipmi_init_msghandler(void) } proc_ipmi_root->owner = THIS_MODULE; +#endif /* CONFIG_PROC_FS */ init_timer(&ipmi_timer); ipmi_timer.data = 0; @@ -3130,13 +3148,12 @@ static __exit void cleanup_ipmi(void) /* Tell the timer to stop, then wait for it to stop. This avoids problems with race conditions removing the timer here. */ - stop_operation = 1; - while (!timer_stopped) { - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(1); - } + atomic_inc(&stop_operation); + del_timer_sync(&ipmi_timer); +#ifdef CONFIG_PROC_FS remove_proc_entry(proc_ipmi_root->name, &proc_root); +#endif /* CONFIG_PROC_FS */ initialized = 0; @@ -3177,4 +3194,5 @@ EXPORT_SYMBOL(ipmi_get_my_address); EXPORT_SYMBOL(ipmi_set_my_LUN); EXPORT_SYMBOL(ipmi_get_my_LUN); EXPORT_SYMBOL(ipmi_smi_add_proc_entry); +EXPORT_SYMBOL(proc_ipmi_root); EXPORT_SYMBOL(ipmi_user_set_run_to_completion); diff --git a/drivers/char/ipmi/ipmi_poweroff.c b/drivers/char/ipmi/ipmi_poweroff.c index cb5cdc6f14b..f951c30236c 100644 --- a/drivers/char/ipmi/ipmi_poweroff.c +++ b/drivers/char/ipmi/ipmi_poweroff.c @@ -31,10 +31,13 @@ * with this program; if not, write to the Free Software Foundation, Inc., * 675 Mass Ave, Cambridge, MA 02139, USA. */ -#include <asm/semaphore.h> -#include <linux/kdev_t.h> +#include <linux/config.h> #include <linux/module.h> +#include <linux/moduleparam.h> +#include <linux/proc_fs.h> #include <linux/string.h> +#include <linux/completion.h> +#include <linux/kdev_t.h> #include <linux/ipmi.h> #include <linux/ipmi_smi.h> @@ -44,6 +47,18 @@ /* Where to we insert our poweroff function? */ extern void (*pm_power_off)(void); +/* Definitions for controlling power off (if the system supports it). It + * conveniently matches the IPMI chassis control values. */ +#define IPMI_CHASSIS_POWER_DOWN 0 /* power down, the default. */ +#define IPMI_CHASSIS_POWER_CYCLE 0x02 /* power cycle */ + +/* the IPMI data command */ +static int poweroff_control = IPMI_CHASSIS_POWER_DOWN; + +/* parameter definition to allow user to flag power cycle */ +module_param(poweroff_control, int, IPMI_CHASSIS_POWER_DOWN); +MODULE_PARM_DESC(poweroff_control, " Set to 2 to enable power cycle instead of power down. Power cycle is contingent on hardware support, otherwise it defaults back to power down."); + /* Stuff from the get device id command. */ static unsigned int mfg_id; static unsigned int prod_id; @@ -75,10 +90,10 @@ static struct ipmi_recv_msg halt_recv_msg = static void receive_handler(struct ipmi_recv_msg *recv_msg, void *handler_data) { - struct semaphore *sem = recv_msg->user_msg_data; + struct completion *comp = recv_msg->user_msg_data; - if (sem) - up(sem); + if (comp) + complete(comp); } static struct ipmi_user_hndl ipmi_poweroff_handler = @@ -91,27 +106,27 @@ static int ipmi_request_wait_for_response(ipmi_user_t user, struct ipmi_addr *addr, struct kernel_ipmi_msg *send_msg) { - int rv; - struct semaphore sem; + int rv; + struct completion comp; - sema_init (&sem, 0); + init_completion(&comp); - rv = ipmi_request_supply_msgs(user, addr, 0, send_msg, &sem, + rv = ipmi_request_supply_msgs(user, addr, 0, send_msg, &comp, &halt_smi_msg, &halt_recv_msg, 0); if (rv) return rv; - down (&sem); + wait_for_completion(&comp); return halt_recv_msg.msg.data[0]; } -/* We are in run-to-completion mode, no semaphore is desired. */ +/* We are in run-to-completion mode, no completion is desired. */ static int ipmi_request_in_rc_mode(ipmi_user_t user, struct ipmi_addr *addr, struct kernel_ipmi_msg *send_msg) { - int rv; + int rv; rv = ipmi_request_supply_msgs(user, addr, 0, send_msg, NULL, &halt_smi_msg, &halt_recv_msg, 0); @@ -349,26 +364,38 @@ static void ipmi_poweroff_chassis (ipmi_user_t user) smi_addr.channel = IPMI_BMC_CHANNEL; smi_addr.lun = 0; - printk(KERN_INFO PFX "Powering down via IPMI chassis control command\n"); + powercyclefailed: + printk(KERN_INFO PFX "Powering %s via IPMI chassis control command\n", + ((poweroff_control != IPMI_CHASSIS_POWER_CYCLE) ? "down" : "cycle")); /* * Power down */ send_msg.netfn = IPMI_NETFN_CHASSIS_REQUEST; send_msg.cmd = IPMI_CHASSIS_CONTROL_CMD; - data[0] = 0; /* Power down */ + data[0] = poweroff_control; send_msg.data = data; send_msg.data_len = sizeof(data); rv = ipmi_request_in_rc_mode(user, (struct ipmi_addr *) &smi_addr, &send_msg); if (rv) { - printk(KERN_ERR PFX "Unable to send chassis powerdown message," - " IPMI error 0x%x\n", rv); - goto out; + switch (poweroff_control) { + case IPMI_CHASSIS_POWER_CYCLE: + /* power cycle failed, default to power down */ + printk(KERN_ERR PFX "Unable to send chassis power " \ + "cycle message, IPMI error 0x%x\n", rv); + poweroff_control = IPMI_CHASSIS_POWER_DOWN; + goto powercyclefailed; + + case IPMI_CHASSIS_POWER_DOWN: + default: + printk(KERN_ERR PFX "Unable to send chassis power " \ + "down message, IPMI error 0x%x\n", rv); + break; + } } - out: return; } @@ -430,7 +457,8 @@ static void ipmi_po_new_smi(int if_num) if (ready) return; - rv = ipmi_create_user(if_num, &ipmi_poweroff_handler, NULL, &ipmi_user); + rv = ipmi_create_user(if_num, &ipmi_poweroff_handler, NULL, + &ipmi_user); if (rv) { printk(KERN_ERR PFX "could not create IPMI user, error %d\n", rv); @@ -509,21 +537,84 @@ static struct ipmi_smi_watcher smi_watcher = }; +#ifdef CONFIG_PROC_FS +/* displays properties to proc */ +static int proc_read_chassctrl(char *page, char **start, off_t off, int count, + int *eof, void *data) +{ + return sprintf(page, "%d\t[ 0=powerdown 2=powercycle ]\n", + poweroff_control); +} + +/* process property writes from proc */ +static int proc_write_chassctrl(struct file *file, const char *buffer, + unsigned long count, void *data) +{ + int rv = count; + unsigned int newval = 0; + + sscanf(buffer, "%d", &newval); + switch (newval) { + case IPMI_CHASSIS_POWER_CYCLE: + printk(KERN_INFO PFX "power cycle is now enabled\n"); + poweroff_control = newval; + break; + + case IPMI_CHASSIS_POWER_DOWN: + poweroff_control = IPMI_CHASSIS_POWER_DOWN; + break; + + default: + rv = -EINVAL; + break; + } + + return rv; +} +#endif /* CONFIG_PROC_FS */ + /* * Startup and shutdown functions. */ static int ipmi_poweroff_init (void) { - int rv; + int rv; + struct proc_dir_entry *file; printk ("Copyright (C) 2004 MontaVista Software -" " IPMI Powerdown via sys_reboot version " IPMI_POWEROFF_VERSION ".\n"); + switch (poweroff_control) { + case IPMI_CHASSIS_POWER_CYCLE: + printk(KERN_INFO PFX "Power cycle is enabled.\n"); + break; + + case IPMI_CHASSIS_POWER_DOWN: + default: + poweroff_control = IPMI_CHASSIS_POWER_DOWN; + break; + } + rv = ipmi_smi_watcher_register(&smi_watcher); - if (rv) + if (rv) { printk(KERN_ERR PFX "Unable to register SMI watcher: %d\n", rv); + goto out_err; + } + +#ifdef CONFIG_PROC_FS + file = create_proc_entry("poweroff_control", 0, proc_ipmi_root); + if (!file) { + printk(KERN_ERR PFX "Unable to create proc power control\n"); + } else { + file->nlink = 1; + file->read_proc = proc_read_chassctrl; + file->write_proc = proc_write_chassctrl; + file->owner = THIS_MODULE; + } +#endif + out_err: return rv; } @@ -532,6 +623,10 @@ static __exit void ipmi_poweroff_cleanup(void) { int rv; +#ifdef CONFIG_PROC_FS + remove_proc_entry("poweroff_control", proc_ipmi_root); +#endif + ipmi_smi_watcher_unregister(&smi_watcher); if (ready) { diff --git a/drivers/char/isicom.c b/drivers/char/isicom.c index 601c7fccb4c..1bbf507adda 100644 --- a/drivers/char/isicom.c +++ b/drivers/char/isicom.c @@ -1756,7 +1756,7 @@ static void isicom_flush_buffer(struct tty_struct * tty) } -static int __init register_ioregion(void) +static int __devinit register_ioregion(void) { int count, done=0; for (count=0; count < BOARD_COUNT; count++ ) { @@ -1771,7 +1771,7 @@ static int __init register_ioregion(void) return done; } -static void __exit unregister_ioregion(void) +static void unregister_ioregion(void) { int count; for (count=0; count < BOARD_COUNT; count++ ) @@ -1803,7 +1803,7 @@ static struct tty_operations isicom_ops = { .tiocmset = isicom_tiocmset, }; -static int __init register_drivers(void) +static int __devinit register_drivers(void) { int error; @@ -1834,7 +1834,7 @@ static int __init register_drivers(void) return 0; } -static void __exit unregister_drivers(void) +static void unregister_drivers(void) { int error = tty_unregister_driver(isicom_normal); if (error) @@ -1842,7 +1842,7 @@ static void __exit unregister_drivers(void) put_tty_driver(isicom_normal); } -static int __init register_isr(void) +static int __devinit register_isr(void) { int count, done=0; unsigned long irqflags; @@ -1883,7 +1883,7 @@ static void __exit unregister_isr(void) } } -static int __init isicom_init(void) +static int __devinit isicom_init(void) { int card, channel, base; struct isi_port * port; diff --git a/drivers/char/istallion.c b/drivers/char/istallion.c index 21aed0e8779..52a073eee20 100644 --- a/drivers/char/istallion.c +++ b/drivers/char/istallion.c @@ -407,7 +407,6 @@ static unsigned long stli_eisamemprobeaddrs[] = { }; static int stli_eisamempsize = sizeof(stli_eisamemprobeaddrs) / sizeof(unsigned long); -int stli_eisaprobe = STLI_EISAPROBE; /* * Define the Stallion PCI vendor and device IDs. @@ -792,7 +791,7 @@ static int stli_timeron; /*****************************************************************************/ -static struct class_simple *istallion_class; +static struct class *istallion_class; #ifdef MODULE @@ -854,10 +853,10 @@ static void __exit istallion_module_exit(void) put_tty_driver(stli_serial); for (i = 0; i < 4; i++) { devfs_remove("staliomem/%d", i); - class_simple_device_remove(MKDEV(STL_SIOMEMMAJOR, i)); + class_device_destroy(istallion_class, MKDEV(STL_SIOMEMMAJOR, i)); } devfs_remove("staliomem"); - class_simple_destroy(istallion_class); + class_destroy(istallion_class); if ((i = unregister_chrdev(STL_SIOMEMMAJOR, "staliomem"))) printk("STALLION: failed to un-register serial memory device, " "errno=%d\n", -i); @@ -4685,7 +4684,7 @@ static int stli_initbrds(void) #ifdef MODULE stli_argbrds(); #endif - if (stli_eisaprobe) + if (STLI_EISAPROBE) stli_findeisabrds(); #ifdef CONFIG_PCI stli_findpcibrds(); @@ -5242,12 +5241,12 @@ int __init stli_init(void) "device\n"); devfs_mk_dir("staliomem"); - istallion_class = class_simple_create(THIS_MODULE, "staliomem"); + istallion_class = class_create(THIS_MODULE, "staliomem"); for (i = 0; i < 4; i++) { devfs_mk_cdev(MKDEV(STL_SIOMEMMAJOR, i), S_IFCHR | S_IRUSR | S_IWUSR, "staliomem/%d", i); - class_simple_device_add(istallion_class, MKDEV(STL_SIOMEMMAJOR, i), + class_device_create(istallion_class, MKDEV(STL_SIOMEMMAJOR, i), NULL, "staliomem%d", i); } diff --git a/drivers/char/lp.c b/drivers/char/lp.c index 4dee945031d..59eebe5a035 100644 --- a/drivers/char/lp.c +++ b/drivers/char/lp.c @@ -146,7 +146,7 @@ static struct lp_struct lp_table[LP_NO]; static unsigned int lp_count = 0; -static struct class_simple *lp_class; +static struct class *lp_class; #ifdef CONFIG_LP_CONSOLE static struct parport *console_registered; // initially NULL @@ -804,7 +804,7 @@ static int lp_register(int nr, struct parport *port) if (reset) lp_reset(nr); - class_simple_device_add(lp_class, MKDEV(LP_MAJOR, nr), NULL, + class_device_create(lp_class, MKDEV(LP_MAJOR, nr), NULL, "lp%d", nr); devfs_mk_cdev(MKDEV(LP_MAJOR, nr), S_IFCHR | S_IRUGO | S_IWUGO, "printers/%d", nr); @@ -907,7 +907,7 @@ static int __init lp_init (void) } devfs_mk_dir("printers"); - lp_class = class_simple_create(THIS_MODULE, "printer"); + lp_class = class_create(THIS_MODULE, "printer"); if (IS_ERR(lp_class)) { err = PTR_ERR(lp_class); goto out_devfs; @@ -930,7 +930,7 @@ static int __init lp_init (void) return 0; out_class: - class_simple_destroy(lp_class); + class_destroy(lp_class); out_devfs: devfs_remove("printers"); unregister_chrdev(LP_MAJOR, "lp"); @@ -981,10 +981,10 @@ static void lp_cleanup_module (void) continue; parport_unregister_device(lp_table[offset].dev); devfs_remove("printers/%d", offset); - class_simple_device_remove(MKDEV(LP_MAJOR, offset)); + class_device_destroy(lp_class, MKDEV(LP_MAJOR, offset)); } devfs_remove("printers"); - class_simple_destroy(lp_class); + class_destroy(lp_class); } __setup("lp=", lp_setup); diff --git a/drivers/char/mbcs.c b/drivers/char/mbcs.c index ac9cfa9701e..115dbb35334 100644 --- a/drivers/char/mbcs.c +++ b/drivers/char/mbcs.c @@ -699,7 +699,7 @@ static inline int mbcs_hw_init(struct mbcs_soft *soft) return 0; } -static ssize_t show_algo(struct device *dev, char *buf) +static ssize_t show_algo(struct device *dev, struct device_attribute *attr, char *buf) { struct cx_dev *cx_dev = to_cx_dev(dev); struct mbcs_soft *soft = cx_dev->soft; @@ -715,7 +715,7 @@ static ssize_t show_algo(struct device *dev, char *buf) (debug0 >> 32), (debug0 & 0xffffffff)); } -static ssize_t store_algo(struct device *dev, const char *buf, size_t count) +static ssize_t store_algo(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { int n; struct cx_dev *cx_dev = to_cx_dev(dev); diff --git a/drivers/char/mem.c b/drivers/char/mem.c index 947cb3cef81..42187381506 100644 --- a/drivers/char/mem.c +++ b/drivers/char/mem.c @@ -23,7 +23,10 @@ #include <linux/devfs_fs_kernel.h> #include <linux/ptrace.h> #include <linux/device.h> +#include <linux/highmem.h> +#include <linux/crash_dump.h> #include <linux/backing-dev.h> +#include <linux/bootmem.h> #include <asm/uaccess.h> #include <asm/io.h> @@ -273,6 +276,40 @@ static int mmap_kmem(struct file * file, struct vm_area_struct * vma) return mmap_mem(file, vma); } +#ifdef CONFIG_CRASH_DUMP +/* + * Read memory corresponding to the old kernel. + */ +static ssize_t read_oldmem(struct file *file, char __user *buf, + size_t count, loff_t *ppos) +{ + unsigned long pfn, offset; + size_t read = 0, csize; + int rc = 0; + + while (count) { + pfn = *ppos / PAGE_SIZE; + if (pfn > saved_max_pfn) + return read; + + offset = (unsigned long)(*ppos % PAGE_SIZE); + if (count > PAGE_SIZE - offset) + csize = PAGE_SIZE - offset; + else + csize = count; + + rc = copy_oldmem_page(pfn, buf, csize, offset, 1); + if (rc < 0) + return rc; + buf += csize; + *ppos += csize; + read += csize; + count -= csize; + } + return read; +} +#endif + extern long vread(char *buf, char *addr, unsigned long count); extern long vwrite(char *buf, char *addr, unsigned long count); @@ -484,7 +521,7 @@ static ssize_t write_kmem(struct file * file, const char __user * buf, return virtr + wrote; } -#if defined(CONFIG_ISA) || !defined(__mc68000__) +#if (defined(CONFIG_ISA) || !defined(__mc68000__)) && (!defined(CONFIG_PPC_ISERIES) || defined(CONFIG_PCI)) static ssize_t read_port(struct file * file, char __user * buf, size_t count, loff_t *ppos) { @@ -721,6 +758,7 @@ static int open_port(struct inode * inode, struct file * filp) #define read_full read_zero #define open_mem open_port #define open_kmem open_mem +#define open_oldmem open_mem static struct file_operations mem_fops = { .llseek = memory_lseek, @@ -744,7 +782,7 @@ static struct file_operations null_fops = { .write = write_null, }; -#if defined(CONFIG_ISA) || !defined(__mc68000__) +#if (defined(CONFIG_ISA) || !defined(__mc68000__)) && (!defined(CONFIG_PPC_ISERIES) || defined(CONFIG_PCI)) static struct file_operations port_fops = { .llseek = memory_lseek, .read = read_port, @@ -770,6 +808,13 @@ static struct file_operations full_fops = { .write = write_full, }; +#ifdef CONFIG_CRASH_DUMP +static struct file_operations oldmem_fops = { + .read = read_oldmem, + .open = open_oldmem, +}; +#endif + static ssize_t kmsg_write(struct file * file, const char __user * buf, size_t count, loff_t *ppos) { @@ -804,7 +849,7 @@ static int memory_open(struct inode * inode, struct file * filp) case 3: filp->f_op = &null_fops; break; -#if defined(CONFIG_ISA) || !defined(__mc68000__) +#if (defined(CONFIG_ISA) || !defined(__mc68000__)) && (!defined(CONFIG_PPC_ISERIES) || defined(CONFIG_PCI)) case 4: filp->f_op = &port_fops; break; @@ -825,6 +870,11 @@ static int memory_open(struct inode * inode, struct file * filp) case 11: filp->f_op = &kmsg_fops; break; +#ifdef CONFIG_CRASH_DUMP + case 12: + filp->f_op = &oldmem_fops; + break; +#endif default: return -ENXIO; } @@ -846,7 +896,7 @@ static const struct { {1, "mem", S_IRUSR | S_IWUSR | S_IRGRP, &mem_fops}, {2, "kmem", S_IRUSR | S_IWUSR | S_IRGRP, &kmem_fops}, {3, "null", S_IRUGO | S_IWUGO, &null_fops}, -#if defined(CONFIG_ISA) || !defined(__mc68000__) +#if (defined(CONFIG_ISA) || !defined(__mc68000__)) && (!defined(CONFIG_PPC_ISERIES) || defined(CONFIG_PCI)) {4, "port", S_IRUSR | S_IWUSR | S_IRGRP, &port_fops}, #endif {5, "zero", S_IRUGO | S_IWUGO, &zero_fops}, @@ -854,9 +904,12 @@ static const struct { {8, "random", S_IRUGO | S_IWUSR, &random_fops}, {9, "urandom", S_IRUGO | S_IWUSR, &urandom_fops}, {11,"kmsg", S_IRUGO | S_IWUSR, &kmsg_fops}, +#ifdef CONFIG_CRASH_DUMP + {12,"oldmem", S_IRUSR | S_IWUSR | S_IRGRP, &oldmem_fops}, +#endif }; -static struct class_simple *mem_class; +static struct class *mem_class; static int __init chr_dev_init(void) { @@ -865,10 +918,9 @@ static int __init chr_dev_init(void) if (register_chrdev(MEM_MAJOR,"mem",&memory_fops)) printk("unable to get major %d for memory devs\n", MEM_MAJOR); - mem_class = class_simple_create(THIS_MODULE, "mem"); + mem_class = class_create(THIS_MODULE, "mem"); for (i = 0; i < ARRAY_SIZE(devlist); i++) { - class_simple_device_add(mem_class, - MKDEV(MEM_MAJOR, devlist[i].minor), + class_device_create(mem_class, MKDEV(MEM_MAJOR, devlist[i].minor), NULL, devlist[i].name); devfs_mk_cdev(MKDEV(MEM_MAJOR, devlist[i].minor), S_IFCHR | devlist[i].mode, devlist[i].name); diff --git a/drivers/char/misc.c b/drivers/char/misc.c index 0937544762d..31cf84d6902 100644 --- a/drivers/char/misc.c +++ b/drivers/char/misc.c @@ -66,8 +66,6 @@ static unsigned char misc_minors[DYNAMIC_MINORS / 8]; extern int rtc_DP8570A_init(void); extern int rtc_MK48T08_init(void); extern int pmu_device_init(void); -extern int tosh_init(void); -extern int i8k_init(void); #ifdef CONFIG_PROC_FS static void *misc_seq_start(struct seq_file *seq, loff_t *pos) @@ -177,10 +175,10 @@ fail: /* * TODO for 2.7: - * - add a struct class_device to struct miscdevice and make all usages of + * - add a struct kref to struct miscdevice and make all usages of * them dynamic. */ -static struct class_simple *misc_class; +static struct class *misc_class; static struct file_operations misc_fops = { .owner = THIS_MODULE, @@ -238,8 +236,8 @@ int misc_register(struct miscdevice * misc) } dev = MKDEV(MISC_MAJOR, misc->minor); - misc->class = class_simple_device_add(misc_class, dev, - misc->dev, misc->name); + misc->class = class_device_create(misc_class, dev, misc->dev, + "%s", misc->name); if (IS_ERR(misc->class)) { err = PTR_ERR(misc->class); goto out; @@ -248,7 +246,7 @@ int misc_register(struct miscdevice * misc) err = devfs_mk_cdev(dev, S_IFCHR|S_IRUSR|S_IWUSR|S_IRGRP, misc->devfs_name); if (err) { - class_simple_device_remove(dev); + class_device_destroy(misc_class, dev); goto out; } @@ -281,7 +279,7 @@ int misc_deregister(struct miscdevice * misc) down(&misc_sem); list_del(&misc->list); - class_simple_device_remove(MKDEV(MISC_MAJOR, misc->minor)); + class_device_destroy(misc_class, MKDEV(MISC_MAJOR, misc->minor)); devfs_remove(misc->devfs_name); if (i < DYNAMIC_MINORS && i>0) { misc_minors[i>>3] &= ~(1 << (misc->minor & 7)); @@ -302,7 +300,7 @@ static int __init misc_init(void) if (ent) ent->proc_fops = &misc_proc_fops; #endif - misc_class = class_simple_create(THIS_MODULE, "misc"); + misc_class = class_create(THIS_MODULE, "misc"); if (IS_ERR(misc_class)) return PTR_ERR(misc_class); #ifdef CONFIG_MVME16x @@ -314,16 +312,10 @@ static int __init misc_init(void) #ifdef CONFIG_PMAC_PBOOK pmu_device_init(); #endif -#ifdef CONFIG_TOSHIBA - tosh_init(); -#endif -#ifdef CONFIG_I8K - i8k_init(); -#endif if (register_chrdev(MISC_MAJOR,"misc",&misc_fops)) { printk("unable to get major %d for misc devices\n", MISC_MAJOR); - class_simple_destroy(misc_class); + class_destroy(misc_class); return -EIO; } return 0; diff --git a/drivers/char/mwave/3780i.c b/drivers/char/mwave/3780i.c index ab00f51475d..613aed9e184 100644 --- a/drivers/char/mwave/3780i.c +++ b/drivers/char/mwave/3780i.c @@ -107,8 +107,8 @@ void dsp3780I_WriteMsaCfg(unsigned short usDspBaseIO, spin_unlock_irqrestore(&dsp_lock, flags); } -void dsp3780I_WriteGenCfg(unsigned short usDspBaseIO, unsigned uIndex, - unsigned char ucValue) +static void dsp3780I_WriteGenCfg(unsigned short usDspBaseIO, unsigned uIndex, + unsigned char ucValue) { DSP_ISA_SLAVE_CONTROL rSlaveControl; DSP_ISA_SLAVE_CONTROL rSlaveControl_Save; @@ -141,6 +141,7 @@ void dsp3780I_WriteGenCfg(unsigned short usDspBaseIO, unsigned uIndex, } +#if 0 unsigned char dsp3780I_ReadGenCfg(unsigned short usDspBaseIO, unsigned uIndex) { @@ -167,6 +168,7 @@ unsigned char dsp3780I_ReadGenCfg(unsigned short usDspBaseIO, return ucValue; } +#endif /* 0 */ int dsp3780I_EnableDSP(DSP_3780I_CONFIG_SETTINGS * pSettings, unsigned short *pIrqMap, diff --git a/drivers/char/mwave/3780i.h b/drivers/char/mwave/3780i.h index 3e7d020d1bf..270431ca7da 100644 --- a/drivers/char/mwave/3780i.h +++ b/drivers/char/mwave/3780i.h @@ -338,10 +338,6 @@ unsigned short dsp3780I_ReadMsaCfg(unsigned short usDspBaseIO, unsigned long ulMsaAddr); void dsp3780I_WriteMsaCfg(unsigned short usDspBaseIO, unsigned long ulMsaAddr, unsigned short usValue); -void dsp3780I_WriteGenCfg(unsigned short usDspBaseIO, unsigned uIndex, - unsigned char ucValue); -unsigned char dsp3780I_ReadGenCfg(unsigned short usDspBaseIO, - unsigned uIndex); int dsp3780I_GetIPCSource(unsigned short usDspBaseIO, unsigned short *pusIPCSource); diff --git a/drivers/char/mwave/mwavedd.c b/drivers/char/mwave/mwavedd.c index d37625d4774..d568991ac6b 100644 --- a/drivers/char/mwave/mwavedd.c +++ b/drivers/char/mwave/mwavedd.c @@ -472,7 +472,7 @@ struct device mwave_device; /* Prevent code redundancy, create a macro for mwave_show_* functions. */ #define mwave_show_function(attr_name, format_string, field) \ -static ssize_t mwave_show_##attr_name(struct device *dev, char *buf) \ +static ssize_t mwave_show_##attr_name(struct device *dev, struct device_attribute *attr, char *buf) \ { \ DSP_3780I_CONFIG_SETTINGS *pSettings = \ &mwave_s_mdd.rBDData.rDspSettings; \ diff --git a/drivers/char/mwave/tp3780i.c b/drivers/char/mwave/tp3780i.c index ab650cd6efc..d6c72e0934e 100644 --- a/drivers/char/mwave/tp3780i.c +++ b/drivers/char/mwave/tp3780i.c @@ -242,20 +242,14 @@ int tp3780I_ClaimResources(THINKPAD_BD_DATA * pBDData) { int retval = 0; DSP_3780I_CONFIG_SETTINGS *pSettings = &pBDData->rDspSettings; -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) struct resource *pres; -#endif PRINTK_2(TRACE_TP3780I, "tp3780i::tp3780I_ClaimResources entry pBDData %p\n", pBDData); -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) pres = request_region(pSettings->usDspBaseIO, 16, "mwave_3780i"); if ( pres == NULL ) retval = -EIO; -#else - retval = check_region(pSettings->usDspBaseIO, 16); - if (!retval) request_region(pSettings->usDspBaseIO, 16, "mwave_3780i"); -#endif + if (retval) { PRINTK_ERROR(KERN_ERR_MWAVE "tp3780i::tp3780I_ClaimResources: Error: Could not claim I/O region starting at %x\n", pSettings->usDspBaseIO); retval = -EIO; @@ -292,7 +286,7 @@ int tp3780I_ReleaseResources(THINKPAD_BD_DATA * pBDData) int tp3780I_EnableDSP(THINKPAD_BD_DATA * pBDData) { DSP_3780I_CONFIG_SETTINGS *pSettings = &pBDData->rDspSettings; - BOOLEAN bDSPPoweredUp = FALSE, bDSPEnabled = FALSE, bInterruptAllocated = FALSE; + BOOLEAN bDSPPoweredUp = FALSE, bInterruptAllocated = FALSE; PRINTK_2(TRACE_TP3780I, "tp3780i::tp3780I_EnableDSP entry pBDData %p\n", pBDData); @@ -397,8 +391,6 @@ int tp3780I_EnableDSP(THINKPAD_BD_DATA * pBDData) if (dsp3780I_EnableDSP(pSettings, s_ausThinkpadIrqToField, s_ausThinkpadDmaToField)) { PRINTK_ERROR("tp3780i::tp3780I_EnableDSP: Error: dsp7880I_EnableDSP() failed\n"); goto exit_cleanup; - } else { - bDSPEnabled = TRUE; } EnableSRAM(pBDData); @@ -411,8 +403,6 @@ int tp3780I_EnableDSP(THINKPAD_BD_DATA * pBDData) exit_cleanup: PRINTK_ERROR("tp3780i::tp3780I_EnableDSP: Cleaning up\n"); - if (bDSPEnabled) - dsp3780I_DisableDSP(pSettings); if (bDSPPoweredUp) smapi_set_DSP_power_state(FALSE); if (bInterruptAllocated) { diff --git a/drivers/char/mxser.c b/drivers/char/mxser.c index 7a245068e3e..f022f094443 100644 --- a/drivers/char/mxser.c +++ b/drivers/char/mxser.c @@ -1995,9 +1995,6 @@ static void mxser_receive_chars(struct mxser_struct *info, int *status) unsigned char ch, gdl; int ignored = 0; int cnt = 0; - unsigned char *cp; - char *fp; - int count; int recv_room; int max = 256; unsigned long flags; @@ -2011,10 +2008,6 @@ static void mxser_receive_chars(struct mxser_struct *info, int *status) //return; } - cp = tty->flip.char_buf; - fp = tty->flip.flag_buf; - count = 0; - // following add by Victor Yu. 09-02-2002 if (info->IsMoxaMustChipFlag != MOXA_OTHER_UART) { @@ -2041,12 +2034,10 @@ static void mxser_receive_chars(struct mxser_struct *info, int *status) } while (gdl--) { ch = inb(info->base + UART_RX); - count++; - *cp++ = ch; - *fp++ = 0; + tty_insert_flip_char(tty, ch, 0); cnt++; /* - if((count>=HI_WATER) && (info->stop_rx==0)){ + if((cnt>=HI_WATER) && (info->stop_rx==0)){ mxser_stoprx(tty); info->stop_rx=1; break; @@ -2061,7 +2052,7 @@ intr_old: if (max-- < 0) break; /* - if((count>=HI_WATER) && (info->stop_rx==0)){ + if((cnt>=HI_WATER) && (info->stop_rx==0)){ mxser_stoprx(tty); info->stop_rx=1; break; @@ -2078,36 +2069,33 @@ intr_old: if (++ignored > 100) break; } else { - count++; + char flag = 0; if (*status & UART_LSR_SPECIAL) { if (*status & UART_LSR_BI) { - *fp++ = TTY_BREAK; + flag = TTY_BREAK; /* added by casper 1/11/2000 */ info->icount.brk++; - /* */ if (info->flags & ASYNC_SAK) do_SAK(tty); } else if (*status & UART_LSR_PE) { - *fp++ = TTY_PARITY; + flag = TTY_PARITY; /* added by casper 1/11/2000 */ info->icount.parity++; /* */ } else if (*status & UART_LSR_FE) { - *fp++ = TTY_FRAME; + flag = TTY_FRAME; /* added by casper 1/11/2000 */ info->icount.frame++; /* */ } else if (*status & UART_LSR_OE) { - *fp++ = TTY_OVERRUN; + flag = TTY_OVERRUN; /* added by casper 1/11/2000 */ info->icount.overrun++; /* */ - } else - *fp++ = 0; - } else - *fp++ = 0; - *cp++ = ch; + } + } + tty_insert_flip_char(tty, ch, flag); cnt++; if (cnt >= recv_room) { if (!info->ldisc_stop_rx) { @@ -2132,13 +2120,13 @@ intr_old: // above add by Victor Yu. 09-02-2002 } while (*status & UART_LSR_DR); - end_intr: // add by Victor Yu. 09-02-2002 +end_intr: // add by Victor Yu. 09-02-2002 mxvar_log.rxcnt[info->port] += cnt; info->mon_data.rxcnt += cnt; info->mon_data.up_rxcnt += cnt; spin_unlock_irqrestore(&info->slock, flags); - + tty_flip_buffer_push(tty); } diff --git a/drivers/char/n_hdlc.c b/drivers/char/n_hdlc.c index b3dbff1cf96..5079beda69b 100644 --- a/drivers/char/n_hdlc.c +++ b/drivers/char/n_hdlc.c @@ -960,7 +960,7 @@ static char hdlc_unregister_fail[] __exitdata = static void __exit n_hdlc_exit(void) { /* Release tty registration of line discipline */ - int status = tty_register_ldisc(N_HDLC, NULL); + int status = tty_unregister_ldisc(N_HDLC); if (status) printk(hdlc_unregister_fail, status); diff --git a/drivers/char/n_r3964.c b/drivers/char/n_r3964.c index 3883073ab48..2291a87e8ad 100644 --- a/drivers/char/n_r3964.c +++ b/drivers/char/n_r3964.c @@ -200,7 +200,7 @@ static void __exit r3964_exit(void) TRACE_M ("cleanup_module()"); - status=tty_register_ldisc(N_R3964, NULL); + status=tty_unregister_ldisc(N_R3964); if(status!=0) { diff --git a/drivers/char/nvram.c b/drivers/char/nvram.c index f63a3fd7ca6..1af733d0732 100644 --- a/drivers/char/nvram.c +++ b/drivers/char/nvram.c @@ -211,12 +211,13 @@ nvram_check_checksum(void) return rv; } -void +static void __nvram_set_checksum(void) { mach_set_checksum(); } +#if 0 void nvram_set_checksum(void) { @@ -226,6 +227,7 @@ nvram_set_checksum(void) __nvram_set_checksum(); spin_unlock_irqrestore(&rtc_lock, flags); } +#endif /* 0 */ /* * The are the file operation function for user access to /dev/nvram @@ -921,6 +923,4 @@ EXPORT_SYMBOL(__nvram_write_byte); EXPORT_SYMBOL(nvram_write_byte); EXPORT_SYMBOL(__nvram_check_checksum); EXPORT_SYMBOL(nvram_check_checksum); -EXPORT_SYMBOL(__nvram_set_checksum); -EXPORT_SYMBOL(nvram_set_checksum); MODULE_ALIAS_MISCDEV(NVRAM_MINOR); diff --git a/drivers/char/ppdev.c b/drivers/char/ppdev.c index 5eda075c62b..0e22880432b 100644 --- a/drivers/char/ppdev.c +++ b/drivers/char/ppdev.c @@ -737,7 +737,7 @@ static unsigned int pp_poll (struct file * file, poll_table * wait) return mask; } -static struct class_simple *ppdev_class; +static struct class *ppdev_class; static struct file_operations pp_fops = { .owner = THIS_MODULE, @@ -752,13 +752,13 @@ static struct file_operations pp_fops = { static void pp_attach(struct parport *port) { - class_simple_device_add(ppdev_class, MKDEV(PP_MAJOR, port->number), + class_device_create(ppdev_class, MKDEV(PP_MAJOR, port->number), NULL, "parport%d", port->number); } static void pp_detach(struct parport *port) { - class_simple_device_remove(MKDEV(PP_MAJOR, port->number)); + class_device_destroy(ppdev_class, MKDEV(PP_MAJOR, port->number)); } static struct parport_driver pp_driver = { @@ -776,7 +776,7 @@ static int __init ppdev_init (void) PP_MAJOR); return -EIO; } - ppdev_class = class_simple_create(THIS_MODULE, CHRDEV); + ppdev_class = class_create(THIS_MODULE, CHRDEV); if (IS_ERR(ppdev_class)) { err = PTR_ERR(ppdev_class); goto out_chrdev; @@ -798,7 +798,7 @@ out_class: for (i = 0; i < PARPORT_MAX; i++) devfs_remove("parports/%d", i); devfs_remove("parports"); - class_simple_destroy(ppdev_class); + class_destroy(ppdev_class); out_chrdev: unregister_chrdev(PP_MAJOR, CHRDEV); out: @@ -813,7 +813,7 @@ static void __exit ppdev_cleanup (void) devfs_remove("parports/%d", i); parport_unregister_driver(&pp_driver); devfs_remove("parports"); - class_simple_destroy(ppdev_class); + class_destroy(ppdev_class); unregister_chrdev (PP_MAJOR, CHRDEV); } diff --git a/drivers/char/raw.c b/drivers/char/raw.c index ca5f42bcaad..f13e5de0220 100644 --- a/drivers/char/raw.c +++ b/drivers/char/raw.c @@ -27,7 +27,7 @@ struct raw_device_data { int inuse; }; -static struct class_simple *raw_class; +static struct class *raw_class; static struct raw_device_data raw_devices[MAX_RAW_MINORS]; static DECLARE_MUTEX(raw_mutex); static struct file_operations raw_ctl_fops; /* forward declaration */ @@ -127,8 +127,8 @@ raw_ioctl(struct inode *inode, struct file *filp, static void bind_device(struct raw_config_request *rq) { - class_simple_device_remove(MKDEV(RAW_MAJOR, rq->raw_minor)); - class_simple_device_add(raw_class, MKDEV(RAW_MAJOR, rq->raw_minor), + class_device_destroy(raw_class, MKDEV(RAW_MAJOR, rq->raw_minor)); + class_device_create(raw_class, MKDEV(RAW_MAJOR, rq->raw_minor), NULL, "raw%d", rq->raw_minor); } @@ -200,8 +200,8 @@ static int raw_ctl_ioctl(struct inode *inode, struct file *filp, if (rq.block_major == 0 && rq.block_minor == 0) { /* unbind */ rawdev->binding = NULL; - class_simple_device_remove(MKDEV(RAW_MAJOR, - rq.raw_minor)); + class_device_destroy(raw_class, + MKDEV(RAW_MAJOR, rq.raw_minor)); } else { rawdev->binding = bdget(dev); if (rawdev->binding == NULL) @@ -300,14 +300,14 @@ static int __init raw_init(void) goto error; } - raw_class = class_simple_create(THIS_MODULE, "raw"); + raw_class = class_create(THIS_MODULE, "raw"); if (IS_ERR(raw_class)) { printk(KERN_ERR "Error creating raw class.\n"); cdev_del(&raw_cdev); unregister_chrdev_region(dev, MAX_RAW_MINORS); goto error; } - class_simple_device_add(raw_class, MKDEV(RAW_MAJOR, 0), NULL, "rawctl"); + class_device_create(raw_class, MKDEV(RAW_MAJOR, 0), NULL, "rawctl"); devfs_mk_cdev(MKDEV(RAW_MAJOR, 0), S_IFCHR | S_IRUGO | S_IWUGO, @@ -331,8 +331,8 @@ static void __exit raw_exit(void) devfs_remove("raw/raw%d", i); devfs_remove("raw/rawctl"); devfs_remove("raw"); - class_simple_device_remove(MKDEV(RAW_MAJOR, 0)); - class_simple_destroy(raw_class); + class_device_destroy(raw_class, MKDEV(RAW_MAJOR, 0)); + class_destroy(raw_class); cdev_del(&raw_cdev); unregister_chrdev_region(MKDEV(RAW_MAJOR, 0), MAX_RAW_MINORS); } diff --git a/drivers/char/rio/func.h b/drivers/char/rio/func.h index e8f3860f472..01987c6dc39 100644 --- a/drivers/char/rio/func.h +++ b/drivers/char/rio/func.h @@ -147,7 +147,6 @@ struct rio_info * rio_info_store( int cmd, struct rio_info * p); extern int rio_pcicopy(char *src, char *dst, int n); extern int rio_minor (struct tty_struct *tty); extern int rio_ismodem (struct tty_struct *tty); -extern void rio_udelay (int usecs); extern void rio_start_card_running (struct Host * HostP); diff --git a/drivers/char/rio/rio_linux.c b/drivers/char/rio/rio_linux.c index 763893e289b..7db3370f497 100644 --- a/drivers/char/rio/rio_linux.c +++ b/drivers/char/rio/rio_linux.c @@ -354,11 +354,6 @@ int rio_ismodem(struct tty_struct *tty) } -void rio_udelay (int usecs) -{ - udelay (usecs); -} - static int rio_set_real_termios (void *ptr) { int rv, modem; diff --git a/drivers/char/rio/rioinit.c b/drivers/char/rio/rioinit.c index dca941ed10c..898a126ae3e 100644 --- a/drivers/char/rio/rioinit.c +++ b/drivers/char/rio/rioinit.c @@ -37,6 +37,7 @@ static char *_rioinit_c_sccs_ = "@(#)rioinit.c 1.3"; #include <linux/module.h> #include <linux/slab.h> #include <linux/errno.h> +#include <linux/delay.h> #include <asm/io.h> #include <asm/system.h> #include <asm/string.h> @@ -1560,14 +1561,14 @@ uint Slot; INTERRUPT_DISABLE | BYTE_OPERATION | SLOW_LINKS | SLOW_AT_BUS); WBYTE(DpRamP->DpResetTpu, 0xFF); - rio_udelay (3); + udelay(3); rio_dprintk (RIO_DEBUG_INIT, "RIOHostReset: Don't know if it worked. Try reset again\n"); WBYTE(DpRamP->DpControl, BOOT_FROM_RAM | EXTERNAL_BUS_OFF | INTERRUPT_DISABLE | BYTE_OPERATION | SLOW_LINKS | SLOW_AT_BUS); WBYTE(DpRamP->DpResetTpu, 0xFF); - rio_udelay (3); + udelay(3); break; #ifdef FUTURE_RELEASE case RIO_EISA: @@ -1599,7 +1600,7 @@ uint Slot; DpRamP->DpControl = RIO_PCI_BOOT_FROM_RAM; DpRamP->DpResetInt = 0xFF; DpRamP->DpResetTpu = 0xFF; - rio_udelay (100); + udelay(100); /* for (i=0; i<6000; i++); */ /* suspend( 3 ); */ break; diff --git a/drivers/char/rio/riotty.c b/drivers/char/rio/riotty.c index db655002671..78a321afdf4 100644 --- a/drivers/char/rio/riotty.c +++ b/drivers/char/rio/riotty.c @@ -524,16 +524,16 @@ riotclose(void *ptr) register uint SysPort = dev; struct ttystatics *tp; /* pointer to our ttystruct */ #endif - struct Port *PortP =ptr; /* pointer to the port structure */ + struct Port *PortP = ptr; /* pointer to the port structure */ int deleted = 0; int try = -1; /* Disable the timeouts by setting them to -1 */ int repeat_this = -1; /* Congrats to those having 15 years of uptime! (You get to break the driver.) */ - long end_time; + unsigned long end_time; struct tty_struct * tty; unsigned long flags; int Modem; - int rv =0; + int rv = 0; rio_dprintk (RIO_DEBUG_TTY, "port close SysPort %d\n",PortP->PortNum); @@ -620,7 +620,7 @@ riotclose(void *ptr) if (repeat_this -- <= 0) { rv = -EINTR; rio_dprintk (RIO_DEBUG_TTY, "Waiting for not idle closed broken by signal\n"); - RIOPreemptiveCmd(p, PortP, FCLOSE ); + RIOPreemptiveCmd(p, PortP, FCLOSE); goto close_end; } rio_dprintk (RIO_DEBUG_TTY, "Calling timeout to flush in closing\n"); @@ -656,14 +656,12 @@ riotclose(void *ptr) goto close_end; } - - /* Can't call RIOShortCommand with the port locked. */ rio_spin_unlock_irqrestore(&PortP->portSem, flags); if (RIOShortCommand(p, PortP, CLOSE, 1, 0) == RIO_FAIL) { - RIOPreemptiveCmd(p, PortP,FCLOSE); - goto close_end; + RIOPreemptiveCmd(p, PortP, FCLOSE); + goto close_end; } if (!deleted) @@ -698,7 +696,6 @@ riotclose(void *ptr) */ PortP->Config &= ~(RIO_CTSFLOW|RIO_RTSFLOW); - #ifdef STATS PortP->Stat.CloseCnt++; #endif diff --git a/drivers/char/rocket.c b/drivers/char/rocket.c index 5bcbeb0cb9a..f463d6baa68 100644 --- a/drivers/char/rocket.c +++ b/drivers/char/rocket.c @@ -161,6 +161,64 @@ static Word_t upci_aiop_intr_bits[AIOP_CTL_SIZE] = { UPCI_AIOP_INTR_BIT_3 }; +static Byte_t RData[RDATASIZE] = { + 0x00, 0x09, 0xf6, 0x82, + 0x02, 0x09, 0x86, 0xfb, + 0x04, 0x09, 0x00, 0x0a, + 0x06, 0x09, 0x01, 0x0a, + 0x08, 0x09, 0x8a, 0x13, + 0x0a, 0x09, 0xc5, 0x11, + 0x0c, 0x09, 0x86, 0x85, + 0x0e, 0x09, 0x20, 0x0a, + 0x10, 0x09, 0x21, 0x0a, + 0x12, 0x09, 0x41, 0xff, + 0x14, 0x09, 0x82, 0x00, + 0x16, 0x09, 0x82, 0x7b, + 0x18, 0x09, 0x8a, 0x7d, + 0x1a, 0x09, 0x88, 0x81, + 0x1c, 0x09, 0x86, 0x7a, + 0x1e, 0x09, 0x84, 0x81, + 0x20, 0x09, 0x82, 0x7c, + 0x22, 0x09, 0x0a, 0x0a +}; + +static Byte_t RRegData[RREGDATASIZE] = { + 0x00, 0x09, 0xf6, 0x82, /* 00: Stop Rx processor */ + 0x08, 0x09, 0x8a, 0x13, /* 04: Tx software flow control */ + 0x0a, 0x09, 0xc5, 0x11, /* 08: XON char */ + 0x0c, 0x09, 0x86, 0x85, /* 0c: XANY */ + 0x12, 0x09, 0x41, 0xff, /* 10: Rx mask char */ + 0x14, 0x09, 0x82, 0x00, /* 14: Compare/Ignore #0 */ + 0x16, 0x09, 0x82, 0x7b, /* 18: Compare #1 */ + 0x18, 0x09, 0x8a, 0x7d, /* 1c: Compare #2 */ + 0x1a, 0x09, 0x88, 0x81, /* 20: Interrupt #1 */ + 0x1c, 0x09, 0x86, 0x7a, /* 24: Ignore/Replace #1 */ + 0x1e, 0x09, 0x84, 0x81, /* 28: Interrupt #2 */ + 0x20, 0x09, 0x82, 0x7c, /* 2c: Ignore/Replace #2 */ + 0x22, 0x09, 0x0a, 0x0a /* 30: Rx FIFO Enable */ +}; + +static CONTROLLER_T sController[CTL_SIZE] = { + {-1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0, 0}, + {0, 0, 0, 0}, {-1, -1, -1, -1}, {0, 0, 0, 0}}, + {-1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0, 0}, + {0, 0, 0, 0}, {-1, -1, -1, -1}, {0, 0, 0, 0}}, + {-1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0, 0}, + {0, 0, 0, 0}, {-1, -1, -1, -1}, {0, 0, 0, 0}}, + {-1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0, 0}, + {0, 0, 0, 0}, {-1, -1, -1, -1}, {0, 0, 0, 0}} +}; + +static Byte_t sBitMapClrTbl[8] = { + 0xfe, 0xfd, 0xfb, 0xf7, 0xef, 0xdf, 0xbf, 0x7f +}; + +static Byte_t sBitMapSetTbl[8] = { + 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80 +}; + +static int sClockPrescale = 0x14; + /* * Line number is the ttySIx number (x), the Minor number. We * assign them sequentially, starting at zero. The following @@ -177,6 +235,26 @@ static void rmSpeakerReset(CONTROLLER_T * CtlP, unsigned long model); static unsigned char GetLineNumber(int ctrl, int aiop, int ch); static unsigned char SetLineNumber(int ctrl, int aiop, int ch); static void rp_start(struct tty_struct *tty); +static int sInitChan(CONTROLLER_T * CtlP, CHANNEL_T * ChP, int AiopNum, + int ChanNum); +static void sSetInterfaceMode(CHANNEL_T * ChP, Byte_t mode); +static void sFlushRxFIFO(CHANNEL_T * ChP); +static void sFlushTxFIFO(CHANNEL_T * ChP); +static void sEnInterrupts(CHANNEL_T * ChP, Word_t Flags); +static void sDisInterrupts(CHANNEL_T * ChP, Word_t Flags); +static void sModemReset(CONTROLLER_T * CtlP, int chan, int on); +static void sPCIModemReset(CONTROLLER_T * CtlP, int chan, int on); +static int sWriteTxPrioByte(CHANNEL_T * ChP, Byte_t Data); +static int sPCIInitController(CONTROLLER_T * CtlP, int CtlNum, + ByteIO_t * AiopIOList, int AiopIOListSize, + WordIO_t ConfigIO, int IRQNum, Byte_t Frequency, + int PeriodicOnly, int altChanRingIndicator, + int UPCIRingInd); +static int sInitController(CONTROLLER_T * CtlP, int CtlNum, ByteIO_t MudbacIO, + ByteIO_t * AiopIOList, int AiopIOListSize, + int IRQNum, Byte_t Frequency, int PeriodicOnly); +static int sReadAiopID(ByteIO_t io); +static int sReadAiopNumChan(WordIO_t io); #ifdef MODULE MODULE_AUTHOR("Theodore Ts'o"); @@ -1798,7 +1876,7 @@ static void rp_flush_buffer(struct tty_struct *tty) * init's aiopic and serial port hardware. * Inputs: i is the board number (0-n) */ -__init int register_PCI(int i, struct pci_dev *dev) +static __init int register_PCI(int i, struct pci_dev *dev) { int num_aiops, aiop, max_num_aiops, num_chan, chan; unsigned int aiopio[MAX_AIOPS_PER_BOARD]; @@ -2453,72 +2531,6 @@ static void rp_cleanup_module(void) } #endif -#ifndef TRUE -#define TRUE 1 -#endif - -#ifndef FALSE -#define FALSE 0 -#endif - -static Byte_t RData[RDATASIZE] = { - 0x00, 0x09, 0xf6, 0x82, - 0x02, 0x09, 0x86, 0xfb, - 0x04, 0x09, 0x00, 0x0a, - 0x06, 0x09, 0x01, 0x0a, - 0x08, 0x09, 0x8a, 0x13, - 0x0a, 0x09, 0xc5, 0x11, - 0x0c, 0x09, 0x86, 0x85, - 0x0e, 0x09, 0x20, 0x0a, - 0x10, 0x09, 0x21, 0x0a, - 0x12, 0x09, 0x41, 0xff, - 0x14, 0x09, 0x82, 0x00, - 0x16, 0x09, 0x82, 0x7b, - 0x18, 0x09, 0x8a, 0x7d, - 0x1a, 0x09, 0x88, 0x81, - 0x1c, 0x09, 0x86, 0x7a, - 0x1e, 0x09, 0x84, 0x81, - 0x20, 0x09, 0x82, 0x7c, - 0x22, 0x09, 0x0a, 0x0a -}; - -static Byte_t RRegData[RREGDATASIZE] = { - 0x00, 0x09, 0xf6, 0x82, /* 00: Stop Rx processor */ - 0x08, 0x09, 0x8a, 0x13, /* 04: Tx software flow control */ - 0x0a, 0x09, 0xc5, 0x11, /* 08: XON char */ - 0x0c, 0x09, 0x86, 0x85, /* 0c: XANY */ - 0x12, 0x09, 0x41, 0xff, /* 10: Rx mask char */ - 0x14, 0x09, 0x82, 0x00, /* 14: Compare/Ignore #0 */ - 0x16, 0x09, 0x82, 0x7b, /* 18: Compare #1 */ - 0x18, 0x09, 0x8a, 0x7d, /* 1c: Compare #2 */ - 0x1a, 0x09, 0x88, 0x81, /* 20: Interrupt #1 */ - 0x1c, 0x09, 0x86, 0x7a, /* 24: Ignore/Replace #1 */ - 0x1e, 0x09, 0x84, 0x81, /* 28: Interrupt #2 */ - 0x20, 0x09, 0x82, 0x7c, /* 2c: Ignore/Replace #2 */ - 0x22, 0x09, 0x0a, 0x0a /* 30: Rx FIFO Enable */ -}; - -CONTROLLER_T sController[CTL_SIZE] = { - {-1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0, 0}, - {0, 0, 0, 0}, {-1, -1, -1, -1}, {0, 0, 0, 0}}, - {-1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0, 0}, - {0, 0, 0, 0}, {-1, -1, -1, -1}, {0, 0, 0, 0}}, - {-1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0, 0}, - {0, 0, 0, 0}, {-1, -1, -1, -1}, {0, 0, 0, 0}}, - {-1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0, 0}, - {0, 0, 0, 0}, {-1, -1, -1, -1}, {0, 0, 0, 0}} -}; - -Byte_t sBitMapClrTbl[8] = { - 0xfe, 0xfd, 0xfb, 0xf7, 0xef, 0xdf, 0xbf, 0x7f -}; - -Byte_t sBitMapSetTbl[8] = { - 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80 -}; - -int sClockPrescale = 0x14; - /*************************************************************************** Function: sInitController Purpose: Initialization of controller global registers and controller @@ -2554,22 +2566,22 @@ Call: sInitController(CtlP,CtlNum,MudbacIO,AiopIOList,AiopIOListSize, FREQ_4HZ - 4 Hertz If IRQNum is set to 0 the Frequency parameter is overidden, it is forced to a value of FREQ_DIS. - int PeriodicOnly: TRUE if all interrupts except the periodic + int PeriodicOnly: 1 if all interrupts except the periodic interrupt are to be blocked. - FALSE is both the periodic interrupt and + 0 is both the periodic interrupt and other channel interrupts are allowed. If IRQNum is set to 0 the PeriodicOnly parameter is - overidden, it is forced to a value of FALSE. + overidden, it is forced to a value of 0. Return: int: Number of AIOPs on the controller, or CTLID_NULL if controller initialization failed. Comments: If periodic interrupts are to be disabled but AIOP interrupts - are allowed, set Frequency to FREQ_DIS and PeriodicOnly to FALSE. + are allowed, set Frequency to FREQ_DIS and PeriodicOnly to 0. If interrupts are to be completely disabled set IRQNum to 0. - Setting Frequency to FREQ_DIS and PeriodicOnly to TRUE is an + Setting Frequency to FREQ_DIS and PeriodicOnly to 1 is an invalid combination. This function performs initialization of global interrupt modes, @@ -2589,9 +2601,9 @@ Warnings: No range checking on any of the parameters is done. After this function all AIOPs on the controller are disabled, they can be enabled with sEnAiop(). */ -int sInitController(CONTROLLER_T * CtlP, int CtlNum, ByteIO_t MudbacIO, - ByteIO_t * AiopIOList, int AiopIOListSize, int IRQNum, - Byte_t Frequency, int PeriodicOnly) +static int sInitController(CONTROLLER_T * CtlP, int CtlNum, ByteIO_t MudbacIO, + ByteIO_t * AiopIOList, int AiopIOListSize, + int IRQNum, Byte_t Frequency, int PeriodicOnly) { int i; ByteIO_t io; @@ -2687,22 +2699,22 @@ Call: sPCIInitController(CtlP,CtlNum,AiopIOList,AiopIOListSize, FREQ_4HZ - 4 Hertz If IRQNum is set to 0 the Frequency parameter is overidden, it is forced to a value of FREQ_DIS. - int PeriodicOnly: TRUE if all interrupts except the periodic + int PeriodicOnly: 1 if all interrupts except the periodic interrupt are to be blocked. - FALSE is both the periodic interrupt and + 0 is both the periodic interrupt and other channel interrupts are allowed. If IRQNum is set to 0 the PeriodicOnly parameter is - overidden, it is forced to a value of FALSE. + overidden, it is forced to a value of 0. Return: int: Number of AIOPs on the controller, or CTLID_NULL if controller initialization failed. Comments: If periodic interrupts are to be disabled but AIOP interrupts - are allowed, set Frequency to FREQ_DIS and PeriodicOnly to FALSE. + are allowed, set Frequency to FREQ_DIS and PeriodicOnly to 0. If interrupts are to be completely disabled set IRQNum to 0. - Setting Frequency to FREQ_DIS and PeriodicOnly to TRUE is an + Setting Frequency to FREQ_DIS and PeriodicOnly to 1 is an invalid combination. This function performs initialization of global interrupt modes, @@ -2722,11 +2734,11 @@ Warnings: No range checking on any of the parameters is done. After this function all AIOPs on the controller are disabled, they can be enabled with sEnAiop(). */ -int sPCIInitController(CONTROLLER_T * CtlP, int CtlNum, - ByteIO_t * AiopIOList, int AiopIOListSize, - WordIO_t ConfigIO, int IRQNum, Byte_t Frequency, - int PeriodicOnly, int altChanRingIndicator, - int UPCIRingInd) +static int sPCIInitController(CONTROLLER_T * CtlP, int CtlNum, + ByteIO_t * AiopIOList, int AiopIOListSize, + WordIO_t ConfigIO, int IRQNum, Byte_t Frequency, + int PeriodicOnly, int altChanRingIndicator, + int UPCIRingInd) { int i; ByteIO_t io; @@ -2784,7 +2796,7 @@ Return: int: Flag AIOPID_XXXX if a valid AIOP is found, where X Warnings: No context switches are allowed while executing this function. */ -int sReadAiopID(ByteIO_t io) +static int sReadAiopID(ByteIO_t io) { Byte_t AiopID; /* ID byte from AIOP */ @@ -2810,7 +2822,7 @@ Comments: The number of channels is determined by write/reads from identical AIOP, otherwise it is an 8 channel. Warnings: No context switches are allowed while executing this function. */ -int sReadAiopNumChan(WordIO_t io) +static int sReadAiopNumChan(WordIO_t io) { Word_t x; static Byte_t R[4] = { 0x00, 0x00, 0x34, 0x12 }; @@ -2834,15 +2846,15 @@ Call: sInitChan(CtlP,ChP,AiopNum,ChanNum) CHANNEL_T *ChP; Ptr to channel structure int AiopNum; AIOP number within controller int ChanNum; Channel number within AIOP -Return: int: TRUE if initialization succeeded, FALSE if it fails because channel +Return: int: 1 if initialization succeeded, 0 if it fails because channel number exceeds number of channels available in AIOP. Comments: This function must be called before a channel can be used. Warnings: No range checking on any of the parameters is done. No context switches are allowed while executing this function. */ -int sInitChan(CONTROLLER_T * CtlP, CHANNEL_T * ChP, int AiopNum, - int ChanNum) +static int sInitChan(CONTROLLER_T * CtlP, CHANNEL_T * ChP, int AiopNum, + int ChanNum) { int i; WordIO_t AiopIO; @@ -2853,7 +2865,7 @@ int sInitChan(CONTROLLER_T * CtlP, CHANNEL_T * ChP, int AiopNum, int brd9600; if (ChanNum >= CtlP->AiopNumChan[AiopNum]) - return (FALSE); /* exceeds num chans in AIOP */ + return 0; /* exceeds num chans in AIOP */ /* Channel, AIOP, and controller identifiers */ ChP->CtlP = CtlP; @@ -2968,7 +2980,7 @@ int sInitChan(CONTROLLER_T * CtlP, CHANNEL_T * ChP, int AiopNum, ChP->TxPrioBuf = ChOff + _TXP_BUF; sEnRxProcessor(ChP); /* start the Rx processor */ - return (TRUE); + return 1; } /*************************************************************************** @@ -2989,7 +3001,7 @@ Warnings: No context switches are allowed while executing this function. After calling this function a delay of 4 uS is required to ensure that the receive processor is no longer processing this channel. */ -void sStopRxProcessor(CHANNEL_T * ChP) +static void sStopRxProcessor(CHANNEL_T * ChP) { Byte_t R[4]; @@ -3014,18 +3026,18 @@ Comments: To prevent data from being enqueued or dequeued in the Tx FIFO this function. Warnings: No context switches are allowed while executing this function. */ -void sFlushRxFIFO(CHANNEL_T * ChP) +static void sFlushRxFIFO(CHANNEL_T * ChP) { int i; Byte_t Ch; /* channel number within AIOP */ - int RxFIFOEnabled; /* TRUE if Rx FIFO enabled */ + int RxFIFOEnabled; /* 1 if Rx FIFO enabled */ if (sGetRxCnt(ChP) == 0) /* Rx FIFO empty */ return; /* don't need to flush */ - RxFIFOEnabled = FALSE; + RxFIFOEnabled = 0; if (ChP->R[0x32] == 0x08) { /* Rx FIFO is enabled */ - RxFIFOEnabled = TRUE; + RxFIFOEnabled = 1; sDisRxFIFO(ChP); /* disable it */ for (i = 0; i < 2000 / 200; i++) /* delay 2 uS to allow proc to disable FIFO */ sInB(ChP->IntChan); /* depends on bus i/o timing */ @@ -3056,18 +3068,18 @@ Comments: To prevent data from being enqueued or dequeued in the Tx FIFO this function. Warnings: No context switches are allowed while executing this function. */ -void sFlushTxFIFO(CHANNEL_T * ChP) +static void sFlushTxFIFO(CHANNEL_T * ChP) { int i; Byte_t Ch; /* channel number within AIOP */ - int TxEnabled; /* TRUE if transmitter enabled */ + int TxEnabled; /* 1 if transmitter enabled */ if (sGetTxCnt(ChP) == 0) /* Tx FIFO empty */ return; /* don't need to flush */ - TxEnabled = FALSE; + TxEnabled = 0; if (ChP->TxControl[3] & TX_ENABLE) { - TxEnabled = TRUE; + TxEnabled = 1; sDisTransmit(ChP); /* disable transmitter */ } sStopRxProcessor(ChP); /* stop Rx processor */ @@ -3096,7 +3108,7 @@ Comments: The priority byte is transmitted before any data in the Tx FIFO. Warnings: No context switches are allowed while executing this function. */ -int sWriteTxPrioByte(CHANNEL_T * ChP, Byte_t Data) +static int sWriteTxPrioByte(CHANNEL_T * ChP, Byte_t Data) { Byte_t DWBuf[4]; /* buffer for double word writes */ Word_t *WordPtr; /* must be far because Win SS != DS */ @@ -3158,7 +3170,7 @@ Comments: If an interrupt enable flag is set in Flags, that interrupt will be enable channel interrupts. This would allow the global interrupt status register to be used to determine which AIOPs need service. */ -void sEnInterrupts(CHANNEL_T * ChP, Word_t Flags) +static void sEnInterrupts(CHANNEL_T * ChP, Word_t Flags) { Byte_t Mask; /* Interrupt Mask Register */ @@ -3202,7 +3214,7 @@ Comments: If an interrupt flag is set in Flags, that interrupt will be this channel's bit from being set in the AIOP's Interrupt Channel Register. */ -void sDisInterrupts(CHANNEL_T * ChP, Word_t Flags) +static void sDisInterrupts(CHANNEL_T * ChP, Word_t Flags) { Byte_t Mask; /* Interrupt Mask Register */ @@ -3218,7 +3230,7 @@ void sDisInterrupts(CHANNEL_T * ChP, Word_t Flags) } } -void sSetInterfaceMode(CHANNEL_T * ChP, Byte_t mode) +static void sSetInterfaceMode(CHANNEL_T * ChP, Byte_t mode) { sOutB(ChP->CtlP->AiopIO[2], (mode & 0x18) | ChP->ChanNum); } @@ -3227,7 +3239,7 @@ void sSetInterfaceMode(CHANNEL_T * ChP, Byte_t mode) * Not an official SSCI function, but how to reset RocketModems. * ISA bus version */ -void sModemReset(CONTROLLER_T * CtlP, int chan, int on) +static void sModemReset(CONTROLLER_T * CtlP, int chan, int on) { ByteIO_t addr; Byte_t val; @@ -3252,7 +3264,7 @@ void sModemReset(CONTROLLER_T * CtlP, int chan, int on) * Not an official SSCI function, but how to reset RocketModems. * PCI bus version */ -void sPCIModemReset(CONTROLLER_T * CtlP, int chan, int on) +static void sPCIModemReset(CONTROLLER_T * CtlP, int chan, int on) { ByteIO_t addr; diff --git a/drivers/char/rocket_int.h b/drivers/char/rocket_int.h index 802687290ee..3a8bcc85bc1 100644 --- a/drivers/char/rocket_int.h +++ b/drivers/char/rocket_int.h @@ -1130,46 +1130,6 @@ Warnings: This function writes the data byte without checking to see if */ #define sWriteTxByte(IO,DATA) sOutB(IO,DATA) -int sInitController(CONTROLLER_T * CtlP, - int CtlNum, - ByteIO_t MudbacIO, - ByteIO_t * AiopIOList, - int AiopIOListSize, - int IRQNum, Byte_t Frequency, int PeriodicOnly); - -int sPCIInitController(CONTROLLER_T * CtlP, - int CtlNum, - ByteIO_t * AiopIOList, - int AiopIOListSize, - WordIO_t ConfigIO, - int IRQNum, - Byte_t Frequency, - int PeriodicOnly, - int altChanRingIndicator, int UPCIRingInd); - -int sReadAiopID(ByteIO_t io); -int sReadAiopNumChan(WordIO_t io); -int sInitChan(CONTROLLER_T * CtlP, - CHANNEL_T * ChP, int AiopNum, int ChanNum); -Byte_t sGetRxErrStatus(CHANNEL_T * ChP); -void sStopRxProcessor(CHANNEL_T * ChP); -void sStopSWInFlowCtl(CHANNEL_T * ChP); -void sFlushRxFIFO(CHANNEL_T * ChP); -void sFlushTxFIFO(CHANNEL_T * ChP); -int sWriteTxPrioByte(CHANNEL_T * ChP, Byte_t Data); -void sEnInterrupts(CHANNEL_T * ChP, Word_t Flags); -void sDisInterrupts(CHANNEL_T * ChP, Word_t Flags); -void sModemReset(CONTROLLER_T * CtlP, int chan, int on); -void sPCIModemReset(CONTROLLER_T * CtlP, int chan, int on); -void sSetInterfaceMode(CHANNEL_T * ChP, Byte_t mode); - -extern Byte_t R[RDATASIZE]; -extern CONTROLLER_T sController[CTL_SIZE]; -extern Byte_t sIRQMap[16]; -extern Byte_t sBitMapClrTbl[8]; -extern Byte_t sBitMapSetTbl[8]; -extern int sClockPrescale; - /* * Begin Linux specific definitions for the Rocketport driver * diff --git a/drivers/char/snsc.c b/drivers/char/snsc.c index e3c0b52d943..261a41bf6d0 100644 --- a/drivers/char/snsc.c +++ b/drivers/char/snsc.c @@ -357,6 +357,8 @@ static struct file_operations scdrv_fops = { .release = scdrv_release, }; +static struct class *snsc_class; + /* * scdrv_init * @@ -372,7 +374,6 @@ scdrv_init(void) char *devnamep; struct sysctl_data_s *scd; void *salbuf; - struct class_simple *snsc_class; dev_t first_dev, dev; nasid_t event_nasid = ia64_sn_get_console_nasid(); @@ -382,7 +383,7 @@ scdrv_init(void) __FUNCTION__); return -ENODEV; } - snsc_class = class_simple_create(THIS_MODULE, SYSCTL_BASENAME); + snsc_class = class_create(THIS_MODULE, SYSCTL_BASENAME); for (cnode = 0; cnode < numionodes; cnode++) { geoid = cnodeid_get_geoid(cnode); @@ -436,7 +437,7 @@ scdrv_init(void) continue; } - class_simple_device_add(snsc_class, dev, NULL, + class_device_create(snsc_class, dev, NULL, "%s", devname); ia64_sn_irtr_intr_enable(scd->scd_nasid, diff --git a/drivers/char/stallion.c b/drivers/char/stallion.c index b8899f560b5..951545a6ef2 100644 --- a/drivers/char/stallion.c +++ b/drivers/char/stallion.c @@ -719,7 +719,7 @@ static struct file_operations stl_fsiomem = { /*****************************************************************************/ -static struct class_simple *stallion_class; +static struct class *stallion_class; /* * Loadable module initialization stuff. @@ -777,13 +777,13 @@ static void __exit stallion_module_exit(void) } for (i = 0; i < 4; i++) { devfs_remove("staliomem/%d", i); - class_simple_device_remove(MKDEV(STL_SIOMEMMAJOR, i)); + class_device_destroy(stallion_class, MKDEV(STL_SIOMEMMAJOR, i)); } devfs_remove("staliomem"); if ((i = unregister_chrdev(STL_SIOMEMMAJOR, "staliomem"))) printk("STALLION: failed to un-register serial memory device, " "errno=%d\n", -i); - class_simple_destroy(stallion_class); + class_destroy(stallion_class); if (stl_tmpwritebuf != (char *) NULL) kfree(stl_tmpwritebuf); @@ -3090,12 +3090,12 @@ static int __init stl_init(void) printk("STALLION: failed to register serial board device\n"); devfs_mk_dir("staliomem"); - stallion_class = class_simple_create(THIS_MODULE, "staliomem"); + stallion_class = class_create(THIS_MODULE, "staliomem"); for (i = 0; i < 4; i++) { devfs_mk_cdev(MKDEV(STL_SIOMEMMAJOR, i), S_IFCHR|S_IRUSR|S_IWUSR, "staliomem/%d", i); - class_simple_device_add(stallion_class, MKDEV(STL_SIOMEMMAJOR, i), NULL, "staliomem%d", i); + class_device_create(stallion_class, MKDEV(STL_SIOMEMMAJOR, i), NULL, "staliomem%d", i); } stl_serial->owner = THIS_MODULE; diff --git a/drivers/char/sysrq.c b/drivers/char/sysrq.c index f59f7cbd525..af79805b557 100644 --- a/drivers/char/sysrq.c +++ b/drivers/char/sysrq.c @@ -35,6 +35,7 @@ #include <linux/spinlock.h> #include <linux/vt_kern.h> #include <linux/workqueue.h> +#include <linux/kexec.h> #include <asm/ptrace.h> @@ -94,6 +95,21 @@ static struct sysrq_key_op sysrq_unraw_op = { }; #endif /* CONFIG_VT */ +#ifdef CONFIG_KEXEC +/* crashdump sysrq handler */ +static void sysrq_handle_crashdump(int key, struct pt_regs *pt_regs, + struct tty_struct *tty) +{ + crash_kexec(pt_regs); +} +static struct sysrq_key_op sysrq_crashdump_op = { + .handler = sysrq_handle_crashdump, + .help_msg = "Crashdump", + .action_msg = "Trigger a crashdump", + .enable_mask = SYSRQ_ENABLE_DUMP, +}; +#endif + /* reboot sysrq handler */ static void sysrq_handle_reboot(int key, struct pt_regs *pt_regs, struct tty_struct *tty) @@ -273,8 +289,12 @@ static struct sysrq_key_op *sysrq_key_table[SYSRQ_KEY_TABLE_LENGTH] = { it is handled specially on the sparc and will never arrive */ /* b */ &sysrq_reboot_op, -/* c */ NULL, -/* d */ NULL, +#ifdef CONFIG_KEXEC +/* c */ &sysrq_crashdump_op, +#else +/* c */ NULL, +#endif +/* d */ NULL, /* e */ &sysrq_term_op, /* f */ &sysrq_moom_op, /* g */ NULL, diff --git a/drivers/char/tipar.c b/drivers/char/tipar.c index 0c5ba9dc906..659335d80ee 100644 --- a/drivers/char/tipar.c +++ b/drivers/char/tipar.c @@ -90,7 +90,7 @@ static int timeout = TIMAXTIME; /* timeout in tenth of seconds */ static unsigned int tp_count; /* tipar count */ static unsigned long opened; /* opened devices */ -static struct class_simple *tipar_class; +static struct class *tipar_class; /* --- macros for parport access -------------------------------------- */ @@ -436,7 +436,7 @@ tipar_register(int nr, struct parport *port) goto out; } - class_simple_device_add(tipar_class, MKDEV(TIPAR_MAJOR, + class_device_create(tipar_class, MKDEV(TIPAR_MAJOR, TIPAR_MINOR + nr), NULL, "par%d", nr); /* Use devfs, tree: /dev/ticables/par/[0..2] */ err = devfs_mk_cdev(MKDEV(TIPAR_MAJOR, TIPAR_MINOR + nr), @@ -458,8 +458,8 @@ tipar_register(int nr, struct parport *port) goto out; out_class: - class_simple_device_remove(MKDEV(TIPAR_MAJOR, TIPAR_MINOR + nr)); - class_simple_destroy(tipar_class); + class_device_destroy(tipar_class, MKDEV(TIPAR_MAJOR, TIPAR_MINOR + nr)); + class_destroy(tipar_class); out: return err; } @@ -505,7 +505,7 @@ tipar_init_module(void) /* Use devfs with tree: /dev/ticables/par/[0..2] */ devfs_mk_dir("ticables/par"); - tipar_class = class_simple_create(THIS_MODULE, "ticables"); + tipar_class = class_create(THIS_MODULE, "ticables"); if (IS_ERR(tipar_class)) { err = PTR_ERR(tipar_class); goto out_chrdev; @@ -539,10 +539,10 @@ tipar_cleanup_module(void) if (table[i].dev == NULL) continue; parport_unregister_device(table[i].dev); - class_simple_device_remove(MKDEV(TIPAR_MAJOR, i)); + class_device_destroy(tipar_class, MKDEV(TIPAR_MAJOR, i)); devfs_remove("ticables/par/%d", i); } - class_simple_destroy(tipar_class); + class_destroy(tipar_class); devfs_remove("ticables/par"); pr_info("tipar: module unloaded\n"); diff --git a/drivers/char/toshiba.c b/drivers/char/toshiba.c index 58e21fe4426..0c6f521abd0 100644 --- a/drivers/char/toshiba.c +++ b/drivers/char/toshiba.c @@ -73,16 +73,20 @@ #define TOSH_MINOR_DEV 181 -static int tosh_id = 0x0000; -static int tosh_bios = 0x0000; -static int tosh_date = 0x0000; -static int tosh_sci = 0x0000; -static int tosh_fan = 0; - -static int tosh_fn = 0; +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Jonathan Buzzard <jonathan@buzzard.org.uk>"); +MODULE_DESCRIPTION("Toshiba laptop SMM driver"); +MODULE_SUPPORTED_DEVICE("toshiba"); -module_param(tosh_fn, int, 0); +static int tosh_fn; +module_param_named(fn, tosh_fn, int, 0); +MODULE_PARM_DESC(fn, "User specified Fn key detection port"); +static int tosh_id; +static int tosh_bios; +static int tosh_date; +static int tosh_sci; +static int tosh_fan; static int tosh_ioctl(struct inode *, struct file *, unsigned int, unsigned long); @@ -359,7 +363,7 @@ static int tosh_get_machine_id(void) unsigned long address; id = (0x100*(int) isa_readb(0xffffe))+((int) isa_readb(0xffffa)); - + /* do we have a SCTTable machine identication number on our hands */ if (id==0xfc2f) { @@ -424,7 +428,7 @@ static int tosh_probe(void) } /* call the Toshiba SCI support check routine */ - + regs.eax = 0xf0f0; regs.ebx = 0x0000; regs.ecx = 0x0000; @@ -440,7 +444,7 @@ static int tosh_probe(void) /* if we get this far then we are running on a Toshiba (probably)! */ tosh_sci = regs.edx & 0xffff; - + /* next get the machine ID of the current laptop */ tosh_id = tosh_get_machine_id(); @@ -475,16 +479,15 @@ static int tosh_probe(void) return 0; } -int __init tosh_init(void) +static int __init toshiba_init(void) { int retval; /* are we running on a Toshiba laptop */ - if (tosh_probe()!=0) - return -EIO; + if (tosh_probe()) + return -ENODEV; - printk(KERN_INFO "Toshiba System Managment Mode driver v" - TOSH_VERSION"\n"); + printk(KERN_INFO "Toshiba System Managment Mode driver v" TOSH_VERSION "\n"); /* set the port to use for Fn status if not specified as a parameter */ if (tosh_fn==0x00) @@ -492,12 +495,12 @@ int __init tosh_init(void) /* register the device file */ retval = misc_register(&tosh_device); - if(retval < 0) + if (retval < 0) return retval; #ifdef CONFIG_PROC_FS /* register the proc entry */ - if(create_proc_info_entry("toshiba", 0, NULL, tosh_get_info) == NULL){ + if (create_proc_info_entry("toshiba", 0, NULL, tosh_get_info) == NULL) { misc_deregister(&tosh_device); return -ENOMEM; } @@ -506,27 +509,12 @@ int __init tosh_init(void) return 0; } -#ifdef MODULE -int init_module(void) -{ - return tosh_init(); -} - -void cleanup_module(void) +static void __exit toshiba_exit(void) { - /* remove the proc entry */ - remove_proc_entry("toshiba", NULL); - - /* unregister the device file */ - misc_deregister(&tosh_device); } -#endif -MODULE_LICENSE("GPL"); -MODULE_PARM_DESC(tosh_fn, "User specified Fn key detection port"); -MODULE_AUTHOR("Jonathan Buzzard <jonathan@buzzard.org.uk>"); -MODULE_DESCRIPTION("Toshiba laptop SMM driver"); -MODULE_SUPPORTED_DEVICE("toshiba"); +module_init(toshiba_init); +module_exit(toshiba_exit); diff --git a/drivers/char/tpm/tpm.c b/drivers/char/tpm/tpm.c index 87235330fdb..854475c54f0 100644 --- a/drivers/char/tpm/tpm.c +++ b/drivers/char/tpm/tpm.c @@ -19,7 +19,7 @@ * * Note, the TPM chip is not interrupt driven (only polling) * and can have very long timeouts (minutes!). Hence the unusual - * calls to schedule_timeout. + * calls to msleep. * */ @@ -28,19 +28,16 @@ #include <linux/spinlock.h> #include "tpm.h" -#define TPM_MINOR 224 /* officially assigned */ - -#define TPM_BUFSIZE 2048 - -/* PCI configuration addresses */ -#define PCI_GEN_PMCON_1 0xA0 -#define PCI_GEN1_DEC 0xE4 -#define PCI_LPC_EN 0xE6 -#define PCI_GEN2_DEC 0xEC +enum tpm_const { + TPM_MINOR = 224, /* officially assigned */ + TPM_BUFSIZE = 2048, + TPM_NUM_DEVICES = 256, + TPM_NUM_MASK_ENTRIES = TPM_NUM_DEVICES / (8 * sizeof(int)) +}; static LIST_HEAD(tpm_chip_list); static DEFINE_SPINLOCK(driver_lock); -static int dev_mask[32]; +static int dev_mask[TPM_NUM_MASK_ENTRIES]; static void user_reader_timeout(unsigned long ptr) { @@ -52,92 +49,17 @@ static void user_reader_timeout(unsigned long ptr) up(&chip->buffer_mutex); } -void tpm_time_expired(unsigned long ptr) -{ - int *exp = (int *) ptr; - *exp = 1; -} - -EXPORT_SYMBOL_GPL(tpm_time_expired); - -/* - * Initialize the LPC bus and enable the TPM ports - */ -int tpm_lpc_bus_init(struct pci_dev *pci_dev, u16 base) -{ - u32 lpcenable, tmp; - int is_lpcm = 0; - - switch (pci_dev->vendor) { - case PCI_VENDOR_ID_INTEL: - switch (pci_dev->device) { - case PCI_DEVICE_ID_INTEL_82801CA_12: - case PCI_DEVICE_ID_INTEL_82801DB_12: - is_lpcm = 1; - break; - } - /* init ICH (enable LPC) */ - pci_read_config_dword(pci_dev, PCI_GEN1_DEC, &lpcenable); - lpcenable |= 0x20000000; - pci_write_config_dword(pci_dev, PCI_GEN1_DEC, lpcenable); - - if (is_lpcm) { - pci_read_config_dword(pci_dev, PCI_GEN1_DEC, - &lpcenable); - if ((lpcenable & 0x20000000) == 0) { - dev_err(&pci_dev->dev, - "cannot enable LPC\n"); - return -ENODEV; - } - } - - /* initialize TPM registers */ - pci_read_config_dword(pci_dev, PCI_GEN2_DEC, &tmp); - - if (!is_lpcm) - tmp = (tmp & 0xFFFF0000) | (base & 0xFFF0); - else - tmp = - (tmp & 0xFFFF0000) | (base & 0xFFF0) | - 0x00000001; - - pci_write_config_dword(pci_dev, PCI_GEN2_DEC, tmp); - - if (is_lpcm) { - pci_read_config_dword(pci_dev, PCI_GEN_PMCON_1, - &tmp); - tmp |= 0x00000004; /* enable CLKRUN */ - pci_write_config_dword(pci_dev, PCI_GEN_PMCON_1, - tmp); - } - tpm_write_index(0x0D, 0x55); /* unlock 4F */ - tpm_write_index(0x0A, 0x00); /* int disable */ - tpm_write_index(0x08, base); /* base addr lo */ - tpm_write_index(0x09, (base & 0xFF00) >> 8); /* base addr hi */ - tpm_write_index(0x0D, 0xAA); /* lock 4F */ - break; - case PCI_VENDOR_ID_AMD: - /* nothing yet */ - break; - } - - return 0; -} - -EXPORT_SYMBOL_GPL(tpm_lpc_bus_init); - /* * Internal kernel interface to transmit TPM commands */ static ssize_t tpm_transmit(struct tpm_chip *chip, const char *buf, size_t bufsiz) { - ssize_t len; + ssize_t rc; u32 count; - __be32 *native_size; + unsigned long stop; - native_size = (__force __be32 *) (buf + 2); - count = be32_to_cpu(*native_size); + count = be32_to_cpu(*((__be32 *) (buf + 2))); if (count == 0) return -ENODATA; @@ -149,53 +71,49 @@ static ssize_t tpm_transmit(struct tpm_chip *chip, const char *buf, down(&chip->tpm_mutex); - if ((len = chip->vendor->send(chip, (u8 *) buf, count)) < 0) { + if ((rc = chip->vendor->send(chip, (u8 *) buf, count)) < 0) { dev_err(&chip->pci_dev->dev, - "tpm_transmit: tpm_send: error %zd\n", len); - return len; + "tpm_transmit: tpm_send: error %zd\n", rc); + goto out; } - down(&chip->timer_manipulation_mutex); - chip->time_expired = 0; - init_timer(&chip->device_timer); - chip->device_timer.function = tpm_time_expired; - chip->device_timer.expires = jiffies + 2 * 60 * HZ; - chip->device_timer.data = (unsigned long) &chip->time_expired; - add_timer(&chip->device_timer); - up(&chip->timer_manipulation_mutex); - + stop = jiffies + 2 * 60 * HZ; do { u8 status = inb(chip->vendor->base + 1); if ((status & chip->vendor->req_complete_mask) == chip->vendor->req_complete_val) { - down(&chip->timer_manipulation_mutex); - del_singleshot_timer_sync(&chip->device_timer); - up(&chip->timer_manipulation_mutex); goto out_recv; } - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(TPM_TIMEOUT); + + if ((status == chip->vendor->req_canceled)) { + dev_err(&chip->pci_dev->dev, "Operation Canceled\n"); + rc = -ECANCELED; + goto out; + } + + msleep(TPM_TIMEOUT); /* CHECK */ rmb(); - } while (!chip->time_expired); + } while (time_before(jiffies, stop)); chip->vendor->cancel(chip); - dev_err(&chip->pci_dev->dev, "Time expired\n"); - up(&chip->tpm_mutex); - return -EIO; + dev_err(&chip->pci_dev->dev, "Operation Timed out\n"); + rc = -ETIME; + goto out; out_recv: - len = chip->vendor->recv(chip, (u8 *) buf, bufsiz); - if (len < 0) + rc = chip->vendor->recv(chip, (u8 *) buf, bufsiz); + if (rc < 0) dev_err(&chip->pci_dev->dev, - "tpm_transmit: tpm_recv: error %zd\n", len); + "tpm_transmit: tpm_recv: error %zd\n", rc); +out: up(&chip->tpm_mutex); - return len; + return rc; } #define TPM_DIGEST_SIZE 20 #define CAP_PCR_RESULT_SIZE 18 -static u8 cap_pcr[] = { +static const u8 cap_pcr[] = { 0, 193, /* TPM_TAG_RQU_COMMAND */ 0, 0, 0, 22, /* length */ 0, 0, 0, 101, /* TPM_ORD_GetCapability */ @@ -205,75 +123,94 @@ static u8 cap_pcr[] = { }; #define READ_PCR_RESULT_SIZE 30 -static u8 pcrread[] = { +static const u8 pcrread[] = { 0, 193, /* TPM_TAG_RQU_COMMAND */ 0, 0, 0, 14, /* length */ 0, 0, 0, 21, /* TPM_ORD_PcrRead */ 0, 0, 0, 0 /* PCR index */ }; -static ssize_t show_pcrs(struct device *dev, char *buf) +ssize_t tpm_show_pcrs(struct device *dev, struct device_attribute *attr, + char *buf) { u8 data[READ_PCR_RESULT_SIZE]; ssize_t len; - int i, j, index, num_pcrs; + int i, j, num_pcrs; + __be32 index; char *str = buf; struct tpm_chip *chip = - pci_get_drvdata(container_of(dev, struct pci_dev, dev)); + pci_get_drvdata(to_pci_dev(dev)); if (chip == NULL) return -ENODEV; memcpy(data, cap_pcr, sizeof(cap_pcr)); if ((len = tpm_transmit(chip, data, sizeof(data))) - < CAP_PCR_RESULT_SIZE) - return len; + < CAP_PCR_RESULT_SIZE) { + dev_dbg(&chip->pci_dev->dev, "A TPM error (%d) occurred " + "attempting to determine the number of PCRS\n", + be32_to_cpu(*((__be32 *) (data + 6)))); + return 0; + } - num_pcrs = be32_to_cpu(*((__force __be32 *) (data + 14))); + num_pcrs = be32_to_cpu(*((__be32 *) (data + 14))); for (i = 0; i < num_pcrs; i++) { memcpy(data, pcrread, sizeof(pcrread)); index = cpu_to_be32(i); memcpy(data + 10, &index, 4); if ((len = tpm_transmit(chip, data, sizeof(data))) - < READ_PCR_RESULT_SIZE) - return len; + < READ_PCR_RESULT_SIZE){ + dev_dbg(&chip->pci_dev->dev, "A TPM error (%d) occurred" + " attempting to read PCR %d of %d\n", + be32_to_cpu(*((__be32 *) (data + 6))), i, num_pcrs); + goto out; + } str += sprintf(str, "PCR-%02d: ", i); for (j = 0; j < TPM_DIGEST_SIZE; j++) str += sprintf(str, "%02X ", *(data + 10 + j)); str += sprintf(str, "\n"); } +out: return str - buf; } - -static DEVICE_ATTR(pcrs, S_IRUGO, show_pcrs, NULL); +EXPORT_SYMBOL_GPL(tpm_show_pcrs); #define READ_PUBEK_RESULT_SIZE 314 -static u8 readpubek[] = { +static const u8 readpubek[] = { 0, 193, /* TPM_TAG_RQU_COMMAND */ 0, 0, 0, 30, /* length */ 0, 0, 0, 124, /* TPM_ORD_ReadPubek */ }; -static ssize_t show_pubek(struct device *dev, char *buf) +ssize_t tpm_show_pubek(struct device *dev, struct device_attribute *attr, + char *buf) { - u8 data[READ_PUBEK_RESULT_SIZE]; + u8 *data; ssize_t len; - __be32 *native_val; - int i; + int i, rc; char *str = buf; struct tpm_chip *chip = - pci_get_drvdata(container_of(dev, struct pci_dev, dev)); + pci_get_drvdata(to_pci_dev(dev)); if (chip == NULL) return -ENODEV; + data = kmalloc(READ_PUBEK_RESULT_SIZE, GFP_KERNEL); + if (!data) + return -ENOMEM; + memcpy(data, readpubek, sizeof(readpubek)); memset(data + sizeof(readpubek), 0, 20); /* zero nonce */ - if ((len = tpm_transmit(chip, data, sizeof(data))) < - READ_PUBEK_RESULT_SIZE) - return len; + if ((len = tpm_transmit(chip, data, READ_PUBEK_RESULT_SIZE)) < + READ_PUBEK_RESULT_SIZE) { + dev_dbg(&chip->pci_dev->dev, "A TPM error (%d) occurred " + "attempting to read the PUBEK\n", + be32_to_cpu(*((__be32 *) (data + 6)))); + rc = 0; + goto out; + } /* ignore header 10 bytes @@ -286,8 +223,6 @@ static ssize_t show_pubek(struct device *dev, char *buf) ignore checksum 20 bytes */ - native_val = (__force __be32 *) (data + 34); - str += sprintf(str, "Algorithm: %02X %02X %02X %02X\nEncscheme: %02X %02X\n" @@ -298,21 +233,23 @@ static ssize_t show_pubek(struct device *dev, char *buf) data[15], data[16], data[17], data[22], data[23], data[24], data[25], data[26], data[27], data[28], data[29], data[30], data[31], data[32], data[33], - be32_to_cpu(*native_val) - ); + be32_to_cpu(*((__be32 *) (data + 34)))); for (i = 0; i < 256; i++) { - str += sprintf(str, "%02X ", data[i + 39]); + str += sprintf(str, "%02X ", data[i + 38]); if ((i + 1) % 16 == 0) str += sprintf(str, "\n"); } - return str - buf; + rc = str - buf; +out: + kfree(data); + return rc; } -static DEVICE_ATTR(pubek, S_IRUGO, show_pubek, NULL); +EXPORT_SYMBOL_GPL(tpm_show_pubek); #define CAP_VER_RESULT_SIZE 18 -static u8 cap_version[] = { +static const u8 cap_version[] = { 0, 193, /* TPM_TAG_RQU_COMMAND */ 0, 0, 0, 18, /* length */ 0, 0, 0, 101, /* TPM_ORD_GetCapability */ @@ -321,7 +258,7 @@ static u8 cap_version[] = { }; #define CAP_MANUFACTURER_RESULT_SIZE 18 -static u8 cap_manufacturer[] = { +static const u8 cap_manufacturer[] = { 0, 193, /* TPM_TAG_RQU_COMMAND */ 0, 0, 0, 22, /* length */ 0, 0, 0, 101, /* TPM_ORD_GetCapability */ @@ -330,14 +267,15 @@ static u8 cap_manufacturer[] = { 0, 0, 1, 3 }; -static ssize_t show_caps(struct device *dev, char *buf) +ssize_t tpm_show_caps(struct device *dev, struct device_attribute *attr, + char *buf) { - u8 data[READ_PUBEK_RESULT_SIZE]; + u8 data[sizeof(cap_manufacturer)]; ssize_t len; char *str = buf; struct tpm_chip *chip = - pci_get_drvdata(container_of(dev, struct pci_dev, dev)); + pci_get_drvdata(to_pci_dev(dev)); if (chip == NULL) return -ENODEV; @@ -348,7 +286,7 @@ static ssize_t show_caps(struct device *dev, char *buf) return len; str += sprintf(str, "Manufacturer: 0x%x\n", - be32_to_cpu(*(data + 14))); + be32_to_cpu(*((__be32 *) (data + 14)))); memcpy(data, cap_version, sizeof(cap_version)); @@ -363,8 +301,20 @@ static ssize_t show_caps(struct device *dev, char *buf) return str - buf; } +EXPORT_SYMBOL_GPL(tpm_show_caps); + +ssize_t tpm_store_cancel(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct tpm_chip *chip = dev_get_drvdata(dev); + if (chip == NULL) + return 0; + + chip->vendor->cancel(chip); + return count; +} +EXPORT_SYMBOL_GPL(tpm_store_cancel); -static DEVICE_ATTR(caps, S_IRUGO, show_caps, NULL); /* * Device file system interface to the TPM @@ -422,24 +372,15 @@ EXPORT_SYMBOL_GPL(tpm_open); int tpm_release(struct inode *inode, struct file *file) { struct tpm_chip *chip = file->private_data; - - file->private_data = NULL; spin_lock(&driver_lock); + file->private_data = NULL; chip->num_opens--; - spin_unlock(&driver_lock); - - down(&chip->timer_manipulation_mutex); - if (timer_pending(&chip->user_read_timer)) - del_singleshot_timer_sync(&chip->user_read_timer); - else if (timer_pending(&chip->device_timer)) - del_singleshot_timer_sync(&chip->device_timer); - up(&chip->timer_manipulation_mutex); - - kfree(chip->data_buffer); + del_singleshot_timer_sync(&chip->user_read_timer); atomic_set(&chip->data_pending, 0); - pci_dev_put(chip->pci_dev); + kfree(chip->data_buffer); + spin_unlock(&driver_lock); return 0; } @@ -453,10 +394,8 @@ ssize_t tpm_write(struct file * file, const char __user * buf, /* cannot perform a write until the read has cleared either via tpm_read or a user_read_timer timeout */ - while (atomic_read(&chip->data_pending) != 0) { - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(TPM_TIMEOUT); - } + while (atomic_read(&chip->data_pending) != 0) + msleep(TPM_TIMEOUT); down(&chip->buffer_mutex); @@ -476,13 +415,7 @@ ssize_t tpm_write(struct file * file, const char __user * buf, up(&chip->buffer_mutex); /* Set a timeout by which the reader must come claim the result */ - down(&chip->timer_manipulation_mutex); - init_timer(&chip->user_read_timer); - chip->user_read_timer.function = user_reader_timeout; - chip->user_read_timer.data = (unsigned long) chip; - chip->user_read_timer.expires = jiffies + (60 * HZ); - add_timer(&chip->user_read_timer); - up(&chip->timer_manipulation_mutex); + mod_timer(&chip->user_read_timer, jiffies + (60 * HZ)); return in_size; } @@ -493,29 +426,19 @@ ssize_t tpm_read(struct file * file, char __user * buf, size_t size, loff_t * off) { struct tpm_chip *chip = file->private_data; - int ret_size = -ENODATA; + int ret_size; - if (atomic_read(&chip->data_pending) != 0) { /* Result available */ - down(&chip->timer_manipulation_mutex); - del_singleshot_timer_sync(&chip->user_read_timer); - up(&chip->timer_manipulation_mutex); + del_singleshot_timer_sync(&chip->user_read_timer); + ret_size = atomic_read(&chip->data_pending); + atomic_set(&chip->data_pending, 0); + if (ret_size > 0) { /* relay data */ + if (size < ret_size) + ret_size = size; down(&chip->buffer_mutex); - - ret_size = atomic_read(&chip->data_pending); - atomic_set(&chip->data_pending, 0); - - if (ret_size == 0) /* timeout just occurred */ - ret_size = -ETIME; - else if (ret_size > 0) { /* relay data */ - if (size < ret_size) - ret_size = size; - - if (copy_to_user((void __user *) buf, - chip->data_buffer, ret_size)) { - ret_size = -EFAULT; - } - } + if (copy_to_user + ((void __user *) buf, chip->data_buffer, ret_size)) + ret_size = -EFAULT; up(&chip->buffer_mutex); } @@ -541,14 +464,13 @@ void __devexit tpm_remove(struct pci_dev *pci_dev) pci_set_drvdata(pci_dev, NULL); misc_deregister(&chip->vendor->miscdev); + kfree(&chip->vendor->miscdev.name); - device_remove_file(&pci_dev->dev, &dev_attr_pubek); - device_remove_file(&pci_dev->dev, &dev_attr_pcrs); - device_remove_file(&pci_dev->dev, &dev_attr_caps); + sysfs_remove_group(&pci_dev->dev.kobj, chip->vendor->attr_group); pci_disable_device(pci_dev); - dev_mask[chip->dev_num / 32] &= !(1 << (chip->dev_num % 32)); + dev_mask[chip->dev_num / TPM_NUM_MASK_ENTRIES ] &= !(1 << (chip->dev_num % TPM_NUM_MASK_ENTRIES)); kfree(chip); @@ -590,10 +512,6 @@ int tpm_pm_resume(struct pci_dev *pci_dev) if (chip == NULL) return -ENODEV; - spin_lock(&driver_lock); - tpm_lpc_bus_init(pci_dev, chip->vendor->base); - spin_unlock(&driver_lock); - return 0; } @@ -609,7 +527,9 @@ EXPORT_SYMBOL_GPL(tpm_pm_resume); int tpm_register_hardware(struct pci_dev *pci_dev, struct tpm_vendor_specific *entry) { - char devname[7]; +#define DEVNAME_SIZE 7 + + char *devname; struct tpm_chip *chip; int i, j; @@ -622,17 +542,21 @@ int tpm_register_hardware(struct pci_dev *pci_dev, init_MUTEX(&chip->buffer_mutex); init_MUTEX(&chip->tpm_mutex); - init_MUTEX(&chip->timer_manipulation_mutex); INIT_LIST_HEAD(&chip->list); + init_timer(&chip->user_read_timer); + chip->user_read_timer.function = user_reader_timeout; + chip->user_read_timer.data = (unsigned long) chip; + chip->vendor = entry; chip->dev_num = -1; - for (i = 0; i < 32; i++) - for (j = 0; j < 8; j++) + for (i = 0; i < TPM_NUM_MASK_ENTRIES; i++) + for (j = 0; j < 8 * sizeof(int); j++) if ((dev_mask[i] & (1 << j)) == 0) { - chip->dev_num = i * 32 + j; + chip->dev_num = + i * TPM_NUM_MASK_ENTRIES + j; dev_mask[i] |= 1 << j; goto dev_num_search_complete; } @@ -648,7 +572,8 @@ dev_num_search_complete: else chip->vendor->miscdev.minor = MISC_DYNAMIC_MINOR; - snprintf(devname, sizeof(devname), "%s%d", "tpm", chip->dev_num); + devname = kmalloc(DEVNAME_SIZE, GFP_KERNEL); + scnprintf(devname, DEVNAME_SIZE, "%s%d", "tpm", chip->dev_num); chip->vendor->miscdev.name = devname; chip->vendor->miscdev.dev = &(pci_dev->dev); @@ -665,31 +590,20 @@ dev_num_search_complete: return -ENODEV; } + spin_lock(&driver_lock); + pci_set_drvdata(pci_dev, chip); list_add(&chip->list, &tpm_chip_list); - device_create_file(&pci_dev->dev, &dev_attr_pubek); - device_create_file(&pci_dev->dev, &dev_attr_pcrs); - device_create_file(&pci_dev->dev, &dev_attr_caps); - - return 0; -} + spin_unlock(&driver_lock); -EXPORT_SYMBOL_GPL(tpm_register_hardware); + sysfs_create_group(&pci_dev->dev.kobj, chip->vendor->attr_group); -static int __init init_tpm(void) -{ return 0; } -static void __exit cleanup_tpm(void) -{ - -} - -module_init(init_tpm); -module_exit(cleanup_tpm); +EXPORT_SYMBOL_GPL(tpm_register_hardware); MODULE_AUTHOR("Leendert van Doorn (leendert@watson.ibm.com)"); MODULE_DESCRIPTION("TPM Driver"); diff --git a/drivers/char/tpm/tpm.h b/drivers/char/tpm/tpm.h index de0c796fce8..373b41f6b46 100644 --- a/drivers/char/tpm/tpm.h +++ b/drivers/char/tpm/tpm.h @@ -25,23 +25,38 @@ #include <linux/fs.h> #include <linux/miscdevice.h> -#define TPM_TIMEOUT msecs_to_jiffies(5) +enum tpm_timeout { + TPM_TIMEOUT = 5, /* msecs */ +}; /* TPM addresses */ -#define TPM_ADDR 0x4E -#define TPM_DATA 0x4F +enum tpm_addr { + TPM_SUPERIO_ADDR = 0x2E, + TPM_ADDR = 0x4E, +}; + +extern ssize_t tpm_show_pubek(struct device *, struct device_attribute *attr, + char *); +extern ssize_t tpm_show_pcrs(struct device *, struct device_attribute *attr, + char *); +extern ssize_t tpm_show_caps(struct device *, struct device_attribute *attr, + char *); +extern ssize_t tpm_store_cancel(struct device *, struct device_attribute *attr, + const char *, size_t); struct tpm_chip; struct tpm_vendor_specific { u8 req_complete_mask; u8 req_complete_val; + u8 req_canceled; u16 base; /* TPM base address */ int (*recv) (struct tpm_chip *, u8 *, size_t); int (*send) (struct tpm_chip *, u8 *, size_t); void (*cancel) (struct tpm_chip *); struct miscdevice miscdev; + struct attribute_group *attr_group; }; struct tpm_chip { @@ -58,29 +73,24 @@ struct tpm_chip { struct timer_list user_read_timer; /* user needs to claim result */ struct semaphore tpm_mutex; /* tpm is processing */ - struct timer_list device_timer; /* tpm is processing */ - struct semaphore timer_manipulation_mutex; struct tpm_vendor_specific *vendor; struct list_head list; }; -static inline int tpm_read_index(int index) +static inline int tpm_read_index(int base, int index) { - outb(index, TPM_ADDR); - return inb(TPM_DATA) & 0xFF; + outb(index, base); + return inb(base+1) & 0xFF; } -static inline void tpm_write_index(int index, int value) +static inline void tpm_write_index(int base, int index, int value) { - outb(index, TPM_ADDR); - outb(value & 0xFF, TPM_DATA); + outb(index, base); + outb(value & 0xFF, base+1); } -extern void tpm_time_expired(unsigned long); -extern int tpm_lpc_bus_init(struct pci_dev *, u16); - extern int tpm_register_hardware(struct pci_dev *, struct tpm_vendor_specific *); extern int tpm_open(struct inode *, struct file *); diff --git a/drivers/char/tpm/tpm_atmel.c b/drivers/char/tpm/tpm_atmel.c index f9333e729b6..cc2cc77fd17 100644 --- a/drivers/char/tpm/tpm_atmel.c +++ b/drivers/char/tpm/tpm_atmel.c @@ -22,17 +22,23 @@ #include "tpm.h" /* Atmel definitions */ -#define TPM_ATML_BASE 0x400 +enum tpm_atmel_addr { + TPM_ATMEL_BASE_ADDR_LO = 0x08, + TPM_ATMEL_BASE_ADDR_HI = 0x09 +}; /* write status bits */ -#define ATML_STATUS_ABORT 0x01 -#define ATML_STATUS_LASTBYTE 0x04 - +enum tpm_atmel_write_status { + ATML_STATUS_ABORT = 0x01, + ATML_STATUS_LASTBYTE = 0x04 +}; /* read status bits */ -#define ATML_STATUS_BUSY 0x01 -#define ATML_STATUS_DATA_AVAIL 0x02 -#define ATML_STATUS_REWRITE 0x04 - +enum tpm_atmel_read_status { + ATML_STATUS_BUSY = 0x01, + ATML_STATUS_DATA_AVAIL = 0x02, + ATML_STATUS_REWRITE = 0x04, + ATML_STATUS_READY = 0x08 +}; static int tpm_atml_recv(struct tpm_chip *chip, u8 * buf, size_t count) { @@ -121,13 +127,29 @@ static struct file_operations atmel_ops = { .release = tpm_release, }; +static DEVICE_ATTR(pubek, S_IRUGO, tpm_show_pubek, NULL); +static DEVICE_ATTR(pcrs, S_IRUGO, tpm_show_pcrs, NULL); +static DEVICE_ATTR(caps, S_IRUGO, tpm_show_caps, NULL); +static DEVICE_ATTR(cancel, S_IWUSR |S_IWGRP, NULL, tpm_store_cancel); + +static struct attribute* atmel_attrs[] = { + &dev_attr_pubek.attr, + &dev_attr_pcrs.attr, + &dev_attr_caps.attr, + &dev_attr_cancel.attr, + 0, +}; + +static struct attribute_group atmel_attr_grp = { .attrs = atmel_attrs }; + static struct tpm_vendor_specific tpm_atmel = { .recv = tpm_atml_recv, .send = tpm_atml_send, .cancel = tpm_atml_cancel, .req_complete_mask = ATML_STATUS_BUSY | ATML_STATUS_DATA_AVAIL, .req_complete_val = ATML_STATUS_DATA_AVAIL, - .base = TPM_ATML_BASE, + .req_canceled = ATML_STATUS_READY, + .attr_group = &atmel_attr_grp, .miscdev = { .fops = &atmel_ops, }, }; @@ -136,27 +158,29 @@ static int __devinit tpm_atml_init(struct pci_dev *pci_dev, { u8 version[4]; int rc = 0; + int lo, hi; if (pci_enable_device(pci_dev)) return -EIO; - if (tpm_lpc_bus_init(pci_dev, TPM_ATML_BASE)) { - rc = -ENODEV; - goto out_err; - } + lo = tpm_read_index(TPM_ADDR, TPM_ATMEL_BASE_ADDR_LO); + hi = tpm_read_index(TPM_ADDR, TPM_ATMEL_BASE_ADDR_HI); + + tpm_atmel.base = (hi<<8)|lo; + dev_dbg( &pci_dev->dev, "Operating with base: 0x%x\n", tpm_atmel.base); /* verify that it is an Atmel part */ - if (tpm_read_index(4) != 'A' || tpm_read_index(5) != 'T' - || tpm_read_index(6) != 'M' || tpm_read_index(7) != 'L') { + if (tpm_read_index(TPM_ADDR, 4) != 'A' || tpm_read_index(TPM_ADDR, 5) != 'T' + || tpm_read_index(TPM_ADDR, 6) != 'M' || tpm_read_index(TPM_ADDR, 7) != 'L') { rc = -ENODEV; goto out_err; } /* query chip for its version number */ - if ((version[0] = tpm_read_index(0x00)) != 0xFF) { - version[1] = tpm_read_index(0x01); - version[2] = tpm_read_index(0x02); - version[3] = tpm_read_index(0x03); + if ((version[0] = tpm_read_index(TPM_ADDR, 0x00)) != 0xFF) { + version[1] = tpm_read_index(TPM_ADDR, 0x01); + version[2] = tpm_read_index(TPM_ADDR, 0x02); + version[3] = tpm_read_index(TPM_ADDR, 0x03); } else { dev_info(&pci_dev->dev, "version query failed\n"); rc = -ENODEV; @@ -183,6 +207,7 @@ static struct pci_device_id tpm_pci_tbl[] __devinitdata = { {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_12)}, {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801EB_0)}, {PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_8111_LPC)}, + {PCI_DEVICE(PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_CSB6LPC)}, {0,} }; diff --git a/drivers/char/tpm/tpm_nsc.c b/drivers/char/tpm/tpm_nsc.c index 9cce833a092..b4127348c06 100644 --- a/drivers/char/tpm/tpm_nsc.c +++ b/drivers/char/tpm/tpm_nsc.c @@ -22,43 +22,52 @@ #include "tpm.h" /* National definitions */ -#define TPM_NSC_BASE 0x360 -#define TPM_NSC_IRQ 0x07 +enum tpm_nsc_addr{ + TPM_NSC_IRQ = 0x07, + TPM_NSC_BASE0_HI = 0x60, + TPM_NSC_BASE0_LO = 0x61, + TPM_NSC_BASE1_HI = 0x62, + TPM_NSC_BASE1_LO = 0x63 +}; -#define NSC_LDN_INDEX 0x07 -#define NSC_SID_INDEX 0x20 -#define NSC_LDC_INDEX 0x30 -#define NSC_DIO_INDEX 0x60 -#define NSC_CIO_INDEX 0x62 -#define NSC_IRQ_INDEX 0x70 -#define NSC_ITS_INDEX 0x71 +enum tpm_nsc_index { + NSC_LDN_INDEX = 0x07, + NSC_SID_INDEX = 0x20, + NSC_LDC_INDEX = 0x30, + NSC_DIO_INDEX = 0x60, + NSC_CIO_INDEX = 0x62, + NSC_IRQ_INDEX = 0x70, + NSC_ITS_INDEX = 0x71 +}; -#define NSC_STATUS 0x01 -#define NSC_COMMAND 0x01 -#define NSC_DATA 0x00 +enum tpm_nsc_status_loc { + NSC_STATUS = 0x01, + NSC_COMMAND = 0x01, + NSC_DATA = 0x00 +}; /* status bits */ -#define NSC_STATUS_OBF 0x01 /* output buffer full */ -#define NSC_STATUS_IBF 0x02 /* input buffer full */ -#define NSC_STATUS_F0 0x04 /* F0 */ -#define NSC_STATUS_A2 0x08 /* A2 */ -#define NSC_STATUS_RDY 0x10 /* ready to receive command */ -#define NSC_STATUS_IBR 0x20 /* ready to receive data */ +enum tpm_nsc_status { + NSC_STATUS_OBF = 0x01, /* output buffer full */ + NSC_STATUS_IBF = 0x02, /* input buffer full */ + NSC_STATUS_F0 = 0x04, /* F0 */ + NSC_STATUS_A2 = 0x08, /* A2 */ + NSC_STATUS_RDY = 0x10, /* ready to receive command */ + NSC_STATUS_IBR = 0x20 /* ready to receive data */ +}; /* command bits */ -#define NSC_COMMAND_NORMAL 0x01 /* normal mode */ -#define NSC_COMMAND_EOC 0x03 -#define NSC_COMMAND_CANCEL 0x22 - +enum tpm_nsc_cmd_mode { + NSC_COMMAND_NORMAL = 0x01, /* normal mode */ + NSC_COMMAND_EOC = 0x03, + NSC_COMMAND_CANCEL = 0x22 +}; /* * Wait for a certain status to appear */ static int wait_for_stat(struct tpm_chip *chip, u8 mask, u8 val, u8 * data) { - int expired = 0; - struct timer_list status_timer = - TIMER_INITIALIZER(tpm_time_expired, jiffies + 10 * HZ, - (unsigned long) &expired); + unsigned long stop; /* status immediately available check */ *data = inb(chip->vendor->base + NSC_STATUS); @@ -66,17 +75,14 @@ static int wait_for_stat(struct tpm_chip *chip, u8 mask, u8 val, u8 * data) return 0; /* wait for status */ - add_timer(&status_timer); + stop = jiffies + 10 * HZ; do { - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(TPM_TIMEOUT); + msleep(TPM_TIMEOUT); *data = inb(chip->vendor->base + 1); - if ((*data & mask) == val) { - del_singleshot_timer_sync(&status_timer); + if ((*data & mask) == val) return 0; - } } - while (!expired); + while (time_before(jiffies, stop)); return -EBUSY; } @@ -84,10 +90,7 @@ static int wait_for_stat(struct tpm_chip *chip, u8 mask, u8 val, u8 * data) static int nsc_wait_for_ready(struct tpm_chip *chip) { int status; - int expired = 0; - struct timer_list status_timer = - TIMER_INITIALIZER(tpm_time_expired, jiffies + 100, - (unsigned long) &expired); + unsigned long stop; /* status immediately available check */ status = inb(chip->vendor->base + NSC_STATUS); @@ -97,19 +100,16 @@ static int nsc_wait_for_ready(struct tpm_chip *chip) return 0; /* wait for status */ - add_timer(&status_timer); + stop = jiffies + 100; do { - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(TPM_TIMEOUT); + msleep(TPM_TIMEOUT); status = inb(chip->vendor->base + NSC_STATUS); if (status & NSC_STATUS_OBF) status = inb(chip->vendor->base + NSC_DATA); - if (status & NSC_STATUS_RDY) { - del_singleshot_timer_sync(&status_timer); + if (status & NSC_STATUS_RDY) return 0; - } } - while (!expired); + while (time_before(jiffies, stop)); dev_info(&chip->pci_dev->dev, "wait for ready failed\n"); return -EBUSY; @@ -150,7 +150,8 @@ static int tpm_nsc_recv(struct tpm_chip *chip, u8 * buf, size_t count) *p = inb(chip->vendor->base + NSC_DATA); } - if ((data & NSC_STATUS_F0) == 0) { + if ((data & NSC_STATUS_F0) == 0 && + (wait_for_stat(chip, NSC_STATUS_F0, NSC_STATUS_F0, &data) < 0)) { dev_err(&chip->pci_dev->dev, "F0 not set\n"); return -EIO; } @@ -228,100 +229,95 @@ static struct file_operations nsc_ops = { .release = tpm_release, }; +static DEVICE_ATTR(pubek, S_IRUGO, tpm_show_pubek, NULL); +static DEVICE_ATTR(pcrs, S_IRUGO, tpm_show_pcrs, NULL); +static DEVICE_ATTR(caps, S_IRUGO, tpm_show_caps, NULL); +static DEVICE_ATTR(cancel, S_IWUSR|S_IWGRP, NULL, tpm_store_cancel); + +static struct attribute * nsc_attrs[] = { + &dev_attr_pubek.attr, + &dev_attr_pcrs.attr, + &dev_attr_caps.attr, + &dev_attr_cancel.attr, + 0, +}; + +static struct attribute_group nsc_attr_grp = { .attrs = nsc_attrs }; + static struct tpm_vendor_specific tpm_nsc = { .recv = tpm_nsc_recv, .send = tpm_nsc_send, .cancel = tpm_nsc_cancel, .req_complete_mask = NSC_STATUS_OBF, .req_complete_val = NSC_STATUS_OBF, - .base = TPM_NSC_BASE, + .req_canceled = NSC_STATUS_RDY, + .attr_group = &nsc_attr_grp, .miscdev = { .fops = &nsc_ops, }, - }; static int __devinit tpm_nsc_init(struct pci_dev *pci_dev, const struct pci_device_id *pci_id) { int rc = 0; + int lo, hi; + int nscAddrBase = TPM_ADDR; + if (pci_enable_device(pci_dev)) return -EIO; - if (tpm_lpc_bus_init(pci_dev, TPM_NSC_BASE)) { - rc = -ENODEV; - goto out_err; - } + /* select PM channel 1 */ + tpm_write_index(nscAddrBase,NSC_LDN_INDEX, 0x12); /* verify that it is a National part (SID) */ - if (tpm_read_index(NSC_SID_INDEX) != 0xEF) { - rc = -ENODEV; - goto out_err; + if (tpm_read_index(TPM_ADDR, NSC_SID_INDEX) != 0xEF) { + nscAddrBase = (tpm_read_index(TPM_SUPERIO_ADDR, 0x2C)<<8)| + (tpm_read_index(TPM_SUPERIO_ADDR, 0x2B)&0xFE); + if (tpm_read_index(nscAddrBase, NSC_SID_INDEX) != 0xF6) { + rc = -ENODEV; + goto out_err; + } } + hi = tpm_read_index(nscAddrBase, TPM_NSC_BASE0_HI); + lo = tpm_read_index(nscAddrBase, TPM_NSC_BASE0_LO); + tpm_nsc.base = (hi<<8) | lo; + dev_dbg(&pci_dev->dev, "NSC TPM detected\n"); dev_dbg(&pci_dev->dev, "NSC LDN 0x%x, SID 0x%x, SRID 0x%x\n", - tpm_read_index(0x07), tpm_read_index(0x20), - tpm_read_index(0x27)); + tpm_read_index(nscAddrBase,0x07), tpm_read_index(nscAddrBase,0x20), + tpm_read_index(nscAddrBase,0x27)); dev_dbg(&pci_dev->dev, "NSC SIOCF1 0x%x SIOCF5 0x%x SIOCF6 0x%x SIOCF8 0x%x\n", - tpm_read_index(0x21), tpm_read_index(0x25), - tpm_read_index(0x26), tpm_read_index(0x28)); + tpm_read_index(nscAddrBase,0x21), tpm_read_index(nscAddrBase,0x25), + tpm_read_index(nscAddrBase,0x26), tpm_read_index(nscAddrBase,0x28)); dev_dbg(&pci_dev->dev, "NSC IO Base0 0x%x\n", - (tpm_read_index(0x60) << 8) | tpm_read_index(0x61)); + (tpm_read_index(nscAddrBase,0x60) << 8) | tpm_read_index(nscAddrBase,0x61)); dev_dbg(&pci_dev->dev, "NSC IO Base1 0x%x\n", - (tpm_read_index(0x62) << 8) | tpm_read_index(0x63)); + (tpm_read_index(nscAddrBase,0x62) << 8) | tpm_read_index(nscAddrBase,0x63)); dev_dbg(&pci_dev->dev, "NSC Interrupt number and wakeup 0x%x\n", - tpm_read_index(0x70)); + tpm_read_index(nscAddrBase,0x70)); dev_dbg(&pci_dev->dev, "NSC IRQ type select 0x%x\n", - tpm_read_index(0x71)); + tpm_read_index(nscAddrBase,0x71)); dev_dbg(&pci_dev->dev, "NSC DMA channel select0 0x%x, select1 0x%x\n", - tpm_read_index(0x74), tpm_read_index(0x75)); + tpm_read_index(nscAddrBase,0x74), tpm_read_index(nscAddrBase,0x75)); dev_dbg(&pci_dev->dev, "NSC Config " "0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x\n", - tpm_read_index(0xF0), tpm_read_index(0xF1), - tpm_read_index(0xF2), tpm_read_index(0xF3), - tpm_read_index(0xF4), tpm_read_index(0xF5), - tpm_read_index(0xF6), tpm_read_index(0xF7), - tpm_read_index(0xF8), tpm_read_index(0xF9)); + tpm_read_index(nscAddrBase,0xF0), tpm_read_index(nscAddrBase,0xF1), + tpm_read_index(nscAddrBase,0xF2), tpm_read_index(nscAddrBase,0xF3), + tpm_read_index(nscAddrBase,0xF4), tpm_read_index(nscAddrBase,0xF5), + tpm_read_index(nscAddrBase,0xF6), tpm_read_index(nscAddrBase,0xF7), + tpm_read_index(nscAddrBase,0xF8), tpm_read_index(nscAddrBase,0xF9)); dev_info(&pci_dev->dev, - "NSC PC21100 TPM revision %d\n", - tpm_read_index(0x27) & 0x1F); - - if (tpm_read_index(NSC_LDC_INDEX) == 0) - dev_info(&pci_dev->dev, ": NSC TPM not active\n"); - - /* select PM channel 1 */ - tpm_write_index(NSC_LDN_INDEX, 0x12); - tpm_read_index(NSC_LDN_INDEX); - - /* disable the DPM module */ - tpm_write_index(NSC_LDC_INDEX, 0); - tpm_read_index(NSC_LDC_INDEX); - - /* set the data register base addresses */ - tpm_write_index(NSC_DIO_INDEX, TPM_NSC_BASE >> 8); - tpm_write_index(NSC_DIO_INDEX + 1, TPM_NSC_BASE); - tpm_read_index(NSC_DIO_INDEX); - tpm_read_index(NSC_DIO_INDEX + 1); - - /* set the command register base addresses */ - tpm_write_index(NSC_CIO_INDEX, (TPM_NSC_BASE + 1) >> 8); - tpm_write_index(NSC_CIO_INDEX + 1, (TPM_NSC_BASE + 1)); - tpm_read_index(NSC_DIO_INDEX); - tpm_read_index(NSC_DIO_INDEX + 1); - - /* set the interrupt number to be used for the host interface */ - tpm_write_index(NSC_IRQ_INDEX, TPM_NSC_IRQ); - tpm_write_index(NSC_ITS_INDEX, 0x00); - tpm_read_index(NSC_IRQ_INDEX); + "NSC TPM revision %d\n", + tpm_read_index(nscAddrBase, 0x27) & 0x1F); /* enable the DPM module */ - tpm_write_index(NSC_LDC_INDEX, 0x01); - tpm_read_index(NSC_LDC_INDEX); + tpm_write_index(nscAddrBase, NSC_LDC_INDEX, 0x01); if ((rc = tpm_register_hardware(pci_dev, &tpm_nsc)) < 0) goto out_err; @@ -339,6 +335,9 @@ static struct pci_device_id tpm_pci_tbl[] __devinitdata = { {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_0)}, {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_12)}, {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801EB_0)}, + {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH6_0)}, + {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH6_1)}, + {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH7_0)}, {PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_8111_LPC)}, {0,} }; diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c index 26e5e19ed85..6e4be3bb2d8 100644 --- a/drivers/char/tty_io.c +++ b/drivers/char/tty_io.c @@ -94,6 +94,7 @@ #include <linux/idr.h> #include <linux/wait.h> #include <linux/bitops.h> +#include <linux/delay.h> #include <asm/uaccess.h> #include <asm/system.h> @@ -251,7 +252,7 @@ static void tty_set_termios_ldisc(struct tty_struct *tty, int num) static DEFINE_SPINLOCK(tty_ldisc_lock); static DECLARE_WAIT_QUEUE_HEAD(tty_ldisc_wait); -static struct tty_ldisc tty_ldiscs[NR_LDISCS]; /* line disc dispatch table */ +static struct tty_ldisc tty_ldiscs[NR_LDISCS]; /* line disc dispatch table */ int tty_register_ldisc(int disc, struct tty_ldisc *new_ldisc) { @@ -262,24 +263,35 @@ int tty_register_ldisc(int disc, struct tty_ldisc *new_ldisc) return -EINVAL; spin_lock_irqsave(&tty_ldisc_lock, flags); - if (new_ldisc) { - tty_ldiscs[disc] = *new_ldisc; - tty_ldiscs[disc].num = disc; - tty_ldiscs[disc].flags |= LDISC_FLAG_DEFINED; - tty_ldiscs[disc].refcount = 0; - } else { - if(tty_ldiscs[disc].refcount) - ret = -EBUSY; - else - tty_ldiscs[disc].flags &= ~LDISC_FLAG_DEFINED; - } + tty_ldiscs[disc] = *new_ldisc; + tty_ldiscs[disc].num = disc; + tty_ldiscs[disc].flags |= LDISC_FLAG_DEFINED; + tty_ldiscs[disc].refcount = 0; spin_unlock_irqrestore(&tty_ldisc_lock, flags); return ret; } - EXPORT_SYMBOL(tty_register_ldisc); +int tty_unregister_ldisc(int disc) +{ + unsigned long flags; + int ret = 0; + + if (disc < N_TTY || disc >= NR_LDISCS) + return -EINVAL; + + spin_lock_irqsave(&tty_ldisc_lock, flags); + if (tty_ldiscs[disc].refcount) + ret = -EBUSY; + else + tty_ldiscs[disc].flags &= ~LDISC_FLAG_DEFINED; + spin_unlock_irqrestore(&tty_ldisc_lock, flags); + + return ret; +} +EXPORT_SYMBOL(tty_unregister_ldisc); + struct tty_ldisc *tty_ldisc_get(int disc) { unsigned long flags; @@ -2169,12 +2181,11 @@ static int tiocsetd(struct tty_struct *tty, int __user *p) return tty_set_ldisc(tty, ldisc); } -static int send_break(struct tty_struct *tty, int duration) +static int send_break(struct tty_struct *tty, unsigned int duration) { tty->driver->break_ctl(tty, -1); if (!signal_pending(current)) { - set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(duration); + msleep_interruptible(duration); } tty->driver->break_ctl(tty, 0); if (signal_pending(current)) @@ -2355,10 +2366,10 @@ int tty_ioctl(struct inode * inode, struct file * file, * all by anyone? */ if (!arg) - return send_break(tty, HZ/4); + return send_break(tty, 250); return 0; case TCSBRKP: /* support for POSIX tcsendbreak() */ - return send_break(tty, arg ? arg*(HZ/10) : HZ/4); + return send_break(tty, arg ? arg*100 : 250); case TIOCMGET: return tty_tiocmget(tty, file, p); @@ -2654,7 +2665,7 @@ static void tty_default_put_char(struct tty_struct *tty, unsigned char ch) tty->driver->write(tty, &ch, 1); } -static struct class_simple *tty_class; +static struct class *tty_class; /** * tty_register_device - register a tty device @@ -2687,7 +2698,7 @@ void tty_register_device(struct tty_driver *driver, unsigned index, pty_line_name(driver, index, name); else tty_line_name(driver, index, name); - class_simple_device_add(tty_class, dev, device, name); + class_device_create(tty_class, dev, device, name); } /** @@ -2701,7 +2712,7 @@ void tty_register_device(struct tty_driver *driver, unsigned index, void tty_unregister_device(struct tty_driver *driver, unsigned index) { devfs_remove("%s%d", driver->devfs_name, index + driver->name_base); - class_simple_device_remove(MKDEV(driver->major, driver->minor_start) + index); + class_device_destroy(tty_class, MKDEV(driver->major, driver->minor_start) + index); } EXPORT_SYMBOL(tty_register_device); @@ -2918,7 +2929,7 @@ extern int vty_init(void); static int __init tty_class_init(void) { - tty_class = class_simple_create(THIS_MODULE, "tty"); + tty_class = class_create(THIS_MODULE, "tty"); if (IS_ERR(tty_class)) return PTR_ERR(tty_class); return 0; @@ -2947,14 +2958,14 @@ static int __init tty_init(void) register_chrdev_region(MKDEV(TTYAUX_MAJOR, 0), 1, "/dev/tty") < 0) panic("Couldn't register /dev/tty driver\n"); devfs_mk_cdev(MKDEV(TTYAUX_MAJOR, 0), S_IFCHR|S_IRUGO|S_IWUGO, "tty"); - class_simple_device_add(tty_class, MKDEV(TTYAUX_MAJOR, 0), NULL, "tty"); + class_device_create(tty_class, MKDEV(TTYAUX_MAJOR, 0), NULL, "tty"); cdev_init(&console_cdev, &console_fops); if (cdev_add(&console_cdev, MKDEV(TTYAUX_MAJOR, 1), 1) || register_chrdev_region(MKDEV(TTYAUX_MAJOR, 1), 1, "/dev/console") < 0) panic("Couldn't register /dev/console driver\n"); devfs_mk_cdev(MKDEV(TTYAUX_MAJOR, 1), S_IFCHR|S_IRUSR|S_IWUSR, "console"); - class_simple_device_add(tty_class, MKDEV(TTYAUX_MAJOR, 1), NULL, "console"); + class_device_create(tty_class, MKDEV(TTYAUX_MAJOR, 1), NULL, "console"); #ifdef CONFIG_UNIX98_PTYS cdev_init(&ptmx_cdev, &ptmx_fops); @@ -2962,7 +2973,7 @@ static int __init tty_init(void) register_chrdev_region(MKDEV(TTYAUX_MAJOR, 2), 1, "/dev/ptmx") < 0) panic("Couldn't register /dev/ptmx driver\n"); devfs_mk_cdev(MKDEV(TTYAUX_MAJOR, 2), S_IFCHR|S_IRUGO|S_IWUGO, "ptmx"); - class_simple_device_add(tty_class, MKDEV(TTYAUX_MAJOR, 2), NULL, "ptmx"); + class_device_create(tty_class, MKDEV(TTYAUX_MAJOR, 2), NULL, "ptmx"); #endif #ifdef CONFIG_VT @@ -2971,7 +2982,7 @@ static int __init tty_init(void) register_chrdev_region(MKDEV(TTY_MAJOR, 0), 1, "/dev/vc/0") < 0) panic("Couldn't register /dev/tty0 driver\n"); devfs_mk_cdev(MKDEV(TTY_MAJOR, 0), S_IFCHR|S_IRUSR|S_IWUSR, "vc/0"); - class_simple_device_add(tty_class, MKDEV(TTY_MAJOR, 0), NULL, "tty0"); + class_device_create(tty_class, MKDEV(TTY_MAJOR, 0), NULL, "tty0"); vty_init(); #endif diff --git a/drivers/char/vc_screen.c b/drivers/char/vc_screen.c index 7abe405b865..79c2928a881 100644 --- a/drivers/char/vc_screen.c +++ b/drivers/char/vc_screen.c @@ -474,7 +474,7 @@ static struct file_operations vcs_fops = { .open = vcs_open, }; -static struct class_simple *vc_class; +static struct class *vc_class; void vcs_make_devfs(struct tty_struct *tty) { @@ -484,26 +484,26 @@ void vcs_make_devfs(struct tty_struct *tty) devfs_mk_cdev(MKDEV(VCS_MAJOR, tty->index + 129), S_IFCHR|S_IRUSR|S_IWUSR, "vcc/a%u", tty->index + 1); - class_simple_device_add(vc_class, MKDEV(VCS_MAJOR, tty->index + 1), NULL, "vcs%u", tty->index + 1); - class_simple_device_add(vc_class, MKDEV(VCS_MAJOR, tty->index + 129), NULL, "vcsa%u", tty->index + 1); + class_device_create(vc_class, MKDEV(VCS_MAJOR, tty->index + 1), NULL, "vcs%u", tty->index + 1); + class_device_create(vc_class, MKDEV(VCS_MAJOR, tty->index + 129), NULL, "vcsa%u", tty->index + 1); } void vcs_remove_devfs(struct tty_struct *tty) { devfs_remove("vcc/%u", tty->index + 1); devfs_remove("vcc/a%u", tty->index + 1); - class_simple_device_remove(MKDEV(VCS_MAJOR, tty->index + 1)); - class_simple_device_remove(MKDEV(VCS_MAJOR, tty->index + 129)); + class_device_destroy(vc_class, MKDEV(VCS_MAJOR, tty->index + 1)); + class_device_destroy(vc_class, MKDEV(VCS_MAJOR, tty->index + 129)); } int __init vcs_init(void) { if (register_chrdev(VCS_MAJOR, "vcs", &vcs_fops)) panic("unable to get major %d for vcs device", VCS_MAJOR); - vc_class = class_simple_create(THIS_MODULE, "vc"); + vc_class = class_create(THIS_MODULE, "vc"); devfs_mk_cdev(MKDEV(VCS_MAJOR, 0), S_IFCHR|S_IRUSR|S_IWUSR, "vcc/0"); devfs_mk_cdev(MKDEV(VCS_MAJOR, 128), S_IFCHR|S_IRUSR|S_IWUSR, "vcc/a0"); - class_simple_device_add(vc_class, MKDEV(VCS_MAJOR, 0), NULL, "vcs"); - class_simple_device_add(vc_class, MKDEV(VCS_MAJOR, 128), NULL, "vcsa"); + class_device_create(vc_class, MKDEV(VCS_MAJOR, 0), NULL, "vcs"); + class_device_create(vc_class, MKDEV(VCS_MAJOR, 128), NULL, "vcsa"); return 0; } diff --git a/drivers/char/viotape.c b/drivers/char/viotape.c index aea3cbf5219..4764b4f9555 100644 --- a/drivers/char/viotape.c +++ b/drivers/char/viotape.c @@ -237,7 +237,7 @@ static dma_addr_t viotape_unitinfo_token; static struct mtget viomtget[VIOTAPE_MAX_TAPE]; -static struct class_simple *tape_class; +static struct class *tape_class; static struct device *tape_device[VIOTAPE_MAX_TAPE]; @@ -956,9 +956,9 @@ static int viotape_probe(struct vio_dev *vdev, const struct vio_device_id *id) state[i].cur_part = 0; for (j = 0; j < MAX_PARTITIONS; ++j) state[i].part_stat_rwi[j] = VIOT_IDLE; - class_simple_device_add(tape_class, MKDEV(VIOTAPE_MAJOR, i), NULL, + class_device_create(tape_class, MKDEV(VIOTAPE_MAJOR, i), NULL, "iseries!vt%d", i); - class_simple_device_add(tape_class, MKDEV(VIOTAPE_MAJOR, i | 0x80), + class_device_create(tape_class, MKDEV(VIOTAPE_MAJOR, i | 0x80), NULL, "iseries!nvt%d", i); devfs_mk_cdev(MKDEV(VIOTAPE_MAJOR, i), S_IFCHR | S_IRUSR | S_IWUSR, "iseries/vt%d", i); @@ -980,8 +980,8 @@ static int viotape_remove(struct vio_dev *vdev) devfs_remove("iseries/nvt%d", i); devfs_remove("iseries/vt%d", i); devfs_unregister_tape(state[i].dev_handle); - class_simple_device_remove(MKDEV(VIOTAPE_MAJOR, i | 0x80)); - class_simple_device_remove(MKDEV(VIOTAPE_MAJOR, i)); + class_device_destroy(tape_class, MKDEV(VIOTAPE_MAJOR, i | 0x80)); + class_device_destroy(tape_class, MKDEV(VIOTAPE_MAJOR, i)); return 0; } @@ -1045,7 +1045,7 @@ int __init viotap_init(void) goto clear_handler; } - tape_class = class_simple_create(THIS_MODULE, "tape"); + tape_class = class_create(THIS_MODULE, "tape"); if (IS_ERR(tape_class)) { printk(VIOTAPE_KERN_WARN "Unable to allocat class\n"); ret = PTR_ERR(tape_class); @@ -1070,7 +1070,7 @@ int __init viotap_init(void) return 0; unreg_class: - class_simple_destroy(tape_class); + class_destroy(tape_class); unreg_chrdev: unregister_chrdev(VIOTAPE_MAJOR, "viotape"); clear_handler: @@ -1110,7 +1110,7 @@ static void __exit viotap_exit(void) remove_proc_entry("iSeries/viotape", NULL); vio_unregister_driver(&viotape_driver); - class_simple_destroy(tape_class); + class_destroy(tape_class); ret = unregister_chrdev(VIOTAPE_MAJOR, "viotape"); if (ret < 0) printk(VIOTAPE_KERN_WARN "Error unregistering device: %d\n", diff --git a/drivers/char/vr41xx_giu.c b/drivers/char/vr41xx_giu.c new file mode 100644 index 00000000000..683278bc524 --- /dev/null +++ b/drivers/char/vr41xx_giu.c @@ -0,0 +1,743 @@ +/* + * Driver for NEC VR4100 series General-purpose I/O Unit. + * + * Copyright (C) 2002 MontaVista Software Inc. + * Author: Yoichi Yuasa <yyuasa@mvista.com or source@mvista.com> + * Copyright (C) 2003-2005 Yoichi Yuasa <yuasa@hh.iij4u.or.jp> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#include <linux/device.h> +#include <linux/errno.h> +#include <linux/fs.h> +#include <linux/init.h> +#include <linux/irq.h> +#include <linux/interrupt.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/spinlock.h> +#include <linux/types.h> + +#include <asm/cpu.h> +#include <asm/io.h> +#include <asm/vr41xx/giu.h> +#include <asm/vr41xx/vr41xx.h> + +MODULE_AUTHOR("Yoichi Yuasa <yuasa@hh.iij4u.or.jp>"); +MODULE_DESCRIPTION("NEC VR4100 series General-purpose I/O Unit driver"); +MODULE_LICENSE("GPL"); + +static int major; /* default is dynamic major device number */ +module_param(major, int, 0); +MODULE_PARM_DESC(major, "Major device number"); + +#define GIU_TYPE1_START 0x0b000100UL +#define GIU_TYPE1_SIZE 0x20UL + +#define GIU_TYPE2_START 0x0f000140UL +#define GIU_TYPE2_SIZE 0x20UL + +#define GIU_TYPE3_START 0x0f000140UL +#define GIU_TYPE3_SIZE 0x28UL + +#define GIU_PULLUPDOWN_START 0x0b0002e0UL +#define GIU_PULLUPDOWN_SIZE 0x04UL + +#define GIUIOSELL 0x00 +#define GIUIOSELH 0x02 +#define GIUPIODL 0x04 +#define GIUPIODH 0x06 +#define GIUINTSTATL 0x08 +#define GIUINTSTATH 0x0a +#define GIUINTENL 0x0c +#define GIUINTENH 0x0e +#define GIUINTTYPL 0x10 +#define GIUINTTYPH 0x12 +#define GIUINTALSELL 0x14 +#define GIUINTALSELH 0x16 +#define GIUINTHTSELL 0x18 +#define GIUINTHTSELH 0x1a +#define GIUPODATL 0x1c +#define GIUPODATEN 0x1c +#define GIUPODATH 0x1e + #define PIOEN0 0x0100 + #define PIOEN1 0x0200 +#define GIUPODAT 0x1e +#define GIUFEDGEINHL 0x20 +#define GIUFEDGEINHH 0x22 +#define GIUREDGEINHL 0x24 +#define GIUREDGEINHH 0x26 + +#define GIUUSEUPDN 0x1e0 +#define GIUTERMUPDN 0x1e2 + +#define GPIO_HAS_PULLUPDOWN_IO 0x0001 +#define GPIO_HAS_OUTPUT_ENABLE 0x0002 +#define GPIO_HAS_INTERRUPT_EDGE_SELECT 0x0100 + +static spinlock_t giu_lock; +static struct resource *giu_resource1; +static struct resource *giu_resource2; +static unsigned long giu_flags; +static unsigned int giu_nr_pins; + +static void __iomem *giu_base; + +#define giu_read(offset) readw(giu_base + (offset)) +#define giu_write(offset, value) writew((value), giu_base + (offset)) + +#define GPIO_PIN_OF_IRQ(irq) ((irq) - GIU_IRQ_BASE) +#define GIUINT_HIGH_OFFSET 16 +#define GIUINT_HIGH_MAX 32 + +static inline uint16_t giu_set(uint16_t offset, uint16_t set) +{ + uint16_t data; + + data = giu_read(offset); + data |= set; + giu_write(offset, data); + + return data; +} + +static inline uint16_t giu_clear(uint16_t offset, uint16_t clear) +{ + uint16_t data; + + data = giu_read(offset); + data &= ~clear; + giu_write(offset, data); + + return data; +} + +static unsigned int startup_giuint_low_irq(unsigned int irq) +{ + unsigned int pin; + + pin = GPIO_PIN_OF_IRQ(irq); + giu_write(GIUINTSTATL, 1 << pin); + giu_set(GIUINTENL, 1 << pin); + + return 0; +} + +static void shutdown_giuint_low_irq(unsigned int irq) +{ + giu_clear(GIUINTENL, 1 << GPIO_PIN_OF_IRQ(irq)); +} + +static void enable_giuint_low_irq(unsigned int irq) +{ + giu_set(GIUINTENL, 1 << GPIO_PIN_OF_IRQ(irq)); +} + +#define disable_giuint_low_irq shutdown_giuint_low_irq + +static void ack_giuint_low_irq(unsigned int irq) +{ + unsigned int pin; + + pin = GPIO_PIN_OF_IRQ(irq); + giu_clear(GIUINTENL, 1 << pin); + giu_write(GIUINTSTATL, 1 << pin); +} + +static void end_giuint_low_irq(unsigned int irq) +{ + if (!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS))) + giu_set(GIUINTENL, 1 << GPIO_PIN_OF_IRQ(irq)); +} + +static struct hw_interrupt_type giuint_low_irq_type = { + .typename = "GIUINTL", + .startup = startup_giuint_low_irq, + .shutdown = shutdown_giuint_low_irq, + .enable = enable_giuint_low_irq, + .disable = disable_giuint_low_irq, + .ack = ack_giuint_low_irq, + .end = end_giuint_low_irq, +}; + +static unsigned int startup_giuint_high_irq(unsigned int irq) +{ + unsigned int pin; + + pin = GPIO_PIN_OF_IRQ(irq) - GIUINT_HIGH_OFFSET; + giu_write(GIUINTSTATH, 1 << pin); + giu_set(GIUINTENH, 1 << pin); + + return 0; +} + +static void shutdown_giuint_high_irq(unsigned int irq) +{ + giu_clear(GIUINTENH, 1 << (GPIO_PIN_OF_IRQ(irq) - GIUINT_HIGH_OFFSET)); +} + +static void enable_giuint_high_irq(unsigned int irq) +{ + giu_set(GIUINTENH, 1 << (GPIO_PIN_OF_IRQ(irq) - GIUINT_HIGH_OFFSET)); +} + +#define disable_giuint_high_irq shutdown_giuint_high_irq + +static void ack_giuint_high_irq(unsigned int irq) +{ + unsigned int pin; + + pin = GPIO_PIN_OF_IRQ(irq) - GIUINT_HIGH_OFFSET; + giu_clear(GIUINTENH, 1 << pin); + giu_write(GIUINTSTATH, 1 << pin); +} + +static void end_giuint_high_irq(unsigned int irq) +{ + if (!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS))) + giu_set(GIUINTENH, 1 << (GPIO_PIN_OF_IRQ(irq) - GIUINT_HIGH_OFFSET)); +} + +static struct hw_interrupt_type giuint_high_irq_type = { + .typename = "GIUINTH", + .startup = startup_giuint_high_irq, + .shutdown = shutdown_giuint_high_irq, + .enable = enable_giuint_high_irq, + .disable = disable_giuint_high_irq, + .ack = ack_giuint_high_irq, + .end = end_giuint_high_irq, +}; + +static int giu_get_irq(unsigned int irq, struct pt_regs *regs) +{ + uint16_t pendl, pendh, maskl, maskh; + int i; + + pendl = giu_read(GIUINTSTATL); + pendh = giu_read(GIUINTSTATH); + maskl = giu_read(GIUINTENL); + maskh = giu_read(GIUINTENH); + + maskl &= pendl; + maskh &= pendh; + + if (maskl) { + for (i = 0; i < 16; i++) { + if (maskl & (1 << i)) + return GIU_IRQ(i); + } + } else if (maskh) { + for (i = 0; i < 16; i++) { + if (maskh & (1 << i)) + return GIU_IRQ(i + GIUINT_HIGH_OFFSET); + } + } + + printk(KERN_ERR "spurious GIU interrupt: %04x(%04x),%04x(%04x)\n", + maskl, pendl, maskh, pendh); + + atomic_inc(&irq_err_count); + + return -EINVAL; +} + +void vr41xx_set_irq_trigger(unsigned int pin, irq_trigger_t trigger, irq_signal_t signal) +{ + uint16_t mask; + + if (pin < GIUINT_HIGH_OFFSET) { + mask = 1 << pin; + if (trigger != IRQ_TRIGGER_LEVEL) { + giu_set(GIUINTTYPL, mask); + if (signal == IRQ_SIGNAL_HOLD) + giu_set(GIUINTHTSELL, mask); + else + giu_clear(GIUINTHTSELL, mask); + if (current_cpu_data.cputype == CPU_VR4133) { + switch (trigger) { + case IRQ_TRIGGER_EDGE_FALLING: + giu_set(GIUFEDGEINHL, mask); + giu_clear(GIUREDGEINHL, mask); + break; + case IRQ_TRIGGER_EDGE_RISING: + giu_clear(GIUFEDGEINHL, mask); + giu_set(GIUREDGEINHL, mask); + break; + default: + giu_set(GIUFEDGEINHL, mask); + giu_set(GIUREDGEINHL, mask); + break; + } + } + } else { + giu_clear(GIUINTTYPL, mask); + giu_clear(GIUINTHTSELL, mask); + } + giu_write(GIUINTSTATL, mask); + } else if (pin < GIUINT_HIGH_MAX) { + mask = 1 << (pin - GIUINT_HIGH_OFFSET); + if (trigger != IRQ_TRIGGER_LEVEL) { + giu_set(GIUINTTYPH, mask); + if (signal == IRQ_SIGNAL_HOLD) + giu_set(GIUINTHTSELH, mask); + else + giu_clear(GIUINTHTSELH, mask); + if (current_cpu_data.cputype == CPU_VR4133) { + switch (trigger) { + case IRQ_TRIGGER_EDGE_FALLING: + giu_set(GIUFEDGEINHH, mask); + giu_clear(GIUREDGEINHH, mask); + break; + case IRQ_TRIGGER_EDGE_RISING: + giu_clear(GIUFEDGEINHH, mask); + giu_set(GIUREDGEINHH, mask); + break; + default: + giu_set(GIUFEDGEINHH, mask); + giu_set(GIUREDGEINHH, mask); + break; + } + } + } else { + giu_clear(GIUINTTYPH, mask); + giu_clear(GIUINTHTSELH, mask); + } + giu_write(GIUINTSTATH, mask); + } +} + +EXPORT_SYMBOL_GPL(vr41xx_set_irq_trigger); + +void vr41xx_set_irq_level(unsigned int pin, irq_level_t level) +{ + uint16_t mask; + + if (pin < GIUINT_HIGH_OFFSET) { + mask = 1 << pin; + if (level == IRQ_LEVEL_HIGH) + giu_set(GIUINTALSELL, mask); + else + giu_clear(GIUINTALSELL, mask); + giu_write(GIUINTSTATL, mask); + } else if (pin < GIUINT_HIGH_MAX) { + mask = 1 << (pin - GIUINT_HIGH_OFFSET); + if (level == IRQ_LEVEL_HIGH) + giu_set(GIUINTALSELH, mask); + else + giu_clear(GIUINTALSELH, mask); + giu_write(GIUINTSTATH, mask); + } +} + +EXPORT_SYMBOL_GPL(vr41xx_set_irq_level); + +gpio_data_t vr41xx_gpio_get_pin(unsigned int pin) +{ + uint16_t reg, mask; + + if (pin >= giu_nr_pins) + return GPIO_DATA_INVAL; + + if (pin < 16) { + reg = giu_read(GIUPIODL); + mask = (uint16_t)1 << pin; + } else if (pin < 32) { + reg = giu_read(GIUPIODH); + mask = (uint16_t)1 << (pin - 16); + } else if (pin < 48) { + reg = giu_read(GIUPODATL); + mask = (uint16_t)1 << (pin - 32); + } else { + reg = giu_read(GIUPODATH); + mask = (uint16_t)1 << (pin - 48); + } + + if (reg & mask) + return GPIO_DATA_HIGH; + + return GPIO_DATA_LOW; +} + +EXPORT_SYMBOL_GPL(vr41xx_gpio_get_pin); + +int vr41xx_gpio_set_pin(unsigned int pin, gpio_data_t data) +{ + uint16_t offset, mask, reg; + unsigned long flags; + + if (pin >= giu_nr_pins) + return -EINVAL; + + if (pin < 16) { + offset = GIUPIODL; + mask = (uint16_t)1 << pin; + } else if (pin < 32) { + offset = GIUPIODH; + mask = (uint16_t)1 << (pin - 16); + } else if (pin < 48) { + offset = GIUPODATL; + mask = (uint16_t)1 << (pin - 32); + } else { + offset = GIUPODATH; + mask = (uint16_t)1 << (pin - 48); + } + + spin_lock_irqsave(&giu_lock, flags); + + reg = giu_read(offset); + if (data == GPIO_DATA_HIGH) + reg |= mask; + else + reg &= ~mask; + giu_write(offset, reg); + + spin_unlock_irqrestore(&giu_lock, flags); + + return 0; +} + +EXPORT_SYMBOL_GPL(vr41xx_gpio_set_pin); + +int vr41xx_gpio_set_direction(unsigned int pin, gpio_direction_t dir) +{ + uint16_t offset, mask, reg; + unsigned long flags; + + if (pin >= giu_nr_pins) + return -EINVAL; + + if (pin < 16) { + offset = GIUIOSELL; + mask = (uint16_t)1 << pin; + } else if (pin < 32) { + offset = GIUIOSELH; + mask = (uint16_t)1 << (pin - 16); + } else { + if (giu_flags & GPIO_HAS_OUTPUT_ENABLE) { + offset = GIUPODATEN; + mask = (uint16_t)1 << (pin - 32); + } else { + switch (pin) { + case 48: + offset = GIUPODATH; + mask = PIOEN0; + break; + case 49: + offset = GIUPODATH; + mask = PIOEN1; + break; + default: + return -EINVAL; + } + } + } + + spin_lock_irqsave(&giu_lock, flags); + + reg = giu_read(offset); + if (dir == GPIO_OUTPUT) + reg |= mask; + else + reg &= ~mask; + giu_write(offset, reg); + + spin_unlock_irqrestore(&giu_lock, flags); + + return 0; +} + +EXPORT_SYMBOL_GPL(vr41xx_gpio_set_direction); + +int vr41xx_gpio_pullupdown(unsigned int pin, gpio_pull_t pull) +{ + uint16_t reg, mask; + unsigned long flags; + + if ((giu_flags & GPIO_HAS_PULLUPDOWN_IO) != GPIO_HAS_PULLUPDOWN_IO) + return -EPERM; + + if (pin >= 15) + return -EINVAL; + + mask = (uint16_t)1 << pin; + + spin_lock_irqsave(&giu_lock, flags); + + if (pull == GPIO_PULL_UP || pull == GPIO_PULL_DOWN) { + reg = giu_read(GIUTERMUPDN); + if (pull == GPIO_PULL_UP) + reg |= mask; + else + reg &= ~mask; + giu_write(GIUTERMUPDN, reg); + + reg = giu_read(GIUUSEUPDN); + reg |= mask; + giu_write(GIUUSEUPDN, reg); + } else { + reg = giu_read(GIUUSEUPDN); + reg &= ~mask; + giu_write(GIUUSEUPDN, reg); + } + + spin_unlock_irqrestore(&giu_lock, flags); + + return 0; +} + +EXPORT_SYMBOL_GPL(vr41xx_gpio_pullupdown); + +static ssize_t gpio_read(struct file *file, char __user *buf, size_t len, + loff_t *ppos) +{ + unsigned int pin; + char value = '0'; + + pin = iminor(file->f_dentry->d_inode); + if (pin >= giu_nr_pins) + return -EBADF; + + if (vr41xx_gpio_get_pin(pin) == GPIO_DATA_HIGH) + value = '1'; + + if (len <= 0) + return -EFAULT; + + if (put_user(value, buf)) + return -EFAULT; + + return 1; +} + +static ssize_t gpio_write(struct file *file, const char __user *data, + size_t len, loff_t *ppos) +{ + unsigned int pin; + size_t i; + char c; + int retval = 0; + + pin = iminor(file->f_dentry->d_inode); + if (pin >= giu_nr_pins) + return -EBADF; + + for (i = 0; i < len; i++) { + if (get_user(c, data + i)) + return -EFAULT; + + switch (c) { + case '0': + retval = vr41xx_gpio_set_pin(pin, GPIO_DATA_LOW); + break; + case '1': + retval = vr41xx_gpio_set_pin(pin, GPIO_DATA_HIGH); + break; + case 'D': + printk(KERN_INFO "GPIO%d: pull down\n", pin); + retval = vr41xx_gpio_pullupdown(pin, GPIO_PULL_DOWN); + break; + case 'd': + printk(KERN_INFO "GPIO%d: pull up/down disable\n", pin); + retval = vr41xx_gpio_pullupdown(pin, GPIO_PULL_DISABLE); + break; + case 'I': + printk(KERN_INFO "GPIO%d: input\n", pin); + retval = vr41xx_gpio_set_direction(pin, GPIO_INPUT); + break; + case 'O': + printk(KERN_INFO "GPIO%d: output\n", pin); + retval = vr41xx_gpio_set_direction(pin, GPIO_OUTPUT); + break; + case 'o': + printk(KERN_INFO "GPIO%d: output disable\n", pin); + retval = vr41xx_gpio_set_direction(pin, GPIO_OUTPUT_DISABLE); + break; + case 'P': + printk(KERN_INFO "GPIO%d: pull up\n", pin); + retval = vr41xx_gpio_pullupdown(pin, GPIO_PULL_UP); + break; + case 'p': + printk(KERN_INFO "GPIO%d: pull up/down disable\n", pin); + retval = vr41xx_gpio_pullupdown(pin, GPIO_PULL_DISABLE); + break; + default: + break; + } + + if (retval < 0) + break; + } + + return i; +} + +static int gpio_open(struct inode *inode, struct file *file) +{ + unsigned int pin; + + pin = iminor(inode); + if (pin >= giu_nr_pins) + return -EBADF; + + return nonseekable_open(inode, file); +} + +static int gpio_release(struct inode *inode, struct file *file) +{ + unsigned int pin; + + pin = iminor(inode); + if (pin >= giu_nr_pins) + return -EBADF; + + return 0; +} + +static struct file_operations gpio_fops = { + .owner = THIS_MODULE, + .read = gpio_read, + .write = gpio_write, + .open = gpio_open, + .release = gpio_release, +}; + +static int giu_probe(struct device *dev) +{ + unsigned long start, size, flags = 0; + unsigned int nr_pins = 0; + struct resource *res1, *res2 = NULL; + void *base; + int retval, i; + + switch (current_cpu_data.cputype) { + case CPU_VR4111: + case CPU_VR4121: + start = GIU_TYPE1_START; + size = GIU_TYPE1_SIZE; + flags = GPIO_HAS_PULLUPDOWN_IO; + nr_pins = 50; + break; + case CPU_VR4122: + case CPU_VR4131: + start = GIU_TYPE2_START; + size = GIU_TYPE2_SIZE; + nr_pins = 36; + break; + case CPU_VR4133: + start = GIU_TYPE3_START; + size = GIU_TYPE3_SIZE; + flags = GPIO_HAS_INTERRUPT_EDGE_SELECT; + nr_pins = 48; + break; + default: + return -ENODEV; + } + + res1 = request_mem_region(start, size, "GIU"); + if (res1 == NULL) + return -EBUSY; + + base = ioremap(start, size); + if (base == NULL) { + release_resource(res1); + return -ENOMEM; + } + + if (flags & GPIO_HAS_PULLUPDOWN_IO) { + res2 = request_mem_region(GIU_PULLUPDOWN_START, GIU_PULLUPDOWN_SIZE, "GIU"); + if (res2 == NULL) { + iounmap(base); + release_resource(res1); + return -EBUSY; + } + } + + retval = register_chrdev(major, "GIU", &gpio_fops); + if (retval < 0) { + iounmap(base); + release_resource(res1); + release_resource(res2); + return retval; + } + + if (major == 0) { + major = retval; + printk(KERN_INFO "GIU: major number %d\n", major); + } + + spin_lock_init(&giu_lock); + giu_base = base; + giu_resource1 = res1; + giu_resource2 = res2; + giu_flags = flags; + giu_nr_pins = nr_pins; + + giu_write(GIUINTENL, 0); + giu_write(GIUINTENH, 0); + + for (i = GIU_IRQ_BASE; i <= GIU_IRQ_LAST; i++) { + if (i < GIU_IRQ(GIUINT_HIGH_OFFSET)) + irq_desc[i].handler = &giuint_low_irq_type; + else + irq_desc[i].handler = &giuint_high_irq_type; + } + + return cascade_irq(GIUINT_IRQ, giu_get_irq); +} + +static int giu_remove(struct device *dev) +{ + iounmap(giu_base); + + release_resource(giu_resource1); + if (giu_flags & GPIO_HAS_PULLUPDOWN_IO) + release_resource(giu_resource2); + + return 0; +} + +static struct platform_device *giu_platform_device; + +static struct device_driver giu_device_driver = { + .name = "GIU", + .bus = &platform_bus_type, + .probe = giu_probe, + .remove = giu_remove, +}; + +static int __devinit vr41xx_giu_init(void) +{ + int retval; + + giu_platform_device = platform_device_register_simple("GIU", -1, NULL, 0); + if (IS_ERR(giu_platform_device)) + return PTR_ERR(giu_platform_device); + + retval = driver_register(&giu_device_driver); + if (retval < 0) + platform_device_unregister(giu_platform_device); + + return retval; +} + +static void __devexit vr41xx_giu_exit(void) +{ + driver_unregister(&giu_device_driver); + + platform_device_unregister(giu_platform_device); +} + +module_init(vr41xx_giu_init); +module_exit(vr41xx_giu_exit); diff --git a/drivers/char/vt.c b/drivers/char/vt.c index e5ef1dfc548..d7aa7a29f67 100644 --- a/drivers/char/vt.c +++ b/drivers/char/vt.c @@ -2867,6 +2867,10 @@ void unblank_screen(void) */ static void blank_screen_t(unsigned long dummy) { + if (unlikely(!keventd_up())) { + mod_timer(&console_timer, jiffies + blankinterval); + return; + } blank_timer_expired = 1; schedule_work(&console_work); } diff --git a/drivers/char/watchdog/Kconfig b/drivers/char/watchdog/Kconfig index 06a31da2381..b53e2e2b5ae 100644 --- a/drivers/char/watchdog/Kconfig +++ b/drivers/char/watchdog/Kconfig @@ -414,6 +414,16 @@ config WATCHDOG_RIO machines. The watchdog timeout period is normally one minute but can be changed with a boot-time parameter. +# ppc64 RTAS watchdog +config WATCHDOG_RTAS + tristate "RTAS watchdog" + depends on WATCHDOG && PPC_RTAS + help + This driver adds watchdog support for the RTAS watchdog. + + To compile this driver as a module, choose M here. The module + will be called wdrtas. + # # ISA-based Watchdog Cards # diff --git a/drivers/char/watchdog/Makefile b/drivers/char/watchdog/Makefile index 1cd27efa35c..c1838834ea7 100644 --- a/drivers/char/watchdog/Makefile +++ b/drivers/char/watchdog/Makefile @@ -33,6 +33,7 @@ obj-$(CONFIG_USBPCWATCHDOG) += pcwd_usb.o obj-$(CONFIG_IXP4XX_WATCHDOG) += ixp4xx_wdt.o obj-$(CONFIG_IXP2000_WATCHDOG) += ixp2000_wdt.o obj-$(CONFIG_8xx_WDT) += mpc8xx_wdt.o +obj-$(CONFIG_WATCHDOG_RTAS) += wdrtas.o # Only one watchdog can succeed. We probe the hardware watchdog # drivers first, then the softdog driver. This means if your hardware diff --git a/drivers/char/watchdog/ixp2000_wdt.c b/drivers/char/watchdog/ixp2000_wdt.c index ab659d37b4d..4e98c215e5b 100644 --- a/drivers/char/watchdog/ixp2000_wdt.c +++ b/drivers/char/watchdog/ixp2000_wdt.c @@ -192,7 +192,12 @@ static struct miscdevice ixp2000_wdt_miscdev = static int __init ixp2000_wdt_init(void) { - wdt_tick_rate = (*IXP2000_T1_CLD * HZ)/ 256;; + if ((*IXP2000_PRODUCT_ID & 0x001ffef0) == 0x00000000) { + printk(KERN_INFO "Unable to use IXP2000 watchdog due to IXP2800 erratum #25.\n"); + return -EIO; + } + + wdt_tick_rate = (*IXP2000_T1_CLD * HZ) / 256; return misc_register(&ixp2000_wdt_miscdev); } diff --git a/drivers/char/watchdog/wdrtas.c b/drivers/char/watchdog/wdrtas.c new file mode 100644 index 00000000000..619e2ffca33 --- /dev/null +++ b/drivers/char/watchdog/wdrtas.c @@ -0,0 +1,696 @@ +/* + * FIXME: add wdrtas_get_status and wdrtas_get_boot_status as soon as + * RTAS calls are available + */ + +/* + * RTAS watchdog driver + * + * (C) Copyright IBM Corp. 2005 + * device driver to exploit watchdog RTAS functions + * + * Authors : Utz Bacher <utz.bacher@de.ibm.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include <linux/config.h> +#include <linux/fs.h> +#include <linux/init.h> +#include <linux/kernel.h> +#include <linux/miscdevice.h> +#include <linux/module.h> +#include <linux/notifier.h> +#include <linux/reboot.h> +#include <linux/types.h> +#include <linux/watchdog.h> + +#include <asm/rtas.h> +#include <asm/uaccess.h> + +#define WDRTAS_MAGIC_CHAR 42 +#define WDRTAS_SUPPORTED_MASK (WDIOF_SETTIMEOUT | \ + WDIOF_MAGICCLOSE) + +MODULE_AUTHOR("Utz Bacher <utz.bacher@de.ibm.com>"); +MODULE_DESCRIPTION("RTAS watchdog driver"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR); +MODULE_ALIAS_MISCDEV(TEMP_MINOR); + +#ifdef CONFIG_WATCHDOG_NOWAYOUT +static int wdrtas_nowayout = 1; +#else +static int wdrtas_nowayout = 0; +#endif + +static atomic_t wdrtas_miscdev_open = ATOMIC_INIT(0); +static char wdrtas_expect_close = 0; + +static int wdrtas_interval; + +#define WDRTAS_THERMAL_SENSOR 3 +static int wdrtas_token_get_sensor_state; +#define WDRTAS_SURVEILLANCE_IND 9000 +static int wdrtas_token_set_indicator; +#define WDRTAS_SP_SPI 28 +static int wdrtas_token_get_sp; +static int wdrtas_token_event_scan; + +#define WDRTAS_DEFAULT_INTERVAL 300 + +#define WDRTAS_LOGBUFFER_LEN 128 +static char wdrtas_logbuffer[WDRTAS_LOGBUFFER_LEN]; + + +/*** watchdog access functions */ + +/** + * wdrtas_set_interval - sets the watchdog interval + * @interval: new interval + * + * returns 0 on success, <0 on failures + * + * wdrtas_set_interval sets the watchdog keepalive interval by calling the + * RTAS function set-indicator (surveillance). The unit of interval is + * seconds. + */ +static int +wdrtas_set_interval(int interval) +{ + long result; + static int print_msg = 10; + + /* rtas uses minutes */ + interval = (interval + 59) / 60; + + result = rtas_call(wdrtas_token_set_indicator, 3, 1, NULL, + WDRTAS_SURVEILLANCE_IND, 0, interval); + if ( (result < 0) && (print_msg) ) { + printk(KERN_ERR "wdrtas: setting the watchdog to %i " + "timeout failed: %li\n", interval, result); + print_msg--; + } + + return result; +} + +/** + * wdrtas_get_interval - returns the current watchdog interval + * @fallback_value: value (in seconds) to use, if the RTAS call fails + * + * returns the interval + * + * wdrtas_get_interval returns the current watchdog keepalive interval + * as reported by the RTAS function ibm,get-system-parameter. The unit + * of the return value is seconds. + */ +static int +wdrtas_get_interval(int fallback_value) +{ + long result; + char value[4]; + + result = rtas_call(wdrtas_token_get_sp, 3, 1, NULL, + WDRTAS_SP_SPI, (void *)__pa(&value), 4); + if ( (value[0] != 0) || (value[1] != 2) || (value[3] != 0) || + (result < 0) ) { + printk(KERN_WARNING "wdrtas: could not get sp_spi watchdog " + "timeout (%li). Continuing\n", result); + return fallback_value; + } + + /* rtas uses minutes */ + return ((int)value[2]) * 60; +} + +/** + * wdrtas_timer_start - starts watchdog + * + * wdrtas_timer_start starts the watchdog by calling the RTAS function + * set-interval (surveillance) + */ +static void +wdrtas_timer_start(void) +{ + wdrtas_set_interval(wdrtas_interval); +} + +/** + * wdrtas_timer_stop - stops watchdog + * + * wdrtas_timer_stop stops the watchdog timer by calling the RTAS function + * set-interval (surveillance) + */ +static void +wdrtas_timer_stop(void) +{ + wdrtas_set_interval(0); +} + +/** + * wdrtas_log_scanned_event - logs an event we received during keepalive + * + * wdrtas_log_scanned_event prints a message to the log buffer dumping + * the results of the last event-scan call + */ +static void +wdrtas_log_scanned_event(void) +{ + int i; + + for (i = 0; i < WDRTAS_LOGBUFFER_LEN; i += 16) + printk(KERN_INFO "wdrtas: dumping event (line %i/%i), data = " + "%02x %02x %02x %02x %02x %02x %02x %02x " + "%02x %02x %02x %02x %02x %02x %02x %02x\n", + (i / 16) + 1, (WDRTAS_LOGBUFFER_LEN / 16), + wdrtas_logbuffer[i + 0], wdrtas_logbuffer[i + 1], + wdrtas_logbuffer[i + 2], wdrtas_logbuffer[i + 3], + wdrtas_logbuffer[i + 4], wdrtas_logbuffer[i + 5], + wdrtas_logbuffer[i + 6], wdrtas_logbuffer[i + 7], + wdrtas_logbuffer[i + 8], wdrtas_logbuffer[i + 9], + wdrtas_logbuffer[i + 10], wdrtas_logbuffer[i + 11], + wdrtas_logbuffer[i + 12], wdrtas_logbuffer[i + 13], + wdrtas_logbuffer[i + 14], wdrtas_logbuffer[i + 15]); +} + +/** + * wdrtas_timer_keepalive - resets watchdog timer to keep system alive + * + * wdrtas_timer_keepalive restarts the watchdog timer by calling the + * RTAS function event-scan and repeats these calls as long as there are + * events available. All events will be dumped. + */ +static void +wdrtas_timer_keepalive(void) +{ + long result; + + do { + result = rtas_call(wdrtas_token_event_scan, 4, 1, NULL, + RTAS_EVENT_SCAN_ALL_EVENTS, 0, + (void *)__pa(wdrtas_logbuffer), + WDRTAS_LOGBUFFER_LEN); + if (result < 0) + printk(KERN_ERR "wdrtas: event-scan failed: %li\n", + result); + if (result == 0) + wdrtas_log_scanned_event(); + } while (result == 0); +} + +/** + * wdrtas_get_temperature - returns current temperature + * + * returns temperature or <0 on failures + * + * wdrtas_get_temperature returns the current temperature in Fahrenheit. It + * uses the RTAS call get-sensor-state, token 3 to do so + */ +static int +wdrtas_get_temperature(void) +{ + long result; + int temperature = 0; + + result = rtas_call(wdrtas_token_get_sensor_state, 2, 2, + (void *)__pa(&temperature), + WDRTAS_THERMAL_SENSOR, 0); + + if (result < 0) + printk(KERN_WARNING "wdrtas: reading the thermal sensor " + "faild: %li\n", result); + else + temperature = ((temperature * 9) / 5) + 32; /* fahrenheit */ + + return temperature; +} + +/** + * wdrtas_get_status - returns the status of the watchdog + * + * returns a bitmask of defines WDIOF_... as defined in + * include/linux/watchdog.h + */ +static int +wdrtas_get_status(void) +{ + return 0; /* TODO */ +} + +/** + * wdrtas_get_boot_status - returns the reason for the last boot + * + * returns a bitmask of defines WDIOF_... as defined in + * include/linux/watchdog.h, indicating why the watchdog rebooted the system + */ +static int +wdrtas_get_boot_status(void) +{ + return 0; /* TODO */ +} + +/*** watchdog API and operations stuff */ + +/* wdrtas_write - called when watchdog device is written to + * @file: file structure + * @buf: user buffer with data + * @len: amount to data written + * @ppos: position in file + * + * returns the number of successfully processed characters, which is always + * the number of bytes passed to this function + * + * wdrtas_write processes all the data given to it and looks for the magic + * character 'V'. This character allows the watchdog device to be closed + * properly. + */ +static ssize_t +wdrtas_write(struct file *file, const char __user *buf, + size_t len, loff_t *ppos) +{ + int i; + char c; + + if (!len) + goto out; + + if (!wdrtas_nowayout) { + wdrtas_expect_close = 0; + /* look for 'V' */ + for (i = 0; i < len; i++) { + if (get_user(c, buf + i)) + return -EFAULT; + /* allow to close device */ + if (c == 'V') + wdrtas_expect_close = WDRTAS_MAGIC_CHAR; + } + } + + wdrtas_timer_keepalive(); + +out: + return len; +} + +/** + * wdrtas_ioctl - ioctl function for the watchdog device + * @inode: inode structure + * @file: file structure + * @cmd: command for ioctl + * @arg: argument pointer + * + * returns 0 on success, <0 on failure + * + * wdrtas_ioctl implements the watchdog API ioctls + */ +static int +wdrtas_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg) +{ + int __user *argp = (void *)arg; + int i; + static struct watchdog_info wdinfo = { + .options = WDRTAS_SUPPORTED_MASK, + .firmware_version = 0, + .identity = "wdrtas" + }; + + switch (cmd) { + case WDIOC_GETSUPPORT: + if (copy_to_user(argp, &wdinfo, sizeof(wdinfo))) + return -EFAULT; + return 0; + + case WDIOC_GETSTATUS: + i = wdrtas_get_status(); + return put_user(i, argp); + + case WDIOC_GETBOOTSTATUS: + i = wdrtas_get_boot_status(); + return put_user(i, argp); + + case WDIOC_GETTEMP: + if (wdrtas_token_get_sensor_state == RTAS_UNKNOWN_SERVICE) + return -EOPNOTSUPP; + + i = wdrtas_get_temperature(); + return put_user(i, argp); + + case WDIOC_SETOPTIONS: + if (get_user(i, argp)) + return -EFAULT; + if (i & WDIOS_DISABLECARD) + wdrtas_timer_stop(); + if (i & WDIOS_ENABLECARD) { + wdrtas_timer_keepalive(); + wdrtas_timer_start(); + } + if (i & WDIOS_TEMPPANIC) { + /* not implemented. Done by H8 */ + } + return 0; + + case WDIOC_KEEPALIVE: + wdrtas_timer_keepalive(); + return 0; + + case WDIOC_SETTIMEOUT: + if (get_user(i, argp)) + return -EFAULT; + + if (wdrtas_set_interval(i)) + return -EINVAL; + + wdrtas_timer_keepalive(); + + if (wdrtas_token_get_sp == RTAS_UNKNOWN_SERVICE) + wdrtas_interval = i; + else + wdrtas_interval = wdrtas_get_interval(i); + /* fallthrough */ + + case WDIOC_GETTIMEOUT: + return put_user(wdrtas_interval, argp); + + default: + return -ENOIOCTLCMD; + } +} + +/** + * wdrtas_open - open function of watchdog device + * @inode: inode structure + * @file: file structure + * + * returns 0 on success, -EBUSY if the file has been opened already, <0 on + * other failures + * + * function called when watchdog device is opened + */ +static int +wdrtas_open(struct inode *inode, struct file *file) +{ + /* only open once */ + if (atomic_inc_return(&wdrtas_miscdev_open) > 1) { + atomic_dec(&wdrtas_miscdev_open); + return -EBUSY; + } + + wdrtas_timer_start(); + wdrtas_timer_keepalive(); + + return nonseekable_open(inode, file); +} + +/** + * wdrtas_close - close function of watchdog device + * @inode: inode structure + * @file: file structure + * + * returns 0 on success + * + * close function. Always succeeds + */ +static int +wdrtas_close(struct inode *inode, struct file *file) +{ + /* only stop watchdog, if this was announced using 'V' before */ + if (wdrtas_expect_close == WDRTAS_MAGIC_CHAR) + wdrtas_timer_stop(); + else { + printk(KERN_WARNING "wdrtas: got unexpected close. Watchdog " + "not stopped.\n"); + wdrtas_timer_keepalive(); + } + + wdrtas_expect_close = 0; + atomic_dec(&wdrtas_miscdev_open); + return 0; +} + +/** + * wdrtas_temp_read - gives back the temperature in fahrenheit + * @file: file structure + * @buf: user buffer + * @count: number of bytes to be read + * @ppos: position in file + * + * returns always 1 or -EFAULT in case of user space copy failures, <0 on + * other failures + * + * wdrtas_temp_read gives the temperature to the users by copying this + * value as one byte into the user space buffer. The unit is Fahrenheit... + */ +static ssize_t +wdrtas_temp_read(struct file *file, char __user *buf, + size_t count, loff_t *ppos) +{ + int temperature = 0; + + temperature = wdrtas_get_temperature(); + if (temperature < 0) + return temperature; + + if (copy_to_user(buf, &temperature, 1)) + return -EFAULT; + + return 1; +} + +/** + * wdrtas_temp_open - open function of temperature device + * @inode: inode structure + * @file: file structure + * + * returns 0 on success, <0 on failure + * + * function called when temperature device is opened + */ +static int +wdrtas_temp_open(struct inode *inode, struct file *file) +{ + return nonseekable_open(inode, file); +} + +/** + * wdrtas_temp_close - close function of temperature device + * @inode: inode structure + * @file: file structure + * + * returns 0 on success + * + * close function. Always succeeds + */ +static int +wdrtas_temp_close(struct inode *inode, struct file *file) +{ + return 0; +} + +/** + * wdrtas_reboot - reboot notifier function + * @nb: notifier block structure + * @code: reboot code + * @ptr: unused + * + * returns NOTIFY_DONE + * + * wdrtas_reboot stops the watchdog in case of a reboot + */ +static int +wdrtas_reboot(struct notifier_block *this, unsigned long code, void *ptr) +{ + if ( (code==SYS_DOWN) || (code==SYS_HALT) ) + wdrtas_timer_stop(); + + return NOTIFY_DONE; +} + +/*** initialization stuff */ + +static struct file_operations wdrtas_fops = { + .owner = THIS_MODULE, + .llseek = no_llseek, + .write = wdrtas_write, + .ioctl = wdrtas_ioctl, + .open = wdrtas_open, + .release = wdrtas_close, +}; + +static struct miscdevice wdrtas_miscdev = { + .minor = WATCHDOG_MINOR, + .name = "watchdog", + .fops = &wdrtas_fops, +}; + +static struct file_operations wdrtas_temp_fops = { + .owner = THIS_MODULE, + .llseek = no_llseek, + .read = wdrtas_temp_read, + .open = wdrtas_temp_open, + .release = wdrtas_temp_close, +}; + +static struct miscdevice wdrtas_tempdev = { + .minor = TEMP_MINOR, + .name = "temperature", + .fops = &wdrtas_temp_fops, +}; + +static struct notifier_block wdrtas_notifier = { + .notifier_call = wdrtas_reboot, +}; + +/** + * wdrtas_get_tokens - reads in RTAS tokens + * + * returns 0 on succes, <0 on failure + * + * wdrtas_get_tokens reads in the tokens for the RTAS calls used in + * this watchdog driver. It tolerates, if "get-sensor-state" and + * "ibm,get-system-parameter" are not available. + */ +static int +wdrtas_get_tokens(void) +{ + wdrtas_token_get_sensor_state = rtas_token("get-sensor-state"); + if (wdrtas_token_get_sensor_state == RTAS_UNKNOWN_SERVICE) { + printk(KERN_WARNING "wdrtas: couldn't get token for " + "get-sensor-state. Trying to continue without " + "temperature support.\n"); + } + + wdrtas_token_get_sp = rtas_token("ibm,get-system-parameter"); + if (wdrtas_token_get_sp == RTAS_UNKNOWN_SERVICE) { + printk(KERN_WARNING "wdrtas: couldn't get token for " + "ibm,get-system-parameter. Trying to continue with " + "a default timeout value of %i seconds.\n", + WDRTAS_DEFAULT_INTERVAL); + } + + wdrtas_token_set_indicator = rtas_token("set-indicator"); + if (wdrtas_token_set_indicator == RTAS_UNKNOWN_SERVICE) { + printk(KERN_ERR "wdrtas: couldn't get token for " + "set-indicator. Terminating watchdog code.\n"); + return -EIO; + } + + wdrtas_token_event_scan = rtas_token("event-scan"); + if (wdrtas_token_event_scan == RTAS_UNKNOWN_SERVICE) { + printk(KERN_ERR "wdrtas: couldn't get token for event-scan. " + "Terminating watchdog code.\n"); + return -EIO; + } + + return 0; +} + +/** + * wdrtas_unregister_devs - unregisters the misc dev handlers + * + * wdrtas_register_devs unregisters the watchdog and temperature watchdog + * misc devs + */ +static void +wdrtas_unregister_devs(void) +{ + misc_deregister(&wdrtas_miscdev); + if (wdrtas_token_get_sensor_state != RTAS_UNKNOWN_SERVICE) + misc_deregister(&wdrtas_tempdev); +} + +/** + * wdrtas_register_devs - registers the misc dev handlers + * + * returns 0 on succes, <0 on failure + * + * wdrtas_register_devs registers the watchdog and temperature watchdog + * misc devs + */ +static int +wdrtas_register_devs(void) +{ + int result; + + result = misc_register(&wdrtas_miscdev); + if (result) { + printk(KERN_ERR "wdrtas: couldn't register watchdog misc " + "device. Terminating watchdog code.\n"); + return result; + } + + if (wdrtas_token_get_sensor_state != RTAS_UNKNOWN_SERVICE) { + result = misc_register(&wdrtas_tempdev); + if (result) { + printk(KERN_WARNING "wdrtas: couldn't register " + "watchdog temperature misc device. Continuing " + "without temperature support.\n"); + wdrtas_token_get_sensor_state = RTAS_UNKNOWN_SERVICE; + } + } + + return 0; +} + +/** + * wdrtas_init - init function of the watchdog driver + * + * returns 0 on succes, <0 on failure + * + * registers the file handlers and the reboot notifier + */ +static int __init +wdrtas_init(void) +{ + if (wdrtas_get_tokens()) + return -ENODEV; + + if (wdrtas_register_devs()) + return -ENODEV; + + if (register_reboot_notifier(&wdrtas_notifier)) { + printk(KERN_ERR "wdrtas: could not register reboot notifier. " + "Terminating watchdog code.\n"); + wdrtas_unregister_devs(); + return -ENODEV; + } + + if (wdrtas_token_get_sp == RTAS_UNKNOWN_SERVICE) + wdrtas_interval = WDRTAS_DEFAULT_INTERVAL; + else + wdrtas_interval = wdrtas_get_interval(WDRTAS_DEFAULT_INTERVAL); + + return 0; +} + +/** + * wdrtas_exit - exit function of the watchdog driver + * + * unregisters the file handlers and the reboot notifier + */ +static void __exit +wdrtas_exit(void) +{ + if (!wdrtas_nowayout) + wdrtas_timer_stop(); + + wdrtas_unregister_devs(); + + unregister_reboot_notifier(&wdrtas_notifier); +} + +module_init(wdrtas_init); +module_exit(wdrtas_exit); |