diff options
Diffstat (limited to 'drivers/char')
67 files changed, 2909 insertions, 1230 deletions
diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig index bf18d757b87..85bf9b2aa74 100644 --- a/drivers/char/Kconfig +++ b/drivers/char/Kconfig @@ -137,7 +137,7 @@ config CYCLADES your Linux box, for instance in order to become a dial-in server. For information about the Cyclades-Z card, read - <file:drivers/char/README.cycladesZ>. + <file:Documentation/README.cycladesZ>. To compile this driver as a module, choose M here: the module will be called cyclades. @@ -276,7 +276,7 @@ config N_HDLC config RISCOM8 tristate "SDL RISCom/8 card support" - depends on SERIAL_NONSTANDARD && BROKEN_ON_SMP + depends on SERIAL_NONSTANDARD help This is a driver for the SDL Communications RISCom/8 multiport card, which gives you many serial ports. You would need something like @@ -373,6 +373,16 @@ config ISTALLION To compile this driver as a module, choose M here: the module will be called istallion. +config NOZOMI + tristate "HSDPA Broadband Wireless Data Card - Globe Trotter" + depends on PCI && EXPERIMENTAL + help + If you have a HSDPA driver Broadband Wireless Data Card - + Globe Trotter PCMCIA card, say Y here. + + To compile this driver as a module, choose M here, the module + will be called nozomi. + config A2232 tristate "Commodore A2232 serial support (EXPERIMENTAL)" depends on EXPERIMENTAL && ZORRO && BROKEN_ON_SMP @@ -457,7 +467,7 @@ config LEGACY_PTYS config LEGACY_PTY_COUNT int "Maximum number of legacy PTY in use" depends on LEGACY_PTYS - range 1 256 + range 0 256 default "256" ---help--- The maximum number of legacy PTYs that can be used at any one time. @@ -543,28 +553,6 @@ config PPDEV If unsure, say N. -config TIPAR - tristate "Texas Instruments parallel link cable support" - depends on PARPORT - ---help--- - If you own a Texas Instruments graphing calculator and use a - parallel link cable, then you might be interested in this driver. - - If you enable this driver, you will be able to communicate with - your calculator through a set of device nodes under /dev. The - main advantage of this driver is that you don't have to be root - to use this precise link cable (depending on the permissions on - the device nodes, though). - - To compile this driver as a module, choose M here: the - module will be called tipar. - - If you don't know what a parallel link cable is or what a Texas - Instruments graphing calculator is, then you probably don't need this - driver. - - If unsure, say N. - config HVC_DRIVER bool help @@ -777,7 +765,7 @@ config JS_RTC config SGI_DS1286 tristate "SGI DS1286 RTC support" - depends on SGI_IP22 + depends on SGI_HAS_DS1286 help If you say Y here and create a character special file /dev/rtc with major number 10 and minor number 135 using mknod ("man mknod"), you diff --git a/drivers/char/Makefile b/drivers/char/Makefile index 07304d50e0c..96fc01eddef 100644 --- a/drivers/char/Makefile +++ b/drivers/char/Makefile @@ -26,6 +26,7 @@ obj-$(CONFIG_SERIAL167) += serial167.o obj-$(CONFIG_CYCLADES) += cyclades.o obj-$(CONFIG_STALLION) += stallion.o obj-$(CONFIG_ISTALLION) += istallion.o +obj-$(CONFIG_NOZOMI) += nozomi.o obj-$(CONFIG_DIGIEPCA) += epca.o obj-$(CONFIG_SPECIALIX) += specialix.o obj-$(CONFIG_MOXA_INTELLIO) += moxa.o diff --git a/drivers/char/agp/agp.h b/drivers/char/agp/agp.h index b83824c4132..c69f79598e4 100644 --- a/drivers/char/agp/agp.h +++ b/drivers/char/agp/agp.h @@ -117,7 +117,8 @@ struct agp_bridge_driver { void (*free_by_type)(struct agp_memory *); void *(*agp_alloc_page)(struct agp_bridge_data *); void (*agp_destroy_page)(void *, int flags); - int (*agp_type_to_mask_type) (struct agp_bridge_data *, int); + int (*agp_type_to_mask_type) (struct agp_bridge_data *, int); + void (*chipset_flush)(struct agp_bridge_data *); }; struct agp_bridge_data { @@ -235,6 +236,9 @@ struct agp_bridge_data { #define I965_PGETBL_SIZE_512KB (0 << 1) #define I965_PGETBL_SIZE_256KB (1 << 1) #define I965_PGETBL_SIZE_128KB (2 << 1) +#define I965_PGETBL_SIZE_1MB (3 << 1) +#define I965_PGETBL_SIZE_2MB (4 << 1) +#define I965_PGETBL_SIZE_1_5MB (5 << 1) #define G33_PGETBL_SIZE_MASK (3 << 8) #define G33_PGETBL_SIZE_1M (1 << 8) #define G33_PGETBL_SIZE_2M (2 << 8) diff --git a/drivers/char/agp/ali-agp.c b/drivers/char/agp/ali-agp.c index aa5ddb716ff..1ffb381130c 100644 --- a/drivers/char/agp/ali-agp.c +++ b/drivers/char/agp/ali-agp.c @@ -145,7 +145,6 @@ static void *m1541_alloc_page(struct agp_bridge_data *bridge) void *addr = agp_generic_alloc_page(agp_bridge); u32 temp; - global_flush_tlb(); if (!addr) return NULL; @@ -162,7 +161,6 @@ static void ali_destroy_page(void * addr, int flags) if (flags & AGP_PAGE_DESTROY_UNMAP) { global_cache_flush(); /* is this really needed? --hch */ agp_generic_destroy_page(addr, flags); - global_flush_tlb(); } else agp_generic_destroy_page(addr, flags); } diff --git a/drivers/char/agp/alpha-agp.c b/drivers/char/agp/alpha-agp.c index aa8f3a39a70..e77c17838c8 100644 --- a/drivers/char/agp/alpha-agp.c +++ b/drivers/char/agp/alpha-agp.c @@ -11,29 +11,28 @@ #include "agp.h" -static struct page *alpha_core_agp_vm_nopage(struct vm_area_struct *vma, - unsigned long address, - int *type) +static int alpha_core_agp_vm_fault(struct vm_area_struct *vma, + struct vm_fault *vmf) { alpha_agp_info *agp = agp_bridge->dev_private_data; dma_addr_t dma_addr; unsigned long pa; struct page *page; - dma_addr = address - vma->vm_start + agp->aperture.bus_base; + dma_addr = (unsigned long)vmf->virtual_address - vma->vm_start + + agp->aperture.bus_base; pa = agp->ops->translate(agp, dma_addr); if (pa == (unsigned long)-EINVAL) - return NULL; /* no translation */ + return VM_FAULT_SIGBUS; /* no translation */ /* * Get the page, inc the use count, and return it */ page = virt_to_page(__va(pa)); get_page(page); - if (type) - *type = VM_FAULT_MINOR; - return page; + vmf->page = page; + return 0; } static struct aper_size_info_fixed alpha_core_agp_sizes[] = @@ -42,7 +41,7 @@ static struct aper_size_info_fixed alpha_core_agp_sizes[] = }; struct vm_operations_struct alpha_core_agp_vm_ops = { - .nopage = alpha_core_agp_vm_nopage, + .fault = alpha_core_agp_vm_fault, }; diff --git a/drivers/char/agp/amd-k7-agp.c b/drivers/char/agp/amd-k7-agp.c index 1405a42585e..87be46406da 100644 --- a/drivers/char/agp/amd-k7-agp.c +++ b/drivers/char/agp/amd-k7-agp.c @@ -436,10 +436,6 @@ static int __devinit agp_amdk7_probe(struct pci_dev *pdev, return -ENODEV; } cap_ptr = pci_find_capability(gfxcard, PCI_CAP_ID_AGP); - if (!cap_ptr) { - pci_dev_put(gfxcard); - continue; - } } /* With so many variants of NVidia cards, it's simpler just diff --git a/drivers/char/agp/backend.c b/drivers/char/agp/backend.c index 832ded20fe7..b1bdd015165 100644 --- a/drivers/char/agp/backend.c +++ b/drivers/char/agp/backend.c @@ -43,7 +43,7 @@ * fix some real stupidity. It's only by chance we can bump * past 0.99 at all due to some boolean logic error. */ #define AGPGART_VERSION_MAJOR 0 -#define AGPGART_VERSION_MINOR 102 +#define AGPGART_VERSION_MINOR 103 static const struct agp_version agp_current_version = { .major = AGPGART_VERSION_MAJOR, @@ -147,7 +147,6 @@ static int agp_backend_initialize(struct agp_bridge_data *bridge) printk(KERN_ERR PFX "unable to get memory for scratch page.\n"); return -ENOMEM; } - flush_agp_mappings(); bridge->scratch_page_real = virt_to_gart(addr); bridge->scratch_page = @@ -191,7 +190,6 @@ err_out: if (bridge->driver->needs_scratch_page) { bridge->driver->agp_destroy_page(gart_to_virt(bridge->scratch_page_real), AGP_PAGE_DESTROY_UNMAP); - flush_agp_mappings(); bridge->driver->agp_destroy_page(gart_to_virt(bridge->scratch_page_real), AGP_PAGE_DESTROY_FREE); } @@ -219,7 +217,6 @@ static void agp_backend_cleanup(struct agp_bridge_data *bridge) bridge->driver->needs_scratch_page) { bridge->driver->agp_destroy_page(gart_to_virt(bridge->scratch_page_real), AGP_PAGE_DESTROY_UNMAP); - flush_agp_mappings(); bridge->driver->agp_destroy_page(gart_to_virt(bridge->scratch_page_real), AGP_PAGE_DESTROY_FREE); } diff --git a/drivers/char/agp/compat_ioctl.c b/drivers/char/agp/compat_ioctl.c index ecd4248861b..39275794fe6 100644 --- a/drivers/char/agp/compat_ioctl.c +++ b/drivers/char/agp/compat_ioctl.c @@ -273,6 +273,10 @@ long compat_agp_ioctl(struct file *file, unsigned int cmd, unsigned long arg) case AGPIOC_UNBIND32: ret_val = compat_agpioc_unbind_wrap(curr_priv, (void __user *) arg); break; + + case AGPIOC_CHIPSET_FLUSH32: + ret_val = agpioc_chipset_flush_wrap(curr_priv); + break; } ioctl_out: diff --git a/drivers/char/agp/compat_ioctl.h b/drivers/char/agp/compat_ioctl.h index 71939d63723..0c9678ac037 100644 --- a/drivers/char/agp/compat_ioctl.h +++ b/drivers/char/agp/compat_ioctl.h @@ -39,6 +39,7 @@ #define AGPIOC_DEALLOCATE32 _IOW (AGPIOC_BASE, 7, compat_int_t) #define AGPIOC_BIND32 _IOW (AGPIOC_BASE, 8, compat_uptr_t) #define AGPIOC_UNBIND32 _IOW (AGPIOC_BASE, 9, compat_uptr_t) +#define AGPIOC_CHIPSET_FLUSH32 _IO (AGPIOC_BASE, 10) struct agp_info32 { struct agp_version version; /* version of the driver */ @@ -101,5 +102,6 @@ void agp_free_memory_wrap(struct agp_memory *memory); struct agp_memory *agp_allocate_memory_wrap(size_t pg_count, u32 type); struct agp_memory *agp_find_mem_by_key(int key); struct agp_client *agp_find_client_by_pid(pid_t id); +int agpioc_chipset_flush_wrap(struct agp_file_private *priv); #endif /* _AGP_COMPAT_H */ diff --git a/drivers/char/agp/frontend.c b/drivers/char/agp/frontend.c index 7791e98de51..55d7a82bd07 100644 --- a/drivers/char/agp/frontend.c +++ b/drivers/char/agp/frontend.c @@ -689,7 +689,7 @@ static int agp_open(struct inode *inode, struct file *file) set_bit(AGP_FF_ALLOW_CLIENT, &priv->access_flags); priv->my_pid = current->pid; - if ((current->uid == 0) || (current->suid == 0)) { + if (capable(CAP_SYS_RAWIO)) { /* Root priv, can be controller */ set_bit(AGP_FF_ALLOW_CONTROLLER, &priv->access_flags); } @@ -960,6 +960,13 @@ static int agpioc_unbind_wrap(struct agp_file_private *priv, void __user *arg) return agp_unbind_memory(memory); } +int agpioc_chipset_flush_wrap(struct agp_file_private *priv) +{ + DBG(""); + agp_flush_chipset(agp_bridge); + return 0; +} + static int agp_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { @@ -1033,6 +1040,10 @@ static int agp_ioctl(struct inode *inode, struct file *file, case AGPIOC_UNBIND: ret_val = agpioc_unbind_wrap(curr_priv, (void __user *) arg); break; + + case AGPIOC_CHIPSET_FLUSH: + ret_val = agpioc_chipset_flush_wrap(curr_priv); + break; } ioctl_out: diff --git a/drivers/char/agp/generic.c b/drivers/char/agp/generic.c index 64b2f6d7059..7484bc759c4 100644 --- a/drivers/char/agp/generic.c +++ b/drivers/char/agp/generic.c @@ -80,6 +80,13 @@ static int agp_get_key(void) return -1; } +void agp_flush_chipset(struct agp_bridge_data *bridge) +{ + if (bridge->driver->chipset_flush) + bridge->driver->chipset_flush(bridge); +} +EXPORT_SYMBOL(agp_flush_chipset); + /* * Use kmalloc if possible for the page list. Otherwise fall back to * vmalloc. This speeds things up and also saves memory for small AGP @@ -197,7 +204,6 @@ void agp_free_memory(struct agp_memory *curr) for (i = 0; i < curr->page_count; i++) { curr->bridge->driver->agp_destroy_page(gart_to_virt(curr->memory[i]), AGP_PAGE_DESTROY_UNMAP); } - flush_agp_mappings(); for (i = 0; i < curr->page_count; i++) { curr->bridge->driver->agp_destroy_page(gart_to_virt(curr->memory[i]), AGP_PAGE_DESTROY_FREE); } @@ -267,8 +273,6 @@ struct agp_memory *agp_allocate_memory(struct agp_bridge_data *bridge, } new->bridge = bridge; - flush_agp_mappings(); - return new; } EXPORT_SYMBOL(agp_allocate_memory); diff --git a/drivers/char/agp/i460-agp.c b/drivers/char/agp/i460-agp.c index e72a83e2bad..76f581c85a7 100644 --- a/drivers/char/agp/i460-agp.c +++ b/drivers/char/agp/i460-agp.c @@ -527,7 +527,6 @@ static void *i460_alloc_page (struct agp_bridge_data *bridge) if (I460_IO_PAGE_SHIFT <= PAGE_SHIFT) { page = agp_generic_alloc_page(agp_bridge); - global_flush_tlb(); } else /* Returning NULL would cause problems */ /* AK: really dubious code. */ @@ -539,7 +538,6 @@ static void i460_destroy_page (void *page, int flags) { if (I460_IO_PAGE_SHIFT <= PAGE_SHIFT) { agp_generic_destroy_page(page, flags); - global_flush_tlb(); } } diff --git a/drivers/char/agp/intel-agp.c b/drivers/char/agp/intel-agp.c index d87961993cc..eeea50a1d22 100644 --- a/drivers/char/agp/intel-agp.c +++ b/drivers/char/agp/intel-agp.c @@ -10,10 +10,12 @@ #include <linux/agp_backend.h> #include "agp.h" +#define PCI_DEVICE_ID_INTEL_E7221_HB 0x2588 +#define PCI_DEVICE_ID_INTEL_E7221_IG 0x258a #define PCI_DEVICE_ID_INTEL_82946GZ_HB 0x2970 #define PCI_DEVICE_ID_INTEL_82946GZ_IG 0x2972 -#define PCI_DEVICE_ID_INTEL_82965G_1_HB 0x2980 -#define PCI_DEVICE_ID_INTEL_82965G_1_IG 0x2982 +#define PCI_DEVICE_ID_INTEL_82G35_HB 0x2980 +#define PCI_DEVICE_ID_INTEL_82G35_IG 0x2982 #define PCI_DEVICE_ID_INTEL_82965Q_HB 0x2990 #define PCI_DEVICE_ID_INTEL_82965Q_IG 0x2992 #define PCI_DEVICE_ID_INTEL_82965G_HB 0x29A0 @@ -30,13 +32,24 @@ #define PCI_DEVICE_ID_INTEL_Q35_IG 0x29B2 #define PCI_DEVICE_ID_INTEL_Q33_HB 0x29D0 #define PCI_DEVICE_ID_INTEL_Q33_IG 0x29D2 +#define PCI_DEVICE_ID_INTEL_IGD_HB 0x2A40 +#define PCI_DEVICE_ID_INTEL_IGD_IG 0x2A42 + +/* cover 915 and 945 variants */ +#define IS_I915 (agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_E7221_HB || \ + agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82915G_HB || \ + agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82915GM_HB || \ + agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82945G_HB || \ + agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82945GM_HB || \ + agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82945GME_HB) #define IS_I965 (agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82946GZ_HB || \ - agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82965G_1_HB || \ - agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82965Q_HB || \ - agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82965G_HB || \ - agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82965GM_HB || \ - agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82965GME_HB) + agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82G35_HB || \ + agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82965Q_HB || \ + agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82965G_HB || \ + agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82965GM_HB || \ + agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82965GME_HB || \ + agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_IGD_HB) #define IS_G33 (agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_G33_HB || \ agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_Q35_HB || \ @@ -69,9 +82,11 @@ extern int agp_memory_reserved; #define I915_GMCH_GMS_STOLEN_64M (0x7 << 4) #define G33_GMCH_GMS_STOLEN_128M (0x8 << 4) #define G33_GMCH_GMS_STOLEN_256M (0x9 << 4) +#define I915_IFPADDR 0x60 /* Intel 965G registers */ #define I965_MSAC 0x62 +#define I965_IFPADDR 0x70 /* Intel 7505 registers */ #define INTEL_I7505_APSIZE 0x74 @@ -113,6 +128,13 @@ static struct _intel_private { * popup and for the GTT. */ int gtt_entries; /* i830+ */ + union { + void __iomem *i9xx_flush_page; + void *i8xx_flush_page; + }; + struct page *i8xx_page; + struct resource ifp_resource; + int resource_valid; } intel_private; static int intel_i810_fetch_size(void) @@ -202,19 +224,17 @@ static void intel_i810_agp_enable(struct agp_bridge_data *bridge, u32 mode) /* Exists to support ARGB cursors */ static void *i8xx_alloc_pages(void) { - struct page * page; + struct page *page; page = alloc_pages(GFP_KERNEL | GFP_DMA32, 2); if (page == NULL) return NULL; - if (change_page_attr(page, 4, PAGE_KERNEL_NOCACHE) < 0) { - change_page_attr(page, 4, PAGE_KERNEL); - global_flush_tlb(); + if (set_pages_uc(page, 4) < 0) { + set_pages_wb(page, 4); __free_pages(page, 2); return NULL; } - global_flush_tlb(); get_page(page); atomic_inc(&agp_bridge->current_memory_agp); return page_address(page); @@ -228,8 +248,7 @@ static void i8xx_destroy_pages(void *addr) return; page = virt_to_page(addr); - change_page_attr(page, 4, PAGE_KERNEL); - global_flush_tlb(); + set_pages_wb(page, 4); put_page(page); __free_pages(page, 2); atomic_dec(&agp_bridge->current_memory_agp); @@ -339,7 +358,6 @@ static struct agp_memory *alloc_agpphysmem_i8xx(size_t pg_count, int type) switch (pg_count) { case 1: addr = agp_bridge->driver->agp_alloc_page(agp_bridge); - global_flush_tlb(); break; case 4: /* kludge to get 4 physical pages for ARGB cursor */ @@ -402,7 +420,6 @@ static void intel_i810_free_by_type(struct agp_memory *curr) else { agp_bridge->driver->agp_destroy_page(gart_to_virt(curr->memory[0]), AGP_PAGE_DESTROY_UNMAP); - global_flush_tlb(); agp_bridge->driver->agp_destroy_page(gart_to_virt(curr->memory[0]), AGP_PAGE_DESTROY_FREE); } @@ -436,7 +453,7 @@ static void intel_i830_init_gtt_entries(void) static const int ddt[4] = { 0, 16, 32, 64 }; int size; /* reserved space (in kb) at the top of stolen memory */ - pci_read_config_word(agp_bridge->dev,I830_GMCH_CTRL,&gmch_ctrl); + pci_read_config_word(agp_bridge->dev, I830_GMCH_CTRL, &gmch_ctrl); if (IS_I965) { u32 pgetbl_ctl; @@ -456,6 +473,15 @@ static void intel_i830_init_gtt_entries(void) case I965_PGETBL_SIZE_512KB: size = 512; break; + case I965_PGETBL_SIZE_1MB: + size = 1024; + break; + case I965_PGETBL_SIZE_2MB: + size = 2048; + break; + case I965_PGETBL_SIZE_1_5MB: + size = 1024 + 512; + break; default: printk(KERN_INFO PFX "Unknown page table size, " "assuming 512KB\n"); @@ -526,24 +552,14 @@ static void intel_i830_init_gtt_entries(void) break; 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_82945G_HB || - agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82945GM_HB || - agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82945GME_HB || - IS_I965 || IS_G33) + if (IS_I915 || IS_I965 || IS_G33) gtt_entries = MB(48) - KB(size); else gtt_entries = 0; break; 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_82945G_HB || - agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82945GM_HB || - agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82945GME_HB || - IS_I965 || IS_G33) + if (IS_I915 || IS_I965 || IS_G33) gtt_entries = MB(64) - KB(size); else gtt_entries = 0; @@ -576,6 +592,45 @@ static void intel_i830_init_gtt_entries(void) intel_private.gtt_entries = gtt_entries; } +static void intel_i830_fini_flush(void) +{ + kunmap(intel_private.i8xx_page); + intel_private.i8xx_flush_page = NULL; + unmap_page_from_agp(intel_private.i8xx_page); + + __free_page(intel_private.i8xx_page); + intel_private.i8xx_page = NULL; +} + +static void intel_i830_setup_flush(void) +{ + /* return if we've already set the flush mechanism up */ + if (intel_private.i8xx_page) + return; + + intel_private.i8xx_page = alloc_page(GFP_KERNEL | __GFP_ZERO | GFP_DMA32); + if (!intel_private.i8xx_page) + return; + + /* make page uncached */ + map_page_into_agp(intel_private.i8xx_page); + + intel_private.i8xx_flush_page = kmap(intel_private.i8xx_page); + if (!intel_private.i8xx_flush_page) + intel_i830_fini_flush(); +} + +static void intel_i830_chipset_flush(struct agp_bridge_data *bridge) +{ + unsigned int *pg = intel_private.i8xx_flush_page; + int i; + + for (i = 0; i < 256; i += 2) + *(pg + i) = i; + + wmb(); +} + /* The intel i830 automatically initializes the agp aperture during POST. * Use the memory already set aside for in the GTT. */ @@ -591,10 +646,10 @@ static int intel_i830_create_gatt_table(struct agp_bridge_data *bridge) num_entries = size->num_entries; agp_bridge->gatt_table_real = NULL; - pci_read_config_dword(intel_private.pcidev,I810_MMADDR,&temp); + pci_read_config_dword(intel_private.pcidev, I810_MMADDR, &temp); temp &= 0xfff80000; - intel_private.registers = ioremap(temp,128 * 4096); + intel_private.registers = ioremap(temp, 128 * 4096); if (!intel_private.registers) return -ENOMEM; @@ -634,7 +689,7 @@ static int intel_i830_fetch_size(void) return values[0].size; } - pci_read_config_word(agp_bridge->dev,I830_GMCH_CTRL,&gmch_ctrl); + pci_read_config_word(agp_bridge->dev, I830_GMCH_CTRL, &gmch_ctrl); if ((gmch_ctrl & I830_GMCH_MEM_MASK) == I830_GMCH_MEM_128M) { agp_bridge->previous_size = agp_bridge->current_size = (void *) values; @@ -658,12 +713,12 @@ static int intel_i830_configure(void) current_size = A_SIZE_FIX(agp_bridge->current_size); - pci_read_config_dword(intel_private.pcidev,I810_GMADDR,&temp); + pci_read_config_dword(intel_private.pcidev, I810_GMADDR, &temp); agp_bridge->gart_bus_addr = (temp & PCI_BASE_ADDRESS_MEM_MASK); - pci_read_config_word(agp_bridge->dev,I830_GMCH_CTRL,&gmch_ctrl); + pci_read_config_word(agp_bridge->dev, I830_GMCH_CTRL, &gmch_ctrl); gmch_ctrl |= I830_GMCH_ENABLED; - pci_write_config_word(agp_bridge->dev,I830_GMCH_CTRL,gmch_ctrl); + pci_write_config_word(agp_bridge->dev, I830_GMCH_CTRL, gmch_ctrl); writel(agp_bridge->gatt_bus_addr|I810_PGETBL_ENABLED, intel_private.registers+I810_PGETBL_CTL); readl(intel_private.registers+I810_PGETBL_CTL); /* PCI Posting. */ @@ -676,6 +731,8 @@ static int intel_i830_configure(void) } global_cache_flush(); + + intel_i830_setup_flush(); return 0; } @@ -684,9 +741,10 @@ static void intel_i830_cleanup(void) iounmap(intel_private.registers); } -static int intel_i830_insert_entries(struct agp_memory *mem,off_t pg_start, int type) +static int intel_i830_insert_entries(struct agp_memory *mem, off_t pg_start, + int type) { - int i,j,num_entries; + int i, j, num_entries; void *temp; int ret = -EINVAL; int mask_type; @@ -698,10 +756,10 @@ static int intel_i830_insert_entries(struct agp_memory *mem,off_t pg_start, int num_entries = A_SIZE_FIX(temp)->num_entries; if (pg_start < intel_private.gtt_entries) { - printk (KERN_DEBUG PFX "pg_start == 0x%.8lx,intel_private.gtt_entries == 0x%.8x\n", - pg_start,intel_private.gtt_entries); + printk(KERN_DEBUG PFX "pg_start == 0x%.8lx,intel_private.gtt_entries == 0x%.8x\n", + pg_start, intel_private.gtt_entries); - printk (KERN_INFO PFX "Trying to insert into local/stolen memory\n"); + printk(KERN_INFO PFX "Trying to insert into local/stolen memory\n"); goto out_err; } @@ -739,8 +797,8 @@ out_err: return ret; } -static int intel_i830_remove_entries(struct agp_memory *mem,off_t pg_start, - int type) +static int intel_i830_remove_entries(struct agp_memory *mem, off_t pg_start, + int type) { int i; @@ -748,7 +806,7 @@ static int intel_i830_remove_entries(struct agp_memory *mem,off_t pg_start, return 0; if (pg_start < intel_private.gtt_entries) { - printk (KERN_INFO PFX "Trying to disable local/stolen memory\n"); + printk(KERN_INFO PFX "Trying to disable local/stolen memory\n"); return -EINVAL; } @@ -761,7 +819,7 @@ static int intel_i830_remove_entries(struct agp_memory *mem,off_t pg_start, return 0; } -static struct agp_memory *intel_i830_alloc_by_type(size_t pg_count,int type) +static struct agp_memory *intel_i830_alloc_by_type(size_t pg_count, int type) { if (type == AGP_PHYS_MEMORY) return alloc_agpphysmem_i8xx(pg_count, type); @@ -769,6 +827,95 @@ static struct agp_memory *intel_i830_alloc_by_type(size_t pg_count,int type) return NULL; } +static int intel_alloc_chipset_flush_resource(void) +{ + int ret; + ret = pci_bus_alloc_resource(agp_bridge->dev->bus, &intel_private.ifp_resource, PAGE_SIZE, + PAGE_SIZE, PCIBIOS_MIN_MEM, 0, + pcibios_align_resource, agp_bridge->dev); + + return ret; +} + +static void intel_i915_setup_chipset_flush(void) +{ + int ret; + u32 temp; + + pci_read_config_dword(agp_bridge->dev, I915_IFPADDR, &temp); + if (!(temp & 0x1)) { + intel_alloc_chipset_flush_resource(); + intel_private.resource_valid = 1; + pci_write_config_dword(agp_bridge->dev, I915_IFPADDR, (intel_private.ifp_resource.start & 0xffffffff) | 0x1); + } else { + temp &= ~1; + + intel_private.resource_valid = 1; + intel_private.ifp_resource.start = temp; + intel_private.ifp_resource.end = temp + PAGE_SIZE; + ret = request_resource(&iomem_resource, &intel_private.ifp_resource); + /* some BIOSes reserve this area in a pnp some don't */ + if (ret) + intel_private.resource_valid = 0; + } +} + +static void intel_i965_g33_setup_chipset_flush(void) +{ + u32 temp_hi, temp_lo; + int ret; + + pci_read_config_dword(agp_bridge->dev, I965_IFPADDR + 4, &temp_hi); + pci_read_config_dword(agp_bridge->dev, I965_IFPADDR, &temp_lo); + + if (!(temp_lo & 0x1)) { + + intel_alloc_chipset_flush_resource(); + + intel_private.resource_valid = 1; + pci_write_config_dword(agp_bridge->dev, I965_IFPADDR + 4, + upper_32_bits(intel_private.ifp_resource.start)); + pci_write_config_dword(agp_bridge->dev, I965_IFPADDR, (intel_private.ifp_resource.start & 0xffffffff) | 0x1); + } else { + u64 l64; + + temp_lo &= ~0x1; + l64 = ((u64)temp_hi << 32) | temp_lo; + + intel_private.resource_valid = 1; + intel_private.ifp_resource.start = l64; + intel_private.ifp_resource.end = l64 + PAGE_SIZE; + ret = request_resource(&iomem_resource, &intel_private.ifp_resource); + /* some BIOSes reserve this area in a pnp some don't */ + if (ret) + intel_private.resource_valid = 0; + } +} + +static void intel_i9xx_setup_flush(void) +{ + /* return if already configured */ + if (intel_private.ifp_resource.start) + return; + + /* setup a resource for this object */ + intel_private.ifp_resource.name = "Intel Flush Page"; + intel_private.ifp_resource.flags = IORESOURCE_MEM; + + /* Setup chipset flush for 915 */ + if (IS_I965 || IS_G33) { + intel_i965_g33_setup_chipset_flush(); + } else { + intel_i915_setup_chipset_flush(); + } + + if (intel_private.ifp_resource.start) { + intel_private.i9xx_flush_page = ioremap_nocache(intel_private.ifp_resource.start, PAGE_SIZE); + if (!intel_private.i9xx_flush_page) + printk(KERN_INFO "unable to ioremap flush page - no chipset flushing"); + } +} + static int intel_i915_configure(void) { struct aper_size_info_fixed *current_size; @@ -782,9 +929,9 @@ static int intel_i915_configure(void) agp_bridge->gart_bus_addr = (temp & PCI_BASE_ADDRESS_MEM_MASK); - pci_read_config_word(agp_bridge->dev,I830_GMCH_CTRL,&gmch_ctrl); + pci_read_config_word(agp_bridge->dev, I830_GMCH_CTRL, &gmch_ctrl); gmch_ctrl |= I830_GMCH_ENABLED; - pci_write_config_word(agp_bridge->dev,I830_GMCH_CTRL,gmch_ctrl); + pci_write_config_word(agp_bridge->dev, I830_GMCH_CTRL, gmch_ctrl); writel(agp_bridge->gatt_bus_addr|I810_PGETBL_ENABLED, intel_private.registers+I810_PGETBL_CTL); readl(intel_private.registers+I810_PGETBL_CTL); /* PCI Posting. */ @@ -797,19 +944,34 @@ static int intel_i915_configure(void) } global_cache_flush(); + + intel_i9xx_setup_flush(); + return 0; } static void intel_i915_cleanup(void) { + if (intel_private.i9xx_flush_page) + iounmap(intel_private.i9xx_flush_page); + if (intel_private.resource_valid) + release_resource(&intel_private.ifp_resource); + intel_private.ifp_resource.start = 0; + intel_private.resource_valid = 0; iounmap(intel_private.gtt); iounmap(intel_private.registers); } -static int intel_i915_insert_entries(struct agp_memory *mem,off_t pg_start, - int type) +static void intel_i915_chipset_flush(struct agp_bridge_data *bridge) { - int i,j,num_entries; + if (intel_private.i9xx_flush_page) + writel(1, intel_private.i9xx_flush_page); +} + +static int intel_i915_insert_entries(struct agp_memory *mem, off_t pg_start, + int type) +{ + int i, j, num_entries; void *temp; int ret = -EINVAL; int mask_type; @@ -821,10 +983,10 @@ static int intel_i915_insert_entries(struct agp_memory *mem,off_t pg_start, num_entries = A_SIZE_FIX(temp)->num_entries; if (pg_start < intel_private.gtt_entries) { - printk (KERN_DEBUG PFX "pg_start == 0x%.8lx,intel_private.gtt_entries == 0x%.8x\n", - pg_start,intel_private.gtt_entries); + printk(KERN_DEBUG PFX "pg_start == 0x%.8lx,intel_private.gtt_entries == 0x%.8x\n", + pg_start, intel_private.gtt_entries); - printk (KERN_INFO PFX "Trying to insert into local/stolen memory\n"); + printk(KERN_INFO PFX "Trying to insert into local/stolen memory\n"); goto out_err; } @@ -862,8 +1024,8 @@ static int intel_i915_insert_entries(struct agp_memory *mem,off_t pg_start, return ret; } -static int intel_i915_remove_entries(struct agp_memory *mem,off_t pg_start, - int type) +static int intel_i915_remove_entries(struct agp_memory *mem, off_t pg_start, + int type) { int i; @@ -871,13 +1033,13 @@ static int intel_i915_remove_entries(struct agp_memory *mem,off_t pg_start, return 0; if (pg_start < intel_private.gtt_entries) { - printk (KERN_INFO PFX "Trying to disable local/stolen memory\n"); + printk(KERN_INFO PFX "Trying to disable local/stolen memory\n"); return -EINVAL; } - for (i = pg_start; i < (mem->page_count + pg_start); i++) { + for (i = pg_start; i < (mem->page_count + pg_start); i++) writel(agp_bridge->scratch_page, intel_private.gtt+i); - } + readl(intel_private.gtt+i-1); agp_bridge->driver->tlb_flush(mem); @@ -924,7 +1086,7 @@ static int intel_i915_create_gatt_table(struct agp_bridge_data *bridge) agp_bridge->gatt_table_real = NULL; pci_read_config_dword(intel_private.pcidev, I915_MMADDR, &temp); - pci_read_config_dword(intel_private.pcidev, I915_PTEADDR,&temp2); + pci_read_config_dword(intel_private.pcidev, I915_PTEADDR, &temp2); if (IS_G33) gtt_map_size = 1024 * 1024; /* 1M on G33 */ @@ -934,7 +1096,7 @@ static int intel_i915_create_gatt_table(struct agp_bridge_data *bridge) temp &= 0xfff80000; - intel_private.registers = ioremap(temp,128 * 4096); + intel_private.registers = ioremap(temp, 128 * 4096); if (!intel_private.registers) { iounmap(intel_private.gtt); return -ENOMEM; @@ -981,6 +1143,7 @@ static int intel_i965_create_gatt_table(struct agp_bridge_data *bridge) struct aper_size_info_fixed *size; int num_entries; u32 temp; + int gtt_offset, gtt_size; size = agp_bridge->current_size; page_order = size->page_order; @@ -990,13 +1153,18 @@ static int intel_i965_create_gatt_table(struct agp_bridge_data *bridge) pci_read_config_dword(intel_private.pcidev, I915_MMADDR, &temp); temp &= 0xfff00000; - intel_private.gtt = ioremap((temp + (512 * 1024)) , 512 * 1024); - if (!intel_private.gtt) - return -ENOMEM; + if (agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_IGD_HB) + gtt_offset = gtt_size = MB(2); + else + gtt_offset = gtt_size = KB(512); + intel_private.gtt = ioremap((temp + gtt_offset) , gtt_size); - intel_private.registers = ioremap(temp,128 * 4096); + if (!intel_private.gtt) + return -ENOMEM; + + intel_private.registers = ioremap(temp, 128 * 4096); if (!intel_private.registers) { iounmap(intel_private.gtt); return -ENOMEM; @@ -1155,7 +1323,7 @@ static int intel_815_configure(void) /* the Intel 815 chipset spec. says that bits 29-31 in the * ATTBASE register are reserved -> try not to write them */ if (agp_bridge->gatt_bus_addr & INTEL_815_ATTBASE_MASK) { - printk (KERN_EMERG PFX "gatt bus addr too high"); + printk(KERN_EMERG PFX "gatt bus addr too high"); return -EINVAL; } @@ -1297,6 +1465,8 @@ static int intel_845_configure(void) pci_write_config_byte(agp_bridge->dev, INTEL_I845_AGPM, temp2 | (1 << 1)); /* clear any possible error conditions */ pci_write_config_word(agp_bridge->dev, INTEL_I845_ERRSTS, 0x001c); + + intel_i830_setup_flush(); return 0; } @@ -1553,6 +1723,7 @@ static const struct agp_bridge_driver intel_830_driver = { .agp_alloc_page = agp_generic_alloc_page, .agp_destroy_page = agp_generic_destroy_page, .agp_type_to_mask_type = intel_i830_type_to_mask_type, + .chipset_flush = intel_i830_chipset_flush, }; static const struct agp_bridge_driver intel_820_driver = { @@ -1649,6 +1820,7 @@ static const struct agp_bridge_driver intel_845_driver = { .agp_alloc_page = agp_generic_alloc_page, .agp_destroy_page = agp_generic_destroy_page, .agp_type_to_mask_type = agp_generic_type_to_mask_type, + .chipset_flush = intel_i830_chipset_flush, }; static const struct agp_bridge_driver intel_850_driver = { @@ -1722,6 +1894,7 @@ static const struct agp_bridge_driver intel_915_driver = { .agp_alloc_page = agp_generic_alloc_page, .agp_destroy_page = agp_generic_destroy_page, .agp_type_to_mask_type = intel_i830_type_to_mask_type, + .chipset_flush = intel_i915_chipset_flush, }; static const struct agp_bridge_driver intel_i965_driver = { @@ -1747,6 +1920,7 @@ static const struct agp_bridge_driver intel_i965_driver = { .agp_alloc_page = agp_generic_alloc_page, .agp_destroy_page = agp_generic_destroy_page, .agp_type_to_mask_type = intel_i830_type_to_mask_type, + .chipset_flush = intel_i915_chipset_flush, }; static const struct agp_bridge_driver intel_7505_driver = { @@ -1796,6 +1970,7 @@ static const struct agp_bridge_driver intel_g33_driver = { .agp_alloc_page = agp_generic_alloc_page, .agp_destroy_page = agp_generic_destroy_page, .agp_type_to_mask_type = intel_i830_type_to_mask_type, + .chipset_flush = intel_i915_chipset_flush, }; static int find_gmch(u16 device) @@ -1805,7 +1980,7 @@ static int find_gmch(u16 device) gmch_device = pci_get_device(PCI_VENDOR_ID_INTEL, device, NULL); if (gmch_device && PCI_FUNC(gmch_device->devfn) != 0) { gmch_device = pci_get_device(PCI_VENDOR_ID_INTEL, - device, gmch_device); + device, gmch_device); } if (!gmch_device) @@ -1854,6 +2029,8 @@ static const struct intel_driver_description { { PCI_DEVICE_ID_INTEL_82865_HB, PCI_DEVICE_ID_INTEL_82865_IG, 0, "865", &intel_845_driver, &intel_830_driver }, { PCI_DEVICE_ID_INTEL_82875_HB, 0, 0, "i875", &intel_845_driver, NULL }, + { PCI_DEVICE_ID_INTEL_E7221_HB, PCI_DEVICE_ID_INTEL_E7221_IG, 0, "E7221 (i915)", + NULL, &intel_915_driver }, { PCI_DEVICE_ID_INTEL_82915G_HB, PCI_DEVICE_ID_INTEL_82915G_IG, 0, "915G", NULL, &intel_915_driver }, { PCI_DEVICE_ID_INTEL_82915GM_HB, PCI_DEVICE_ID_INTEL_82915GM_IG, 0, "915GM", @@ -1866,7 +2043,7 @@ static const struct intel_driver_description { NULL, &intel_915_driver }, { PCI_DEVICE_ID_INTEL_82946GZ_HB, PCI_DEVICE_ID_INTEL_82946GZ_IG, 0, "946GZ", NULL, &intel_i965_driver }, - { PCI_DEVICE_ID_INTEL_82965G_1_HB, PCI_DEVICE_ID_INTEL_82965G_1_IG, 0, "965G", + { PCI_DEVICE_ID_INTEL_82G35_HB, PCI_DEVICE_ID_INTEL_82G35_IG, 0, "G35", NULL, &intel_i965_driver }, { PCI_DEVICE_ID_INTEL_82965Q_HB, PCI_DEVICE_ID_INTEL_82965Q_IG, 0, "965Q", NULL, &intel_i965_driver }, @@ -1884,6 +2061,8 @@ static const struct intel_driver_description { NULL, &intel_g33_driver }, { PCI_DEVICE_ID_INTEL_Q33_HB, PCI_DEVICE_ID_INTEL_Q33_IG, 0, "Q33", NULL, &intel_g33_driver }, + { PCI_DEVICE_ID_INTEL_IGD_HB, PCI_DEVICE_ID_INTEL_IGD_IG, 0, + "Intel Integrated Graphics Device", NULL, &intel_i965_driver }, { 0, 0, 0, NULL, NULL, NULL } }; @@ -1923,7 +2102,7 @@ static int __devinit agp_intel_probe(struct pci_dev *pdev, if (intel_agp_chipsets[i].name == NULL) { if (cap_ptr) printk(KERN_WARNING PFX "Unsupported Intel chipset" - "(device id: %04x)\n", pdev->device); + "(device id: %04x)\n", pdev->device); agp_put_bridge(bridge); return -ENODEV; } @@ -1936,7 +2115,7 @@ static int __devinit agp_intel_probe(struct pci_dev *pdev, intel_agp_chipsets[i].gmch_chip_id); agp_put_bridge(bridge); return -ENODEV; - } + } bridge->dev = pdev; bridge->capndx = cap_ptr; @@ -2059,13 +2238,14 @@ static struct pci_device_id agp_intel_pci_table[] = { ID(PCI_DEVICE_ID_INTEL_82875_HB), ID(PCI_DEVICE_ID_INTEL_7505_0), ID(PCI_DEVICE_ID_INTEL_7205_0), + ID(PCI_DEVICE_ID_INTEL_E7221_HB), ID(PCI_DEVICE_ID_INTEL_82915G_HB), ID(PCI_DEVICE_ID_INTEL_82915GM_HB), ID(PCI_DEVICE_ID_INTEL_82945G_HB), ID(PCI_DEVICE_ID_INTEL_82945GM_HB), ID(PCI_DEVICE_ID_INTEL_82945GME_HB), ID(PCI_DEVICE_ID_INTEL_82946GZ_HB), - ID(PCI_DEVICE_ID_INTEL_82965G_1_HB), + ID(PCI_DEVICE_ID_INTEL_82G35_HB), ID(PCI_DEVICE_ID_INTEL_82965Q_HB), ID(PCI_DEVICE_ID_INTEL_82965G_HB), ID(PCI_DEVICE_ID_INTEL_82965GM_HB), @@ -2073,6 +2253,7 @@ static struct pci_device_id agp_intel_pci_table[] = { ID(PCI_DEVICE_ID_INTEL_G33_HB), ID(PCI_DEVICE_ID_INTEL_Q35_HB), ID(PCI_DEVICE_ID_INTEL_Q33_HB), + ID(PCI_DEVICE_ID_INTEL_IGD_HB), { } }; diff --git a/drivers/char/apm-emulation.c b/drivers/char/apm-emulation.c index c99e43b837f..17d54315e14 100644 --- a/drivers/char/apm-emulation.c +++ b/drivers/char/apm-emulation.c @@ -295,7 +295,6 @@ static int apm_ioctl(struct inode * inode, struct file *filp, u_int cmd, u_long arg) { struct apm_user *as = filp->private_data; - unsigned long flags; int err = -EINVAL; if (!as->suser || !as->writer) @@ -331,10 +330,16 @@ apm_ioctl(struct inode * inode, struct file *filp, u_int cmd, u_long arg) * Wait for the suspend/resume to complete. If there * are pending acknowledges, we wait here for them. */ - flags = current->flags; + freezer_do_not_count(); wait_event(apm_suspend_waitqueue, as->suspend_state == SUSPEND_DONE); + + /* + * Since we are waiting until the suspend is done, the + * try_to_freeze() in freezer_count() will not trigger + */ + freezer_count(); } else { as->suspend_state = SUSPEND_WAIT; mutex_unlock(&state_lock); @@ -362,14 +367,10 @@ apm_ioctl(struct inode * inode, struct file *filp, u_int cmd, u_long arg) * Wait for the suspend/resume to complete. If there * are pending acknowledges, we wait here for them. */ - flags = current->flags; - - wait_event_interruptible(apm_suspend_waitqueue, + wait_event_freezable(apm_suspend_waitqueue, as->suspend_state == SUSPEND_DONE); } - current->flags = flags; - mutex_lock(&state_lock); err = as->suspend_result; as->suspend_state = SUSPEND_NONE; diff --git a/drivers/char/cs5535_gpio.c b/drivers/char/cs5535_gpio.c index fe6d2407bae..c2d23cae951 100644 --- a/drivers/char/cs5535_gpio.c +++ b/drivers/char/cs5535_gpio.c @@ -104,6 +104,11 @@ static ssize_t cs5535_gpio_write(struct file *file, const char __user *data, for (j = 0; j < ARRAY_SIZE(rm); j++) { if (c == rm[j].on) { outl(m1, base + rm[j].wr_offset); + /* If enabling output, turn off AUX 1 and AUX 2 */ + if (c == 'O') { + outl(m0, base + 0x10); + outl(m0, base + 0x14); + } break; } else if (c == rm[j].off) { outl(m0, base + rm[j].wr_offset); diff --git a/drivers/char/drm/drm_pciids.h b/drivers/char/drm/drm_pciids.h index f3593974496..43d3c42df36 100644 --- a/drivers/char/drm/drm_pciids.h +++ b/drivers/char/drm/drm_pciids.h @@ -297,6 +297,7 @@ {0x8086, 0x3582, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ {0x8086, 0x2572, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ {0x8086, 0x2582, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ + {0x8086, 0x258a, 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}, \ {0x8086, 0x27a2, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ diff --git a/drivers/char/drm/drm_vm.c b/drivers/char/drm/drm_vm.c index e8d50af5820..ef5e6b130c4 100644 --- a/drivers/char/drm/drm_vm.c +++ b/drivers/char/drm/drm_vm.c @@ -506,6 +506,7 @@ static int drm_mmap_dma(struct file *filp, struct vm_area_struct *vma) vma->vm_ops = &drm_vm_dma_ops; vma->vm_flags |= VM_RESERVED; /* Don't swap */ + vma->vm_flags |= VM_DONTEXPAND; vma->vm_file = filp; /* Needed for drm_vm_open() */ drm_vm_open_locked(vma); @@ -655,6 +656,7 @@ static int drm_mmap_locked(struct file *filp, struct vm_area_struct *vma) return -EINVAL; /* This should never happen. */ } vma->vm_flags |= VM_RESERVED; /* Don't swap */ + vma->vm_flags |= VM_DONTEXPAND; vma->vm_file = filp; /* Needed for drm_vm_open() */ drm_vm_open_locked(vma); diff --git a/drivers/char/drm/r300_reg.h b/drivers/char/drm/r300_reg.h index 3ae57ecc7af..fa194a46c1e 100644 --- a/drivers/char/drm/r300_reg.h +++ b/drivers/char/drm/r300_reg.h @@ -584,7 +584,7 @@ USE OR OTHER DEALINGS IN THE SOFTWARE. #define R300_RE_FOG_START 0x4298 /* Not sure why there are duplicate of factor and constant values. - * My best guess so far is that there are seperate zbiases for test and write. + * My best guess so far is that there are separate zbiases for test and write. * Ordering might be wrong. * Some of the tests indicate that fgl has a fallback implementation of zbias * via pixel shaders. diff --git a/drivers/char/drm/via_dma.c b/drivers/char/drm/via_dma.c index 75d6b748c2c..7009dbddac4 100644 --- a/drivers/char/drm/via_dma.c +++ b/drivers/char/drm/via_dma.c @@ -400,7 +400,7 @@ static inline uint32_t *via_align_buffer(drm_via_private_t * dev_priv, } /* - * This function is used internally by ring buffer mangement code. + * This function is used internally by ring buffer management code. * * Returns virtual pointer to ring buffer. */ diff --git a/drivers/char/efirtc.c b/drivers/char/efirtc.c index 004141d535a..49233f58987 100644 --- a/drivers/char/efirtc.c +++ b/drivers/char/efirtc.c @@ -18,7 +18,7 @@ * * NOTES: * - Locking is required for safe execution of EFI calls with regards - * to interrrupts and SMP. + * to interrupts and SMP. * * TODO (December 1999): * - provide the API to set/get the WakeUp Alarm (different from the diff --git a/drivers/char/epca.c b/drivers/char/epca.c index ffcecde9e2a..ffd747c5dff 100644 --- a/drivers/char/epca.c +++ b/drivers/char/epca.c @@ -1797,7 +1797,7 @@ static unsigned termios2digi_c(struct channel *ch, unsigned cflag) res |= cflag & ((CBAUD ^ CBAUDEX) | PARODD | PARENB | CSTOPB | CSIZE); /* * This gets a little confusing. The Digi cards have their own - * representation of c_cflags controling baud rate. For the most part + * representation of c_cflags controlling baud rate. For the most part * this is identical to the Linux implementation. However; Digi * supports one rate (76800) that Linux doesn't. This means that the * c_cflag entry that would normally mean 76800 for Digi actually means @@ -2068,7 +2068,7 @@ static int info_ioctl(struct tty_struct *tty, struct file *file, { /* * This call is made by the apps to complete the - * initilization of the board(s). This routine is + * initialization of the board(s). This routine is * responsible for setting the card to its initial * state and setting the drivers control fields to the * sutianle settings for the card in question. diff --git a/drivers/char/hangcheck-timer.c b/drivers/char/hangcheck-timer.c index 0e8ceea5ea7..712d9f271aa 100644 --- a/drivers/char/hangcheck-timer.c +++ b/drivers/char/hangcheck-timer.c @@ -26,7 +26,7 @@ * The hangcheck-timer driver uses the TSC to catch delays that * jiffies does not notice. A timer is set. When the timer fires, it * checks whether it was delayed and if that delay exceeds a given - * margin of error. The hangcheck_tick module paramter takes the timer + * margin of error. The hangcheck_tick module parameter takes the timer * duration in seconds. The hangcheck_margin parameter defines the * margin of error, in seconds. The defaults are 60 seconds for the * timer and 180 seconds for the margin of error. IOW, a timer is set diff --git a/drivers/char/hpet.c b/drivers/char/hpet.c index 4c16778e3f8..465ad35ed38 100644 --- a/drivers/char/hpet.c +++ b/drivers/char/hpet.c @@ -600,63 +600,6 @@ static int hpet_is_known(struct hpet_data *hdp) return 0; } -EXPORT_SYMBOL(hpet_alloc); -EXPORT_SYMBOL(hpet_register); -EXPORT_SYMBOL(hpet_unregister); -EXPORT_SYMBOL(hpet_control); - -int hpet_register(struct hpet_task *tp, int periodic) -{ - unsigned int i; - u64 mask; - struct hpet_timer __iomem *timer; - struct hpet_dev *devp; - struct hpets *hpetp; - - switch (periodic) { - case 1: - mask = Tn_PER_INT_CAP_MASK; - break; - case 0: - mask = 0; - break; - default: - return -EINVAL; - } - - tp->ht_opaque = NULL; - - spin_lock_irq(&hpet_task_lock); - spin_lock(&hpet_lock); - - for (devp = NULL, hpetp = hpets; hpetp && !devp; hpetp = hpetp->hp_next) - for (timer = hpetp->hp_hpet->hpet_timers, i = 0; - i < hpetp->hp_ntimer; i++, timer++) { - if ((readq(&timer->hpet_config) & Tn_PER_INT_CAP_MASK) - != mask) - continue; - - devp = &hpetp->hp_dev[i]; - - if (devp->hd_flags & HPET_OPEN || devp->hd_task) { - devp = NULL; - continue; - } - - tp->ht_opaque = devp; - devp->hd_task = tp; - break; - } - - spin_unlock(&hpet_lock); - spin_unlock_irq(&hpet_task_lock); - - if (tp->ht_opaque) - return 0; - else - return -EBUSY; -} - static inline int hpet_tpcheck(struct hpet_task *tp) { struct hpet_dev *devp; @@ -706,24 +649,6 @@ int hpet_unregister(struct hpet_task *tp) return 0; } -int hpet_control(struct hpet_task *tp, unsigned int cmd, unsigned long arg) -{ - struct hpet_dev *devp; - int err; - - if ((err = hpet_tpcheck(tp))) - return err; - - spin_lock_irq(&hpet_lock); - devp = tp->ht_opaque; - if (devp->hd_task != tp) { - spin_unlock_irq(&hpet_lock); - return -ENXIO; - } - spin_unlock_irq(&hpet_lock); - return hpet_ioctl_common(devp, cmd, arg, 1); -} - static ctl_table hpet_table[] = { { .ctl_name = CTL_UNNUMBERED, @@ -806,14 +731,14 @@ static unsigned long hpet_calibrate(struct hpets *hpetp) int hpet_alloc(struct hpet_data *hdp) { - u64 cap, mcfg; + u64 cap, mcfg, hpet_config; struct hpet_dev *devp; - u32 i, ntimer; + u32 i, ntimer, irq; struct hpets *hpetp; size_t siz; struct hpet __iomem *hpet; static struct hpets *last = NULL; - unsigned long period; + unsigned long period, irq_bitmap; unsigned long long temp; /* @@ -840,11 +765,47 @@ int hpet_alloc(struct hpet_data *hdp) hpetp->hp_hpet_phys = hdp->hd_phys_address; hpetp->hp_ntimer = hdp->hd_nirqs; + hpet = hpetp->hp_hpet; - for (i = 0; i < hdp->hd_nirqs; i++) - hpetp->hp_dev[i].hd_hdwirq = hdp->hd_irq[i]; + /* Assign IRQs statically for legacy devices */ + hpetp->hp_dev[0].hd_hdwirq = hdp->hd_irq[0]; + hpetp->hp_dev[1].hd_hdwirq = hdp->hd_irq[1]; - hpet = hpetp->hp_hpet; + /* Assign IRQs dynamically for the others */ + for (i = 2, devp = &hpetp->hp_dev[2]; i < hdp->hd_nirqs; i++, devp++) { + struct hpet_timer __iomem *timer; + + timer = &hpet->hpet_timers[devp - hpetp->hp_dev]; + + /* Check if there's already an IRQ assigned to the timer */ + if (hdp->hd_irq[i]) { + hpetp->hp_dev[i].hd_hdwirq = hdp->hd_irq[i]; + continue; + } + + hpet_config = readq(&timer->hpet_config); + irq_bitmap = (hpet_config & Tn_INT_ROUTE_CAP_MASK) + >> Tn_INT_ROUTE_CAP_SHIFT; + if (!irq_bitmap) + irq = 0; /* No valid IRQ Assignable */ + else { + irq = find_first_bit(&irq_bitmap, 32); + do { + hpet_config |= irq << Tn_INT_ROUTE_CNF_SHIFT; + writeq(hpet_config, &timer->hpet_config); + + /* + * Verify whether we have written a valid + * IRQ number by reading it back again + */ + hpet_config = readq(&timer->hpet_config); + if (irq == (hpet_config & Tn_INT_ROUTE_CNF_MASK) + >> Tn_INT_ROUTE_CNF_SHIFT) + break; /* Success */ + } while ((irq = (find_next_bit(&irq_bitmap, 32, irq)))); + } + hpetp->hp_dev[i].hd_hdwirq = irq; + } cap = readq(&hpet->hpet_cap); @@ -875,7 +836,8 @@ int hpet_alloc(struct hpet_data *hdp) hpetp->hp_which, hdp->hd_phys_address, hpetp->hp_ntimer > 1 ? "s" : ""); for (i = 0; i < hpetp->hp_ntimer; i++) - printk("%s %d", i > 0 ? "," : "", hdp->hd_irq[i]); + printk("%s %d", i > 0 ? "," : "", + hpetp->hp_dev[i].hd_hdwirq); printk("\n"); printk(KERN_INFO "hpet%u: %u %d-bit timers, %Lu Hz\n", diff --git a/drivers/char/hvc_console.c b/drivers/char/hvc_console.c index 8252f866853..44160d5ebca 100644 --- a/drivers/char/hvc_console.c +++ b/drivers/char/hvc_console.c @@ -27,7 +27,7 @@ #include <linux/init.h> #include <linux/kbd_kern.h> #include <linux/kernel.h> -#include <linux/kobject.h> +#include <linux/kref.h> #include <linux/kthread.h> #include <linux/list.h> #include <linux/module.h> @@ -89,11 +89,11 @@ struct hvc_struct { int irq_requested; int irq; struct list_head next; - struct kobject kobj; /* ref count & hvc_struct lifetime */ + struct kref kref; /* ref count & hvc_struct lifetime */ }; /* dynamic list of hvc_struct instances */ -static struct list_head hvc_structs = LIST_HEAD_INIT(hvc_structs); +static LIST_HEAD(hvc_structs); /* * Protect the list of hvc_struct instances from inserts and removals during @@ -110,7 +110,7 @@ static int last_hvc = -1; /* * Do not call this function with either the hvc_structs_lock or the hvc_struct - * lock held. If successful, this function increments the kobject reference + * lock held. If successful, this function increments the kref reference * count against the target hvc_struct so it should be released when finished. */ static struct hvc_struct *hvc_get_by_index(int index) @@ -123,7 +123,7 @@ static struct hvc_struct *hvc_get_by_index(int index) list_for_each_entry(hp, &hvc_structs, next) { spin_lock_irqsave(&hp->lock, flags); if (hp->index == index) { - kobject_get(&hp->kobj); + kref_get(&hp->kref); spin_unlock_irqrestore(&hp->lock, flags); spin_unlock(&hvc_structs_lock); return hp; @@ -242,6 +242,23 @@ static int __init hvc_console_init(void) } console_initcall(hvc_console_init); +/* callback when the kboject ref count reaches zero. */ +static void destroy_hvc_struct(struct kref *kref) +{ + struct hvc_struct *hp = container_of(kref, struct hvc_struct, kref); + unsigned long flags; + + spin_lock(&hvc_structs_lock); + + spin_lock_irqsave(&hp->lock, flags); + list_del(&(hp->next)); + spin_unlock_irqrestore(&hp->lock, flags); + + spin_unlock(&hvc_structs_lock); + + kfree(hp); +} + /* * hvc_instantiate() is an early console discovery method which locates * consoles * prior to the vio subsystem discovering them. Hotplugged @@ -261,7 +278,7 @@ int hvc_instantiate(uint32_t vtermno, int index, struct hv_ops *ops) /* make sure no no tty has been registered in this index */ hp = hvc_get_by_index(index); if (hp) { - kobject_put(&hp->kobj); + kref_put(&hp->kref, destroy_hvc_struct); return -1; } @@ -318,9 +335,8 @@ static int hvc_open(struct tty_struct *tty, struct file * filp) unsigned long flags; int irq = 0; int rc = 0; - struct kobject *kobjp; - /* Auto increments kobject reference if found. */ + /* Auto increments kref reference if found. */ if (!(hp = hvc_get_by_index(tty->index))) return -ENODEV; @@ -341,8 +357,6 @@ static int hvc_open(struct tty_struct *tty, struct file * filp) if (irq) hp->irq_requested = 1; - kobjp = &hp->kobj; - spin_unlock_irqrestore(&hp->lock, flags); /* check error, fallback to non-irq */ if (irq) @@ -352,7 +366,7 @@ static int hvc_open(struct tty_struct *tty, struct file * filp) * If the request_irq() fails and we return an error. The tty layer * will call hvc_close() after a failed open but we don't want to clean * up there so we'll clean up here and clear out the previously set - * tty fields and return the kobject reference. + * tty fields and return the kref reference. */ if (rc) { spin_lock_irqsave(&hp->lock, flags); @@ -360,7 +374,7 @@ static int hvc_open(struct tty_struct *tty, struct file * filp) hp->irq_requested = 0; spin_unlock_irqrestore(&hp->lock, flags); tty->driver_data = NULL; - kobject_put(kobjp); + kref_put(&hp->kref, destroy_hvc_struct); printk(KERN_ERR "hvc_open: request_irq failed with rc %d.\n", rc); } /* Force wakeup of the polling thread */ @@ -372,7 +386,6 @@ static int hvc_open(struct tty_struct *tty, struct file * filp) static void hvc_close(struct tty_struct *tty, struct file * filp) { struct hvc_struct *hp; - struct kobject *kobjp; int irq = 0; unsigned long flags; @@ -382,7 +395,7 @@ static void hvc_close(struct tty_struct *tty, struct file * filp) /* * No driver_data means that this close was issued after a failed * hvc_open by the tty layer's release_dev() function and we can just - * exit cleanly because the kobject reference wasn't made. + * exit cleanly because the kref reference wasn't made. */ if (!tty->driver_data) return; @@ -390,7 +403,6 @@ static void hvc_close(struct tty_struct *tty, struct file * filp) hp = tty->driver_data; spin_lock_irqsave(&hp->lock, flags); - kobjp = &hp->kobj; if (--hp->count == 0) { if (hp->irq_requested) irq = hp->irq; @@ -417,7 +429,7 @@ static void hvc_close(struct tty_struct *tty, struct file * filp) spin_unlock_irqrestore(&hp->lock, flags); } - kobject_put(kobjp); + kref_put(&hp->kref, destroy_hvc_struct); } static void hvc_hangup(struct tty_struct *tty) @@ -426,7 +438,6 @@ static void hvc_hangup(struct tty_struct *tty) unsigned long flags; int irq = 0; int temp_open_count; - struct kobject *kobjp; if (!hp) return; @@ -443,7 +454,6 @@ static void hvc_hangup(struct tty_struct *tty) return; } - kobjp = &hp->kobj; temp_open_count = hp->count; hp->count = 0; hp->n_outbuf = 0; @@ -457,7 +467,7 @@ static void hvc_hangup(struct tty_struct *tty) free_irq(irq, hp); while(temp_open_count) { --temp_open_count; - kobject_put(kobjp); + kref_put(&hp->kref, destroy_hvc_struct); } } @@ -729,27 +739,6 @@ static const struct tty_operations hvc_ops = { .chars_in_buffer = hvc_chars_in_buffer, }; -/* callback when the kboject ref count reaches zero. */ -static void destroy_hvc_struct(struct kobject *kobj) -{ - struct hvc_struct *hp = container_of(kobj, struct hvc_struct, kobj); - unsigned long flags; - - spin_lock(&hvc_structs_lock); - - spin_lock_irqsave(&hp->lock, flags); - list_del(&(hp->next)); - spin_unlock_irqrestore(&hp->lock, flags); - - spin_unlock(&hvc_structs_lock); - - kfree(hp); -} - -static struct kobj_type hvc_kobj_type = { - .release = destroy_hvc_struct, -}; - struct hvc_struct __devinit *hvc_alloc(uint32_t vtermno, int irq, struct hv_ops *ops, int outbuf_size) { @@ -776,8 +765,7 @@ struct hvc_struct __devinit *hvc_alloc(uint32_t vtermno, int irq, hp->outbuf_size = outbuf_size; hp->outbuf = &((char *)hp)[ALIGN(sizeof(*hp), sizeof(long))]; - kobject_init(&hp->kobj); - hp->kobj.ktype = &hvc_kobj_type; + kref_init(&hp->kref); spin_lock_init(&hp->lock); spin_lock(&hvc_structs_lock); @@ -806,12 +794,10 @@ struct hvc_struct __devinit *hvc_alloc(uint32_t vtermno, int irq, int __devexit hvc_remove(struct hvc_struct *hp) { unsigned long flags; - struct kobject *kobjp; struct tty_struct *tty; spin_lock_irqsave(&hp->lock, flags); tty = hp->tty; - kobjp = &hp->kobj; if (hp->index < MAX_NR_HVC_CONSOLES) vtermnos[hp->index] = -1; @@ -821,12 +807,12 @@ int __devexit hvc_remove(struct hvc_struct *hp) spin_unlock_irqrestore(&hp->lock, flags); /* - * We 'put' the instance that was grabbed when the kobject instance - * was initialized using kobject_init(). Let the last holder of this - * kobject cause it to be removed, which will probably be the tty_hangup + * We 'put' the instance that was grabbed when the kref instance + * was initialized using kref_init(). Let the last holder of this + * kref cause it to be removed, which will probably be the tty_hangup * below. */ - kobject_put(kobjp); + kref_put(&hp->kref, destroy_hvc_struct); /* * This function call will auto chain call hvc_hangup. The tty should diff --git a/drivers/char/hvcs.c b/drivers/char/hvcs.c index 69d8866de78..786d518e947 100644 --- a/drivers/char/hvcs.c +++ b/drivers/char/hvcs.c @@ -57,11 +57,7 @@ * rescanning partner information upon a user's request. * * Each vty-server, prior to being exposed to this driver is reference counted - * using the 2.6 Linux kernel kobject construct. This kobject is also used by - * the vio bus to provide a vio device sysfs entry that this driver attaches - * device specific attributes to, including partner information. The vio bus - * framework also provides a sysfs entry for each vio driver. The hvcs driver - * provides driver attributes in this entry. + * using the 2.6 Linux kernel kref construct. * * For direction on installation and usage of this driver please reference * Documentation/powerpc/hvcs.txt. @@ -71,7 +67,7 @@ #include <linux/init.h> #include <linux/interrupt.h> #include <linux/kernel.h> -#include <linux/kobject.h> +#include <linux/kref.h> #include <linux/kthread.h> #include <linux/list.h> #include <linux/major.h> @@ -293,12 +289,12 @@ struct hvcs_struct { int chars_in_buffer; /* - * Any variable below the kobject is valid before a tty is connected and + * Any variable below the kref is valid before a tty is connected and * stays valid after the tty is disconnected. These shouldn't be * whacked until the koject refcount reaches zero though some entries * may be changed via sysfs initiatives. */ - struct kobject kobj; /* ref count & hvcs_struct lifetime */ + struct kref kref; /* ref count & hvcs_struct lifetime */ int connected; /* is the vty-server currently connected to a vty? */ uint32_t p_unit_address; /* partner unit address */ uint32_t p_partition_ID; /* partner partition ID */ @@ -307,10 +303,10 @@ struct hvcs_struct { struct vio_dev *vdev; }; -/* Required to back map a kobject to its containing object */ -#define from_kobj(kobj) container_of(kobj, struct hvcs_struct, kobj) +/* Required to back map a kref to its containing object */ +#define from_kref(k) container_of(k, struct hvcs_struct, kref) -static struct list_head hvcs_structs = LIST_HEAD_INIT(hvcs_structs); +static LIST_HEAD(hvcs_structs); static DEFINE_SPINLOCK(hvcs_structs_lock); static void hvcs_unthrottle(struct tty_struct *tty); @@ -334,7 +330,6 @@ static void hvcs_partner_free(struct hvcs_struct *hvcsd); static int hvcs_enable_device(struct hvcs_struct *hvcsd, uint32_t unit_address, unsigned int irq, struct vio_dev *dev); -static void destroy_hvcs_struct(struct kobject *kobj); static int hvcs_open(struct tty_struct *tty, struct file *filp); static void hvcs_close(struct tty_struct *tty, struct file *filp); static void hvcs_hangup(struct tty_struct * tty); @@ -703,10 +698,10 @@ static void hvcs_return_index(int index) hvcs_index_list[index] = -1; } -/* callback when the kboject ref count reaches zero */ -static void destroy_hvcs_struct(struct kobject *kobj) +/* callback when the kref ref count reaches zero */ +static void destroy_hvcs_struct(struct kref *kref) { - struct hvcs_struct *hvcsd = from_kobj(kobj); + struct hvcs_struct *hvcsd = from_kref(kref); struct vio_dev *vdev; unsigned long flags; @@ -743,10 +738,6 @@ static void destroy_hvcs_struct(struct kobject *kobj) kfree(hvcsd); } -static struct kobj_type hvcs_kobj_type = { - .release = destroy_hvcs_struct, -}; - static int hvcs_get_index(void) { int i; @@ -791,9 +782,7 @@ static int __devinit hvcs_probe( spin_lock_init(&hvcsd->lock); /* Automatically incs the refcount the first time */ - kobject_init(&hvcsd->kobj); - /* Set up the callback for terminating the hvcs_struct's life */ - hvcsd->kobj.ktype = &hvcs_kobj_type; + kref_init(&hvcsd->kref); hvcsd->vdev = dev; dev->dev.driver_data = hvcsd; @@ -844,27 +833,24 @@ static int __devexit hvcs_remove(struct vio_dev *dev) { struct hvcs_struct *hvcsd = dev->dev.driver_data; unsigned long flags; - struct kobject *kobjp; struct tty_struct *tty; if (!hvcsd) return -ENODEV; - /* By this time the vty-server won't be getting any more interrups */ + /* By this time the vty-server won't be getting any more interrupts */ spin_lock_irqsave(&hvcsd->lock, flags); tty = hvcsd->tty; - kobjp = &hvcsd->kobj; - spin_unlock_irqrestore(&hvcsd->lock, flags); /* * Let the last holder of this object cause it to be removed, which * would probably be tty_hangup below. */ - kobject_put (kobjp); + kref_put(&hvcsd->kref, destroy_hvcs_struct); /* * The hangup is a scheduled function which will auto chain call @@ -1086,7 +1072,7 @@ static int hvcs_enable_device(struct hvcs_struct *hvcsd, uint32_t unit_address, } /* - * This always increments the kobject ref count if the call is successful. + * This always increments the kref ref count if the call is successful. * Please remember to dec when you are done with the instance. * * NOTICE: Do NOT hold either the hvcs_struct.lock or hvcs_structs_lock when @@ -1103,7 +1089,7 @@ static struct hvcs_struct *hvcs_get_by_index(int index) list_for_each_entry(hvcsd, &hvcs_structs, next) { spin_lock_irqsave(&hvcsd->lock, flags); if (hvcsd->index == index) { - kobject_get(&hvcsd->kobj); + kref_get(&hvcsd->kref); spin_unlock_irqrestore(&hvcsd->lock, flags); spin_unlock(&hvcs_structs_lock); return hvcsd; @@ -1129,14 +1115,13 @@ static int hvcs_open(struct tty_struct *tty, struct file *filp) unsigned int irq; struct vio_dev *vdev; unsigned long unit_address; - struct kobject *kobjp; if (tty->driver_data) goto fast_open; /* * Is there a vty-server that shares the same index? - * This function increments the kobject index. + * This function increments the kref index. */ if (!(hvcsd = hvcs_get_by_index(tty->index))) { printk(KERN_WARNING "HVCS: open failed, no device associated" @@ -1181,7 +1166,7 @@ static int hvcs_open(struct tty_struct *tty, struct file *filp) * and will grab the spinlock and free the connection if it fails. */ if (((rc = hvcs_enable_device(hvcsd, unit_address, irq, vdev)))) { - kobject_put(&hvcsd->kobj); + kref_put(&hvcsd->kref, destroy_hvcs_struct); printk(KERN_WARNING "HVCS: enable device failed.\n"); return rc; } @@ -1192,17 +1177,11 @@ fast_open: hvcsd = tty->driver_data; spin_lock_irqsave(&hvcsd->lock, flags); - if (!kobject_get(&hvcsd->kobj)) { - spin_unlock_irqrestore(&hvcsd->lock, flags); - printk(KERN_ERR "HVCS: Kobject of open" - " hvcs doesn't exist.\n"); - return -EFAULT; /* Is this the right return value? */ - } - + kref_get(&hvcsd->kref); hvcsd->open_count++; - hvcsd->todo_mask |= HVCS_SCHED_READ; spin_unlock_irqrestore(&hvcsd->lock, flags); + open_success: hvcs_kick(); @@ -1212,9 +1191,8 @@ open_success: return 0; error_release: - kobjp = &hvcsd->kobj; spin_unlock_irqrestore(&hvcsd->lock, flags); - kobject_put(&hvcsd->kobj); + kref_put(&hvcsd->kref, destroy_hvcs_struct); printk(KERN_WARNING "HVCS: partner connect failed.\n"); return retval; @@ -1224,7 +1202,6 @@ static void hvcs_close(struct tty_struct *tty, struct file *filp) { struct hvcs_struct *hvcsd; unsigned long flags; - struct kobject *kobjp; int irq = NO_IRQ; /* @@ -1245,7 +1222,6 @@ static void hvcs_close(struct tty_struct *tty, struct file *filp) hvcsd = tty->driver_data; spin_lock_irqsave(&hvcsd->lock, flags); - kobjp = &hvcsd->kobj; if (--hvcsd->open_count == 0) { vio_disable_interrupts(hvcsd->vdev); @@ -1270,7 +1246,7 @@ static void hvcs_close(struct tty_struct *tty, struct file *filp) tty->driver_data = NULL; free_irq(irq, hvcsd); - kobject_put(kobjp); + kref_put(&hvcsd->kref, destroy_hvcs_struct); return; } else if (hvcsd->open_count < 0) { printk(KERN_ERR "HVCS: vty-server@%X open_count: %d" @@ -1279,7 +1255,7 @@ static void hvcs_close(struct tty_struct *tty, struct file *filp) } spin_unlock_irqrestore(&hvcsd->lock, flags); - kobject_put(kobjp); + kref_put(&hvcsd->kref, destroy_hvcs_struct); } static void hvcs_hangup(struct tty_struct * tty) @@ -1287,21 +1263,17 @@ static void hvcs_hangup(struct tty_struct * tty) struct hvcs_struct *hvcsd = tty->driver_data; unsigned long flags; int temp_open_count; - struct kobject *kobjp; int irq = NO_IRQ; spin_lock_irqsave(&hvcsd->lock, flags); - /* Preserve this so that we know how many kobject refs to put */ + /* Preserve this so that we know how many kref refs to put */ temp_open_count = hvcsd->open_count; /* - * Don't kobject put inside the spinlock because the destruction + * Don't kref put inside the spinlock because the destruction * callback may use the spinlock and it may get called before the - * spinlock has been released. Get a pointer to the kobject and - * kobject_put on that after releasing the spinlock. + * spinlock has been released. */ - kobjp = &hvcsd->kobj; - vio_disable_interrupts(hvcsd->vdev); hvcsd->todo_mask = 0; @@ -1324,7 +1296,7 @@ static void hvcs_hangup(struct tty_struct * tty) free_irq(irq, hvcsd); /* - * We need to kobject_put() for every open_count we have since the + * We need to kref_put() for every open_count we have since the * tty_hangup() function doesn't invoke a close per open connection on a * non-console device. */ @@ -1335,7 +1307,7 @@ static void hvcs_hangup(struct tty_struct * tty) * NOTE: If this hangup was signaled from user space then the * final put will never happen. */ - kobject_put(kobjp); + kref_put(&hvcsd->kref, destroy_hvcs_struct); } } diff --git a/drivers/char/hw_random/Kconfig b/drivers/char/hw_random/Kconfig index 2d7cd486e02..6bbd4fa50f3 100644 --- a/drivers/char/hw_random/Kconfig +++ b/drivers/char/hw_random/Kconfig @@ -98,7 +98,7 @@ config HW_RANDOM_PASEMI default HW_RANDOM ---help--- This driver provides kernel-side support for the Random Number - Generator hardware found on PA6T-1682M processor. + Generator hardware found on PA Semi PWRficient SoCs. To compile this driver as a module, choose M here: the module will be called pasemi-rng. diff --git a/drivers/char/hw_random/amd-rng.c b/drivers/char/hw_random/amd-rng.c index 556fd81fa81..c422e870dc5 100644 --- a/drivers/char/hw_random/amd-rng.c +++ b/drivers/char/hw_random/amd-rng.c @@ -28,6 +28,7 @@ #include <linux/kernel.h> #include <linux/pci.h> #include <linux/hw_random.h> +#include <linux/delay.h> #include <asm/io.h> @@ -52,11 +53,18 @@ MODULE_DEVICE_TABLE(pci, pci_tbl); static struct pci_dev *amd_pdev; -static int amd_rng_data_present(struct hwrng *rng) +static int amd_rng_data_present(struct hwrng *rng, int wait) { u32 pmbase = (u32)rng->priv; + int data, i; - return !!(inl(pmbase + 0xF4) & 1); + for (i = 0; i < 20; i++) { + data = !!(inl(pmbase + 0xF4) & 1); + if (data || !wait) + break; + udelay(10); + } + return data; } static int amd_rng_data_read(struct hwrng *rng, u32 *data) diff --git a/drivers/char/hw_random/core.c b/drivers/char/hw_random/core.c index 26a860adcb3..84cdf902573 100644 --- a/drivers/char/hw_random/core.c +++ b/drivers/char/hw_random/core.c @@ -66,11 +66,11 @@ static inline void hwrng_cleanup(struct hwrng *rng) rng->cleanup(rng); } -static inline int hwrng_data_present(struct hwrng *rng) +static inline int hwrng_data_present(struct hwrng *rng, int wait) { if (!rng->data_present) return 1; - return rng->data_present(rng); + return rng->data_present(rng, wait); } static inline int hwrng_data_read(struct hwrng *rng, u32 *data) @@ -94,8 +94,7 @@ static ssize_t rng_dev_read(struct file *filp, char __user *buf, { u32 data; ssize_t ret = 0; - int i, err = 0; - int data_present; + int err = 0; int bytes_read; while (size) { @@ -107,21 +106,10 @@ static ssize_t rng_dev_read(struct file *filp, char __user *buf, err = -ENODEV; goto out; } - if (filp->f_flags & O_NONBLOCK) { - data_present = hwrng_data_present(current_rng); - } else { - /* Some RNG require some time between data_reads to gather - * new entropy. Poll it. - */ - for (i = 0; i < 20; i++) { - data_present = hwrng_data_present(current_rng); - if (data_present) - break; - udelay(10); - } - } + bytes_read = 0; - if (data_present) + if (hwrng_data_present(current_rng, + !(filp->f_flags & O_NONBLOCK))) bytes_read = hwrng_data_read(current_rng, &data); mutex_unlock(&rng_mutex); @@ -246,11 +234,11 @@ static DEVICE_ATTR(rng_available, S_IRUGO, NULL); -static void unregister_miscdev(void) +static void unregister_miscdev(bool suspended) { device_remove_file(rng_miscdev.this_device, &dev_attr_rng_available); device_remove_file(rng_miscdev.this_device, &dev_attr_rng_current); - misc_deregister(&rng_miscdev); + __misc_deregister(&rng_miscdev, suspended); } static int register_miscdev(void) @@ -325,7 +313,7 @@ out: } EXPORT_SYMBOL_GPL(hwrng_register); -void hwrng_unregister(struct hwrng *rng) +void __hwrng_unregister(struct hwrng *rng, bool suspended) { int err; @@ -344,11 +332,11 @@ void hwrng_unregister(struct hwrng *rng) } } if (list_empty(&rng_list)) - unregister_miscdev(); + unregister_miscdev(suspended); mutex_unlock(&rng_mutex); } -EXPORT_SYMBOL_GPL(hwrng_unregister); +EXPORT_SYMBOL_GPL(__hwrng_unregister); MODULE_DESCRIPTION("H/W Random Number Generator (RNG) driver"); diff --git a/drivers/char/hw_random/geode-rng.c b/drivers/char/hw_random/geode-rng.c index 8e8658dcd2e..fed4ef5569f 100644 --- a/drivers/char/hw_random/geode-rng.c +++ b/drivers/char/hw_random/geode-rng.c @@ -28,6 +28,7 @@ #include <linux/kernel.h> #include <linux/pci.h> #include <linux/hw_random.h> +#include <linux/delay.h> #include <asm/io.h> @@ -61,11 +62,18 @@ static int geode_rng_data_read(struct hwrng *rng, u32 *data) return 4; } -static int geode_rng_data_present(struct hwrng *rng) +static int geode_rng_data_present(struct hwrng *rng, int wait) { void __iomem *mem = (void __iomem *)rng->priv; + int data, i; - return !!(readl(mem + GEODE_RNG_STATUS_REG)); + for (i = 0; i < 20; i++) { + data = !!(readl(mem + GEODE_RNG_STATUS_REG)); + if (data || !wait) + break; + udelay(10); + } + return data; } diff --git a/drivers/char/hw_random/intel-rng.c b/drivers/char/hw_random/intel-rng.c index 753f46052b8..5cc651ef75e 100644 --- a/drivers/char/hw_random/intel-rng.c +++ b/drivers/char/hw_random/intel-rng.c @@ -29,6 +29,7 @@ #include <linux/module.h> #include <linux/pci.h> #include <linux/stop_machine.h> +#include <linux/delay.h> #include <asm/io.h> @@ -162,11 +163,19 @@ static inline u8 hwstatus_set(void __iomem *mem, return hwstatus_get(mem); } -static int intel_rng_data_present(struct hwrng *rng) +static int intel_rng_data_present(struct hwrng *rng, int wait) { void __iomem *mem = (void __iomem *)rng->priv; - - return !!(readb(mem + INTEL_RNG_STATUS) & INTEL_RNG_DATA_PRESENT); + int data, i; + + for (i = 0; i < 20; i++) { + data = !!(readb(mem + INTEL_RNG_STATUS) & + INTEL_RNG_DATA_PRESENT); + if (data || !wait) + break; + udelay(10); + } + return data; } static int intel_rng_data_read(struct hwrng *rng, u32 *data) diff --git a/drivers/char/hw_random/omap-rng.c b/drivers/char/hw_random/omap-rng.c index 3f35a1c562b..7e319951fa4 100644 --- a/drivers/char/hw_random/omap-rng.c +++ b/drivers/char/hw_random/omap-rng.c @@ -29,6 +29,7 @@ #include <linux/err.h> #include <linux/platform_device.h> #include <linux/hw_random.h> +#include <linux/delay.h> #include <asm/io.h> @@ -65,9 +66,17 @@ static void omap_rng_write_reg(int reg, u32 val) } /* REVISIT: Does the status bit really work on 16xx? */ -static int omap_rng_data_present(struct hwrng *rng) +static int omap_rng_data_present(struct hwrng *rng, int wait) { - return omap_rng_read_reg(RNG_STAT_REG) ? 0 : 1; + int data, i; + + for (i = 0; i < 20; i++) { + data = omap_rng_read_reg(RNG_STAT_REG) ? 0 : 1; + if (data || !wait) + break; + udelay(10); + } + return data; } static int omap_rng_data_read(struct hwrng *rng, u32 *data) diff --git a/drivers/char/hw_random/pasemi-rng.c b/drivers/char/hw_random/pasemi-rng.c index fa6040b6c8f..6d50e9bc700 100644 --- a/drivers/char/hw_random/pasemi-rng.c +++ b/drivers/char/hw_random/pasemi-rng.c @@ -23,6 +23,7 @@ #include <linux/kernel.h> #include <linux/platform_device.h> #include <linux/hw_random.h> +#include <linux/delay.h> #include <asm/of_platform.h> #include <asm/io.h> @@ -41,12 +42,19 @@ #define MODULE_NAME "pasemi_rng" -static int pasemi_rng_data_present(struct hwrng *rng) +static int pasemi_rng_data_present(struct hwrng *rng, int wait) { void __iomem *rng_regs = (void __iomem *)rng->priv; - - return (in_le32(rng_regs + SDCRNG_CTL_REG) - & SDCRNG_CTL_FVLD_M) ? 1 : 0; + int data, i; + + for (i = 0; i < 20; i++) { + data = (in_le32(rng_regs + SDCRNG_CTL_REG) + & SDCRNG_CTL_FVLD_M) ? 1 : 0; + if (data || !wait) + break; + udelay(10); + } + return data; } static int pasemi_rng_data_read(struct hwrng *rng, u32 *data) @@ -126,10 +134,9 @@ static int __devexit rng_remove(struct of_device *dev) } static struct of_device_id rng_match[] = { - { - .compatible = "1682m-rng", - }, - {}, + { .compatible = "1682m-rng", }, + { .compatible = "pasemi,pwrficient-rng", }, + { }, }; static struct of_platform_driver rng_driver = { diff --git a/drivers/char/hw_random/via-rng.c b/drivers/char/hw_random/via-rng.c index ec435cb25c4..f7feae4ebb5 100644 --- a/drivers/char/hw_random/via-rng.c +++ b/drivers/char/hw_random/via-rng.c @@ -27,6 +27,7 @@ #include <linux/module.h> #include <linux/kernel.h> #include <linux/hw_random.h> +#include <linux/delay.h> #include <asm/io.h> #include <asm/msr.h> #include <asm/cpufeature.h> @@ -41,6 +42,8 @@ enum { VIA_STRFILT_ENABLE = (1 << 14), VIA_RAWBITS_ENABLE = (1 << 13), VIA_RNG_ENABLE = (1 << 6), + VIA_NOISESRC1 = (1 << 8), + VIA_NOISESRC2 = (1 << 9), VIA_XSTORE_CNT_MASK = 0x0F, VIA_RNG_CHUNK_8 = 0x00, /* 64 rand bits, 64 stored bits */ @@ -77,10 +80,11 @@ static inline u32 xstore(u32 *addr, u32 edx_in) return eax_out; } -static int via_rng_data_present(struct hwrng *rng) +static int via_rng_data_present(struct hwrng *rng, int wait) { u32 bytes_out; u32 *via_rng_datum = (u32 *)(&rng->priv); + int i; /* We choose the recommended 1-byte-per-instruction RNG rate, * for greater randomness at the expense of speed. Larger @@ -95,12 +99,15 @@ static int via_rng_data_present(struct hwrng *rng) * completes. */ - *via_rng_datum = 0; /* paranoia, not really necessary */ - bytes_out = xstore(via_rng_datum, VIA_RNG_CHUNK_1); - bytes_out &= VIA_XSTORE_CNT_MASK; - if (bytes_out == 0) - return 0; - return 1; + for (i = 0; i < 20; i++) { + *via_rng_datum = 0; /* paranoia, not really necessary */ + bytes_out = xstore(via_rng_datum, VIA_RNG_CHUNK_1); + bytes_out &= VIA_XSTORE_CNT_MASK; + if (bytes_out || !wait) + break; + udelay(10); + } + return bytes_out ? 1 : 0; } static int via_rng_data_read(struct hwrng *rng, u32 *data) @@ -114,6 +121,7 @@ static int via_rng_data_read(struct hwrng *rng, u32 *data) static int via_rng_init(struct hwrng *rng) { + struct cpuinfo_x86 *c = &cpu_data(0); u32 lo, hi, old_lo; /* Control the RNG via MSR. Tread lightly and pay very close @@ -129,6 +137,17 @@ static int via_rng_init(struct hwrng *rng) lo &= ~VIA_XSTORE_CNT_MASK; lo &= ~(VIA_STRFILT_ENABLE | VIA_STRFILT_FAIL | VIA_RAWBITS_ENABLE); lo |= VIA_RNG_ENABLE; + lo |= VIA_NOISESRC1; + + /* Enable secondary noise source on CPUs where it is present. */ + + /* Nehemiah stepping 8 and higher */ + if ((c->x86_model == 9) && (c->x86_mask > 7)) + lo |= VIA_NOISESRC2; + + /* Esther */ + if (c->x86_model >= 10) + lo |= VIA_NOISESRC2; if (lo != old_lo) wrmsr(MSR_VIA_RNG, lo, hi); diff --git a/drivers/char/i8k.c b/drivers/char/i8k.c index 30e56451642..179223a1741 100644 --- a/drivers/char/i8k.c +++ b/drivers/char/i8k.c @@ -439,6 +439,13 @@ static struct dmi_system_id __initdata i8k_dmi_table[] = { DMI_MATCH(DMI_PRODUCT_NAME, "Latitude"), }, }, + { /* UK Inspiron 6400 */ + .ident = "Dell Inspiron 3", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), + DMI_MATCH(DMI_PRODUCT_NAME, "MM061"), + }, + }, { } }; diff --git a/drivers/char/ip2/i2lib.c b/drivers/char/ip2/i2lib.c index e46120d05b6..d6567b32fb5 100644 --- a/drivers/char/ip2/i2lib.c +++ b/drivers/char/ip2/i2lib.c @@ -661,7 +661,7 @@ i2QueueCommands(int type, i2ChanStrPtr pCh, int timeout, int nCommands, if (!in_interrupt()) { schedule_timeout_interruptible(1); // short nap } else { - // we cannot sched/sleep in interrrupt silly + // we cannot sched/sleep in interrupt silly return 0; } if (signal_pending(current)) { diff --git a/drivers/char/ip2/ip2main.c b/drivers/char/ip2/ip2main.c index e04e66cf2c6..0f49ccf02a7 100644 --- a/drivers/char/ip2/ip2main.c +++ b/drivers/char/ip2/ip2main.c @@ -1251,7 +1251,7 @@ ip2_poll(unsigned long arg) // Just polled boards, IRQ = 0 will hit all non-interrupt boards. // It will NOT poll boards handled by hard interrupts. - // The issue of queued BH interrups is handled in ip2_interrupt(). + // The issue of queued BH interrupts is handled in ip2_interrupt(). ip2_polled_interrupt(); PollTimer.expires = POLL_TIMEOUT; diff --git a/drivers/char/ip27-rtc.c b/drivers/char/ip27-rtc.c index 932264a657d..86e6538a77b 100644 --- a/drivers/char/ip27-rtc.c +++ b/drivers/char/ip27-rtc.c @@ -46,8 +46,8 @@ #include <asm/sn/sn0/hub.h> #include <asm/sn/sn_private.h> -static int rtc_ioctl(struct inode *inode, struct file *file, - unsigned int cmd, unsigned long arg); +static long rtc_ioctl(struct file *filp, unsigned int cmd, + unsigned long arg); static int rtc_read_proc(char *page, char **start, off_t off, int count, int *eof, void *data); @@ -75,8 +75,7 @@ static unsigned long epoch = 1970; /* year corresponding to 0x00 */ static const unsigned char days_in_mo[] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; -static int rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd, - unsigned long arg) +static long rtc_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) { struct rtc_time wtime; @@ -197,7 +196,7 @@ static int rtc_release(struct inode *inode, struct file *file) static const struct file_operations rtc_fops = { .owner = THIS_MODULE, - .ioctl = rtc_ioctl, + .unlocked_ioctl = rtc_ioctl, .open = rtc_open, .release = rtc_release, }; diff --git a/drivers/char/ipmi/ipmi_msghandler.c b/drivers/char/ipmi/ipmi_msghandler.c index 5dc1265ce1d..32b2b22996d 100644 --- a/drivers/char/ipmi/ipmi_msghandler.c +++ b/drivers/char/ipmi/ipmi_msghandler.c @@ -365,12 +365,12 @@ static struct device_driver ipmidriver = { }; static DEFINE_MUTEX(ipmidriver_mutex); -static struct list_head ipmi_interfaces = LIST_HEAD_INIT(ipmi_interfaces); +static LIST_HEAD(ipmi_interfaces); static DEFINE_MUTEX(ipmi_interfaces_mutex); /* List of watchers that want to know when smi's are added and deleted. */ -static struct list_head smi_watchers = LIST_HEAD_INIT(smi_watchers); +static LIST_HEAD(smi_watchers); static DEFINE_MUTEX(smi_watchers_mutex); @@ -441,7 +441,7 @@ struct watcher_entry { int ipmi_smi_watcher_register(struct ipmi_smi_watcher *watcher) { ipmi_smi_t intf; - struct list_head to_deliver = LIST_HEAD_INIT(to_deliver); + LIST_HEAD(to_deliver); struct watcher_entry *e, *e2; mutex_lock(&smi_watchers_mutex); diff --git a/drivers/char/ipmi/ipmi_watchdog.c b/drivers/char/ipmi/ipmi_watchdog.c index e686fc92516..8f45ca9235a 100644 --- a/drivers/char/ipmi/ipmi_watchdog.c +++ b/drivers/char/ipmi/ipmi_watchdog.c @@ -669,6 +669,7 @@ static int ipmi_ioctl(struct inode *inode, struct file *file, return 0; case WDIOC_SET_PRETIMEOUT: + case WDIOC_SETPRETIMEOUT: i = copy_from_user(&val, argp, sizeof(int)); if (i) return -EFAULT; @@ -676,6 +677,7 @@ static int ipmi_ioctl(struct inode *inode, struct file *file, return ipmi_set_timeout(IPMI_SET_TIMEOUT_HB_IF_NECESSARY); case WDIOC_GET_PRETIMEOUT: + case WDIOC_GETPRETIMEOUT: i = copy_to_user(argp, &pretimeout, sizeof(pretimeout)); if (i) return -EFAULT; diff --git a/drivers/char/lp.c b/drivers/char/lp.c index 81674d7c56c..60ac642752b 100644 --- a/drivers/char/lp.c +++ b/drivers/char/lp.c @@ -312,7 +312,7 @@ static ssize_t lp_write(struct file * file, const char __user * buf, if (copy_size > LP_BUFFER_SIZE) copy_size = LP_BUFFER_SIZE; - if (down_interruptible (&lp_table[minor].port_mutex)) + if (mutex_lock_interruptible(&lp_table[minor].port_mutex)) return -EINTR; if (copy_from_user (kbuf, buf, copy_size)) { @@ -399,7 +399,7 @@ static ssize_t lp_write(struct file * file, const char __user * buf, lp_release_parport (&lp_table[minor]); } out_unlock: - up (&lp_table[minor].port_mutex); + mutex_unlock(&lp_table[minor].port_mutex); return retv; } @@ -421,7 +421,7 @@ static ssize_t lp_read(struct file * file, char __user * buf, if (count > LP_BUFFER_SIZE) count = LP_BUFFER_SIZE; - if (down_interruptible (&lp_table[minor].port_mutex)) + if (mutex_lock_interruptible(&lp_table[minor].port_mutex)) return -EINTR; lp_claim_parport_or_block (&lp_table[minor]); @@ -479,7 +479,7 @@ static ssize_t lp_read(struct file * file, char __user * buf, if (retval > 0 && copy_to_user (buf, kbuf, retval)) retval = -EFAULT; - up (&lp_table[minor].port_mutex); + mutex_unlock(&lp_table[minor].port_mutex); return retval; } @@ -888,7 +888,7 @@ static int __init lp_init (void) lp_table[i].last_error = 0; init_waitqueue_head (&lp_table[i].waitq); init_waitqueue_head (&lp_table[i].dataq); - init_MUTEX (&lp_table[i].port_mutex); + mutex_init(&lp_table[i].port_mutex); lp_table[i].timeout = 10 * HZ; } diff --git a/drivers/char/misc.c b/drivers/char/misc.c index 71c8cd7fa15..a39101feb2e 100644 --- a/drivers/char/misc.c +++ b/drivers/char/misc.c @@ -232,8 +232,9 @@ int misc_register(struct miscdevice * misc) } /** - * misc_deregister - unregister a miscellaneous device + * __misc_deregister - unregister a miscellaneous device * @misc: device to unregister + * @suspended: to be set if the function is used during suspend/resume * * Unregister a miscellaneous device that was previously * successfully registered with misc_register(). Success @@ -241,7 +242,7 @@ int misc_register(struct miscdevice * misc) * indicates an error. */ -int misc_deregister(struct miscdevice * misc) +int __misc_deregister(struct miscdevice *misc, bool suspended) { int i = misc->minor; @@ -250,7 +251,11 @@ int misc_deregister(struct miscdevice * misc) mutex_lock(&misc_mtx); list_del(&misc->list); - device_destroy(misc_class, MKDEV(MISC_MAJOR, misc->minor)); + if (suspended) + destroy_suspended_device(misc_class, + MKDEV(MISC_MAJOR, misc->minor)); + else + device_destroy(misc_class, MKDEV(MISC_MAJOR, misc->minor)); if (i < DYNAMIC_MINORS && i>0) { misc_minors[i>>3] &= ~(1 << (misc->minor & 7)); } @@ -259,7 +264,7 @@ int misc_deregister(struct miscdevice * misc) } EXPORT_SYMBOL(misc_register); -EXPORT_SYMBOL(misc_deregister); +EXPORT_SYMBOL(__misc_deregister); static int __init misc_init(void) { diff --git a/drivers/char/mspec.c b/drivers/char/mspec.c index 82f2e27dca7..ff146c2b08f 100644 --- a/drivers/char/mspec.c +++ b/drivers/char/mspec.c @@ -283,7 +283,7 @@ mspec_mmap(struct file *file, struct vm_area_struct *vma, vdata->refcnt = ATOMIC_INIT(1); vma->vm_private_data = vdata; - vma->vm_flags |= (VM_IO | VM_RESERVED | VM_PFNMAP); + vma->vm_flags |= (VM_IO | VM_RESERVED | VM_PFNMAP | VM_DONTEXPAND); if (vdata->type == MSPEC_FETCHOP || vdata->type == MSPEC_UNCACHED) vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); vma->vm_ops = &mspec_vm_ops; diff --git a/drivers/char/mxser.c b/drivers/char/mxser.c index fd0abef7ee0..47420787a01 100644 --- a/drivers/char/mxser.c +++ b/drivers/char/mxser.c @@ -37,7 +37,6 @@ #include <linux/module.h> -#include <linux/autoconf.h> #include <linux/errno.h> #include <linux/signal.h> #include <linux/sched.h> diff --git a/drivers/char/mxser_new.c b/drivers/char/mxser_new.c index 081c84c7b54..bf1bee4e1f5 100644 --- a/drivers/char/mxser_new.c +++ b/drivers/char/mxser_new.c @@ -20,7 +20,6 @@ */ #include <linux/module.h> -#include <linux/autoconf.h> #include <linux/errno.h> #include <linux/signal.h> #include <linux/sched.h> diff --git a/drivers/char/n_tty.c b/drivers/char/n_tty.c index 596c7173997..90c3969012a 100644 --- a/drivers/char/n_tty.c +++ b/drivers/char/n_tty.c @@ -695,17 +695,16 @@ static inline void n_tty_receive_char(struct tty_struct *tty, unsigned char c) return; } - if (tty->stopped && !tty->flow_stopped && - I_IXON(tty) && I_IXANY(tty)) { - start_tty(tty); - return; - } - if (I_ISTRIP(tty)) c &= 0x7f; if (I_IUCLC(tty) && L_IEXTEN(tty)) c=tolower(c); + if (tty->stopped && !tty->flow_stopped && I_IXON(tty) && + ((I_IXANY(tty) && c != START_CHAR(tty) && c != STOP_CHAR(tty)) || + c == INTR_CHAR(tty) || c == QUIT_CHAR(tty))) + start_tty(tty); + if (tty->closing) { if (I_IXON(tty)) { if (c == START_CHAR(tty)) @@ -769,7 +768,21 @@ static inline void n_tty_receive_char(struct tty_struct *tty, unsigned char c) signal = SIGTSTP; if (c == SUSP_CHAR(tty)) { send_signal: - isig(signal, tty, 0); + /* + * Echo character, and then send the signal. + * Note that we do not use isig() here because we want + * the order to be: + * 1) flush, 2) echo, 3) signal + */ + if (!L_NOFLSH(tty)) { + n_tty_flush_buffer(tty); + if (tty->driver->flush_buffer) + tty->driver->flush_buffer(tty); + } + if (L_ECHO(tty)) + echo_char(c, tty); + if (tty->pgrp) + kill_pgrp(tty->pgrp, signal, 1); return; } } diff --git a/drivers/char/nozomi.c b/drivers/char/nozomi.c new file mode 100644 index 00000000000..dfaab2322de --- /dev/null +++ b/drivers/char/nozomi.c @@ -0,0 +1,1941 @@ +/* + * nozomi.c -- HSDPA driver Broadband Wireless Data Card - Globe Trotter + * + * Written by: Ulf Jakobsson, + * Jan Ã…kerfeldt, + * Stefan Thomasson, + * + * Maintained by: Paul Hardwick (p.hardwick@option.com) + * + * Patches: + * Locking code changes for Vodafone by Sphere Systems Ltd, + * Andrew Bird (ajb@spheresystems.co.uk ) + * & Phil Sanderson + * + * Source has been ported from an implementation made by Filip Aben @ Option + * + * -------------------------------------------------------------------------- + * + * Copyright (c) 2005,2006 Option Wireless Sweden AB + * Copyright (c) 2006 Sphere Systems Ltd + * Copyright (c) 2006 Option Wireless n/v + * All rights Reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + * -------------------------------------------------------------------------- + */ + +/* Enable this to have a lot of debug printouts */ +#define DEBUG + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/pci.h> +#include <linux/ioport.h> +#include <linux/tty.h> +#include <linux/tty_driver.h> +#include <linux/tty_flip.h> +#include <linux/serial.h> +#include <linux/interrupt.h> +#include <linux/kmod.h> +#include <linux/init.h> +#include <linux/kfifo.h> +#include <linux/uaccess.h> +#include <asm/byteorder.h> + +#include <linux/delay.h> + + +#define VERSION_STRING DRIVER_DESC " 2.1d (build date: " \ + __DATE__ " " __TIME__ ")" + +/* Macros definitions */ + +/* Default debug printout level */ +#define NOZOMI_DEBUG_LEVEL 0x00 + +#define P_BUF_SIZE 128 +#define NFO(_err_flag_, args...) \ +do { \ + char tmp[P_BUF_SIZE]; \ + snprintf(tmp, sizeof(tmp), ##args); \ + printk(_err_flag_ "[%d] %s(): %s\n", __LINE__, \ + __FUNCTION__, tmp); \ +} while (0) + +#define DBG1(args...) D_(0x01, ##args) +#define DBG2(args...) D_(0x02, ##args) +#define DBG3(args...) D_(0x04, ##args) +#define DBG4(args...) D_(0x08, ##args) +#define DBG5(args...) D_(0x10, ##args) +#define DBG6(args...) D_(0x20, ##args) +#define DBG7(args...) D_(0x40, ##args) +#define DBG8(args...) D_(0x80, ##args) + +#ifdef DEBUG +/* Do we need this settable at runtime? */ +static int debug = NOZOMI_DEBUG_LEVEL; + +#define D(lvl, args...) do \ + {if (lvl & debug) NFO(KERN_DEBUG, ##args); } \ + while (0) +#define D_(lvl, args...) D(lvl, ##args) + +/* These printouts are always printed */ + +#else +static int debug; +#define D_(lvl, args...) +#endif + +/* TODO: rewrite to optimize macros... */ + +#define TMP_BUF_MAX 256 + +#define DUMP(buf__,len__) \ + do { \ + char tbuf[TMP_BUF_MAX] = {0};\ + if (len__ > 1) {\ + snprintf(tbuf, len__ > TMP_BUF_MAX ? TMP_BUF_MAX : len__, "%s", buf__);\ + if (tbuf[len__-2] == '\r') {\ + tbuf[len__-2] = 'r';\ + } \ + DBG1("SENDING: '%s' (%d+n)", tbuf, len__);\ + } else {\ + DBG1("SENDING: '%s' (%d)", tbuf, len__);\ + } \ +} while (0) + +/* Defines */ +#define NOZOMI_NAME "nozomi" +#define NOZOMI_NAME_TTY "nozomi_tty" +#define DRIVER_DESC "Nozomi driver" + +#define NTTY_TTY_MAXMINORS 256 +#define NTTY_FIFO_BUFFER_SIZE 8192 + +/* Must be power of 2 */ +#define FIFO_BUFFER_SIZE_UL 8192 + +/* Size of tmp send buffer to card */ +#define SEND_BUF_MAX 1024 +#define RECEIVE_BUF_MAX 4 + + +/* Define all types of vendors and devices to support */ +#define VENDOR1 0x1931 /* Vendor Option */ +#define DEVICE1 0x000c /* HSDPA card */ + +#define R_IIR 0x0000 /* Interrupt Identity Register */ +#define R_FCR 0x0000 /* Flow Control Register */ +#define R_IER 0x0004 /* Interrupt Enable Register */ + +#define CONFIG_MAGIC 0xEFEFFEFE +#define TOGGLE_VALID 0x0000 + +/* Definition of interrupt tokens */ +#define MDM_DL1 0x0001 +#define MDM_UL1 0x0002 +#define MDM_DL2 0x0004 +#define MDM_UL2 0x0008 +#define DIAG_DL1 0x0010 +#define DIAG_DL2 0x0020 +#define DIAG_UL 0x0040 +#define APP1_DL 0x0080 +#define APP1_UL 0x0100 +#define APP2_DL 0x0200 +#define APP2_UL 0x0400 +#define CTRL_DL 0x0800 +#define CTRL_UL 0x1000 +#define RESET 0x8000 + +#define MDM_DL (MDM_DL1 | MDM_DL2) +#define MDM_UL (MDM_UL1 | MDM_UL2) +#define DIAG_DL (DIAG_DL1 | DIAG_DL2) + +/* modem signal definition */ +#define CTRL_DSR 0x0001 +#define CTRL_DCD 0x0002 +#define CTRL_RI 0x0004 +#define CTRL_CTS 0x0008 + +#define CTRL_DTR 0x0001 +#define CTRL_RTS 0x0002 + +#define MAX_PORT 4 +#define NOZOMI_MAX_PORTS 5 +#define NOZOMI_MAX_CARDS (NTTY_TTY_MAXMINORS / MAX_PORT) + +/* Type definitions */ + +/* + * There are two types of nozomi cards, + * one with 2048 memory and with 8192 memory + */ +enum card_type { + F32_2 = 2048, /* 512 bytes downlink + uplink * 2 -> 2048 */ + F32_8 = 8192, /* 3072 bytes downl. + 1024 bytes uplink * 2 -> 8192 */ +}; + +/* Two different toggle channels exist */ +enum channel_type { + CH_A = 0, + CH_B = 1, +}; + +/* Port definition for the card regarding flow control */ +enum ctrl_port_type { + CTRL_CMD = 0, + CTRL_MDM = 1, + CTRL_DIAG = 2, + CTRL_APP1 = 3, + CTRL_APP2 = 4, + CTRL_ERROR = -1, +}; + +/* Ports that the nozomi has */ +enum port_type { + PORT_MDM = 0, + PORT_DIAG = 1, + PORT_APP1 = 2, + PORT_APP2 = 3, + PORT_CTRL = 4, + PORT_ERROR = -1, +}; + +#ifdef __BIG_ENDIAN +/* Big endian */ + +struct toggles { + unsigned int enabled:5; /* + * Toggle fields are valid if enabled is 0, + * else A-channels must always be used. + */ + unsigned int diag_dl:1; + unsigned int mdm_dl:1; + unsigned int mdm_ul:1; +} __attribute__ ((packed)); + +/* Configuration table to read at startup of card */ +/* Is for now only needed during initialization phase */ +struct config_table { + u32 signature; + u16 product_information; + u16 version; + u8 pad3[3]; + struct toggles toggle; + u8 pad1[4]; + u16 dl_mdm_len1; /* + * If this is 64, it can hold + * 60 bytes + 4 that is length field + */ + u16 dl_start; + + u16 dl_diag_len1; + u16 dl_mdm_len2; /* + * If this is 64, it can hold + * 60 bytes + 4 that is length field + */ + u16 dl_app1_len; + + u16 dl_diag_len2; + u16 dl_ctrl_len; + u16 dl_app2_len; + u8 pad2[16]; + u16 ul_mdm_len1; + u16 ul_start; + u16 ul_diag_len; + u16 ul_mdm_len2; + u16 ul_app1_len; + u16 ul_app2_len; + u16 ul_ctrl_len; +} __attribute__ ((packed)); + +/* This stores all control downlink flags */ +struct ctrl_dl { + u8 port; + unsigned int reserved:4; + unsigned int CTS:1; + unsigned int RI:1; + unsigned int DCD:1; + unsigned int DSR:1; +} __attribute__ ((packed)); + +/* This stores all control uplink flags */ +struct ctrl_ul { + u8 port; + unsigned int reserved:6; + unsigned int RTS:1; + unsigned int DTR:1; +} __attribute__ ((packed)); + +#else +/* Little endian */ + +/* This represents the toggle information */ +struct toggles { + unsigned int mdm_ul:1; + unsigned int mdm_dl:1; + unsigned int diag_dl:1; + unsigned int enabled:5; /* + * Toggle fields are valid if enabled is 0, + * else A-channels must always be used. + */ +} __attribute__ ((packed)); + +/* Configuration table to read at startup of card */ +struct config_table { + u32 signature; + u16 version; + u16 product_information; + struct toggles toggle; + u8 pad1[7]; + u16 dl_start; + u16 dl_mdm_len1; /* + * If this is 64, it can hold + * 60 bytes + 4 that is length field + */ + u16 dl_mdm_len2; + u16 dl_diag_len1; + u16 dl_diag_len2; + u16 dl_app1_len; + u16 dl_app2_len; + u16 dl_ctrl_len; + u8 pad2[16]; + u16 ul_start; + u16 ul_mdm_len2; + u16 ul_mdm_len1; + u16 ul_diag_len; + u16 ul_app1_len; + u16 ul_app2_len; + u16 ul_ctrl_len; +} __attribute__ ((packed)); + +/* This stores all control downlink flags */ +struct ctrl_dl { + unsigned int DSR:1; + unsigned int DCD:1; + unsigned int RI:1; + unsigned int CTS:1; + unsigned int reserverd:4; + u8 port; +} __attribute__ ((packed)); + +/* This stores all control uplink flags */ +struct ctrl_ul { + unsigned int DTR:1; + unsigned int RTS:1; + unsigned int reserved:6; + u8 port; +} __attribute__ ((packed)); +#endif + +/* This holds all information that is needed regarding a port */ +struct port { + u8 update_flow_control; + struct ctrl_ul ctrl_ul; + struct ctrl_dl ctrl_dl; + struct kfifo *fifo_ul; + void __iomem *dl_addr[2]; + u32 dl_size[2]; + u8 toggle_dl; + void __iomem *ul_addr[2]; + u32 ul_size[2]; + u8 toggle_ul; + u16 token_dl; + + struct tty_struct *tty; + int tty_open_count; + /* mutex to ensure one access patch to this port */ + struct mutex tty_sem; + wait_queue_head_t tty_wait; + struct async_icount tty_icount; +}; + +/* Private data one for each card in the system */ +struct nozomi { + void __iomem *base_addr; + unsigned long flip; + + /* Pointers to registers */ + void __iomem *reg_iir; + void __iomem *reg_fcr; + void __iomem *reg_ier; + + u16 last_ier; + enum card_type card_type; + struct config_table config_table; /* Configuration table */ + struct pci_dev *pdev; + struct port port[NOZOMI_MAX_PORTS]; + u8 *send_buf; + + spinlock_t spin_mutex; /* secures access to registers and tty */ + + unsigned int index_start; + u32 open_ttys; +}; + +/* This is a data packet that is read or written to/from card */ +struct buffer { + u32 size; /* size is the length of the data buffer */ + u8 *data; +} __attribute__ ((packed)); + +/* Global variables */ +static const struct pci_device_id nozomi_pci_tbl[] __devinitconst = { + {PCI_DEVICE(VENDOR1, DEVICE1)}, + {}, +}; + +MODULE_DEVICE_TABLE(pci, nozomi_pci_tbl); + +static struct nozomi *ndevs[NOZOMI_MAX_CARDS]; +static struct tty_driver *ntty_driver; + +/* + * find card by tty_index + */ +static inline struct nozomi *get_dc_by_tty(const struct tty_struct *tty) +{ + return tty ? ndevs[tty->index / MAX_PORT] : NULL; +} + +static inline struct port *get_port_by_tty(const struct tty_struct *tty) +{ + struct nozomi *ndev = get_dc_by_tty(tty); + return ndev ? &ndev->port[tty->index % MAX_PORT] : NULL; +} + +/* + * TODO: + * -Optimize + * -Rewrite cleaner + */ + +static void read_mem32(u32 *buf, const void __iomem *mem_addr_start, + u32 size_bytes) +{ + u32 i = 0; + const u32 *ptr = (__force u32 *) mem_addr_start; + u16 *buf16; + + if (unlikely(!ptr || !buf)) + goto out; + + /* shortcut for extremely often used cases */ + switch (size_bytes) { + case 2: /* 2 bytes */ + buf16 = (u16 *) buf; + *buf16 = __le16_to_cpu(readw((void __iomem *)ptr)); + goto out; + break; + case 4: /* 4 bytes */ + *(buf) = __le32_to_cpu(readl((void __iomem *)ptr)); + goto out; + break; + } + + while (i < size_bytes) { + if (size_bytes - i == 2) { + /* Handle 2 bytes in the end */ + buf16 = (u16 *) buf; + *(buf16) = __le16_to_cpu(readw((void __iomem *)ptr)); + i += 2; + } else { + /* Read 4 bytes */ + *(buf) = __le32_to_cpu(readl((void __iomem *)ptr)); + i += 4; + } + buf++; + ptr++; + } +out: + return; +} + +/* + * TODO: + * -Optimize + * -Rewrite cleaner + */ +static u32 write_mem32(void __iomem *mem_addr_start, const u32 *buf, + u32 size_bytes) +{ + u32 i = 0; + u32 *ptr = (__force u32 *) mem_addr_start; + const u16 *buf16; + + if (unlikely(!ptr || !buf)) + return 0; + + /* shortcut for extremely often used cases */ + switch (size_bytes) { + case 2: /* 2 bytes */ + buf16 = (const u16 *)buf; + writew(__cpu_to_le16(*buf16), (void __iomem *)ptr); + return 2; + break; + case 1: /* + * also needs to write 4 bytes in this case + * so falling through.. + */ + case 4: /* 4 bytes */ + writel(__cpu_to_le32(*buf), (void __iomem *)ptr); + return 4; + break; + } + + while (i < size_bytes) { + if (size_bytes - i == 2) { + /* 2 bytes */ + buf16 = (const u16 *)buf; + writew(__cpu_to_le16(*buf16), (void __iomem *)ptr); + i += 2; + } else { + /* 4 bytes */ + writel(__cpu_to_le32(*buf), (void __iomem *)ptr); + i += 4; + } + buf++; + ptr++; + } + return i; +} + +/* Setup pointers to different channels and also setup buffer sizes. */ +static void setup_memory(struct nozomi *dc) +{ + void __iomem *offset = dc->base_addr + dc->config_table.dl_start; + /* The length reported is including the length field of 4 bytes, + * hence subtract with 4. + */ + const u16 buff_offset = 4; + + /* Modem port dl configuration */ + dc->port[PORT_MDM].dl_addr[CH_A] = offset; + dc->port[PORT_MDM].dl_addr[CH_B] = + (offset += dc->config_table.dl_mdm_len1); + dc->port[PORT_MDM].dl_size[CH_A] = + dc->config_table.dl_mdm_len1 - buff_offset; + dc->port[PORT_MDM].dl_size[CH_B] = + dc->config_table.dl_mdm_len2 - buff_offset; + + /* Diag port dl configuration */ + dc->port[PORT_DIAG].dl_addr[CH_A] = + (offset += dc->config_table.dl_mdm_len2); + dc->port[PORT_DIAG].dl_size[CH_A] = + dc->config_table.dl_diag_len1 - buff_offset; + dc->port[PORT_DIAG].dl_addr[CH_B] = + (offset += dc->config_table.dl_diag_len1); + dc->port[PORT_DIAG].dl_size[CH_B] = + dc->config_table.dl_diag_len2 - buff_offset; + + /* App1 port dl configuration */ + dc->port[PORT_APP1].dl_addr[CH_A] = + (offset += dc->config_table.dl_diag_len2); + dc->port[PORT_APP1].dl_size[CH_A] = + dc->config_table.dl_app1_len - buff_offset; + + /* App2 port dl configuration */ + dc->port[PORT_APP2].dl_addr[CH_A] = + (offset += dc->config_table.dl_app1_len); + dc->port[PORT_APP2].dl_size[CH_A] = + dc->config_table.dl_app2_len - buff_offset; + + /* Ctrl dl configuration */ + dc->port[PORT_CTRL].dl_addr[CH_A] = + (offset += dc->config_table.dl_app2_len); + dc->port[PORT_CTRL].dl_size[CH_A] = + dc->config_table.dl_ctrl_len - buff_offset; + + offset = dc->base_addr + dc->config_table.ul_start; + + /* Modem Port ul configuration */ + dc->port[PORT_MDM].ul_addr[CH_A] = offset; + dc->port[PORT_MDM].ul_size[CH_A] = + dc->config_table.ul_mdm_len1 - buff_offset; + dc->port[PORT_MDM].ul_addr[CH_B] = + (offset += dc->config_table.ul_mdm_len1); + dc->port[PORT_MDM].ul_size[CH_B] = + dc->config_table.ul_mdm_len2 - buff_offset; + + /* Diag port ul configuration */ + dc->port[PORT_DIAG].ul_addr[CH_A] = + (offset += dc->config_table.ul_mdm_len2); + dc->port[PORT_DIAG].ul_size[CH_A] = + dc->config_table.ul_diag_len - buff_offset; + + /* App1 port ul configuration */ + dc->port[PORT_APP1].ul_addr[CH_A] = + (offset += dc->config_table.ul_diag_len); + dc->port[PORT_APP1].ul_size[CH_A] = + dc->config_table.ul_app1_len - buff_offset; + + /* App2 port ul configuration */ + dc->port[PORT_APP2].ul_addr[CH_A] = + (offset += dc->config_table.ul_app1_len); + dc->port[PORT_APP2].ul_size[CH_A] = + dc->config_table.ul_app2_len - buff_offset; + + /* Ctrl ul configuration */ + dc->port[PORT_CTRL].ul_addr[CH_A] = + (offset += dc->config_table.ul_app2_len); + dc->port[PORT_CTRL].ul_size[CH_A] = + dc->config_table.ul_ctrl_len - buff_offset; +} + +/* Dump config table under initalization phase */ +#ifdef DEBUG +static void dump_table(const struct nozomi *dc) +{ + DBG3("signature: 0x%08X", dc->config_table.signature); + DBG3("version: 0x%04X", dc->config_table.version); + DBG3("product_information: 0x%04X", \ + dc->config_table.product_information); + DBG3("toggle enabled: %d", dc->config_table.toggle.enabled); + DBG3("toggle up_mdm: %d", dc->config_table.toggle.mdm_ul); + DBG3("toggle dl_mdm: %d", dc->config_table.toggle.mdm_dl); + DBG3("toggle dl_dbg: %d", dc->config_table.toggle.diag_dl); + + DBG3("dl_start: 0x%04X", dc->config_table.dl_start); + DBG3("dl_mdm_len0: 0x%04X, %d", dc->config_table.dl_mdm_len1, + dc->config_table.dl_mdm_len1); + DBG3("dl_mdm_len1: 0x%04X, %d", dc->config_table.dl_mdm_len2, + dc->config_table.dl_mdm_len2); + DBG3("dl_diag_len0: 0x%04X, %d", dc->config_table.dl_diag_len1, + dc->config_table.dl_diag_len1); + DBG3("dl_diag_len1: 0x%04X, %d", dc->config_table.dl_diag_len2, + dc->config_table.dl_diag_len2); + DBG3("dl_app1_len: 0x%04X, %d", dc->config_table.dl_app1_len, + dc->config_table.dl_app1_len); + DBG3("dl_app2_len: 0x%04X, %d", dc->config_table.dl_app2_len, + dc->config_table.dl_app2_len); + DBG3("dl_ctrl_len: 0x%04X, %d", dc->config_table.dl_ctrl_len, + dc->config_table.dl_ctrl_len); + DBG3("ul_start: 0x%04X, %d", dc->config_table.ul_start, + dc->config_table.ul_start); + DBG3("ul_mdm_len[0]: 0x%04X, %d", dc->config_table.ul_mdm_len1, + dc->config_table.ul_mdm_len1); + DBG3("ul_mdm_len[1]: 0x%04X, %d", dc->config_table.ul_mdm_len2, + dc->config_table.ul_mdm_len2); + DBG3("ul_diag_len: 0x%04X, %d", dc->config_table.ul_diag_len, + dc->config_table.ul_diag_len); + DBG3("ul_app1_len: 0x%04X, %d", dc->config_table.ul_app1_len, + dc->config_table.ul_app1_len); + DBG3("ul_app2_len: 0x%04X, %d", dc->config_table.ul_app2_len, + dc->config_table.ul_app2_len); + DBG3("ul_ctrl_len: 0x%04X, %d", dc->config_table.ul_ctrl_len, + dc->config_table.ul_ctrl_len); +} +#else +static inline void dump_table(const struct nozomi *dc) { } +#endif + +/* + * Read configuration table from card under intalization phase + * Returns 1 if ok, else 0 + */ +static int nozomi_read_config_table(struct nozomi *dc) +{ + read_mem32((u32 *) &dc->config_table, dc->base_addr + 0, + sizeof(struct config_table)); + + if (dc->config_table.signature != CONFIG_MAGIC) { + dev_err(&dc->pdev->dev, "ConfigTable Bad! 0x%08X != 0x%08X\n", + dc->config_table.signature, CONFIG_MAGIC); + return 0; + } + + if ((dc->config_table.version == 0) + || (dc->config_table.toggle.enabled == TOGGLE_VALID)) { + int i; + DBG1("Second phase, configuring card"); + + setup_memory(dc); + + dc->port[PORT_MDM].toggle_ul = dc->config_table.toggle.mdm_ul; + dc->port[PORT_MDM].toggle_dl = dc->config_table.toggle.mdm_dl; + dc->port[PORT_DIAG].toggle_dl = dc->config_table.toggle.diag_dl; + DBG1("toggle ports: MDM UL:%d MDM DL:%d, DIAG DL:%d", + dc->port[PORT_MDM].toggle_ul, + dc->port[PORT_MDM].toggle_dl, dc->port[PORT_DIAG].toggle_dl); + + dump_table(dc); + + for (i = PORT_MDM; i < MAX_PORT; i++) { + dc->port[i].fifo_ul = + kfifo_alloc(FIFO_BUFFER_SIZE_UL, GFP_ATOMIC, NULL); + memset(&dc->port[i].ctrl_dl, 0, sizeof(struct ctrl_dl)); + memset(&dc->port[i].ctrl_ul, 0, sizeof(struct ctrl_ul)); + } + + /* Enable control channel */ + dc->last_ier = dc->last_ier | CTRL_DL; + writew(dc->last_ier, dc->reg_ier); + + dev_info(&dc->pdev->dev, "Initialization OK!\n"); + return 1; + } + + if ((dc->config_table.version > 0) + && (dc->config_table.toggle.enabled != TOGGLE_VALID)) { + u32 offset = 0; + DBG1("First phase: pushing upload buffers, clearing download"); + + dev_info(&dc->pdev->dev, "Version of card: %d\n", + dc->config_table.version); + + /* Here we should disable all I/O over F32. */ + setup_memory(dc); + + /* + * We should send ALL channel pair tokens back along + * with reset token + */ + + /* push upload modem buffers */ + write_mem32(dc->port[PORT_MDM].ul_addr[CH_A], + (u32 *) &offset, 4); + write_mem32(dc->port[PORT_MDM].ul_addr[CH_B], + (u32 *) &offset, 4); + + writew(MDM_UL | DIAG_DL | MDM_DL, dc->reg_fcr); + + DBG1("First phase done"); + } + + return 1; +} + +/* Enable uplink interrupts */ +static void enable_transmit_ul(enum port_type port, struct nozomi *dc) +{ + static const u16 mask[] = {MDM_UL, DIAG_UL, APP1_UL, APP2_UL, CTRL_UL}; + + if (port < NOZOMI_MAX_PORTS) { + dc->last_ier |= mask[port]; + writew(dc->last_ier, dc->reg_ier); + } else { + dev_err(&dc->pdev->dev, "Called with wrong port?\n"); + } +} + +/* Disable uplink interrupts */ +static void disable_transmit_ul(enum port_type port, struct nozomi *dc) +{ + static const u16 mask[] = + {~MDM_UL, ~DIAG_UL, ~APP1_UL, ~APP2_UL, ~CTRL_UL}; + + if (port < NOZOMI_MAX_PORTS) { + dc->last_ier &= mask[port]; + writew(dc->last_ier, dc->reg_ier); + } else { + dev_err(&dc->pdev->dev, "Called with wrong port?\n"); + } +} + +/* Enable downlink interrupts */ +static void enable_transmit_dl(enum port_type port, struct nozomi *dc) +{ + static const u16 mask[] = {MDM_DL, DIAG_DL, APP1_DL, APP2_DL, CTRL_DL}; + + if (port < NOZOMI_MAX_PORTS) { + dc->last_ier |= mask[port]; + writew(dc->last_ier, dc->reg_ier); + } else { + dev_err(&dc->pdev->dev, "Called with wrong port?\n"); + } +} + +/* Disable downlink interrupts */ +static void disable_transmit_dl(enum port_type port, struct nozomi *dc) +{ + static const u16 mask[] = + {~MDM_DL, ~DIAG_DL, ~APP1_DL, ~APP2_DL, ~CTRL_DL}; + + if (port < NOZOMI_MAX_PORTS) { + dc->last_ier &= mask[port]; + writew(dc->last_ier, dc->reg_ier); + } else { + dev_err(&dc->pdev->dev, "Called with wrong port?\n"); + } +} + +/* + * Return 1 - send buffer to card and ack. + * Return 0 - don't ack, don't send buffer to card. + */ +static int send_data(enum port_type index, const struct nozomi *dc) +{ + u32 size = 0; + const struct port *port = &dc->port[index]; + const u8 toggle = port->toggle_ul; + void __iomem *addr = port->ul_addr[toggle]; + const u32 ul_size = port->ul_size[toggle]; + struct tty_struct *tty = port->tty; + + /* Get data from tty and place in buf for now */ + size = __kfifo_get(port->fifo_ul, dc->send_buf, + ul_size < SEND_BUF_MAX ? ul_size : SEND_BUF_MAX); + + if (size == 0) { + DBG4("No more data to send, disable link:"); + return 0; + } + + /* DUMP(buf, size); */ + + /* Write length + data */ + write_mem32(addr, (u32 *) &size, 4); + write_mem32(addr + 4, (u32 *) dc->send_buf, size); + + if (tty) + tty_wakeup(tty); + + return 1; +} + +/* If all data has been read, return 1, else 0 */ +static int receive_data(enum port_type index, struct nozomi *dc) +{ + u8 buf[RECEIVE_BUF_MAX] = { 0 }; + int size; + u32 offset = 4; + struct port *port = &dc->port[index]; + void __iomem *addr = port->dl_addr[port->toggle_dl]; + struct tty_struct *tty = port->tty; + int i; + + if (unlikely(!tty)) { + DBG1("tty not open for port: %d?", index); + return 1; + } + + read_mem32((u32 *) &size, addr, 4); + /* DBG1( "%d bytes port: %d", size, index); */ + + if (test_bit(TTY_THROTTLED, &tty->flags)) { + DBG1("No room in tty, don't read data, don't ack interrupt, " + "disable interrupt"); + + /* disable interrupt in downlink... */ + disable_transmit_dl(index, dc); + return 0; + } + + if (unlikely(size == 0)) { + dev_err(&dc->pdev->dev, "size == 0?\n"); + return 1; + } + + tty_buffer_request_room(tty, size); + + while (size > 0) { + read_mem32((u32 *) buf, addr + offset, RECEIVE_BUF_MAX); + + if (size == 1) { + tty_insert_flip_char(tty, buf[0], TTY_NORMAL); + size = 0; + } else if (size < RECEIVE_BUF_MAX) { + size -= tty_insert_flip_string(tty, (char *) buf, size); + } else { + i = tty_insert_flip_string(tty, \ + (char *) buf, RECEIVE_BUF_MAX); + size -= i; + offset += i; + } + } + + set_bit(index, &dc->flip); + + return 1; +} + +/* Debug for interrupts */ +#ifdef DEBUG +static char *interrupt2str(u16 interrupt) +{ + static char buf[TMP_BUF_MAX]; + char *p = buf; + + interrupt & MDM_DL1 ? p += snprintf(p, TMP_BUF_MAX, "MDM_DL1 ") : NULL; + interrupt & MDM_DL2 ? p += snprintf(p, TMP_BUF_MAX - (p - buf), + "MDM_DL2 ") : NULL; + + interrupt & MDM_UL1 ? p += snprintf(p, TMP_BUF_MAX - (p - buf), + "MDM_UL1 ") : NULL; + interrupt & MDM_UL2 ? p += snprintf(p, TMP_BUF_MAX - (p - buf), + "MDM_UL2 ") : NULL; + + interrupt & DIAG_DL1 ? p += snprintf(p, TMP_BUF_MAX - (p - buf), + "DIAG_DL1 ") : NULL; + interrupt & DIAG_DL2 ? p += snprintf(p, TMP_BUF_MAX - (p - buf), + "DIAG_DL2 ") : NULL; + + interrupt & DIAG_UL ? p += snprintf(p, TMP_BUF_MAX - (p - buf), + "DIAG_UL ") : NULL; + + interrupt & APP1_DL ? p += snprintf(p, TMP_BUF_MAX - (p - buf), + "APP1_DL ") : NULL; + interrupt & APP2_DL ? p += snprintf(p, TMP_BUF_MAX - (p - buf), + "APP2_DL ") : NULL; + + interrupt & APP1_UL ? p += snprintf(p, TMP_BUF_MAX - (p - buf), + "APP1_UL ") : NULL; + interrupt & APP2_UL ? p += snprintf(p, TMP_BUF_MAX - (p - buf), + "APP2_UL ") : NULL; + + interrupt & CTRL_DL ? p += snprintf(p, TMP_BUF_MAX - (p - buf), + "CTRL_DL ") : NULL; + interrupt & CTRL_UL ? p += snprintf(p, TMP_BUF_MAX - (p - buf), + "CTRL_UL ") : NULL; + + interrupt & RESET ? p += snprintf(p, TMP_BUF_MAX - (p - buf), + "RESET ") : NULL; + + return buf; +} +#endif + +/* + * Receive flow control + * Return 1 - If ok, else 0 + */ +static int receive_flow_control(struct nozomi *dc) +{ + enum port_type port = PORT_MDM; + struct ctrl_dl ctrl_dl; + struct ctrl_dl old_ctrl; + u16 enable_ier = 0; + + read_mem32((u32 *) &ctrl_dl, dc->port[PORT_CTRL].dl_addr[CH_A], 2); + + switch (ctrl_dl.port) { + case CTRL_CMD: + DBG1("The Base Band sends this value as a response to a " + "request for IMSI detach sent over the control " + "channel uplink (see section 7.6.1)."); + break; + case CTRL_MDM: + port = PORT_MDM; + enable_ier = MDM_DL; + break; + case CTRL_DIAG: + port = PORT_DIAG; + enable_ier = DIAG_DL; + break; + case CTRL_APP1: + port = PORT_APP1; + enable_ier = APP1_DL; + break; + case CTRL_APP2: + port = PORT_APP2; + enable_ier = APP2_DL; + break; + default: + dev_err(&dc->pdev->dev, + "ERROR: flow control received for non-existing port\n"); + return 0; + }; + + DBG1("0x%04X->0x%04X", *((u16 *)&dc->port[port].ctrl_dl), + *((u16 *)&ctrl_dl)); + + old_ctrl = dc->port[port].ctrl_dl; + dc->port[port].ctrl_dl = ctrl_dl; + + if (old_ctrl.CTS == 1 && ctrl_dl.CTS == 0) { + DBG1("Disable interrupt (0x%04X) on port: %d", + enable_ier, port); + disable_transmit_ul(port, dc); + + } else if (old_ctrl.CTS == 0 && ctrl_dl.CTS == 1) { + + if (__kfifo_len(dc->port[port].fifo_ul)) { + DBG1("Enable interrupt (0x%04X) on port: %d", + enable_ier, port); + DBG1("Data in buffer [%d], enable transmit! ", + __kfifo_len(dc->port[port].fifo_ul)); + enable_transmit_ul(port, dc); + } else { + DBG1("No data in buffer..."); + } + } + + if (*(u16 *)&old_ctrl == *(u16 *)&ctrl_dl) { + DBG1(" No change in mctrl"); + return 1; + } + /* Update statistics */ + if (old_ctrl.CTS != ctrl_dl.CTS) + dc->port[port].tty_icount.cts++; + if (old_ctrl.DSR != ctrl_dl.DSR) + dc->port[port].tty_icount.dsr++; + if (old_ctrl.RI != ctrl_dl.RI) + dc->port[port].tty_icount.rng++; + if (old_ctrl.DCD != ctrl_dl.DCD) + dc->port[port].tty_icount.dcd++; + + wake_up_interruptible(&dc->port[port].tty_wait); + + DBG1("port: %d DCD(%d), CTS(%d), RI(%d), DSR(%d)", + port, + dc->port[port].tty_icount.dcd, dc->port[port].tty_icount.cts, + dc->port[port].tty_icount.rng, dc->port[port].tty_icount.dsr); + + return 1; +} + +static enum ctrl_port_type port2ctrl(enum port_type port, + const struct nozomi *dc) +{ + switch (port) { + case PORT_MDM: + return CTRL_MDM; + case PORT_DIAG: + return CTRL_DIAG; + case PORT_APP1: + return CTRL_APP1; + case PORT_APP2: + return CTRL_APP2; + default: + dev_err(&dc->pdev->dev, + "ERROR: send flow control " \ + "received for non-existing port\n"); + }; + return CTRL_ERROR; +} + +/* + * Send flow control, can only update one channel at a time + * Return 0 - If we have updated all flow control + * Return 1 - If we need to update more flow control, ack current enable more + */ +static int send_flow_control(struct nozomi *dc) +{ + u32 i, more_flow_control_to_be_updated = 0; + u16 *ctrl; + + for (i = PORT_MDM; i < MAX_PORT; i++) { + if (dc->port[i].update_flow_control) { + if (more_flow_control_to_be_updated) { + /* We have more flow control to be updated */ + return 1; + } + dc->port[i].ctrl_ul.port = port2ctrl(i, dc); + ctrl = (u16 *)&dc->port[i].ctrl_ul; + write_mem32(dc->port[PORT_CTRL].ul_addr[0], \ + (u32 *) ctrl, 2); + dc->port[i].update_flow_control = 0; + more_flow_control_to_be_updated = 1; + } + } + return 0; +} + +/* + * Handle downlink data, ports that are handled are modem and diagnostics + * Return 1 - ok + * Return 0 - toggle fields are out of sync + */ +static int handle_data_dl(struct nozomi *dc, enum port_type port, u8 *toggle, + u16 read_iir, u16 mask1, u16 mask2) +{ + if (*toggle == 0 && read_iir & mask1) { + if (receive_data(port, dc)) { + writew(mask1, dc->reg_fcr); + *toggle = !(*toggle); + } + + if (read_iir & mask2) { + if (receive_data(port, dc)) { + writew(mask2, dc->reg_fcr); + *toggle = !(*toggle); + } + } + } else if (*toggle == 1 && read_iir & mask2) { + if (receive_data(port, dc)) { + writew(mask2, dc->reg_fcr); + *toggle = !(*toggle); + } + + if (read_iir & mask1) { + if (receive_data(port, dc)) { + writew(mask1, dc->reg_fcr); + *toggle = !(*toggle); + } + } + } else { + dev_err(&dc->pdev->dev, "port out of sync!, toggle:%d\n", + *toggle); + return 0; + } + return 1; +} + +/* + * Handle uplink data, this is currently for the modem port + * Return 1 - ok + * Return 0 - toggle field are out of sync + */ +static int handle_data_ul(struct nozomi *dc, enum port_type port, u16 read_iir) +{ + u8 *toggle = &(dc->port[port].toggle_ul); + + if (*toggle == 0 && read_iir & MDM_UL1) { + dc->last_ier &= ~MDM_UL; + writew(dc->last_ier, dc->reg_ier); + if (send_data(port, dc)) { + writew(MDM_UL1, dc->reg_fcr); + dc->last_ier = dc->last_ier | MDM_UL; + writew(dc->last_ier, dc->reg_ier); + *toggle = !*toggle; + } + + if (read_iir & MDM_UL2) { + dc->last_ier &= ~MDM_UL; + writew(dc->last_ier, dc->reg_ier); + if (send_data(port, dc)) { + writew(MDM_UL2, dc->reg_fcr); + dc->last_ier = dc->last_ier | MDM_UL; + writew(dc->last_ier, dc->reg_ier); + *toggle = !*toggle; + } + } + + } else if (*toggle == 1 && read_iir & MDM_UL2) { + dc->last_ier &= ~MDM_UL; + writew(dc->last_ier, dc->reg_ier); + if (send_data(port, dc)) { + writew(MDM_UL2, dc->reg_fcr); + dc->last_ier = dc->last_ier | MDM_UL; + writew(dc->last_ier, dc->reg_ier); + *toggle = !*toggle; + } + + if (read_iir & MDM_UL1) { + dc->last_ier &= ~MDM_UL; + writew(dc->last_ier, dc->reg_ier); + if (send_data(port, dc)) { + writew(MDM_UL1, dc->reg_fcr); + dc->last_ier = dc->last_ier | MDM_UL; + writew(dc->last_ier, dc->reg_ier); + *toggle = !*toggle; + } + } + } else { + writew(read_iir & MDM_UL, dc->reg_fcr); + dev_err(&dc->pdev->dev, "port out of sync!\n"); + return 0; + } + return 1; +} + +static irqreturn_t interrupt_handler(int irq, void *dev_id) +{ + struct nozomi *dc = dev_id; + unsigned int a; + u16 read_iir; + + if (!dc) + return IRQ_NONE; + + spin_lock(&dc->spin_mutex); + read_iir = readw(dc->reg_iir); + + /* Card removed */ + if (read_iir == (u16)-1) + goto none; + /* + * Just handle interrupt enabled in IER + * (by masking with dc->last_ier) + */ + read_iir &= dc->last_ier; + + if (read_iir == 0) + goto none; + + + DBG4("%s irq:0x%04X, prev:0x%04X", interrupt2str(read_iir), read_iir, + dc->last_ier); + + if (read_iir & RESET) { + if (unlikely(!nozomi_read_config_table(dc))) { + dc->last_ier = 0x0; + writew(dc->last_ier, dc->reg_ier); + dev_err(&dc->pdev->dev, "Could not read status from " + "card, we should disable interface\n"); + } else { + writew(RESET, dc->reg_fcr); + } + /* No more useful info if this was the reset interrupt. */ + goto exit_handler; + } + if (read_iir & CTRL_UL) { + DBG1("CTRL_UL"); + dc->last_ier &= ~CTRL_UL; + writew(dc->last_ier, dc->reg_ier); + if (send_flow_control(dc)) { + writew(CTRL_UL, dc->reg_fcr); + dc->last_ier = dc->last_ier | CTRL_UL; + writew(dc->last_ier, dc->reg_ier); + } + } + if (read_iir & CTRL_DL) { + receive_flow_control(dc); + writew(CTRL_DL, dc->reg_fcr); + } + if (read_iir & MDM_DL) { + if (!handle_data_dl(dc, PORT_MDM, + &(dc->port[PORT_MDM].toggle_dl), read_iir, + MDM_DL1, MDM_DL2)) { + dev_err(&dc->pdev->dev, "MDM_DL out of sync!\n"); + goto exit_handler; + } + } + if (read_iir & MDM_UL) { + if (!handle_data_ul(dc, PORT_MDM, read_iir)) { + dev_err(&dc->pdev->dev, "MDM_UL out of sync!\n"); + goto exit_handler; + } + } + if (read_iir & DIAG_DL) { + if (!handle_data_dl(dc, PORT_DIAG, + &(dc->port[PORT_DIAG].toggle_dl), read_iir, + DIAG_DL1, DIAG_DL2)) { + dev_err(&dc->pdev->dev, "DIAG_DL out of sync!\n"); + goto exit_handler; + } + } + if (read_iir & DIAG_UL) { + dc->last_ier &= ~DIAG_UL; + writew(dc->last_ier, dc->reg_ier); + if (send_data(PORT_DIAG, dc)) { + writew(DIAG_UL, dc->reg_fcr); + dc->last_ier = dc->last_ier | DIAG_UL; + writew(dc->last_ier, dc->reg_ier); + } + } + if (read_iir & APP1_DL) { + if (receive_data(PORT_APP1, dc)) + writew(APP1_DL, dc->reg_fcr); + } + if (read_iir & APP1_UL) { + dc->last_ier &= ~APP1_UL; + writew(dc->last_ier, dc->reg_ier); + if (send_data(PORT_APP1, dc)) { + writew(APP1_UL, dc->reg_fcr); + dc->last_ier = dc->last_ier | APP1_UL; + writew(dc->last_ier, dc->reg_ier); + } + } + if (read_iir & APP2_DL) { + if (receive_data(PORT_APP2, dc)) + writew(APP2_DL, dc->reg_fcr); + } + if (read_iir & APP2_UL) { + dc->last_ier &= ~APP2_UL; + writew(dc->last_ier, dc->reg_ier); + if (send_data(PORT_APP2, dc)) { + writew(APP2_UL, dc->reg_fcr); + dc->last_ier = dc->last_ier | APP2_UL; + writew(dc->last_ier, dc->reg_ier); + } + } + +exit_handler: + spin_unlock(&dc->spin_mutex); + for (a = 0; a < NOZOMI_MAX_PORTS; a++) + if (test_and_clear_bit(a, &dc->flip)) + tty_flip_buffer_push(dc->port[a].tty); + return IRQ_HANDLED; +none: + spin_unlock(&dc->spin_mutex); + return IRQ_NONE; +} + +static void nozomi_get_card_type(struct nozomi *dc) +{ + int i; + u32 size = 0; + + for (i = 0; i < 6; i++) + size += pci_resource_len(dc->pdev, i); + + /* Assume card type F32_8 if no match */ + dc->card_type = size == 2048 ? F32_2 : F32_8; + + dev_info(&dc->pdev->dev, "Card type is: %d\n", dc->card_type); +} + +static void nozomi_setup_private_data(struct nozomi *dc) +{ + void __iomem *offset = dc->base_addr + dc->card_type / 2; + unsigned int i; + + dc->reg_fcr = (void __iomem *)(offset + R_FCR); + dc->reg_iir = (void __iomem *)(offset + R_IIR); + dc->reg_ier = (void __iomem *)(offset + R_IER); + dc->last_ier = 0; + dc->flip = 0; + + dc->port[PORT_MDM].token_dl = MDM_DL; + dc->port[PORT_DIAG].token_dl = DIAG_DL; + dc->port[PORT_APP1].token_dl = APP1_DL; + dc->port[PORT_APP2].token_dl = APP2_DL; + + for (i = 0; i < MAX_PORT; i++) + init_waitqueue_head(&dc->port[i].tty_wait); +} + +static ssize_t card_type_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + const struct nozomi *dc = pci_get_drvdata(to_pci_dev(dev)); + + return sprintf(buf, "%d\n", dc->card_type); +} +static DEVICE_ATTR(card_type, S_IRUGO, card_type_show, NULL); + +static ssize_t open_ttys_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + const struct nozomi *dc = pci_get_drvdata(to_pci_dev(dev)); + + return sprintf(buf, "%u\n", dc->open_ttys); +} +static DEVICE_ATTR(open_ttys, S_IRUGO, open_ttys_show, NULL); + +static void make_sysfs_files(struct nozomi *dc) +{ + if (device_create_file(&dc->pdev->dev, &dev_attr_card_type)) + dev_err(&dc->pdev->dev, + "Could not create sysfs file for card_type\n"); + if (device_create_file(&dc->pdev->dev, &dev_attr_open_ttys)) + dev_err(&dc->pdev->dev, + "Could not create sysfs file for open_ttys\n"); +} + +static void remove_sysfs_files(struct nozomi *dc) +{ + device_remove_file(&dc->pdev->dev, &dev_attr_card_type); + device_remove_file(&dc->pdev->dev, &dev_attr_open_ttys); +} + +/* Allocate memory for one device */ +static int __devinit nozomi_card_init(struct pci_dev *pdev, + const struct pci_device_id *ent) +{ + resource_size_t start; + int ret; + struct nozomi *dc = NULL; + int ndev_idx; + int i; + + dev_dbg(&pdev->dev, "Init, new card found\n"); + + for (ndev_idx = 0; ndev_idx < ARRAY_SIZE(ndevs); ndev_idx++) + if (!ndevs[ndev_idx]) + break; + + if (ndev_idx >= ARRAY_SIZE(ndevs)) { + dev_err(&pdev->dev, "no free tty range for this card left\n"); + ret = -EIO; + goto err; + } + + dc = kzalloc(sizeof(struct nozomi), GFP_KERNEL); + if (unlikely(!dc)) { + dev_err(&pdev->dev, "Could not allocate memory\n"); + ret = -ENOMEM; + goto err_free; + } + + dc->pdev = pdev; + + /* Find out what card type it is */ + nozomi_get_card_type(dc); + + ret = pci_enable_device(dc->pdev); + if (ret) { + dev_err(&pdev->dev, "Failed to enable PCI Device\n"); + goto err_free; + } + + start = pci_resource_start(dc->pdev, 0); + if (start == 0) { + dev_err(&pdev->dev, "No I/O address for card detected\n"); + ret = -ENODEV; + goto err_disable_device; + } + + ret = pci_request_regions(dc->pdev, NOZOMI_NAME); + if (ret) { + dev_err(&pdev->dev, "I/O address 0x%04x already in use\n", + (int) /* nozomi_private.io_addr */ 0); + goto err_disable_device; + } + + dc->base_addr = ioremap(start, dc->card_type); + if (!dc->base_addr) { + dev_err(&pdev->dev, "Unable to map card MMIO\n"); + ret = -ENODEV; + goto err_rel_regs; + } + + dc->send_buf = kmalloc(SEND_BUF_MAX, GFP_KERNEL); + if (!dc->send_buf) { + dev_err(&pdev->dev, "Could not allocate send buffer?\n"); + ret = -ENOMEM; + goto err_free_sbuf; + } + + spin_lock_init(&dc->spin_mutex); + + nozomi_setup_private_data(dc); + + /* Disable all interrupts */ + dc->last_ier = 0; + writew(dc->last_ier, dc->reg_ier); + + ret = request_irq(pdev->irq, &interrupt_handler, IRQF_SHARED, + NOZOMI_NAME, dc); + if (unlikely(ret)) { + dev_err(&pdev->dev, "can't request irq %d\n", pdev->irq); + goto err_free_sbuf; + } + + DBG1("base_addr: %p", dc->base_addr); + + make_sysfs_files(dc); + + dc->index_start = ndev_idx * MAX_PORT; + ndevs[ndev_idx] = dc; + + for (i = 0; i < MAX_PORT; i++) { + mutex_init(&dc->port[i].tty_sem); + dc->port[i].tty_open_count = 0; + dc->port[i].tty = NULL; + tty_register_device(ntty_driver, dc->index_start + i, + &pdev->dev); + } + + /* Enable RESET interrupt. */ + dc->last_ier = RESET; + writew(dc->last_ier, dc->reg_ier); + + pci_set_drvdata(pdev, dc); + + return 0; + +err_free_sbuf: + kfree(dc->send_buf); + iounmap(dc->base_addr); +err_rel_regs: + pci_release_regions(pdev); +err_disable_device: + pci_disable_device(pdev); +err_free: + kfree(dc); +err: + return ret; +} + +static void __devexit tty_exit(struct nozomi *dc) +{ + unsigned int i; + + DBG1(" "); + + flush_scheduled_work(); + + for (i = 0; i < MAX_PORT; ++i) + if (dc->port[i].tty && \ + list_empty(&dc->port[i].tty->hangup_work.entry)) + tty_hangup(dc->port[i].tty); + + while (dc->open_ttys) + msleep(1); + + for (i = dc->index_start; i < dc->index_start + MAX_PORT; ++i) + tty_unregister_device(ntty_driver, i); +} + +/* Deallocate memory for one device */ +static void __devexit nozomi_card_exit(struct pci_dev *pdev) +{ + int i; + struct ctrl_ul ctrl; + struct nozomi *dc = pci_get_drvdata(pdev); + + /* Disable all interrupts */ + dc->last_ier = 0; + writew(dc->last_ier, dc->reg_ier); + + tty_exit(dc); + + /* Send 0x0001, command card to resend the reset token. */ + /* This is to get the reset when the module is reloaded. */ + ctrl.port = 0x00; + ctrl.reserved = 0; + ctrl.RTS = 0; + ctrl.DTR = 1; + DBG1("sending flow control 0x%04X", *((u16 *)&ctrl)); + + /* Setup dc->reg addresses to we can use defines here */ + write_mem32(dc->port[PORT_CTRL].ul_addr[0], (u32 *)&ctrl, 2); + writew(CTRL_UL, dc->reg_fcr); /* push the token to the card. */ + + remove_sysfs_files(dc); + + free_irq(pdev->irq, dc); + + for (i = 0; i < MAX_PORT; i++) + if (dc->port[i].fifo_ul) + kfifo_free(dc->port[i].fifo_ul); + + kfree(dc->send_buf); + + iounmap(dc->base_addr); + + pci_release_regions(pdev); + + pci_disable_device(pdev); + + ndevs[dc->index_start / MAX_PORT] = NULL; + + kfree(dc); +} + +static void set_rts(const struct tty_struct *tty, int rts) +{ + struct port *port = get_port_by_tty(tty); + + port->ctrl_ul.RTS = rts; + port->update_flow_control = 1; + enable_transmit_ul(PORT_CTRL, get_dc_by_tty(tty)); +} + +static void set_dtr(const struct tty_struct *tty, int dtr) +{ + struct port *port = get_port_by_tty(tty); + + DBG1("SETTING DTR index: %d, dtr: %d", tty->index, dtr); + + port->ctrl_ul.DTR = dtr; + port->update_flow_control = 1; + enable_transmit_ul(PORT_CTRL, get_dc_by_tty(tty)); +} + +/* + * ---------------------------------------------------------------------------- + * TTY code + * ---------------------------------------------------------------------------- + */ + +/* Called when the userspace process opens the tty, /dev/noz*. */ +static int ntty_open(struct tty_struct *tty, struct file *file) +{ + struct port *port = get_port_by_tty(tty); + struct nozomi *dc = get_dc_by_tty(tty); + unsigned long flags; + + if (!port || !dc) + return -ENODEV; + + if (mutex_lock_interruptible(&port->tty_sem)) + return -ERESTARTSYS; + + port->tty_open_count++; + dc->open_ttys++; + + /* Enable interrupt downlink for channel */ + if (port->tty_open_count == 1) { + tty->low_latency = 1; + tty->driver_data = port; + port->tty = tty; + DBG1("open: %d", port->token_dl); + spin_lock_irqsave(&dc->spin_mutex, flags); + dc->last_ier = dc->last_ier | port->token_dl; + writew(dc->last_ier, dc->reg_ier); + spin_unlock_irqrestore(&dc->spin_mutex, flags); + } + + mutex_unlock(&port->tty_sem); + + return 0; +} + +/* Called when the userspace process close the tty, /dev/noz*. */ +static void ntty_close(struct tty_struct *tty, struct file *file) +{ + struct nozomi *dc = get_dc_by_tty(tty); + struct port *port = tty->driver_data; + unsigned long flags; + + if (!dc || !port) + return; + + if (mutex_lock_interruptible(&port->tty_sem)) + return; + + if (!port->tty_open_count) + goto exit; + + dc->open_ttys--; + port->tty_open_count--; + + if (port->tty_open_count == 0) { + DBG1("close: %d", port->token_dl); + spin_lock_irqsave(&dc->spin_mutex, flags); + dc->last_ier &= ~(port->token_dl); + writew(dc->last_ier, dc->reg_ier); + spin_unlock_irqrestore(&dc->spin_mutex, flags); + } + +exit: + mutex_unlock(&port->tty_sem); +} + +/* + * called when the userspace process writes to the tty (/dev/noz*). + * Data is inserted into a fifo, which is then read and transfered to the modem. + */ +static int ntty_write(struct tty_struct *tty, const unsigned char *buffer, + int count) +{ + int rval = -EINVAL; + struct nozomi *dc = get_dc_by_tty(tty); + struct port *port = tty->driver_data; + unsigned long flags; + + /* DBG1( "WRITEx: %d, index = %d", count, index); */ + + if (!dc || !port) + return -ENODEV; + + if (unlikely(!mutex_trylock(&port->tty_sem))) { + /* + * must test lock as tty layer wraps calls + * to this function with BKL + */ + dev_err(&dc->pdev->dev, "Would have deadlocked - " + "return EAGAIN\n"); + return -EAGAIN; + } + + if (unlikely(!port->tty_open_count)) { + DBG1(" "); + goto exit; + } + + rval = __kfifo_put(port->fifo_ul, (unsigned char *)buffer, count); + + /* notify card */ + if (unlikely(dc == NULL)) { + DBG1("No device context?"); + goto exit; + } + + spin_lock_irqsave(&dc->spin_mutex, flags); + /* CTS is only valid on the modem channel */ + if (port == &(dc->port[PORT_MDM])) { + if (port->ctrl_dl.CTS) { + DBG4("Enable interrupt"); + enable_transmit_ul(tty->index % MAX_PORT, dc); + } else { + dev_err(&dc->pdev->dev, + "CTS not active on modem port?\n"); + } + } else { + enable_transmit_ul(tty->index % MAX_PORT, dc); + } + spin_unlock_irqrestore(&dc->spin_mutex, flags); + +exit: + mutex_unlock(&port->tty_sem); + return rval; +} + +/* + * Calculate how much is left in device + * This method is called by the upper tty layer. + * #according to sources N_TTY.c it expects a value >= 0 and + * does not check for negative values. + */ +static int ntty_write_room(struct tty_struct *tty) +{ + struct port *port = tty->driver_data; + int room = 0; + const struct nozomi *dc = get_dc_by_tty(tty); + + if (!dc || !port) + return 0; + if (!mutex_trylock(&port->tty_sem)) + return 0; + + if (!port->tty_open_count) + goto exit; + + room = port->fifo_ul->size - __kfifo_len(port->fifo_ul); + +exit: + mutex_unlock(&port->tty_sem); + return room; +} + +/* Gets io control parameters */ +static int ntty_tiocmget(struct tty_struct *tty, struct file *file) +{ + const struct port *port = tty->driver_data; + const struct ctrl_dl *ctrl_dl = &port->ctrl_dl; + const struct ctrl_ul *ctrl_ul = &port->ctrl_ul; + + return (ctrl_ul->RTS ? TIOCM_RTS : 0) | + (ctrl_ul->DTR ? TIOCM_DTR : 0) | + (ctrl_dl->DCD ? TIOCM_CAR : 0) | + (ctrl_dl->RI ? TIOCM_RNG : 0) | + (ctrl_dl->DSR ? TIOCM_DSR : 0) | + (ctrl_dl->CTS ? TIOCM_CTS : 0); +} + +/* Sets io controls parameters */ +static int ntty_tiocmset(struct tty_struct *tty, struct file *file, + unsigned int set, unsigned int clear) +{ + if (set & TIOCM_RTS) + set_rts(tty, 1); + else if (clear & TIOCM_RTS) + set_rts(tty, 0); + + if (set & TIOCM_DTR) + set_dtr(tty, 1); + else if (clear & TIOCM_DTR) + set_dtr(tty, 0); + + return 0; +} + +static int ntty_cflags_changed(struct port *port, unsigned long flags, + struct async_icount *cprev) +{ + const struct async_icount cnow = port->tty_icount; + int ret; + + ret = ((flags & TIOCM_RNG) && (cnow.rng != cprev->rng)) || + ((flags & TIOCM_DSR) && (cnow.dsr != cprev->dsr)) || + ((flags & TIOCM_CD) && (cnow.dcd != cprev->dcd)) || + ((flags & TIOCM_CTS) && (cnow.cts != cprev->cts)); + + *cprev = cnow; + + return ret; +} + +static int ntty_ioctl_tiocgicount(struct port *port, void __user *argp) +{ + const struct async_icount cnow = port->tty_icount; + struct serial_icounter_struct icount; + + icount.cts = cnow.cts; + icount.dsr = cnow.dsr; + icount.rng = cnow.rng; + icount.dcd = cnow.dcd; + icount.rx = cnow.rx; + icount.tx = cnow.tx; + icount.frame = cnow.frame; + icount.overrun = cnow.overrun; + icount.parity = cnow.parity; + icount.brk = cnow.brk; + icount.buf_overrun = cnow.buf_overrun; + + return copy_to_user(argp, &icount, sizeof(icount)); +} + +static int ntty_ioctl(struct tty_struct *tty, struct file *file, + unsigned int cmd, unsigned long arg) +{ + struct port *port = tty->driver_data; + void __user *argp = (void __user *)arg; + int rval = -ENOIOCTLCMD; + + DBG1("******** IOCTL, cmd: %d", cmd); + + switch (cmd) { + case TIOCMIWAIT: { + struct async_icount cprev = port->tty_icount; + + rval = wait_event_interruptible(port->tty_wait, + ntty_cflags_changed(port, arg, &cprev)); + break; + } case TIOCGICOUNT: + rval = ntty_ioctl_tiocgicount(port, argp); + break; + default: + DBG1("ERR: 0x%08X, %d", cmd, cmd); + break; + }; + + return rval; +} + +/* + * Called by the upper tty layer when tty buffers are ready + * to receive data again after a call to throttle. + */ +static void ntty_unthrottle(struct tty_struct *tty) +{ + struct nozomi *dc = get_dc_by_tty(tty); + unsigned long flags; + + DBG1("UNTHROTTLE"); + spin_lock_irqsave(&dc->spin_mutex, flags); + enable_transmit_dl(tty->index % MAX_PORT, dc); + set_rts(tty, 1); + + spin_unlock_irqrestore(&dc->spin_mutex, flags); +} + +/* + * Called by the upper tty layer when the tty buffers are almost full. + * The driver should stop send more data. + */ +static void ntty_throttle(struct tty_struct *tty) +{ + struct nozomi *dc = get_dc_by_tty(tty); + unsigned long flags; + + DBG1("THROTTLE"); + spin_lock_irqsave(&dc->spin_mutex, flags); + set_rts(tty, 0); + spin_unlock_irqrestore(&dc->spin_mutex, flags); +} + +/* just to discard single character writes */ +static void ntty_put_char(struct tty_struct *tty, unsigned char c) +{ + /* + * card does not react correct when we write single chars + * to the card, so we discard them + */ + DBG2("PUT CHAR Function: %c", c); +} + +/* Returns number of chars in buffer, called by tty layer */ +static s32 ntty_chars_in_buffer(struct tty_struct *tty) +{ + struct port *port = tty->driver_data; + struct nozomi *dc = get_dc_by_tty(tty); + s32 rval; + + if (unlikely(!dc || !port)) { + rval = -ENODEV; + goto exit_in_buffer; + } + + if (unlikely(!port->tty_open_count)) { + dev_err(&dc->pdev->dev, "No tty open?\n"); + rval = -ENODEV; + goto exit_in_buffer; + } + + rval = __kfifo_len(port->fifo_ul); + +exit_in_buffer: + return rval; +} + +static const struct tty_operations tty_ops = { + .ioctl = ntty_ioctl, + .open = ntty_open, + .close = ntty_close, + .write = ntty_write, + .write_room = ntty_write_room, + .unthrottle = ntty_unthrottle, + .throttle = ntty_throttle, + .chars_in_buffer = ntty_chars_in_buffer, + .put_char = ntty_put_char, + .tiocmget = ntty_tiocmget, + .tiocmset = ntty_tiocmset, +}; + +/* Module initialization */ +static struct pci_driver nozomi_driver = { + .name = NOZOMI_NAME, + .id_table = nozomi_pci_tbl, + .probe = nozomi_card_init, + .remove = __devexit_p(nozomi_card_exit), +}; + +static __init int nozomi_init(void) +{ + int ret; + + printk(KERN_INFO "Initializing %s\n", VERSION_STRING); + + ntty_driver = alloc_tty_driver(NTTY_TTY_MAXMINORS); + if (!ntty_driver) + return -ENOMEM; + + ntty_driver->owner = THIS_MODULE; + ntty_driver->driver_name = NOZOMI_NAME_TTY; + ntty_driver->name = "noz"; + ntty_driver->major = 0; + ntty_driver->type = TTY_DRIVER_TYPE_SERIAL; + ntty_driver->subtype = SERIAL_TYPE_NORMAL; + ntty_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV; + ntty_driver->init_termios = tty_std_termios; + ntty_driver->init_termios.c_cflag = B115200 | CS8 | CREAD | \ + HUPCL | CLOCAL; + ntty_driver->init_termios.c_ispeed = 115200; + ntty_driver->init_termios.c_ospeed = 115200; + tty_set_operations(ntty_driver, &tty_ops); + + ret = tty_register_driver(ntty_driver); + if (ret) { + printk(KERN_ERR "Nozomi: failed to register ntty driver\n"); + goto free_tty; + } + + ret = pci_register_driver(&nozomi_driver); + if (ret) { + printk(KERN_ERR "Nozomi: can't register pci driver\n"); + goto unr_tty; + } + + return 0; +unr_tty: + tty_unregister_driver(ntty_driver); +free_tty: + put_tty_driver(ntty_driver); + return ret; +} + +static __exit void nozomi_exit(void) +{ + printk(KERN_INFO "Unloading %s\n", DRIVER_DESC); + pci_unregister_driver(&nozomi_driver); + tty_unregister_driver(ntty_driver); + put_tty_driver(ntty_driver); +} + +module_init(nozomi_init); +module_exit(nozomi_exit); + +module_param(debug, int, S_IRUGO | S_IWUSR); + +MODULE_LICENSE("Dual BSD/GPL"); +MODULE_DESCRIPTION(DRIVER_DESC); diff --git a/drivers/char/pcmcia/cm4000_cs.c b/drivers/char/pcmcia/cm4000_cs.c index 02518da6a38..454d7324ba4 100644 --- a/drivers/char/pcmcia/cm4000_cs.c +++ b/drivers/char/pcmcia/cm4000_cs.c @@ -308,7 +308,8 @@ static unsigned int calc_baudv(unsigned char fidi) return (wcrcf / wbrcf); } -static unsigned short io_read_num_rec_bytes(ioaddr_t iobase, unsigned short *s) +static unsigned short io_read_num_rec_bytes(unsigned int iobase, + unsigned short *s) { unsigned short tmp; @@ -426,7 +427,7 @@ static struct card_fixup card_fixups[] = { static void set_cardparameter(struct cm4000_dev *dev) { int i; - ioaddr_t iobase = dev->p_dev->io.BasePort1; + unsigned int iobase = dev->p_dev->io.BasePort1; u_int8_t stopbits = 0x02; /* ISO default */ DEBUGP(3, dev, "-> set_cardparameter\n"); @@ -459,7 +460,7 @@ static int set_protocol(struct cm4000_dev *dev, struct ptsreq *ptsreq) unsigned short num_bytes_read; unsigned char pts_reply[4]; ssize_t rc; - ioaddr_t iobase = dev->p_dev->io.BasePort1; + unsigned int iobase = dev->p_dev->io.BasePort1; rc = 0; @@ -610,7 +611,7 @@ exit_setprotocol: return rc; } -static int io_detect_cm4000(ioaddr_t iobase, struct cm4000_dev *dev) +static int io_detect_cm4000(unsigned int iobase, struct cm4000_dev *dev) { /* note: statemachine is assumed to be reset */ @@ -671,7 +672,7 @@ static void terminate_monitor(struct cm4000_dev *dev) static void monitor_card(unsigned long p) { struct cm4000_dev *dev = (struct cm4000_dev *) p; - ioaddr_t iobase = dev->p_dev->io.BasePort1; + unsigned int iobase = dev->p_dev->io.BasePort1; unsigned short s; struct ptsreq ptsreq; int i, atrc; @@ -933,7 +934,7 @@ static ssize_t cmm_read(struct file *filp, __user char *buf, size_t count, loff_t *ppos) { struct cm4000_dev *dev = filp->private_data; - ioaddr_t iobase = dev->p_dev->io.BasePort1; + unsigned int iobase = dev->p_dev->io.BasePort1; ssize_t rc; int i, j, k; @@ -1054,7 +1055,7 @@ static ssize_t cmm_write(struct file *filp, const char __user *buf, size_t count, loff_t *ppos) { struct cm4000_dev *dev = (struct cm4000_dev *) filp->private_data; - ioaddr_t iobase = dev->p_dev->io.BasePort1; + unsigned int iobase = dev->p_dev->io.BasePort1; unsigned short s; unsigned char tmp; unsigned char infolen; @@ -1408,7 +1409,7 @@ static int cmm_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg) { struct cm4000_dev *dev = filp->private_data; - ioaddr_t iobase = dev->p_dev->io.BasePort1; + unsigned int iobase = dev->p_dev->io.BasePort1; struct pcmcia_device *link; int size; int rc; diff --git a/drivers/char/pcmcia/synclink_cs.c b/drivers/char/pcmcia/synclink_cs.c index 8caff0ca80f..279ff5005ce 100644 --- a/drivers/char/pcmcia/synclink_cs.c +++ b/drivers/char/pcmcia/synclink_cs.c @@ -57,6 +57,7 @@ #include <linux/init.h> #include <linux/delay.h> #include <linux/ioctl.h> +#include <linux/synclink.h> #include <asm/system.h> #include <asm/io.h> @@ -87,8 +88,6 @@ #include <asm/uaccess.h> -#include "linux/synclink.h" - static MGSL_PARAMS default_params = { MGSL_MODE_HDLC, /* unsigned long mode */ 0, /* unsigned char loopback; */ diff --git a/drivers/char/random.c b/drivers/char/random.c index 5fee0566182..f43c89f7c44 100644 --- a/drivers/char/random.c +++ b/drivers/char/random.c @@ -667,8 +667,6 @@ void add_disk_randomness(struct gendisk *disk) add_timer_randomness(disk->random, 0x100 + MKDEV(disk->major, disk->first_minor)); } - -EXPORT_SYMBOL(add_disk_randomness); #endif #define EXTRACT_SIZE 10 @@ -1041,6 +1039,7 @@ write_pool(struct entropy_store *r, const char __user *buffer, size_t count) p += bytes; add_entropy_words(r, buf, (bytes + 3) / 4); + cond_resched(); } return 0; diff --git a/drivers/char/riscom8.c b/drivers/char/riscom8.c index 102ece4c4e0..d130b87d8ed 100644 --- a/drivers/char/riscom8.c +++ b/drivers/char/riscom8.c @@ -47,6 +47,7 @@ #include <linux/init.h> #include <linux/delay.h> #include <linux/tty_flip.h> +#include <linux/spinlock.h> #include <asm/uaccess.h> @@ -81,6 +82,8 @@ static struct tty_driver *riscom_driver; +static DEFINE_SPINLOCK(riscom_lock); + static struct riscom_board rc_board[RC_NBOARD] = { { .base = RC_IOBASE1, @@ -217,13 +220,14 @@ static void __init rc_init_CD180(struct riscom_board const * bp) { unsigned long flags; - save_flags(flags); cli(); + spin_lock_irqsave(&riscom_lock, flags); + rc_out(bp, RC_CTOUT, 0); /* Clear timeout */ rc_wait_CCR(bp); /* Wait for CCR ready */ rc_out(bp, CD180_CCR, CCR_HARDRESET); /* Reset CD180 chip */ - sti(); + spin_unlock_irqrestore(&riscom_lock, flags); msleep(50); /* Delay 0.05 sec */ - cli(); + spin_lock_irqsave(&riscom_lock, flags); rc_out(bp, CD180_GIVR, RC_ID); /* Set ID for this chip */ rc_out(bp, CD180_GICR, 0); /* Clear all bits */ rc_out(bp, CD180_PILR1, RC_ACK_MINT); /* Prio for modem intr */ @@ -234,7 +238,7 @@ static void __init rc_init_CD180(struct riscom_board const * bp) rc_out(bp, CD180_PPRH, (RC_OSCFREQ/(1000000/RISCOM_TPS)) >> 8); rc_out(bp, CD180_PPRL, (RC_OSCFREQ/(1000000/RISCOM_TPS)) & 0xff); - restore_flags(flags); + spin_unlock_irqrestore(&riscom_lock, flags); } /* Main probing routine, also sets irq. */ @@ -812,9 +816,9 @@ static int rc_setup_port(struct riscom_board *bp, struct riscom_port *port) } port->xmit_buf = (unsigned char *) tmp; } - - save_flags(flags); cli(); - + + spin_lock_irqsave(&riscom_lock, flags); + if (port->tty) clear_bit(TTY_IO_ERROR, &port->tty->flags); @@ -825,7 +829,7 @@ static int rc_setup_port(struct riscom_board *bp, struct riscom_port *port) rc_change_speed(bp, port); port->flags |= ASYNC_INITIALIZED; - restore_flags(flags); + spin_unlock_irqrestore(&riscom_lock, flags); return 0; } @@ -901,6 +905,7 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp, int retval; int do_clocal = 0; int CD; + unsigned long flags; /* * If the device is in the middle of being closed, then block @@ -936,19 +941,26 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp, */ retval = 0; add_wait_queue(&port->open_wait, &wait); - cli(); + + spin_lock_irqsave(&riscom_lock, flags); + if (!tty_hung_up_p(filp)) port->count--; - sti(); + + spin_unlock_irqrestore(&riscom_lock, flags); + port->blocked_open++; while (1) { - cli(); + spin_lock_irqsave(&riscom_lock, flags); + rc_out(bp, CD180_CAR, port_No(port)); CD = rc_in(bp, CD180_MSVR) & MSVR_CD; rc_out(bp, CD180_MSVR, MSVR_RTS); bp->DTR &= ~(1u << port_No(port)); rc_out(bp, RC_DTR, bp->DTR); - sti(); + + spin_unlock_irqrestore(&riscom_lock, flags); + set_current_state(TASK_INTERRUPTIBLE); if (tty_hung_up_p(filp) || !(port->flags & ASYNC_INITIALIZED)) { @@ -1020,8 +1032,9 @@ static void rc_close(struct tty_struct * tty, struct file * filp) if (!port || rc_paranoia_check(port, tty->name, "close")) return; - - save_flags(flags); cli(); + + spin_lock_irqsave(&riscom_lock, flags); + if (tty_hung_up_p(filp)) goto out; @@ -1088,7 +1101,9 @@ static void rc_close(struct tty_struct * tty, struct file * filp) } port->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING); wake_up_interruptible(&port->close_wait); -out: restore_flags(flags); + +out: + spin_unlock_irqrestore(&riscom_lock, flags); } static int rc_write(struct tty_struct * tty, @@ -1107,34 +1122,33 @@ static int rc_write(struct tty_struct * tty, if (!tty || !port->xmit_buf) return 0; - save_flags(flags); while (1) { - cli(); + spin_lock_irqsave(&riscom_lock, flags); + c = min_t(int, count, min(SERIAL_XMIT_SIZE - port->xmit_cnt - 1, SERIAL_XMIT_SIZE - port->xmit_head)); - if (c <= 0) { - restore_flags(flags); - break; - } + if (c <= 0) + break; /* lock continues to be held */ memcpy(port->xmit_buf + port->xmit_head, buf, c); port->xmit_head = (port->xmit_head + c) & (SERIAL_XMIT_SIZE-1); port->xmit_cnt += c; - restore_flags(flags); + + spin_unlock_irqrestore(&riscom_lock, flags); buf += c; count -= c; total += c; } - cli(); if (port->xmit_cnt && !tty->stopped && !tty->hw_stopped && !(port->IER & IER_TXRDY)) { port->IER |= IER_TXRDY; rc_out(bp, CD180_CAR, port_No(port)); rc_out(bp, CD180_IER, port->IER); } - restore_flags(flags); + + spin_unlock_irqrestore(&riscom_lock, flags); return total; } @@ -1150,7 +1164,7 @@ static void rc_put_char(struct tty_struct * tty, unsigned char ch) if (!tty || !port->xmit_buf) return; - save_flags(flags); cli(); + spin_lock_irqsave(&riscom_lock, flags); if (port->xmit_cnt >= SERIAL_XMIT_SIZE - 1) goto out; @@ -1158,7 +1172,9 @@ static void rc_put_char(struct tty_struct * tty, unsigned char ch) port->xmit_buf[port->xmit_head++] = ch; port->xmit_head &= SERIAL_XMIT_SIZE - 1; port->xmit_cnt++; -out: restore_flags(flags); + +out: + spin_unlock_irqrestore(&riscom_lock, flags); } static void rc_flush_chars(struct tty_struct * tty) @@ -1173,11 +1189,13 @@ static void rc_flush_chars(struct tty_struct * tty) !port->xmit_buf) return; - save_flags(flags); cli(); + spin_lock_irqsave(&riscom_lock, flags); + port->IER |= IER_TXRDY; rc_out(port_Board(port), CD180_CAR, port_No(port)); rc_out(port_Board(port), CD180_IER, port->IER); - restore_flags(flags); + + spin_unlock_irqrestore(&riscom_lock, flags); } static int rc_write_room(struct tty_struct * tty) @@ -1212,9 +1230,11 @@ static void rc_flush_buffer(struct tty_struct *tty) if (rc_paranoia_check(port, tty->name, "rc_flush_buffer")) return; - save_flags(flags); cli(); + spin_lock_irqsave(&riscom_lock, flags); + port->xmit_cnt = port->xmit_head = port->xmit_tail = 0; - restore_flags(flags); + + spin_unlock_irqrestore(&riscom_lock, flags); tty_wakeup(tty); } @@ -1231,11 +1251,15 @@ static int rc_tiocmget(struct tty_struct *tty, struct file *file) return -ENODEV; bp = port_Board(port); - save_flags(flags); cli(); + + spin_lock_irqsave(&riscom_lock, flags); + rc_out(bp, CD180_CAR, port_No(port)); status = rc_in(bp, CD180_MSVR); result = rc_in(bp, RC_RI) & (1u << port_No(port)) ? 0 : TIOCM_RNG; - restore_flags(flags); + + spin_unlock_irqrestore(&riscom_lock, flags); + result |= ((status & MSVR_RTS) ? TIOCM_RTS : 0) | ((status & MSVR_DTR) ? TIOCM_DTR : 0) | ((status & MSVR_CD) ? TIOCM_CAR : 0) @@ -1256,7 +1280,8 @@ static int rc_tiocmset(struct tty_struct *tty, struct file *file, bp = port_Board(port); - save_flags(flags); cli(); + spin_lock_irqsave(&riscom_lock, flags); + if (set & TIOCM_RTS) port->MSVR |= MSVR_RTS; if (set & TIOCM_DTR) @@ -1270,7 +1295,9 @@ static int rc_tiocmset(struct tty_struct *tty, struct file *file, rc_out(bp, CD180_CAR, port_No(port)); rc_out(bp, CD180_MSVR, port->MSVR); rc_out(bp, RC_DTR, bp->DTR); - restore_flags(flags); + + spin_unlock_irqrestore(&riscom_lock, flags); + return 0; } @@ -1279,7 +1306,8 @@ static inline void rc_send_break(struct riscom_port * port, unsigned long length struct riscom_board *bp = port_Board(port); unsigned long flags; - save_flags(flags); cli(); + spin_lock_irqsave(&riscom_lock, flags); + port->break_length = RISCOM_TPS / HZ * length; port->COR2 |= COR2_ETC; port->IER |= IER_TXRDY; @@ -1289,7 +1317,8 @@ static inline void rc_send_break(struct riscom_port * port, unsigned long length rc_wait_CCR(bp); rc_out(bp, CD180_CCR, CCR_CORCHG2); rc_wait_CCR(bp); - restore_flags(flags); + + spin_unlock_irqrestore(&riscom_lock, flags); } static inline int rc_set_serial_info(struct riscom_port * port, @@ -1298,7 +1327,6 @@ static inline int rc_set_serial_info(struct riscom_port * port, struct serial_struct tmp; struct riscom_board *bp = port_Board(port); int change_speed; - unsigned long flags; if (copy_from_user(&tmp, newinfo, sizeof(tmp))) return -EFAULT; @@ -1332,9 +1360,11 @@ static inline int rc_set_serial_info(struct riscom_port * port, port->closing_wait = tmp.closing_wait; } if (change_speed) { - save_flags(flags); cli(); + unsigned long flags; + + spin_lock_irqsave(&riscom_lock, flags); rc_change_speed(bp, port); - restore_flags(flags); + spin_unlock_irqrestore(&riscom_lock, flags); } return 0; } @@ -1414,17 +1444,19 @@ static void rc_throttle(struct tty_struct * tty) return; bp = port_Board(port); - - save_flags(flags); cli(); + + spin_lock_irqsave(&riscom_lock, flags); + port->MSVR &= ~MSVR_RTS; rc_out(bp, CD180_CAR, port_No(port)); - if (I_IXOFF(tty)) { + if (I_IXOFF(tty)) { rc_wait_CCR(bp); rc_out(bp, CD180_CCR, CCR_SSCH2); rc_wait_CCR(bp); } rc_out(bp, CD180_MSVR, port->MSVR); - restore_flags(flags); + + spin_unlock_irqrestore(&riscom_lock, flags); } static void rc_unthrottle(struct tty_struct * tty) @@ -1438,7 +1470,8 @@ static void rc_unthrottle(struct tty_struct * tty) bp = port_Board(port); - save_flags(flags); cli(); + spin_lock_irqsave(&riscom_lock, flags); + port->MSVR |= MSVR_RTS; rc_out(bp, CD180_CAR, port_No(port)); if (I_IXOFF(tty)) { @@ -1447,7 +1480,8 @@ static void rc_unthrottle(struct tty_struct * tty) rc_wait_CCR(bp); } rc_out(bp, CD180_MSVR, port->MSVR); - restore_flags(flags); + + spin_unlock_irqrestore(&riscom_lock, flags); } static void rc_stop(struct tty_struct * tty) @@ -1461,11 +1495,13 @@ static void rc_stop(struct tty_struct * tty) bp = port_Board(port); - save_flags(flags); cli(); + spin_lock_irqsave(&riscom_lock, flags); + port->IER &= ~IER_TXRDY; rc_out(bp, CD180_CAR, port_No(port)); rc_out(bp, CD180_IER, port->IER); - restore_flags(flags); + + spin_unlock_irqrestore(&riscom_lock, flags); } static void rc_start(struct tty_struct * tty) @@ -1479,13 +1515,15 @@ static void rc_start(struct tty_struct * tty) bp = port_Board(port); - save_flags(flags); cli(); + spin_lock_irqsave(&riscom_lock, flags); + if (port->xmit_cnt && port->xmit_buf && !(port->IER & IER_TXRDY)) { port->IER |= IER_TXRDY; rc_out(bp, CD180_CAR, port_No(port)); rc_out(bp, CD180_IER, port->IER); } - restore_flags(flags); + + spin_unlock_irqrestore(&riscom_lock, flags); } /* @@ -1537,9 +1575,9 @@ static void rc_set_termios(struct tty_struct * tty, struct ktermios * old_termio tty->termios->c_iflag == old_termios->c_iflag) return; - save_flags(flags); cli(); + spin_lock_irqsave(&riscom_lock, flags); rc_change_speed(port_Board(port), port); - restore_flags(flags); + spin_unlock_irqrestore(&riscom_lock, flags); if ((old_termios->c_cflag & CRTSCTS) && !(tty->termios->c_cflag & CRTSCTS)) { @@ -1627,11 +1665,12 @@ static void rc_release_drivers(void) { unsigned long flags; - save_flags(flags); - cli(); + spin_lock_irqsave(&riscom_lock, flags); + tty_unregister_driver(riscom_driver); put_tty_driver(riscom_driver); - restore_flags(flags); + + spin_unlock_irqrestore(&riscom_lock, flags); } #ifndef MODULE diff --git a/drivers/char/rtc.c b/drivers/char/rtc.c index 0c66b802736..78b151c4d20 100644 --- a/drivers/char/rtc.c +++ b/drivers/char/rtc.c @@ -1,5 +1,5 @@ /* - * Real Time Clock interface for Linux + * Real Time Clock interface for Linux * * Copyright (C) 1996 Paul Gortmaker * @@ -17,7 +17,7 @@ * has been received. If a RTC interrupt has already happened, * it will output an unsigned long and then block. The output value * contains the interrupt status in the low byte and the number of - * interrupts since the last read in the remaining high bytes. The + * interrupts since the last read in the remaining high bytes. The * /dev/rtc interface can also be used with the select(2) call. * * This program is free software; you can redistribute it and/or @@ -104,12 +104,14 @@ static int rtc_has_irq = 1; #ifndef CONFIG_HPET_EMULATE_RTC #define is_hpet_enabled() 0 -#define hpet_set_alarm_time(hrs, min, sec) 0 -#define hpet_set_periodic_freq(arg) 0 -#define hpet_mask_rtc_irq_bit(arg) 0 -#define hpet_set_rtc_irq_bit(arg) 0 -#define hpet_rtc_timer_init() do { } while (0) -#define hpet_rtc_dropped_irq() 0 +#define hpet_set_alarm_time(hrs, min, sec) 0 +#define hpet_set_periodic_freq(arg) 0 +#define hpet_mask_rtc_irq_bit(arg) 0 +#define hpet_set_rtc_irq_bit(arg) 0 +#define hpet_rtc_timer_init() do { } while (0) +#define hpet_rtc_dropped_irq() 0 +#define hpet_register_irq_handler(h) 0 +#define hpet_unregister_irq_handler(h) 0 #ifdef RTC_IRQ static irqreturn_t hpet_rtc_interrupt(int irq, void *dev_id) { @@ -147,7 +149,7 @@ static int rtc_ioctl(struct inode *inode, struct file *file, static unsigned int rtc_poll(struct file *file, poll_table *wait); #endif -static void get_rtc_alm_time (struct rtc_time *alm_tm); +static void get_rtc_alm_time(struct rtc_time *alm_tm); #ifdef RTC_IRQ static void set_rtc_irq_bit_locked(unsigned char bit); static void mask_rtc_irq_bit_locked(unsigned char bit); @@ -185,9 +187,9 @@ static int rtc_proc_open(struct inode *inode, struct file *file); * rtc_status but before mod_timer is called, which would then reenable the * timer (but you would need to have an awful timing before you'd trip on it) */ -static unsigned long rtc_status = 0; /* bitmapped status byte. */ -static unsigned long rtc_freq = 0; /* Current periodic IRQ rate */ -static unsigned long rtc_irq_data = 0; /* our output to the world */ +static unsigned long rtc_status; /* bitmapped status byte. */ +static unsigned long rtc_freq; /* Current periodic IRQ rate */ +static unsigned long rtc_irq_data; /* our output to the world */ static unsigned long rtc_max_user_freq = 64; /* > this, need CAP_SYS_RESOURCE */ #ifdef RTC_IRQ @@ -195,7 +197,7 @@ static unsigned long rtc_max_user_freq = 64; /* > this, need CAP_SYS_RESOURCE */ * rtc_task_lock nests inside rtc_lock. */ static DEFINE_SPINLOCK(rtc_task_lock); -static rtc_task_t *rtc_callback = NULL; +static rtc_task_t *rtc_callback; #endif /* @@ -205,7 +207,7 @@ static rtc_task_t *rtc_callback = NULL; static unsigned long epoch = 1900; /* year corresponding to 0x00 */ -static const unsigned char days_in_mo[] = +static const unsigned char days_in_mo[] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; /* @@ -242,7 +244,7 @@ irqreturn_t rtc_interrupt(int irq, void *dev_id) * the last read in the remainder of rtc_irq_data. */ - spin_lock (&rtc_lock); + spin_lock(&rtc_lock); rtc_irq_data += 0x100; rtc_irq_data &= ~0xff; if (is_hpet_enabled()) { @@ -259,16 +261,16 @@ irqreturn_t rtc_interrupt(int irq, void *dev_id) if (rtc_status & RTC_TIMER_ON) mod_timer(&rtc_irq_timer, jiffies + HZ/rtc_freq + 2*HZ/100); - spin_unlock (&rtc_lock); + spin_unlock(&rtc_lock); /* Now do the rest of the actions */ spin_lock(&rtc_task_lock); if (rtc_callback) rtc_callback->func(rtc_callback->private_data); spin_unlock(&rtc_task_lock); - wake_up_interruptible(&rtc_wait); + wake_up_interruptible(&rtc_wait); - kill_fasync (&rtc_async_queue, SIGIO, POLL_IN); + kill_fasync(&rtc_async_queue, SIGIO, POLL_IN); return IRQ_HANDLED; } @@ -335,7 +337,7 @@ static ssize_t rtc_read(struct file *file, char __user *buf, DECLARE_WAITQUEUE(wait, current); unsigned long data; ssize_t retval; - + if (rtc_has_irq == 0) return -EIO; @@ -358,11 +360,11 @@ static ssize_t rtc_read(struct file *file, char __user *buf, * confusing. And no, xchg() is not the answer. */ __set_current_state(TASK_INTERRUPTIBLE); - - spin_lock_irq (&rtc_lock); + + spin_lock_irq(&rtc_lock); data = rtc_irq_data; rtc_irq_data = 0; - spin_unlock_irq (&rtc_lock); + spin_unlock_irq(&rtc_lock); if (data != 0) break; @@ -378,10 +380,13 @@ static ssize_t rtc_read(struct file *file, char __user *buf, schedule(); } while (1); - if (count == sizeof(unsigned int)) - retval = put_user(data, (unsigned int __user *)buf) ?: sizeof(int); - else - retval = put_user(data, (unsigned long __user *)buf) ?: sizeof(long); + if (count == sizeof(unsigned int)) { + retval = put_user(data, + (unsigned int __user *)buf) ?: sizeof(int); + } else { + retval = put_user(data, + (unsigned long __user *)buf) ?: sizeof(long); + } if (!retval) retval = count; out: @@ -394,7 +399,7 @@ static ssize_t rtc_read(struct file *file, char __user *buf, static int rtc_do_ioctl(unsigned int cmd, unsigned long arg, int kernel) { - struct rtc_time wtime; + struct rtc_time wtime; #ifdef RTC_IRQ if (rtc_has_irq == 0) { @@ -426,35 +431,41 @@ static int rtc_do_ioctl(unsigned int cmd, unsigned long arg, int kernel) } case RTC_PIE_OFF: /* Mask periodic int. enab. bit */ { - unsigned long flags; /* can be called from isr via rtc_control() */ - spin_lock_irqsave (&rtc_lock, flags); + /* can be called from isr via rtc_control() */ + unsigned long flags; + + spin_lock_irqsave(&rtc_lock, flags); mask_rtc_irq_bit_locked(RTC_PIE); if (rtc_status & RTC_TIMER_ON) { rtc_status &= ~RTC_TIMER_ON; del_timer(&rtc_irq_timer); } - spin_unlock_irqrestore (&rtc_lock, flags); + spin_unlock_irqrestore(&rtc_lock, flags); + return 0; } case RTC_PIE_ON: /* Allow periodic ints */ { - unsigned long flags; /* can be called from isr via rtc_control() */ + /* can be called from isr via rtc_control() */ + unsigned long flags; + /* * We don't really want Joe User enabling more * than 64Hz of interrupts on a multi-user machine. */ if (!kernel && (rtc_freq > rtc_max_user_freq) && - (!capable(CAP_SYS_RESOURCE))) + (!capable(CAP_SYS_RESOURCE))) return -EACCES; - spin_lock_irqsave (&rtc_lock, flags); + spin_lock_irqsave(&rtc_lock, flags); if (!(rtc_status & RTC_TIMER_ON)) { mod_timer(&rtc_irq_timer, jiffies + HZ/rtc_freq + 2*HZ/100); rtc_status |= RTC_TIMER_ON; } set_rtc_irq_bit_locked(RTC_PIE); - spin_unlock_irqrestore (&rtc_lock, flags); + spin_unlock_irqrestore(&rtc_lock, flags); + return 0; } case RTC_UIE_OFF: /* Mask ints from RTC updates. */ @@ -477,7 +488,7 @@ static int rtc_do_ioctl(unsigned int cmd, unsigned long arg, int kernel) */ memset(&wtime, 0, sizeof(struct rtc_time)); get_rtc_alm_time(&wtime); - break; + break; } case RTC_ALM_SET: /* Store a time into the alarm */ { @@ -505,16 +516,21 @@ static int rtc_do_ioctl(unsigned int cmd, unsigned long arg, int kernel) */ } if (!(CMOS_READ(RTC_CONTROL) & RTC_DM_BINARY) || - RTC_ALWAYS_BCD) - { - if (sec < 60) BIN_TO_BCD(sec); - else sec = 0xff; - - if (min < 60) BIN_TO_BCD(min); - else min = 0xff; - - if (hrs < 24) BIN_TO_BCD(hrs); - else hrs = 0xff; + RTC_ALWAYS_BCD) { + if (sec < 60) + BIN_TO_BCD(sec); + else + sec = 0xff; + + if (min < 60) + BIN_TO_BCD(min); + else + min = 0xff; + + if (hrs < 24) + BIN_TO_BCD(hrs); + else + hrs = 0xff; } CMOS_WRITE(hrs, RTC_HOURS_ALARM); CMOS_WRITE(min, RTC_MINUTES_ALARM); @@ -563,11 +579,12 @@ static int rtc_do_ioctl(unsigned int cmd, unsigned long arg, int kernel) if (day > (days_in_mo[mon] + ((mon == 2) && leap_yr))) return -EINVAL; - + if ((hrs >= 24) || (min >= 60) || (sec >= 60)) return -EINVAL; - if ((yrs -= epoch) > 255) /* They are unsigned */ + yrs -= epoch; + if (yrs > 255) /* They are unsigned */ return -EINVAL; spin_lock_irq(&rtc_lock); @@ -635,9 +652,10 @@ static int rtc_do_ioctl(unsigned int cmd, unsigned long arg, int kernel) { int tmp = 0; unsigned char val; - unsigned long flags; /* can be called from isr via rtc_control() */ + /* can be called from isr via rtc_control() */ + unsigned long flags; - /* + /* * The max we can do is 8192Hz. */ if ((arg < 2) || (arg > 8192)) @@ -646,7 +664,8 @@ static int rtc_do_ioctl(unsigned int cmd, unsigned long arg, int kernel) * We don't really want Joe User generating more * than 64Hz of interrupts on a multi-user machine. */ - if (!kernel && (arg > rtc_max_user_freq) && (!capable(CAP_SYS_RESOURCE))) + if (!kernel && (arg > rtc_max_user_freq) && + !capable(CAP_SYS_RESOURCE)) return -EACCES; while (arg > (1<<tmp)) @@ -674,11 +693,11 @@ static int rtc_do_ioctl(unsigned int cmd, unsigned long arg, int kernel) #endif case RTC_EPOCH_READ: /* Read the epoch. */ { - return put_user (epoch, (unsigned long __user *)arg); + return put_user(epoch, (unsigned long __user *)arg); } case RTC_EPOCH_SET: /* Set the epoch. */ { - /* + /* * There were no RTC clocks before 1900. */ if (arg < 1900) @@ -693,7 +712,8 @@ static int rtc_do_ioctl(unsigned int cmd, unsigned long arg, int kernel) default: return -ENOTTY; } - return copy_to_user((void __user *)arg, &wtime, sizeof wtime) ? -EFAULT : 0; + return copy_to_user((void __user *)arg, + &wtime, sizeof wtime) ? -EFAULT : 0; } static int rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd, @@ -712,26 +732,25 @@ static int rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd, * needed here. Or anywhere else in this driver. */ static int rtc_open(struct inode *inode, struct file *file) { - spin_lock_irq (&rtc_lock); + spin_lock_irq(&rtc_lock); - if(rtc_status & RTC_IS_OPEN) + if (rtc_status & RTC_IS_OPEN) goto out_busy; rtc_status |= RTC_IS_OPEN; rtc_irq_data = 0; - spin_unlock_irq (&rtc_lock); + spin_unlock_irq(&rtc_lock); return 0; out_busy: - spin_unlock_irq (&rtc_lock); + spin_unlock_irq(&rtc_lock); return -EBUSY; } -static int rtc_fasync (int fd, struct file *filp, int on) - +static int rtc_fasync(int fd, struct file *filp, int on) { - return fasync_helper (fd, filp, on, &rtc_async_queue); + return fasync_helper(fd, filp, on, &rtc_async_queue); } static int rtc_release(struct inode *inode, struct file *file) @@ -762,16 +781,16 @@ static int rtc_release(struct inode *inode, struct file *file) } spin_unlock_irq(&rtc_lock); - if (file->f_flags & FASYNC) { - rtc_fasync (-1, file, 0); - } + if (file->f_flags & FASYNC) + rtc_fasync(-1, file, 0); no_irq: #endif - spin_lock_irq (&rtc_lock); + spin_lock_irq(&rtc_lock); rtc_irq_data = 0; rtc_status &= ~RTC_IS_OPEN; - spin_unlock_irq (&rtc_lock); + spin_unlock_irq(&rtc_lock); + return 0; } @@ -786,9 +805,9 @@ static unsigned int rtc_poll(struct file *file, poll_table *wait) poll_wait(file, &rtc_wait, wait); - spin_lock_irq (&rtc_lock); + spin_lock_irq(&rtc_lock); l = rtc_irq_data; - spin_unlock_irq (&rtc_lock); + spin_unlock_irq(&rtc_lock); if (l != 0) return POLLIN | POLLRDNORM; @@ -796,14 +815,6 @@ static unsigned int rtc_poll(struct file *file, poll_table *wait) } #endif -/* - * exported stuffs - */ - -EXPORT_SYMBOL(rtc_register); -EXPORT_SYMBOL(rtc_unregister); -EXPORT_SYMBOL(rtc_control); - int rtc_register(rtc_task_t *task) { #ifndef RTC_IRQ @@ -829,6 +840,7 @@ int rtc_register(rtc_task_t *task) return 0; #endif } +EXPORT_SYMBOL(rtc_register); int rtc_unregister(rtc_task_t *task) { @@ -845,7 +857,7 @@ int rtc_unregister(rtc_task_t *task) return -ENXIO; } rtc_callback = NULL; - + /* disable controls */ if (!hpet_mask_rtc_irq_bit(RTC_PIE | RTC_AIE | RTC_UIE)) { tmp = CMOS_READ(RTC_CONTROL); @@ -865,6 +877,7 @@ int rtc_unregister(rtc_task_t *task) return 0; #endif } +EXPORT_SYMBOL(rtc_unregister); int rtc_control(rtc_task_t *task, unsigned int cmd, unsigned long arg) { @@ -883,7 +896,7 @@ int rtc_control(rtc_task_t *task, unsigned int cmd, unsigned long arg) return rtc_do_ioctl(cmd, arg, 1); #endif } - +EXPORT_SYMBOL(rtc_control); /* * The various file operations we support. @@ -910,11 +923,11 @@ static struct miscdevice rtc_dev = { #ifdef CONFIG_PROC_FS static const struct file_operations rtc_proc_fops = { - .owner = THIS_MODULE, - .open = rtc_proc_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, + .owner = THIS_MODULE, + .open = rtc_proc_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, }; #endif @@ -965,7 +978,7 @@ static int __init rtc_init(void) #ifdef CONFIG_SPARC32 for_each_ebus(ebus) { for_each_ebusdev(edev, ebus) { - if(strcmp(edev->prom_node->name, "rtc") == 0) { + if (strcmp(edev->prom_node->name, "rtc") == 0) { rtc_port = edev->resource[0].start; rtc_irq = edev->irqs[0]; goto found; @@ -986,7 +999,8 @@ found: * XXX Interrupt pin #7 in Espresso is shared between RTC and * PCI Slot 2 INTA# (and some INTx# in Slot 1). */ - if (request_irq(rtc_irq, rtc_interrupt, IRQF_SHARED, "rtc", (void *)&rtc_port)) { + if (request_irq(rtc_irq, rtc_interrupt, IRQF_SHARED, "rtc", + (void *)&rtc_port)) { rtc_has_irq = 0; printk(KERN_ERR "rtc: cannot register IRQ %d\n", rtc_irq); return -EIO; @@ -1015,16 +1029,26 @@ no_irq: #ifdef RTC_IRQ if (is_hpet_enabled()) { + int err; + rtc_int_handler_ptr = hpet_rtc_interrupt; + err = hpet_register_irq_handler(rtc_interrupt); + if (err != 0) { + printk(KERN_WARNING "hpet_register_irq_handler failed " + "in rtc_init()."); + return err; + } } else { rtc_int_handler_ptr = rtc_interrupt; } - if(request_irq(RTC_IRQ, rtc_int_handler_ptr, IRQF_DISABLED, "rtc", NULL)) { + if (request_irq(RTC_IRQ, rtc_int_handler_ptr, IRQF_DISABLED, + "rtc", NULL)) { /* Yeah right, seeing as irq 8 doesn't even hit the bus. */ rtc_has_irq = 0; printk(KERN_ERR "rtc: IRQ %d is not free.\n", RTC_IRQ); rtc_release_region(); + return -EIO; } hpet_rtc_timer_init(); @@ -1036,6 +1060,7 @@ no_irq: if (misc_register(&rtc_dev)) { #ifdef RTC_IRQ free_irq(RTC_IRQ, NULL); + hpet_unregister_irq_handler(rtc_interrupt); rtc_has_irq = 0; #endif rtc_release_region(); @@ -1052,21 +1077,21 @@ no_irq: #if defined(__alpha__) || defined(__mips__) rtc_freq = HZ; - + /* Each operating system on an Alpha uses its own epoch. Let's try to guess which one we are using now. */ - + if (rtc_is_updating() != 0) msleep(20); - + spin_lock_irq(&rtc_lock); year = CMOS_READ(RTC_YEAR); ctrl = CMOS_READ(RTC_CONTROL); spin_unlock_irq(&rtc_lock); - + if (!(ctrl & RTC_DM_BINARY) || RTC_ALWAYS_BCD) BCD_TO_BIN(year); /* This should never happen... */ - + if (year < 20) { epoch = 2000; guess = "SRM (post-2000)"; @@ -1087,7 +1112,8 @@ no_irq: #endif } if (guess) - printk(KERN_INFO "rtc: %s epoch (%lu) detected\n", guess, epoch); + printk(KERN_INFO "rtc: %s epoch (%lu) detected\n", + guess, epoch); #endif #ifdef RTC_IRQ if (rtc_has_irq == 0) @@ -1096,8 +1122,12 @@ no_irq: spin_lock_irq(&rtc_lock); rtc_freq = 1024; if (!hpet_set_periodic_freq(rtc_freq)) { - /* Initialize periodic freq. to CMOS reset default, which is 1024Hz */ - CMOS_WRITE(((CMOS_READ(RTC_FREQ_SELECT) & 0xF0) | 0x06), RTC_FREQ_SELECT); + /* + * Initialize periodic frequency to CMOS reset default, + * which is 1024Hz + */ + CMOS_WRITE(((CMOS_READ(RTC_FREQ_SELECT) & 0xF0) | 0x06), + RTC_FREQ_SELECT); } spin_unlock_irq(&rtc_lock); no_irq2: @@ -1110,20 +1140,22 @@ no_irq2: return 0; } -static void __exit rtc_exit (void) +static void __exit rtc_exit(void) { cleanup_sysctl(); - remove_proc_entry ("driver/rtc", NULL); + remove_proc_entry("driver/rtc", NULL); misc_deregister(&rtc_dev); #ifdef CONFIG_SPARC32 if (rtc_has_irq) - free_irq (rtc_irq, &rtc_port); + free_irq(rtc_irq, &rtc_port); #else rtc_release_region(); #ifdef RTC_IRQ - if (rtc_has_irq) - free_irq (RTC_IRQ, NULL); + if (rtc_has_irq) { + free_irq(RTC_IRQ, NULL); + hpet_unregister_irq_handler(hpet_rtc_interrupt); + } #endif #endif /* CONFIG_SPARC32 */ } @@ -1133,14 +1165,14 @@ module_exit(rtc_exit); #ifdef RTC_IRQ /* - * At IRQ rates >= 4096Hz, an interrupt may get lost altogether. + * At IRQ rates >= 4096Hz, an interrupt may get lost altogether. * (usually during an IDE disk interrupt, with IRQ unmasking off) * Since the interrupt handler doesn't get called, the IRQ status * byte doesn't get read, and the RTC stops generating interrupts. * A timer is set, and will call this function if/when that happens. * To get it out of this stalled state, we just read the status. * At least a jiffy of interrupts (rtc_freq/HZ) will have been lost. - * (You *really* shouldn't be trying to use a non-realtime system + * (You *really* shouldn't be trying to use a non-realtime system * for something that requires a steady > 1KHz signal anyways.) */ @@ -1148,7 +1180,7 @@ static void rtc_dropped_irq(unsigned long data) { unsigned long freq; - spin_lock_irq (&rtc_lock); + spin_lock_irq(&rtc_lock); if (hpet_rtc_dropped_irq()) { spin_unlock_irq(&rtc_lock); @@ -1167,13 +1199,15 @@ static void rtc_dropped_irq(unsigned long data) spin_unlock_irq(&rtc_lock); - if (printk_ratelimit()) - printk(KERN_WARNING "rtc: lost some interrupts at %ldHz.\n", freq); + if (printk_ratelimit()) { + printk(KERN_WARNING "rtc: lost some interrupts at %ldHz.\n", + freq); + } /* Now we have new data */ wake_up_interruptible(&rtc_wait); - kill_fasync (&rtc_async_queue, SIGIO, POLL_IN); + kill_fasync(&rtc_async_queue, SIGIO, POLL_IN); } #endif @@ -1277,7 +1311,7 @@ void rtc_get_rtc_time(struct rtc_time *rtc_tm) * can take just over 2ms. We wait 20ms. There is no need to * to poll-wait (up to 1s - eeccch) for the falling edge of RTC_UIP. * If you need to know *exactly* when a second has started, enable - * periodic update complete interrupts, (via ioctl) and then + * periodic update complete interrupts, (via ioctl) and then * immediately read /dev/rtc which will block until you get the IRQ. * Once the read clears, read the RTC time (again via ioctl). Easy. */ @@ -1307,8 +1341,7 @@ void rtc_get_rtc_time(struct rtc_time *rtc_tm) ctrl = CMOS_READ(RTC_CONTROL); spin_unlock_irqrestore(&rtc_lock, flags); - if (!(ctrl & RTC_DM_BINARY) || RTC_ALWAYS_BCD) - { + if (!(ctrl & RTC_DM_BINARY) || RTC_ALWAYS_BCD) { BCD_TO_BIN(rtc_tm->tm_sec); BCD_TO_BIN(rtc_tm->tm_min); BCD_TO_BIN(rtc_tm->tm_hour); @@ -1326,7 +1359,8 @@ void rtc_get_rtc_time(struct rtc_time *rtc_tm) * Account for differences between how the RTC uses the values * and how they are defined in a struct rtc_time; */ - if ((rtc_tm->tm_year += (epoch - 1900)) <= 69) + rtc_tm->tm_year += epoch - 1900; + if (rtc_tm->tm_year <= 69) rtc_tm->tm_year += 100; rtc_tm->tm_mon--; @@ -1347,8 +1381,7 @@ static void get_rtc_alm_time(struct rtc_time *alm_tm) ctrl = CMOS_READ(RTC_CONTROL); spin_unlock_irq(&rtc_lock); - if (!(ctrl & RTC_DM_BINARY) || RTC_ALWAYS_BCD) - { + if (!(ctrl & RTC_DM_BINARY) || RTC_ALWAYS_BCD) { BCD_TO_BIN(alm_tm->tm_sec); BCD_TO_BIN(alm_tm->tm_min); BCD_TO_BIN(alm_tm->tm_hour); diff --git a/drivers/char/ser_a2232.c b/drivers/char/ser_a2232.c index 3c869145bfd..4ba3aec9e1c 100644 --- a/drivers/char/ser_a2232.c +++ b/drivers/char/ser_a2232.c @@ -653,7 +653,7 @@ static void a2232_init_portstructs(void) port->gs.closing_wait = 30 * HZ; port->gs.rd = &a2232_real_driver; #ifdef NEW_WRITE_LOCKING - init_MUTEX(&(port->gs.port_write_mutex)); + mutex_init(&(port->gs.port_write_mutex)); #endif init_waitqueue_head(&port->gs.open_wait); init_waitqueue_head(&port->gs.close_wait); diff --git a/drivers/char/sonypi.c b/drivers/char/sonypi.c index 877e53dcb99..921c6d2bc8f 100644 --- a/drivers/char/sonypi.c +++ b/drivers/char/sonypi.c @@ -1163,7 +1163,7 @@ static struct acpi_driver sonypi_acpi_driver = { }; #endif -static int __devinit sonypi_create_input_devices(void) +static int __devinit sonypi_create_input_devices(struct platform_device *pdev) { struct input_dev *jog_dev; struct input_dev *key_dev; @@ -1177,6 +1177,7 @@ static int __devinit sonypi_create_input_devices(void) jog_dev->name = "Sony Vaio Jogdial"; jog_dev->id.bustype = BUS_ISA; jog_dev->id.vendor = PCI_VENDOR_ID_SONY; + jog_dev->dev.parent = &pdev->dev; jog_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REL); jog_dev->keybit[BIT_WORD(BTN_MOUSE)] = BIT_MASK(BTN_MIDDLE); @@ -1191,6 +1192,7 @@ static int __devinit sonypi_create_input_devices(void) key_dev->name = "Sony Vaio Keys"; key_dev->id.bustype = BUS_ISA; key_dev->id.vendor = PCI_VENDOR_ID_SONY; + key_dev->dev.parent = &pdev->dev; /* Initialize the Input Drivers: special keys */ key_dev->evbit[0] = BIT_MASK(EV_KEY); @@ -1385,7 +1387,7 @@ static int __devinit sonypi_probe(struct platform_device *dev) if (useinput) { - error = sonypi_create_input_devices(); + error = sonypi_create_input_devices(dev); if (error) { printk(KERN_ERR "sonypi: failed to create input devices\n"); @@ -1432,7 +1434,7 @@ static int __devexit sonypi_remove(struct platform_device *dev) { sonypi_disable(); - synchronize_sched(); /* Allow sonypi interrupt to complete. */ + synchronize_irq(sonypi_device.irq); flush_scheduled_work(); if (useinput) { diff --git a/drivers/char/synclink.c b/drivers/char/synclink.c index 905d1f51a7b..ddc74d1f4f1 100644 --- a/drivers/char/synclink.c +++ b/drivers/char/synclink.c @@ -85,6 +85,7 @@ #include <linux/vmalloc.h> #include <linux/init.h> #include <linux/ioctl.h> +#include <linux/synclink.h> #include <asm/system.h> #include <asm/io.h> @@ -110,8 +111,6 @@ #include <asm/uaccess.h> -#include "linux/synclink.h" - #define RCLRVALUE 0xffff static MGSL_PARAMS default_params = { @@ -1544,7 +1543,7 @@ static void mgsl_isr_receive_data( struct mgsl_struct *info ) /* mgsl_isr_misc() * - * Service a miscellaneos interrupt source. + * Service a miscellaneous interrupt source. * * Arguments: info pointer to device extension (instance data) * Return Value: None diff --git a/drivers/char/synclink_gt.c b/drivers/char/synclink_gt.c index 64e835f6243..1f954acf2ba 100644 --- a/drivers/char/synclink_gt.c +++ b/drivers/char/synclink_gt.c @@ -73,6 +73,7 @@ #include <linux/bitops.h> #include <linux/workqueue.h> #include <linux/hdlc.h> +#include <linux/synclink.h> #include <asm/system.h> #include <asm/io.h> @@ -81,8 +82,6 @@ #include <asm/types.h> #include <asm/uaccess.h> -#include "linux/synclink.h" - #if defined(CONFIG_HDLC) || (defined(CONFIG_HDLC_MODULE) && defined(CONFIG_SYNCLINK_GT_MODULE)) #define SYNCLINK_GENERIC_HDLC 1 #else @@ -2040,37 +2039,41 @@ static void bh_transmit(struct slgt_info *info) tty_wakeup(tty); } -static void dsr_change(struct slgt_info *info) +static void dsr_change(struct slgt_info *info, unsigned short status) { - get_signals(info); + if (status & BIT3) { + info->signals |= SerialSignal_DSR; + info->input_signal_events.dsr_up++; + } else { + info->signals &= ~SerialSignal_DSR; + info->input_signal_events.dsr_down++; + } DBGISR(("dsr_change %s signals=%04X\n", info->device_name, info->signals)); if ((info->dsr_chkcount)++ == IO_PIN_SHUTDOWN_LIMIT) { slgt_irq_off(info, IRQ_DSR); return; } info->icount.dsr++; - if (info->signals & SerialSignal_DSR) - info->input_signal_events.dsr_up++; - else - info->input_signal_events.dsr_down++; wake_up_interruptible(&info->status_event_wait_q); wake_up_interruptible(&info->event_wait_q); info->pending_bh |= BH_STATUS; } -static void cts_change(struct slgt_info *info) +static void cts_change(struct slgt_info *info, unsigned short status) { - get_signals(info); + if (status & BIT2) { + info->signals |= SerialSignal_CTS; + info->input_signal_events.cts_up++; + } else { + info->signals &= ~SerialSignal_CTS; + info->input_signal_events.cts_down++; + } DBGISR(("cts_change %s signals=%04X\n", info->device_name, info->signals)); if ((info->cts_chkcount)++ == IO_PIN_SHUTDOWN_LIMIT) { slgt_irq_off(info, IRQ_CTS); return; } info->icount.cts++; - if (info->signals & SerialSignal_CTS) - info->input_signal_events.cts_up++; - else - info->input_signal_events.cts_down++; wake_up_interruptible(&info->status_event_wait_q); wake_up_interruptible(&info->event_wait_q); info->pending_bh |= BH_STATUS; @@ -2091,20 +2094,21 @@ static void cts_change(struct slgt_info *info) } } -static void dcd_change(struct slgt_info *info) +static void dcd_change(struct slgt_info *info, unsigned short status) { - get_signals(info); + if (status & BIT1) { + info->signals |= SerialSignal_DCD; + info->input_signal_events.dcd_up++; + } else { + info->signals &= ~SerialSignal_DCD; + info->input_signal_events.dcd_down++; + } DBGISR(("dcd_change %s signals=%04X\n", info->device_name, info->signals)); if ((info->dcd_chkcount)++ == IO_PIN_SHUTDOWN_LIMIT) { slgt_irq_off(info, IRQ_DCD); return; } info->icount.dcd++; - if (info->signals & SerialSignal_DCD) { - info->input_signal_events.dcd_up++; - } else { - info->input_signal_events.dcd_down++; - } #if SYNCLINK_GENERIC_HDLC if (info->netcount) { if (info->signals & SerialSignal_DCD) @@ -2127,20 +2131,21 @@ static void dcd_change(struct slgt_info *info) } } -static void ri_change(struct slgt_info *info) +static void ri_change(struct slgt_info *info, unsigned short status) { - get_signals(info); + if (status & BIT0) { + info->signals |= SerialSignal_RI; + info->input_signal_events.ri_up++; + } else { + info->signals &= ~SerialSignal_RI; + info->input_signal_events.ri_down++; + } DBGISR(("ri_change %s signals=%04X\n", info->device_name, info->signals)); if ((info->ri_chkcount)++ == IO_PIN_SHUTDOWN_LIMIT) { slgt_irq_off(info, IRQ_RI); return; } - info->icount.dcd++; - if (info->signals & SerialSignal_RI) { - info->input_signal_events.ri_up++; - } else { - info->input_signal_events.ri_down++; - } + info->icount.rng++; wake_up_interruptible(&info->status_event_wait_q); wake_up_interruptible(&info->event_wait_q); info->pending_bh |= BH_STATUS; @@ -2191,13 +2196,13 @@ static void isr_serial(struct slgt_info *info) } if (status & IRQ_DSR) - dsr_change(info); + dsr_change(info, status); if (status & IRQ_CTS) - cts_change(info); + cts_change(info, status); if (status & IRQ_DCD) - dcd_change(info); + dcd_change(info, status); if (status & IRQ_RI) - ri_change(info); + ri_change(info, status); } static void isr_rdma(struct slgt_info *info) diff --git a/drivers/char/synclinkmp.c b/drivers/char/synclinkmp.c index c63013b2fc3..f3e7807f78d 100644 --- a/drivers/char/synclinkmp.c +++ b/drivers/char/synclinkmp.c @@ -66,6 +66,7 @@ #include <linux/termios.h> #include <linux/workqueue.h> #include <linux/hdlc.h> +#include <linux/synclink.h> #if defined(CONFIG_HDLC) || (defined(CONFIG_HDLC_MODULE) && defined(CONFIG_SYNCLINKMP_MODULE)) #define SYNCLINK_GENERIC_HDLC 1 @@ -80,8 +81,6 @@ #include <asm/uaccess.h> -#include "linux/synclink.h" - static MGSL_PARAMS default_params = { MGSL_MODE_HDLC, /* unsigned long mode */ 0, /* unsigned char loopback; */ diff --git a/drivers/char/tipar.c b/drivers/char/tipar.c deleted file mode 100644 index cef55c40654..00000000000 --- a/drivers/char/tipar.c +++ /dev/null @@ -1,557 +0,0 @@ -/* Hey EMACS -*- linux-c -*- - * - * tipar - low level driver for handling a parallel link cable designed - * for Texas Instruments graphing calculators (http://lpg.ticalc.org). - * A part of the TiLP project. - * - * Copyright (C) 2000-2002, Romain Lievin <roms@lpg.ticalc.org> - * under the terms of the GNU General Public License. - * - * Various fixes & clean-up from the Linux Kernel Mailing List - * (Alan Cox, Richard B. Johnson, Christoph Hellwig). - */ - -/* This driver should, in theory, work with any parallel port that has an - * appropriate low-level driver; all I/O is done through the parport - * abstraction layer. - * - * If this driver is built into the kernel, you can configure it using the - * kernel command-line. For example: - * - * tipar=timeout,delay (set timeout and delay) - * - * If the driver is loaded as a module, similar functionality is available - * using module parameters. The equivalent of the above commands would be: - * - * # insmod tipar timeout=15 delay=10 - */ - -/* COMPATIBILITY WITH OLD KERNELS - * - * Usually, parallel cables were bound to ports at - * particular I/O addresses, as follows: - * - * tipar0 0x378 - * tipar1 0x278 - * tipar2 0x3bc - * - * - * This driver, by default, binds tipar devices according to parport and - * the minor number. - * - */ -#undef DEBUG /* change to #define to get debugging - * output - for pr_debug() */ -#include <linux/module.h> -#include <linux/types.h> -#include <linux/errno.h> -#include <linux/kernel.h> -#include <linux/sched.h> -#include <linux/delay.h> -#include <linux/fcntl.h> -#include <linux/fs.h> -#include <linux/init.h> -#include <asm/uaccess.h> -#include <linux/ioport.h> -#include <asm/io.h> -#include <linux/bitops.h> -#include <linux/parport.h> /* Our code depend on parport */ -#include <linux/device.h> - -/* - * TI definitions - */ -#include <linux/ticable.h> - -/* - * Version Information - */ -#define DRIVER_VERSION "1.19" -#define DRIVER_AUTHOR "Romain Lievin <roms@lpg.ticalc.org>" -#define DRIVER_DESC "Device driver for TI/PC parallel link cables" -#define DRIVER_LICENSE "GPL" - -#define VERSION(ver,rel,seq) (((ver)<<16) | ((rel)<<8) | (seq)) - -/* ----- global variables --------------------------------------------- */ - -struct tipar_struct { - struct pardevice *dev; /* Parport device entry */ -}; - -#define PP_NO 3 -static struct tipar_struct table[PP_NO]; - -static int delay = IO_DELAY; /* inter-bit delay in microseconds */ -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 *tipar_class; - -/* --- macros for parport access -------------------------------------- */ - -#define r_dtr(x) (parport_read_data(table[(x)].dev->port)) -#define r_str(x) (parport_read_status(table[(x)].dev->port)) -#define w_ctr(x,y) (parport_write_control(table[(x)].dev->port, (y))) -#define w_dtr(x,y) (parport_write_data(table[(x)].dev->port, (y))) - -/* --- setting states on the D-bus with the right timing: ------------- */ - -static inline void -outbyte(int value, int minor) -{ - w_dtr(minor, value); -} - -static inline int -inbyte(int minor) -{ - return (r_str(minor)); -} - -static inline void -init_ti_parallel(int minor) -{ - outbyte(3, minor); -} - -/* ----- global defines ----------------------------------------------- */ - -#define START(x) { x = jiffies + (HZ * timeout) / 10; } -#define WAIT(x) { \ - if (time_before((x), jiffies)) return -1; \ - if (need_resched()) schedule(); } - -/* ----- D-bus bit-banging functions ---------------------------------- */ - -/* D-bus protocol (45kbit/s max): - 1 0 0 - _______ ______|______ __________|________ __________ -Red : ________ | ____ | ____ - _ ____________|________ ______|__________ _____ -White: ________ | ______ | _______ -*/ - -/* Try to transmit a byte on the specified port (-1 if error). */ -static int -put_ti_parallel(int minor, unsigned char data) -{ - unsigned int bit; - unsigned long max; - - for (bit = 0; bit < 8; bit++) { - if (data & 1) { - outbyte(2, minor); - START(max); - do { - WAIT(max); - } while (inbyte(minor) & 0x10); - - outbyte(3, minor); - START(max); - do { - WAIT(max); - } while (!(inbyte(minor) & 0x10)); - } else { - outbyte(1, minor); - START(max); - do { - WAIT(max); - } while (inbyte(minor) & 0x20); - - outbyte(3, minor); - START(max); - do { - WAIT(max); - } while (!(inbyte(minor) & 0x20)); - } - - data >>= 1; - udelay(delay); - - if (need_resched()) - schedule(); - } - - return 0; -} - -/* Receive a byte on the specified port or -1 if error. */ -static int -get_ti_parallel(int minor) -{ - unsigned int bit; - unsigned char v, data = 0; - unsigned long max; - - for (bit = 0; bit < 8; bit++) { - START(max); - do { - WAIT(max); - } while ((v = inbyte(minor) & 0x30) == 0x30); - - if (v == 0x10) { - data = (data >> 1) | 0x80; - outbyte(1, minor); - START(max); - do { - WAIT(max); - } while (!(inbyte(minor) & 0x20)); - outbyte(3, minor); - } else { - data = data >> 1; - outbyte(2, minor); - START(max); - do { - WAIT(max); - } while (!(inbyte(minor) & 0x10)); - outbyte(3, minor); - } - - udelay(delay); - if (need_resched()) - schedule(); - } - - return (int) data; -} - -/* Try to detect a parallel link cable on the specified port */ -static int -probe_ti_parallel(int minor) -{ - int i; - int seq[] = { 0x00, 0x20, 0x10, 0x30 }; - int data; - - for (i = 3; i >= 0; i--) { - outbyte(3, minor); - outbyte(i, minor); - udelay(delay); - data = inbyte(minor) & 0x30; - pr_debug("tipar: Probing -> %i: 0x%02x 0x%02x\n", i, - data, seq[i]); - if (data != seq[i]) { - outbyte(3, minor); - return -1; - } - } - - outbyte(3, minor); - return 0; -} - -/* ----- kernel module functions--------------------------------------- */ - -static int -tipar_open(struct inode *inode, struct file *file) -{ - unsigned int minor = iminor(inode) - TIPAR_MINOR; - - if (tp_count == 0 || minor > tp_count - 1) - return -ENXIO; - - if (test_and_set_bit(minor, &opened)) - return -EBUSY; - - if (!table[minor].dev) { - printk(KERN_ERR "%s: NULL device for minor %u\n", - __FUNCTION__, minor); - return -ENXIO; - } - parport_claim_or_block(table[minor].dev); - init_ti_parallel(minor); - parport_release(table[minor].dev); - - return nonseekable_open(inode, file); -} - -static int -tipar_close(struct inode *inode, struct file *file) -{ - unsigned int minor = iminor(inode) - TIPAR_MINOR; - - if (minor > tp_count - 1) - return -ENXIO; - - clear_bit(minor, &opened); - - return 0; -} - -static ssize_t -tipar_write (struct file *file, const char __user *buf, size_t count, - loff_t * ppos) -{ - unsigned int minor = iminor(file->f_path.dentry->d_inode) - TIPAR_MINOR; - ssize_t n; - - parport_claim_or_block(table[minor].dev); - - for (n = 0; n < count; n++) { - unsigned char b; - - if (get_user(b, buf + n)) { - n = -EFAULT; - goto out; - } - - if (put_ti_parallel(minor, b) == -1) { - init_ti_parallel(minor); - n = -ETIMEDOUT; - goto out; - } - } - out: - parport_release(table[minor].dev); - return n; -} - -static ssize_t -tipar_read(struct file *file, char __user *buf, size_t count, loff_t * ppos) -{ - int b = 0; - unsigned int minor = iminor(file->f_path.dentry->d_inode) - TIPAR_MINOR; - ssize_t retval = 0; - ssize_t n = 0; - - if (count == 0) - return 0; - - parport_claim_or_block(table[minor].dev); - - while (n < count) { - b = get_ti_parallel(minor); - if (b == -1) { - init_ti_parallel(minor); - retval = -ETIMEDOUT; - goto out; - } else { - if (put_user(b, buf + n)) { - retval = -EFAULT; - break; - } else - retval = ++n; - } - - /* Non-blocking mode : try again ! */ - if (file->f_flags & O_NONBLOCK) { - retval = -EAGAIN; - goto out; - } - - /* Signal pending, try again ! */ - if (signal_pending(current)) { - retval = -ERESTARTSYS; - goto out; - } - - if (need_resched()) - schedule(); - } - - out: - parport_release(table[minor].dev); - return retval; -} - -static int -tipar_ioctl(struct inode *inode, struct file *file, - unsigned int cmd, unsigned long arg) -{ - int retval = 0; - - switch (cmd) { - case IOCTL_TIPAR_DELAY: - delay = (int)arg; //get_user(delay, &arg); - break; - case IOCTL_TIPAR_TIMEOUT: - if (arg != 0) - timeout = (int)arg; - else - retval = -EINVAL; - break; - default: - retval = -ENOTTY; - break; - } - - return retval; -} - -/* ----- kernel module registering ------------------------------------ */ - -static const struct file_operations tipar_fops = { - .owner = THIS_MODULE, - .llseek = no_llseek, - .read = tipar_read, - .write = tipar_write, - .ioctl = tipar_ioctl, - .open = tipar_open, - .release = tipar_close, -}; - -/* --- initialisation code ------------------------------------- */ - -#ifndef MODULE -/* You must set these - there is no sane way to probe for this cable. - * You can use 'tipar=timeout,delay' to set these now. */ -static int __init -tipar_setup(char *str) -{ - int ints[3]; - - str = get_options(str, ARRAY_SIZE(ints), ints); - - if (ints[0] > 0) { - if (ints[1] != 0) - timeout = ints[1]; - else - printk(KERN_WARNING "tipar: bad timeout value (0), " - "using default value instead"); - if (ints[0] > 1) { - delay = ints[2]; - } - } - - return 1; -} -#endif - -/* - * Register our module into parport. - * Pass also 2 callbacks functions to parport: a pre-emptive function and an - * interrupt handler function (unused). - * Display a message such "tipar0: using parport0 (polling)". - */ -static int -tipar_register(int nr, struct parport *port) -{ - int err = 0; - - /* Register our module into parport */ - table[nr].dev = parport_register_device(port, "tipar", - NULL, NULL, NULL, 0, - (void *) &table[nr]); - - if (table[nr].dev == NULL) { - err = 1; - goto out; - } - - device_create(tipar_class, port->dev, MKDEV(TIPAR_MAJOR, - TIPAR_MINOR + nr), "par%d", nr); - - /* Display informations */ - pr_info("tipar%d: using %s (%s)\n", nr, port->name, (port->irq == - PARPORT_IRQ_NONE) ? "polling" : "interrupt-driven"); - - if (probe_ti_parallel(nr) != -1) - pr_info("tipar%d: link cable found\n", nr); - else - pr_info("tipar%d: link cable not found\n", nr); - - err = 0; - -out: - return err; -} - -static void -tipar_attach(struct parport *port) -{ - if (tp_count == PP_NO) { - pr_info("tipar: ignoring parallel port (max. %d)\n", PP_NO); - return; - } - - if (!tipar_register(tp_count, port)) - tp_count++; -} - -static void -tipar_detach(struct parport *port) -{ - /* Nothing to do */ -} - -static struct parport_driver tipar_driver = { - .name = "tipar", - .attach = tipar_attach, - .detach = tipar_detach, -}; - -static int __init -tipar_init_module(void) -{ - int err = 0; - - pr_info("tipar: parallel link cable driver, version %s\n", - DRIVER_VERSION); - - if (register_chrdev(TIPAR_MAJOR, "tipar", &tipar_fops)) { - printk(KERN_ERR "tipar: unable to get major %d\n", TIPAR_MAJOR); - err = -EIO; - goto out; - } - - tipar_class = class_create(THIS_MODULE, "ticables"); - if (IS_ERR(tipar_class)) { - err = PTR_ERR(tipar_class); - goto out_chrdev; - } - if (parport_register_driver(&tipar_driver)) { - printk(KERN_ERR "tipar: unable to register with parport\n"); - err = -EIO; - goto out_class; - } - - err = 0; - goto out; - -out_class: - class_destroy(tipar_class); - -out_chrdev: - unregister_chrdev(TIPAR_MAJOR, "tipar"); -out: - return err; -} - -static void __exit -tipar_cleanup_module(void) -{ - unsigned int i; - - /* Unregistering module */ - parport_unregister_driver(&tipar_driver); - - unregister_chrdev(TIPAR_MAJOR, "tipar"); - - for (i = 0; i < PP_NO; i++) { - if (table[i].dev == NULL) - continue; - parport_unregister_device(table[i].dev); - device_destroy(tipar_class, MKDEV(TIPAR_MAJOR, i)); - } - class_destroy(tipar_class); - - pr_info("tipar: module unloaded\n"); -} - -/* --------------------------------------------------------------------- */ - -__setup("tipar=", tipar_setup); -module_init(tipar_init_module); -module_exit(tipar_cleanup_module); - -MODULE_AUTHOR(DRIVER_AUTHOR); -MODULE_DESCRIPTION(DRIVER_DESC); -MODULE_LICENSE(DRIVER_LICENSE); - -module_param(timeout, int, 0); -MODULE_PARM_DESC(timeout, "Timeout (default=1.5 seconds)"); -module_param(delay, int, 0); -MODULE_PARM_DESC(delay, "Inter-bit delay (default=10 microseconds)"); diff --git a/drivers/char/toshiba.c b/drivers/char/toshiba.c index 5422f999636..ce5ebe3b168 100644 --- a/drivers/char/toshiba.c +++ b/drivers/char/toshiba.c @@ -505,7 +505,7 @@ static int __init toshiba_init(void) if (tosh_probe()) return -ENODEV; - printk(KERN_INFO "Toshiba System Managment Mode driver v" TOSH_VERSION "\n"); + printk(KERN_INFO "Toshiba System Management Mode driver v" TOSH_VERSION "\n"); /* set the port to use for Fn status if not specified as a parameter */ if (tosh_fn==0x00) diff --git a/drivers/char/tpm/tpm.c b/drivers/char/tpm/tpm.c index 39564b76d4a..a5d8bcb4000 100644 --- a/drivers/char/tpm/tpm.c +++ b/drivers/char/tpm/tpm.c @@ -1031,27 +1031,16 @@ void tpm_remove_hardware(struct device *dev) spin_unlock(&driver_lock); - dev_set_drvdata(dev, NULL); misc_deregister(&chip->vendor.miscdev); - kfree(chip->vendor.miscdev.name); sysfs_remove_group(&dev->kobj, chip->vendor.attr_group); tpm_bios_log_teardown(chip->bios_dir); - clear_bit(chip->dev_num, dev_mask); - - kfree(chip); - - put_device(dev); + /* write it this way to be explicit (chip->dev == dev) */ + put_device(chip->dev); } EXPORT_SYMBOL_GPL(tpm_remove_hardware); -static u8 savestate[] = { - 0, 193, /* TPM_TAG_RQU_COMMAND */ - 0, 0, 0, 10, /* blob length (in bytes) */ - 0, 0, 0, 152 /* TPM_ORD_SaveState */ -}; - /* * We are about to suspend. Save the TPM state * so that it can be restored. @@ -1059,6 +1048,12 @@ static u8 savestate[] = { int tpm_pm_suspend(struct device *dev, pm_message_t pm_state) { struct tpm_chip *chip = dev_get_drvdata(dev); + u8 savestate[] = { + 0, 193, /* TPM_TAG_RQU_COMMAND */ + 0, 0, 0, 10, /* blob length (in bytes) */ + 0, 0, 0, 152 /* TPM_ORD_SaveState */ + }; + if (chip == NULL) return -ENODEV; @@ -1083,6 +1078,26 @@ int tpm_pm_resume(struct device *dev) EXPORT_SYMBOL_GPL(tpm_pm_resume); /* + * Once all references to platform device are down to 0, + * release all allocated structures. + * In case vendor provided release function, + * call it too. + */ +static void tpm_dev_release(struct device *dev) +{ + struct tpm_chip *chip = dev_get_drvdata(dev); + + if (chip->vendor.release) + chip->vendor.release(dev); + + chip->release(dev); + + clear_bit(chip->dev_num, dev_mask); + kfree(chip->vendor.miscdev.name); + kfree(chip); +} + +/* * Called from tpm_<specific>.c probe function only for devices * the driver has determined it should claim. Prior to calling * this function the specific probe function has called pci_enable_device @@ -1136,23 +1151,21 @@ struct tpm_chip *tpm_register_hardware(struct device *dev, const struct tpm_vend chip->vendor.miscdev.parent = dev; chip->dev = get_device(dev); + chip->release = dev->release; + dev->release = tpm_dev_release; + dev_set_drvdata(dev, chip); if (misc_register(&chip->vendor.miscdev)) { dev_err(chip->dev, "unable to misc_register %s, minor %d\n", chip->vendor.miscdev.name, chip->vendor.miscdev.minor); - put_device(dev); - clear_bit(chip->dev_num, dev_mask); - kfree(chip); - kfree(devname); + put_device(chip->dev); return NULL; } spin_lock(&driver_lock); - dev_set_drvdata(dev, chip); - list_add(&chip->list, &tpm_chip_list); spin_unlock(&driver_lock); @@ -1160,10 +1173,7 @@ struct tpm_chip *tpm_register_hardware(struct device *dev, const struct tpm_vend if (sysfs_create_group(&dev->kobj, chip->vendor.attr_group)) { list_del(&chip->list); misc_deregister(&chip->vendor.miscdev); - put_device(dev); - clear_bit(chip->dev_num, dev_mask); - kfree(chip); - kfree(devname); + put_device(chip->dev); return NULL; } diff --git a/drivers/char/tpm/tpm.h b/drivers/char/tpm/tpm.h index d15ccddc92e..e885148b4cf 100644 --- a/drivers/char/tpm/tpm.h +++ b/drivers/char/tpm/tpm.h @@ -74,6 +74,7 @@ struct tpm_vendor_specific { int (*send) (struct tpm_chip *, u8 *, size_t); void (*cancel) (struct tpm_chip *); u8 (*status) (struct tpm_chip *); + void (*release) (struct device *); struct miscdevice miscdev; struct attribute_group *attr_group; struct list_head list; @@ -106,6 +107,7 @@ struct tpm_chip { struct dentry **bios_dir; struct list_head list; + void (*release) (struct device *); }; #define to_tpm_chip(n) container_of(n, struct tpm_chip, vendor) diff --git a/drivers/char/tpm/tpm_infineon.c b/drivers/char/tpm/tpm_infineon.c index 967002a5a1e..726ee8a0277 100644 --- a/drivers/char/tpm/tpm_infineon.c +++ b/drivers/char/tpm/tpm_infineon.c @@ -611,7 +611,7 @@ static __devexit void tpm_inf_pnp_remove(struct pnp_dev *dev) } } -static struct pnp_driver tpm_inf_pnp = { +static struct pnp_driver tpm_inf_pnp_driver = { .name = "tpm_inf_pnp", .driver = { .owner = THIS_MODULE, @@ -625,12 +625,12 @@ static struct pnp_driver tpm_inf_pnp = { static int __init init_inf(void) { - return pnp_register_driver(&tpm_inf_pnp); + return pnp_register_driver(&tpm_inf_pnp_driver); } static void __exit cleanup_inf(void) { - pnp_unregister_driver(&tpm_inf_pnp); + pnp_unregister_driver(&tpm_inf_pnp_driver); } module_init(init_inf); diff --git a/drivers/char/tpm/tpm_tis.c b/drivers/char/tpm/tpm_tis.c index fd771a4d6d1..81503d94fec 100644 --- a/drivers/char/tpm/tpm_tis.c +++ b/drivers/char/tpm/tpm_tis.c @@ -450,6 +450,11 @@ static int tpm_tis_init(struct device *dev, resource_size_t start, goto out_err; } + if (request_locality(chip, 0) != 0) { + rc = -ENODEV; + goto out_err; + } + vendor = ioread32(chip->vendor.iobase + TPM_DID_VID(0)); /* Default timeouts */ @@ -487,11 +492,6 @@ static int tpm_tis_init(struct device *dev, resource_size_t start, if (intfcaps & TPM_INTF_DATA_AVAIL_INT) dev_dbg(dev, "\tData Avail Int Support\n"); - if (request_locality(chip, 0) != 0) { - rc = -ENODEV; - goto out_err; - } - /* INTERRUPT Setup */ init_waitqueue_head(&chip->vendor.read_queue); init_waitqueue_head(&chip->vendor.int_queue); diff --git a/drivers/char/tty_audit.c b/drivers/char/tty_audit.c index d222012c1b0..bacded0eefa 100644 --- a/drivers/char/tty_audit.c +++ b/drivers/char/tty_audit.c @@ -73,6 +73,7 @@ static void tty_audit_buf_put(struct tty_audit_buf *buf) * @tsk with @loginuid. @buf->mutex must be locked. */ static void tty_audit_buf_push(struct task_struct *tsk, uid_t loginuid, + unsigned int sessionid, struct tty_audit_buf *buf) { struct audit_buffer *ab; @@ -85,9 +86,9 @@ static void tty_audit_buf_push(struct task_struct *tsk, uid_t loginuid, if (ab) { char name[sizeof(tsk->comm)]; - audit_log_format(ab, "tty pid=%u uid=%u auid=%u major=%d " - "minor=%d comm=", tsk->pid, tsk->uid, - loginuid, buf->major, buf->minor); + audit_log_format(ab, "tty pid=%u uid=%u auid=%u ses=%u " + "major=%d minor=%d comm=", tsk->pid, tsk->uid, + loginuid, sessionid, buf->major, buf->minor); get_task_comm(name, tsk); audit_log_untrustedstring(ab, name); audit_log_format(ab, " data="); @@ -105,8 +106,9 @@ static void tty_audit_buf_push(struct task_struct *tsk, uid_t loginuid, */ static void tty_audit_buf_push_current(struct tty_audit_buf *buf) { - tty_audit_buf_push(current, audit_get_loginuid(current->audit_context), - buf); + uid_t auid = audit_get_loginuid(current); + unsigned int sessionid = audit_get_sessionid(current); + tty_audit_buf_push(current, auid, sessionid, buf); } /** @@ -152,6 +154,11 @@ void tty_audit_fork(struct signal_struct *sig) void tty_audit_push_task(struct task_struct *tsk, uid_t loginuid) { struct tty_audit_buf *buf; + /* FIXME I think this is correct. Check against netlink once that is + * I really need to read this code more closely. But that's for + * another patch. + */ + unsigned int sessionid = audit_get_sessionid(tsk); spin_lock_irq(&tsk->sighand->siglock); buf = tsk->signal->tty_audit_buf; @@ -162,7 +169,7 @@ void tty_audit_push_task(struct task_struct *tsk, uid_t loginuid) return; mutex_lock(&buf->mutex); - tty_audit_buf_push(tsk, loginuid, buf); + tty_audit_buf_push(tsk, loginuid, sessionid, buf); mutex_unlock(&buf->mutex); tty_audit_buf_put(buf); diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c index f36fecd3fd2..79c86c47947 100644 --- a/drivers/char/tty_io.c +++ b/drivers/char/tty_io.c @@ -138,7 +138,7 @@ EXPORT_SYMBOL(tty_mutex); extern struct tty_driver *ptm_driver; /* Unix98 pty masters; for /dev/ptmx */ extern int pty_limit; /* Config limit on Unix98 ptys */ static DEFINE_IDR(allocated_ptys); -static DECLARE_MUTEX(allocated_ptys_lock); +static DEFINE_MUTEX(allocated_ptys_lock); static int ptmx_open(struct inode *, struct file *); #endif @@ -2571,9 +2571,9 @@ static void release_dev(struct file * filp) #ifdef CONFIG_UNIX98_PTYS /* Make this pty number available for reallocation */ if (devpts) { - down(&allocated_ptys_lock); + mutex_lock(&allocated_ptys_lock); idr_remove(&allocated_ptys, idx); - up(&allocated_ptys_lock); + mutex_unlock(&allocated_ptys_lock); } #endif @@ -2737,24 +2737,24 @@ static int ptmx_open(struct inode * inode, struct file * filp) nonseekable_open(inode, filp); /* find a device that is not in use. */ - down(&allocated_ptys_lock); + mutex_lock(&allocated_ptys_lock); if (!idr_pre_get(&allocated_ptys, GFP_KERNEL)) { - up(&allocated_ptys_lock); + mutex_unlock(&allocated_ptys_lock); return -ENOMEM; } idr_ret = idr_get_new(&allocated_ptys, NULL, &index); if (idr_ret < 0) { - up(&allocated_ptys_lock); + mutex_unlock(&allocated_ptys_lock); if (idr_ret == -EAGAIN) return -ENOMEM; return -EIO; } if (index >= pty_limit) { idr_remove(&allocated_ptys, index); - up(&allocated_ptys_lock); + mutex_unlock(&allocated_ptys_lock); return -EIO; } - up(&allocated_ptys_lock); + mutex_unlock(&allocated_ptys_lock); mutex_lock(&tty_mutex); retval = init_dev(ptm_driver, index, &tty); @@ -2781,9 +2781,9 @@ out1: release_dev(filp); return retval; out: - down(&allocated_ptys_lock); + mutex_lock(&allocated_ptys_lock); idr_remove(&allocated_ptys, index); - up(&allocated_ptys_lock); + mutex_unlock(&allocated_ptys_lock); return retval; } #endif @@ -3721,7 +3721,6 @@ static void initialize_tty_struct(struct tty_struct *tty) tty->buf.head = tty->buf.tail = NULL; tty_buffer_init(tty); INIT_DELAYED_WORK(&tty->buf.work, flush_to_ldisc); - init_MUTEX(&tty->buf.pty_sem); mutex_init(&tty->termios_mutex); init_waitqueue_head(&tty->write_wait); init_waitqueue_head(&tty->read_wait); @@ -4048,10 +4047,6 @@ void __init console_init(void) } } -#ifdef CONFIG_VT -extern int vty_init(void); -#endif - static int __init tty_class_init(void) { tty_class = class_create(THIS_MODULE, "tty"); diff --git a/drivers/char/tty_ioctl.c b/drivers/char/tty_ioctl.c index 1bdd2bf4f37..d4b6d64e858 100644 --- a/drivers/char/tty_ioctl.c +++ b/drivers/char/tty_ioctl.c @@ -62,7 +62,7 @@ void tty_wait_until_sent(struct tty_struct * tty, long timeout) if (!timeout) timeout = MAX_SCHEDULE_TIMEOUT; if (wait_event_interruptible_timeout(tty->write_wait, - !tty->driver->chars_in_buffer(tty), timeout)) + !tty->driver->chars_in_buffer(tty), timeout) < 0) return; if (tty->driver->wait_until_sent) tty->driver->wait_until_sent(tty, timeout); @@ -365,6 +365,25 @@ void tty_termios_copy_hw(struct ktermios *new, struct ktermios *old) EXPORT_SYMBOL(tty_termios_copy_hw); /** + * tty_termios_hw_change - check for setting change + * @a: termios + * @b: termios to compare + * + * Check if any of the bits that affect a dumb device have changed + * between the two termios structures, or a speed change is needed. + */ + +int tty_termios_hw_change(struct ktermios *a, struct ktermios *b) +{ + if (a->c_ispeed != b->c_ispeed || a->c_ospeed != b->c_ospeed) + return 1; + if ((a->c_cflag ^ b->c_cflag) & ~(HUPCL | CREAD | CLOCAL)) + return 1; + return 0; +} +EXPORT_SYMBOL(tty_termios_hw_change); + +/** * change_termios - update termios values * @tty: tty to update * @new_termios: desired new value diff --git a/drivers/char/virtio_console.c b/drivers/char/virtio_console.c index e34da5c9719..dc17fe3a88b 100644 --- a/drivers/char/virtio_console.c +++ b/drivers/char/virtio_console.c @@ -158,13 +158,13 @@ static int __devinit virtcons_probe(struct virtio_device *dev) /* Find the input queue. */ /* FIXME: This is why we want to wean off hvc: we do nothing * when input comes in. */ - in_vq = vdev->config->find_vq(vdev, NULL); + in_vq = vdev->config->find_vq(vdev, 0, NULL); if (IS_ERR(in_vq)) { err = PTR_ERR(in_vq); goto free; } - out_vq = vdev->config->find_vq(vdev, NULL); + out_vq = vdev->config->find_vq(vdev, 1, NULL); if (IS_ERR(out_vq)) { err = PTR_ERR(out_vq); goto free_in_vq; diff --git a/drivers/char/vt.c b/drivers/char/vt.c index 7a5badfb7d8..367be917506 100644 --- a/drivers/char/vt.c +++ b/drivers/char/vt.c @@ -2400,13 +2400,15 @@ static void vt_console_print(struct console *co, const char *b, unsigned count) { struct vc_data *vc = vc_cons[fg_console].d; unsigned char c; - static unsigned long printing; + static DEFINE_SPINLOCK(printing_lock); const ushort *start; ushort cnt = 0; ushort myx; /* console busy or not yet initialized */ - if (!printable || test_and_set_bit(0, &printing)) + if (!printable) + return; + if (!spin_trylock(&printing_lock)) return; if (kmsg_redirect && vc_cons_allocated(kmsg_redirect - 1)) @@ -2481,7 +2483,7 @@ static void vt_console_print(struct console *co, const char *b, unsigned count) notify_update(vc); quit: - clear_bit(0, &printing); + spin_unlock(&printing_lock); } static struct tty_driver *vt_console_device(struct console *c, int *index) |