diff options
Diffstat (limited to 'drivers/char')
61 files changed, 1114 insertions, 612 deletions
diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig index 7cfcc629a7f..3d44ec724c1 100644 --- a/drivers/char/Kconfig +++ b/drivers/char/Kconfig @@ -1002,7 +1002,7 @@ config SCx200_GPIO config PC8736x_GPIO tristate "NatSemi PC8736x GPIO Support" - depends on X86 + depends on X86_32 default SCx200_GPIO # mostly N select NSC_GPIO # needed for support routines help diff --git a/drivers/char/Makefile b/drivers/char/Makefile index 88d6eac6975..dc964166060 100644 --- a/drivers/char/Makefile +++ b/drivers/char/Makefile @@ -9,6 +9,7 @@ FONTMAPFILE = cp437.uni obj-y += mem.o random.o tty_io.o n_tty.o tty_ioctl.o tty_ldisc.o tty_buffer.o tty_port.o +obj-y += tty_mutex.o obj-$(CONFIG_LEGACY_PTYS) += pty.o obj-$(CONFIG_UNIX98_PTYS) += pty.o obj-y += misc.o @@ -47,6 +48,7 @@ obj-$(CONFIG_RIO) += rio/ generic_serial.o obj-$(CONFIG_HVC_CONSOLE) += hvc_vio.o hvsi.o obj-$(CONFIG_HVC_ISERIES) += hvc_iseries.o obj-$(CONFIG_HVC_RTAS) += hvc_rtas.o +obj-$(CONFIG_HVC_TILE) += hvc_tile.o obj-$(CONFIG_HVC_BEAT) += hvc_beat.o obj-$(CONFIG_HVC_DRIVER) += hvc_console.o obj-$(CONFIG_HVC_IRQ) += hvc_irq.o diff --git a/drivers/char/agp/efficeon-agp.c b/drivers/char/agp/efficeon-agp.c index aa109cbe0e6..d607f53d8af 100644 --- a/drivers/char/agp/efficeon-agp.c +++ b/drivers/char/agp/efficeon-agp.c @@ -372,6 +372,17 @@ static int __devinit agp_efficeon_probe(struct pci_dev *pdev, bridge->capndx = cap_ptr; /* + * If the device has not been properly setup, the following will catch + * the problem and should stop the system from crashing. + * 20030610 - hamish@zot.org + */ + if (pci_enable_device(pdev)) { + printk(KERN_ERR PFX "Unable to Enable PCI device\n"); + agp_put_bridge(bridge); + return -ENODEV; + } + + /* * The following fixes the case where the BIOS has "forgotten" to * provide an address range for the GART. * 20030610 - hamish@zot.org @@ -385,17 +396,6 @@ static int __devinit agp_efficeon_probe(struct pci_dev *pdev, } } - /* - * If the device has not been properly setup, the following will catch - * the problem and should stop the system from crashing. - * 20030610 - hamish@zot.org - */ - if (pci_enable_device(pdev)) { - printk(KERN_ERR PFX "Unable to Enable PCI device\n"); - agp_put_bridge(bridge); - return -ENODEV; - } - /* Fill in the mode register */ if (cap_ptr) { pci_read_config_dword(pdev, diff --git a/drivers/char/agp/intel-agp.c b/drivers/char/agp/intel-agp.c index d836a71bf06..eab58db5f91 100644 --- a/drivers/char/agp/intel-agp.c +++ b/drivers/char/agp/intel-agp.c @@ -12,6 +12,7 @@ #include <asm/smp.h> #include "agp.h" #include "intel-agp.h" +#include <linux/intel-gtt.h> #include "intel-gtt.c" @@ -815,17 +816,28 @@ static const struct intel_driver_description { "HD Graphics", NULL, &intel_i965_driver }, { PCI_DEVICE_ID_INTEL_IRONLAKE_MC2_HB, PCI_DEVICE_ID_INTEL_IRONLAKE_M_IG, "HD Graphics", NULL, &intel_i965_driver }, - { PCI_DEVICE_ID_INTEL_SANDYBRIDGE_HB, PCI_DEVICE_ID_INTEL_SANDYBRIDGE_IG, - "Sandybridge", NULL, &intel_i965_driver }, - { PCI_DEVICE_ID_INTEL_SANDYBRIDGE_M_HB, PCI_DEVICE_ID_INTEL_SANDYBRIDGE_M_IG, - "Sandybridge", NULL, &intel_i965_driver }, + { PCI_DEVICE_ID_INTEL_SANDYBRIDGE_HB, PCI_DEVICE_ID_INTEL_SANDYBRIDGE_GT1_IG, + "Sandybridge", NULL, &intel_gen6_driver }, + { PCI_DEVICE_ID_INTEL_SANDYBRIDGE_HB, PCI_DEVICE_ID_INTEL_SANDYBRIDGE_GT2_IG, + "Sandybridge", NULL, &intel_gen6_driver }, + { PCI_DEVICE_ID_INTEL_SANDYBRIDGE_HB, PCI_DEVICE_ID_INTEL_SANDYBRIDGE_GT2_PLUS_IG, + "Sandybridge", NULL, &intel_gen6_driver }, + { PCI_DEVICE_ID_INTEL_SANDYBRIDGE_M_HB, PCI_DEVICE_ID_INTEL_SANDYBRIDGE_M_GT1_IG, + "Sandybridge", NULL, &intel_gen6_driver }, + { PCI_DEVICE_ID_INTEL_SANDYBRIDGE_M_HB, PCI_DEVICE_ID_INTEL_SANDYBRIDGE_M_GT2_IG, + "Sandybridge", NULL, &intel_gen6_driver }, + { PCI_DEVICE_ID_INTEL_SANDYBRIDGE_M_HB, PCI_DEVICE_ID_INTEL_SANDYBRIDGE_M_GT2_PLUS_IG, + "Sandybridge", NULL, &intel_gen6_driver }, + { PCI_DEVICE_ID_INTEL_SANDYBRIDGE_S_HB, PCI_DEVICE_ID_INTEL_SANDYBRIDGE_S_IG, + "Sandybridge", NULL, &intel_gen6_driver }, { 0, 0, NULL, NULL, NULL } }; static int __devinit intel_gmch_probe(struct pci_dev *pdev, struct agp_bridge_data *bridge) { - int i; + int i, mask; + bridge->driver = NULL; for (i = 0; intel_agp_chipsets[i].name != NULL; i++) { @@ -845,14 +857,19 @@ static int __devinit intel_gmch_probe(struct pci_dev *pdev, dev_info(&pdev->dev, "Intel %s Chipset\n", intel_agp_chipsets[i].name); - if (bridge->driver->mask_memory == intel_i965_mask_memory) { - if (pci_set_dma_mask(intel_private.pcidev, DMA_BIT_MASK(36))) - dev_err(&intel_private.pcidev->dev, - "set gfx device dma mask 36bit failed!\n"); - else - pci_set_consistent_dma_mask(intel_private.pcidev, - DMA_BIT_MASK(36)); - } + if (bridge->driver->mask_memory == intel_gen6_mask_memory) + mask = 40; + else if (bridge->driver->mask_memory == intel_i965_mask_memory) + mask = 36; + else + mask = 32; + + if (pci_set_dma_mask(intel_private.pcidev, DMA_BIT_MASK(mask))) + dev_err(&intel_private.pcidev->dev, + "set gfx device dma mask %d-bit failed!\n", mask); + else + pci_set_consistent_dma_mask(intel_private.pcidev, + DMA_BIT_MASK(mask)); return 1; } @@ -908,6 +925,17 @@ static int __devinit agp_intel_probe(struct pci_dev *pdev, dev_info(&pdev->dev, "Intel %s Chipset\n", intel_agp_chipsets[i].name); /* + * If the device has not been properly setup, the following will catch + * the problem and should stop the system from crashing. + * 20030610 - hamish@zot.org + */ + if (pci_enable_device(pdev)) { + dev_err(&pdev->dev, "can't enable PCI device\n"); + agp_put_bridge(bridge); + return -ENODEV; + } + + /* * The following fixes the case where the BIOS has "forgotten" to * provide an address range for the GART. * 20030610 - hamish@zot.org @@ -921,17 +949,6 @@ static int __devinit agp_intel_probe(struct pci_dev *pdev, } } - /* - * If the device has not been properly setup, the following will catch - * the problem and should stop the system from crashing. - * 20030610 - hamish@zot.org - */ - if (pci_enable_device(pdev)) { - dev_err(&pdev->dev, "can't enable PCI device\n"); - agp_put_bridge(bridge); - return -ENODEV; - } - /* Fill in the mode register */ if (cap_ptr) { pci_read_config_dword(pdev, @@ -1036,6 +1053,7 @@ static struct pci_device_id agp_intel_pci_table[] = { ID(PCI_DEVICE_ID_INTEL_IRONLAKE_MC2_HB), ID(PCI_DEVICE_ID_INTEL_SANDYBRIDGE_HB), ID(PCI_DEVICE_ID_INTEL_SANDYBRIDGE_M_HB), + ID(PCI_DEVICE_ID_INTEL_SANDYBRIDGE_S_HB), { } }; diff --git a/drivers/char/agp/intel-agp.h b/drivers/char/agp/intel-agp.h index 2547465d465..ee189c74d34 100644 --- a/drivers/char/agp/intel-agp.h +++ b/drivers/char/agp/intel-agp.h @@ -1,6 +1,8 @@ /* * Common Intel AGPGART and GTT definitions. */ +#ifndef _INTEL_AGP_H +#define _INTEL_AGP_H /* Intel registers */ #define INTEL_APSIZE 0xb4 @@ -60,6 +62,12 @@ #define I810_PTE_LOCAL 0x00000002 #define I810_PTE_VALID 0x00000001 #define I830_PTE_SYSTEM_CACHED 0x00000006 +/* GT PTE cache control fields */ +#define GEN6_PTE_UNCACHED 0x00000002 +#define GEN6_PTE_LLC 0x00000004 +#define GEN6_PTE_LLC_MLC 0x00000006 +#define GEN6_PTE_GFDT 0x00000008 + #define I810_SMRAM_MISCC 0x70 #define I810_GFX_MEM_WIN_SIZE 0x00010000 #define I810_GFX_MEM_WIN_32M 0x00010000 @@ -194,10 +202,16 @@ #define PCI_DEVICE_ID_INTEL_IRONLAKE_MA_HB 0x0062 #define PCI_DEVICE_ID_INTEL_IRONLAKE_MC2_HB 0x006a #define PCI_DEVICE_ID_INTEL_IRONLAKE_M_IG 0x0046 -#define PCI_DEVICE_ID_INTEL_SANDYBRIDGE_HB 0x0100 -#define PCI_DEVICE_ID_INTEL_SANDYBRIDGE_IG 0x0102 -#define PCI_DEVICE_ID_INTEL_SANDYBRIDGE_M_HB 0x0104 -#define PCI_DEVICE_ID_INTEL_SANDYBRIDGE_M_IG 0x0106 +#define PCI_DEVICE_ID_INTEL_SANDYBRIDGE_HB 0x0100 /* Desktop */ +#define PCI_DEVICE_ID_INTEL_SANDYBRIDGE_GT1_IG 0x0102 +#define PCI_DEVICE_ID_INTEL_SANDYBRIDGE_GT2_IG 0x0112 +#define PCI_DEVICE_ID_INTEL_SANDYBRIDGE_GT2_PLUS_IG 0x0122 +#define PCI_DEVICE_ID_INTEL_SANDYBRIDGE_M_HB 0x0104 /* Mobile */ +#define PCI_DEVICE_ID_INTEL_SANDYBRIDGE_M_GT1_IG 0x0106 +#define PCI_DEVICE_ID_INTEL_SANDYBRIDGE_M_GT2_IG 0x0116 +#define PCI_DEVICE_ID_INTEL_SANDYBRIDGE_M_GT2_PLUS_IG 0x0126 +#define PCI_DEVICE_ID_INTEL_SANDYBRIDGE_S_HB 0x0108 /* Server */ +#define PCI_DEVICE_ID_INTEL_SANDYBRIDGE_S_IG 0x010A /* cover 915 and 945 variants */ #define IS_I915 (agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_E7221_HB || \ @@ -224,7 +238,8 @@ agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_PINEVIEW_HB) #define IS_SNB (agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_SANDYBRIDGE_HB || \ - agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_SANDYBRIDGE_M_HB) + agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_SANDYBRIDGE_M_HB || \ + agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_SANDYBRIDGE_S_HB) #define IS_G4X (agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_EAGLELAKE_HB || \ agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_Q45_HB || \ @@ -237,3 +252,5 @@ agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_IRONLAKE_MA_HB || \ agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_IRONLAKE_MC2_HB || \ IS_SNB) + +#endif diff --git a/drivers/char/agp/intel-gtt.c b/drivers/char/agp/intel-gtt.c index a7547150a70..75e0a349788 100644 --- a/drivers/char/agp/intel-gtt.c +++ b/drivers/char/agp/intel-gtt.c @@ -25,6 +25,10 @@ #define USE_PCI_DMA_API 1 #endif +/* Max amount of stolen space, anything above will be returned to Linux */ +int intel_max_stolen = 32 * 1024 * 1024; +EXPORT_SYMBOL(intel_max_stolen); + static const struct aper_size_info_fixed intel_i810_sizes[] = { {64, 16384, 4}, @@ -45,6 +49,26 @@ static struct gatt_mask intel_i810_masks[] = .type = INTEL_AGP_CACHED_MEMORY} }; +#define INTEL_AGP_UNCACHED_MEMORY 0 +#define INTEL_AGP_CACHED_MEMORY_LLC 1 +#define INTEL_AGP_CACHED_MEMORY_LLC_GFDT 2 +#define INTEL_AGP_CACHED_MEMORY_LLC_MLC 3 +#define INTEL_AGP_CACHED_MEMORY_LLC_MLC_GFDT 4 + +static struct gatt_mask intel_gen6_masks[] = +{ + {.mask = I810_PTE_VALID | GEN6_PTE_UNCACHED, + .type = INTEL_AGP_UNCACHED_MEMORY }, + {.mask = I810_PTE_VALID | GEN6_PTE_LLC, + .type = INTEL_AGP_CACHED_MEMORY_LLC }, + {.mask = I810_PTE_VALID | GEN6_PTE_LLC | GEN6_PTE_GFDT, + .type = INTEL_AGP_CACHED_MEMORY_LLC_GFDT }, + {.mask = I810_PTE_VALID | GEN6_PTE_LLC_MLC, + .type = INTEL_AGP_CACHED_MEMORY_LLC_MLC }, + {.mask = I810_PTE_VALID | GEN6_PTE_LLC_MLC | GEN6_PTE_GFDT, + .type = INTEL_AGP_CACHED_MEMORY_LLC_MLC_GFDT }, +}; + static struct _intel_private { struct pci_dev *pcidev; /* device one */ u8 __iomem *registers; @@ -104,7 +128,7 @@ static int intel_agp_map_memory(struct agp_memory *mem) DBG("try mapping %lu pages\n", (unsigned long)mem->page_count); if (sg_alloc_table(&st, mem->page_count, GFP_KERNEL)) - return -ENOMEM; + goto err; mem->sg_list = sg = st.sgl; @@ -113,11 +137,14 @@ static int intel_agp_map_memory(struct agp_memory *mem) mem->num_sg = pci_map_sg(intel_private.pcidev, mem->sg_list, mem->page_count, PCI_DMA_BIDIRECTIONAL); - if (unlikely(!mem->num_sg)) { - intel_agp_free_sglist(mem); - return -ENOMEM; - } + if (unlikely(!mem->num_sg)) + goto err; + return 0; + +err: + sg_free_table(&st); + return -ENOMEM; } static void intel_agp_unmap_memory(struct agp_memory *mem) @@ -171,13 +198,6 @@ static void intel_agp_insert_sg_entries(struct agp_memory *mem, off_t pg_start, int mask_type) { int i, j; - u32 cache_bits = 0; - - if (agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_SANDYBRIDGE_HB || - agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_SANDYBRIDGE_M_HB) - { - cache_bits = I830_PTE_SYSTEM_CACHED; - } for (i = 0, j = pg_start; i < mem->page_count; i++, j++) { writel(agp_bridge->driver->mask_memory(agp_bridge, @@ -310,6 +330,23 @@ static int intel_i830_type_to_mask_type(struct agp_bridge_data *bridge, return 0; } +static int intel_gen6_type_to_mask_type(struct agp_bridge_data *bridge, + int type) +{ + unsigned int type_mask = type & ~AGP_USER_CACHED_MEMORY_GFDT; + unsigned int gfdt = type & AGP_USER_CACHED_MEMORY_GFDT; + + if (type_mask == AGP_USER_UNCACHED_MEMORY) + return INTEL_AGP_UNCACHED_MEMORY; + else if (type_mask == AGP_USER_CACHED_MEMORY_LLC_MLC) + return gfdt ? INTEL_AGP_CACHED_MEMORY_LLC_MLC_GFDT : + INTEL_AGP_CACHED_MEMORY_LLC_MLC; + else /* set 'normal'/'cached' to LLC by default */ + return gfdt ? INTEL_AGP_CACHED_MEMORY_LLC_GFDT : + INTEL_AGP_CACHED_MEMORY_LLC; +} + + static int intel_i810_insert_entries(struct agp_memory *mem, off_t pg_start, int type) { @@ -581,8 +618,7 @@ static void intel_i830_init_gtt_entries(void) gtt_entries = 0; break; } - } else if (agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_SANDYBRIDGE_HB || - agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_SANDYBRIDGE_M_HB) { + } else if (IS_SNB) { /* * SandyBridge has new memory control reg at 0x50.w */ @@ -710,7 +746,12 @@ static void intel_i830_init_gtt_entries(void) break; } } - if (gtt_entries > 0) { + if (!local && gtt_entries > intel_max_stolen) { + dev_info(&agp_bridge->dev->dev, + "detected %dK stolen memory, trimming to %dK\n", + gtt_entries / KB(1), intel_max_stolen / KB(1)); + gtt_entries = intel_max_stolen / KB(4); + } else if (gtt_entries > 0) { dev_info(&agp_bridge->dev->dev, "detected %dK %s memory\n", gtt_entries / KB(1), local ? "local" : "stolen"); gtt_entries /= KB(4); @@ -797,6 +838,10 @@ static int intel_i830_create_gatt_table(struct agp_bridge_data *bridge) /* we have to call this as early as possible after the MMIO base address is known */ intel_i830_init_gtt_entries(); + if (intel_private.gtt_entries == 0) { + iounmap(intel_private.registers); + return -ENOMEM; + } agp_bridge->gatt_table = NULL; @@ -1052,11 +1097,11 @@ static void intel_i9xx_setup_flush(void) intel_i915_setup_chipset_flush(); } - if (intel_private.ifp_resource.start) { + 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) - dev_info(&intel_private.pcidev->dev, "can't ioremap flush page - no chipset flushing"); - } + if (!intel_private.i9xx_flush_page) + dev_err(&intel_private.pcidev->dev, + "can't ioremap flush page - no chipset flushing\n"); } static int intel_i9xx_configure(void) @@ -1147,7 +1192,7 @@ static int intel_i915_insert_entries(struct agp_memory *mem, off_t pg_start, mask_type = agp_bridge->driver->agp_type_to_mask_type(agp_bridge, type); - if (mask_type != 0 && mask_type != AGP_PHYS_MEMORY && + if (!IS_SNB && mask_type != 0 && mask_type != AGP_PHYS_MEMORY && mask_type != INTEL_AGP_CACHED_MEMORY) goto out_err; @@ -1282,6 +1327,11 @@ static int intel_i915_create_gatt_table(struct agp_bridge_data *bridge) /* we have to call this as early as possible after the MMIO base address is known */ intel_i830_init_gtt_entries(); + if (intel_private.gtt_entries == 0) { + iounmap(intel_private.gtt); + iounmap(intel_private.registers); + return -ENOMEM; + } agp_bridge->gatt_table = NULL; @@ -1309,6 +1359,16 @@ static unsigned long intel_i965_mask_memory(struct agp_bridge_data *bridge, return addr | bridge->driver->masks[type].mask; } +static unsigned long intel_gen6_mask_memory(struct agp_bridge_data *bridge, + dma_addr_t addr, int type) +{ + /* gen6 has bit11-4 for physical addr bit39-32 */ + addr |= (addr >> 28) & 0xff0; + + /* Type checking must be done elsewhere */ + return addr | bridge->driver->masks[type].mask; +} + static void intel_i965_get_gtt_range(int *gtt_offset, int *gtt_size) { u16 snb_gmch_ctl; @@ -1328,6 +1388,7 @@ static void intel_i965_get_gtt_range(int *gtt_offset, int *gtt_size) break; case PCI_DEVICE_ID_INTEL_SANDYBRIDGE_HB: case PCI_DEVICE_ID_INTEL_SANDYBRIDGE_M_HB: + case PCI_DEVICE_ID_INTEL_SANDYBRIDGE_S_HB: *gtt_offset = MB(2); pci_read_config_word(intel_private.pcidev, SNB_GMCH_CTRL, &snb_gmch_ctl); @@ -1390,6 +1451,11 @@ static int intel_i965_create_gatt_table(struct agp_bridge_data *bridge) /* we have to call this as early as possible after the MMIO base address is known */ intel_i830_init_gtt_entries(); + if (intel_private.gtt_entries == 0) { + iounmap(intel_private.gtt); + iounmap(intel_private.registers); + return -ENOMEM; + } agp_bridge->gatt_table = NULL; @@ -1517,6 +1583,39 @@ static const struct agp_bridge_driver intel_i965_driver = { #endif }; +static const struct agp_bridge_driver intel_gen6_driver = { + .owner = THIS_MODULE, + .aperture_sizes = intel_i830_sizes, + .size_type = FIXED_APER_SIZE, + .num_aperture_sizes = 4, + .needs_scratch_page = true, + .configure = intel_i9xx_configure, + .fetch_size = intel_i9xx_fetch_size, + .cleanup = intel_i915_cleanup, + .mask_memory = intel_gen6_mask_memory, + .masks = intel_gen6_masks, + .agp_enable = intel_i810_agp_enable, + .cache_flush = global_cache_flush, + .create_gatt_table = intel_i965_create_gatt_table, + .free_gatt_table = intel_i830_free_gatt_table, + .insert_memory = intel_i915_insert_entries, + .remove_memory = intel_i915_remove_entries, + .alloc_by_type = intel_i830_alloc_by_type, + .free_by_type = intel_i810_free_by_type, + .agp_alloc_page = agp_generic_alloc_page, + .agp_alloc_pages = agp_generic_alloc_pages, + .agp_destroy_page = agp_generic_destroy_page, + .agp_destroy_pages = agp_generic_destroy_pages, + .agp_type_to_mask_type = intel_gen6_type_to_mask_type, + .chipset_flush = intel_i915_chipset_flush, +#ifdef USE_PCI_DMA_API + .agp_map_page = intel_agp_map_page, + .agp_unmap_page = intel_agp_unmap_page, + .agp_map_memory = intel_agp_map_memory, + .agp_unmap_memory = intel_agp_unmap_memory, +#endif +}; + static const struct agp_bridge_driver intel_g33_driver = { .owner = THIS_MODULE, .aperture_sizes = intel_i830_sizes, diff --git a/drivers/char/amiserial.c b/drivers/char/amiserial.c index 4f8d60c25a9..a11c8c9ca3d 100644 --- a/drivers/char/amiserial.c +++ b/drivers/char/amiserial.c @@ -1072,7 +1072,7 @@ static int get_serial_info(struct async_struct * info, if (!retinfo) return -EFAULT; memset(&tmp, 0, sizeof(tmp)); - lock_kernel(); + tty_lock(); tmp.type = state->type; tmp.line = state->line; tmp.port = state->port; @@ -1083,7 +1083,7 @@ static int get_serial_info(struct async_struct * info, tmp.close_delay = state->close_delay; tmp.closing_wait = state->closing_wait; tmp.custom_divisor = state->custom_divisor; - unlock_kernel(); + tty_unlock(); if (copy_to_user(retinfo,&tmp,sizeof(*retinfo))) return -EFAULT; return 0; @@ -1100,14 +1100,14 @@ static int set_serial_info(struct async_struct * info, if (copy_from_user(&new_serial,new_info,sizeof(new_serial))) return -EFAULT; - lock_kernel(); + tty_lock(); state = info->state; old_state = *state; change_irq = new_serial.irq != state->irq; change_port = (new_serial.port != state->port); if(change_irq || change_port || (new_serial.xmit_fifo_size != state->xmit_fifo_size)) { - unlock_kernel(); + tty_unlock(); return -EINVAL; } @@ -1127,7 +1127,7 @@ static int set_serial_info(struct async_struct * info, } if (new_serial.baud_base < 9600) { - unlock_kernel(); + tty_unlock(); return -EINVAL; } @@ -1163,7 +1163,7 @@ check_and_exit: } } else retval = startup(info); - unlock_kernel(); + tty_unlock(); return retval; } @@ -1528,6 +1528,7 @@ static void rs_wait_until_sent(struct tty_struct *tty, int timeout) { struct async_struct * info = tty->driver_data; unsigned long orig_jiffies, char_time; + int tty_was_locked = tty_locked(); int lsr; if (serial_paranoia_check(info, tty->name, "rs_wait_until_sent")) @@ -1538,7 +1539,12 @@ static void rs_wait_until_sent(struct tty_struct *tty, int timeout) orig_jiffies = jiffies; - lock_kernel(); + /* + * tty_wait_until_sent is called from lots of places, + * with or without the BTM. + */ + if (!tty_was_locked) + tty_lock(); /* * Set the check interval to be 1/5 of the estimated time to * send a single character, and make it at least 1. The check @@ -1579,7 +1585,8 @@ static void rs_wait_until_sent(struct tty_struct *tty, int timeout) break; } __set_current_state(TASK_RUNNING); - unlock_kernel(); + if (!tty_was_locked) + tty_unlock(); #ifdef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT printk("lsr = %d (jiff=%lu)...done\n", lsr, jiffies); #endif @@ -1703,7 +1710,9 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp, printk("block_til_ready blocking: ttys%d, count = %d\n", info->line, state->count); #endif + tty_unlock(); schedule(); + tty_lock(); } __set_current_state(TASK_RUNNING); remove_wait_queue(&info->open_wait, &wait); diff --git a/drivers/char/briq_panel.c b/drivers/char/briq_panel.c index 555cd93c2ee..d5fa113afe3 100644 --- a/drivers/char/briq_panel.c +++ b/drivers/char/briq_panel.c @@ -67,15 +67,15 @@ static void set_led(char state) static int briq_panel_open(struct inode *ino, struct file *filep) { - lock_kernel(); + tty_lock(); /* enforce single access, vfd_is_open is protected by BKL */ if (vfd_is_open) { - unlock_kernel(); + tty_unlock(); return -EBUSY; } vfd_is_open = 1; - unlock_kernel(); + tty_unlock(); return 0; } diff --git a/drivers/char/bsr.c b/drivers/char/bsr.c index 89d871ef8c2..91917133ae0 100644 --- a/drivers/char/bsr.c +++ b/drivers/char/bsr.c @@ -23,6 +23,7 @@ #include <linux/of.h> #include <linux/of_device.h> #include <linux/of_platform.h> +#include <linux/fs.h> #include <linux/module.h> #include <linux/cdev.h> #include <linux/list.h> diff --git a/drivers/char/cyclades.c b/drivers/char/cyclades.c index 9824b416290..27aad942233 100644 --- a/drivers/char/cyclades.c +++ b/drivers/char/cyclades.c @@ -65,7 +65,6 @@ #include <linux/tty.h> #include <linux/tty_flip.h> #include <linux/serial.h> -#include <linux/smp_lock.h> #include <linux/major.h> #include <linux/string.h> #include <linux/fcntl.h> @@ -1608,7 +1607,7 @@ static int cy_open(struct tty_struct *tty, struct file *filp) * If the port is the middle of closing, bail out now */ if (tty_hung_up_p(filp) || (info->port.flags & ASYNC_CLOSING)) { - wait_event_interruptible(info->port.close_wait, + wait_event_interruptible_tty(info->port.close_wait, !(info->port.flags & ASYNC_CLOSING)); return (info->port.flags & ASYNC_HUP_NOTIFY) ? -EAGAIN: -ERESTARTSYS; } @@ -1655,7 +1654,6 @@ static void cy_wait_until_sent(struct tty_struct *tty, int timeout) return; /* Just in case.... */ orig_jiffies = jiffies; - lock_kernel(); /* * Set the check interval to be 1/5 of the estimated time to * send a single character, and make it at least 1. The check @@ -1702,7 +1700,6 @@ static void cy_wait_until_sent(struct tty_struct *tty, int timeout) } /* Run one more char cycle */ msleep_interruptible(jiffies_to_msecs(char_time * 5)); - unlock_kernel(); #ifdef CY_DEBUG_WAIT_UNTIL_SENT printk(KERN_DEBUG "Clean (jiff=%lu)...done\n", jiffies); #endif @@ -1959,7 +1956,6 @@ static int cy_chars_in_buffer(struct tty_struct *tty) int char_count; __u32 tx_put, tx_get, tx_bufsize; - lock_kernel(); tx_get = readl(&buf_ctrl->tx_get); tx_put = readl(&buf_ctrl->tx_put); tx_bufsize = readl(&buf_ctrl->tx_bufsize); @@ -1971,7 +1967,6 @@ static int cy_chars_in_buffer(struct tty_struct *tty) printk(KERN_DEBUG "cyc:cy_chars_in_buffer ttyC%d %d\n", info->line, info->xmit_cnt + char_count); #endif - unlock_kernel(); return info->xmit_cnt + char_count; } #endif /* Z_EXT_CHARS_IN_BUFFER */ @@ -2359,17 +2354,22 @@ cy_set_serial_info(struct cyclades_port *info, struct tty_struct *tty, struct serial_struct __user *new_info) { struct serial_struct new_serial; + int ret; if (copy_from_user(&new_serial, new_info, sizeof(new_serial))) return -EFAULT; + mutex_lock(&info->port.mutex); if (!capable(CAP_SYS_ADMIN)) { if (new_serial.close_delay != info->port.close_delay || new_serial.baud_base != info->baud || (new_serial.flags & ASYNC_FLAGS & ~ASYNC_USR_MASK) != (info->port.flags & ASYNC_FLAGS & ~ASYNC_USR_MASK)) + { + mutex_unlock(&info->port.mutex); return -EPERM; + } info->port.flags = (info->port.flags & ~ASYNC_USR_MASK) | (new_serial.flags & ASYNC_USR_MASK); info->baud = new_serial.baud_base; @@ -2392,10 +2392,12 @@ cy_set_serial_info(struct cyclades_port *info, struct tty_struct *tty, check_and_exit: if (info->port.flags & ASYNC_INITIALIZED) { cy_set_line_char(info, tty); - return 0; + ret = 0; } else { - return cy_startup(info, tty); + ret = cy_startup(info, tty); } + mutex_unlock(&info->port.mutex); + return ret; } /* set_serial_info */ /* @@ -2438,7 +2440,6 @@ static int cy_tiocmget(struct tty_struct *tty, struct file *file) card = info->card; - lock_kernel(); if (!cy_is_Z(card)) { unsigned long flags; int channel = info->line - card->first_line; @@ -2478,7 +2479,6 @@ static int cy_tiocmget(struct tty_struct *tty, struct file *file) ((lstatus & C_RS_CTS) ? TIOCM_CTS : 0); } end: - unlock_kernel(); return result; } /* cy_tiomget */ @@ -2696,7 +2696,6 @@ cy_ioctl(struct tty_struct *tty, struct file *file, printk(KERN_DEBUG "cyc:cy_ioctl ttyC%d, cmd = %x arg = %lx\n", info->line, cmd, arg); #endif - lock_kernel(); switch (cmd) { case CYGETMON: @@ -2817,7 +2816,6 @@ cy_ioctl(struct tty_struct *tty, struct file *file, default: ret_val = -ENOIOCTLCMD; } - unlock_kernel(); #ifdef CY_DEBUG_OTHER printk(KERN_DEBUG "cyc:cy_ioctl done\n"); diff --git a/drivers/char/epca.c b/drivers/char/epca.c index 6f5ffe1320f..d9df46aa0fb 100644 --- a/drivers/char/epca.c +++ b/drivers/char/epca.c @@ -36,7 +36,7 @@ #include <linux/ctype.h> #include <linux/tty.h> #include <linux/tty_flip.h> -#include <linux/smp_lock.h> +#include <linux/slab.h> #include <linux/ioport.h> #include <linux/interrupt.h> #include <linux/uaccess.h> @@ -2105,7 +2105,6 @@ static int pc_ioctl(struct tty_struct *tty, struct file *file, break; case DIGI_SETAW: case DIGI_SETAF: - lock_kernel(); if (cmd == DIGI_SETAW) { /* Setup an event to indicate when the transmit buffer empties */ @@ -2118,7 +2117,6 @@ static int pc_ioctl(struct tty_struct *tty, struct file *file, if (tty->ldisc->ops->flush_buffer) tty->ldisc->ops->flush_buffer(tty); } - unlock_kernel(); /* Fall Thru */ case DIGI_SETA: if (copy_from_user(&ch->digiext, argp, sizeof(digi_t))) diff --git a/drivers/char/hangcheck-timer.c b/drivers/char/hangcheck-timer.c index e0249722d25..f953c96efc8 100644 --- a/drivers/char/hangcheck-timer.c +++ b/drivers/char/hangcheck-timer.c @@ -159,7 +159,7 @@ static void hangcheck_fire(unsigned long data) if (hangcheck_dump_tasks) { printk(KERN_CRIT "Hangcheck: Task state:\n"); #ifdef CONFIG_MAGIC_SYSRQ - handle_sysrq('t', NULL); + handle_sysrq('t'); #endif /* CONFIG_MAGIC_SYSRQ */ } if (hangcheck_reboot) { diff --git a/drivers/char/hvc_console.c b/drivers/char/hvc_console.c index 35cca4c7fb1..3afd62e856e 100644 --- a/drivers/char/hvc_console.c +++ b/drivers/char/hvc_console.c @@ -194,7 +194,7 @@ static int __init hvc_console_setup(struct console *co, char *options) return 0; } -static struct console hvc_con_driver = { +static struct console hvc_console = { .name = "hvc", .write = hvc_console_print, .device = hvc_console_device, @@ -220,7 +220,7 @@ static struct console hvc_con_driver = { */ static int __init hvc_console_init(void) { - register_console(&hvc_con_driver); + register_console(&hvc_console); return 0; } console_initcall(hvc_console_init); @@ -276,8 +276,8 @@ int hvc_instantiate(uint32_t vtermno, int index, const struct hv_ops *ops) * now (setup won't fail at this point). It's ok to just * call register again if previously .setup failed. */ - if (index == hvc_con_driver.index) - register_console(&hvc_con_driver); + if (index == hvc_console.index) + register_console(&hvc_console); return 0; } @@ -641,7 +641,7 @@ int hvc_poll(struct hvc_struct *hp) } for (i = 0; i < n; ++i) { #ifdef CONFIG_MAGIC_SYSRQ - if (hp->index == hvc_con_driver.index) { + if (hp->index == hvc_console.index) { /* Handle the SysRq Hack */ /* XXX should support a sequence */ if (buf[i] == '\x0f') { /* ^O */ @@ -651,7 +651,7 @@ int hvc_poll(struct hvc_struct *hp) if (sysrq_pressed) continue; } else if (sysrq_pressed) { - handle_sysrq(buf[i], tty); + handle_sysrq(buf[i]); sysrq_pressed = 0; continue; } @@ -909,7 +909,7 @@ static void __exit hvc_exit(void) tty_unregister_driver(hvc_driver); /* return tty_struct instances allocated in hvc_init(). */ put_tty_driver(hvc_driver); - unregister_console(&hvc_con_driver); + unregister_console(&hvc_console); } } module_exit(hvc_exit); diff --git a/drivers/char/hvc_iucv.c b/drivers/char/hvc_iucv.c index 5a80ad68ef2..7b01bc609de 100644 --- a/drivers/char/hvc_iucv.c +++ b/drivers/char/hvc_iucv.c @@ -1149,7 +1149,7 @@ out_err: * Note: If it is called early in the boot process, @val is stored and * parsed later in hvc_iucv_init(). */ -static int param_set_vmidfilter(const char *val, struct kernel_param *kp) +static int param_set_vmidfilter(const char *val, const struct kernel_param *kp) { int rc; @@ -1176,7 +1176,7 @@ static int param_set_vmidfilter(const char *val, struct kernel_param *kp) * The function stores the filter as a comma-separated list of z/VM user IDs * in @buffer. Typically, sysfs routines call this function for attr show. */ -static int param_get_vmidfilter(char *buffer, struct kernel_param *kp) +static int param_get_vmidfilter(char *buffer, const struct kernel_param *kp) { int rc; size_t index, len; @@ -1203,6 +1203,11 @@ static int param_get_vmidfilter(char *buffer, struct kernel_param *kp) #define param_check_vmidfilter(name, p) __param_check(name, p, void) +static struct kernel_param_ops param_ops_vmidfilter = { + .set = param_set_vmidfilter, + .get = param_get_vmidfilter, +}; + /** * hvc_iucv_init() - z/VM IUCV HVC device driver initialization */ diff --git a/drivers/char/hvc_tile.c b/drivers/char/hvc_tile.c new file mode 100644 index 00000000000..c4efb55cbc0 --- /dev/null +++ b/drivers/char/hvc_tile.c @@ -0,0 +1,67 @@ +/* + * Copyright 2010 Tilera Corporation. 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, version 2. + * + * 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, GOOD TITLE or + * NON INFRINGEMENT. See the GNU General Public License for + * more details. + * + * Tilera TILE Processor hypervisor console + */ + +#include <linux/console.h> +#include <linux/delay.h> +#include <linux/err.h> +#include <linux/init.h> +#include <linux/moduleparam.h> +#include <linux/types.h> + +#include <hv/hypervisor.h> + +#include "hvc_console.h" + +static int hvc_tile_put_chars(uint32_t vt, const char *buf, int count) +{ + return hv_console_write((HV_VirtAddr)buf, count); +} + +static int hvc_tile_get_chars(uint32_t vt, char *buf, int count) +{ + int i, c; + + for (i = 0; i < count; ++i) { + c = hv_console_read_if_ready(); + if (c < 0) + break; + buf[i] = c; + } + + return i; +} + +static const struct hv_ops hvc_tile_get_put_ops = { + .get_chars = hvc_tile_get_chars, + .put_chars = hvc_tile_put_chars, +}; + +static int __init hvc_tile_console_init(void) +{ + extern void disable_early_printk(void); + hvc_instantiate(0, 0, &hvc_tile_get_put_ops); + add_preferred_console("hvc", 0, NULL); + disable_early_printk(); + return 0; +} +console_initcall(hvc_tile_console_init); + +static int __init hvc_tile_init(void) +{ + hvc_alloc(0, 0, &hvc_tile_get_put_ops, 128); + return 0; +} +device_initcall(hvc_tile_init); diff --git a/drivers/char/hvsi.c b/drivers/char/hvsi.c index d4b14ff1c4c..a2bc885ce60 100644 --- a/drivers/char/hvsi.c +++ b/drivers/char/hvsi.c @@ -403,7 +403,7 @@ static void hvsi_insert_chars(struct hvsi_struct *hp, const char *buf, int len) hp->sysrq = 1; continue; } else if (hp->sysrq) { - handle_sysrq(c, hp->tty); + handle_sysrq(c); hp->sysrq = 0; continue; } @@ -1255,7 +1255,7 @@ static int __init hvsi_console_setup(struct console *console, char *options) return 0; } -static struct console hvsi_con_driver = { +static struct console hvsi_console = { .name = "hvsi", .write = hvsi_console_print, .device = hvsi_console_device, @@ -1308,7 +1308,7 @@ static int __init hvsi_console_init(void) } if (hvsi_count) - register_console(&hvsi_con_driver); + register_console(&hvsi_console); return 0; } console_initcall(hvsi_console_init); diff --git a/drivers/char/hw_random/n2-drv.c b/drivers/char/hw_random/n2-drv.c index 101d5f23554..a3f5e381e74 100644 --- a/drivers/char/hw_random/n2-drv.c +++ b/drivers/char/hw_random/n2-drv.c @@ -387,7 +387,7 @@ static int n2rng_init_control(struct n2rng *np) static int n2rng_data_read(struct hwrng *rng, u32 *data) { - struct n2rng *np = rng->priv; + struct n2rng *np = (struct n2rng *) rng->priv; unsigned long ra = __pa(&np->test_data); int len; @@ -619,7 +619,7 @@ static void __devinit n2rng_driver_version(void) pr_info("%s", version); } -static int __devinit n2rng_probe(struct of_device *op, +static int __devinit n2rng_probe(struct platform_device *op, const struct of_device_id *match) { int victoria_falls = (match->data != NULL); @@ -714,7 +714,7 @@ out: return err; } -static int __devexit n2rng_remove(struct of_device *op) +static int __devexit n2rng_remove(struct platform_device *op) { struct n2rng *np = dev_get_drvdata(&op->dev); @@ -762,12 +762,12 @@ static struct of_platform_driver n2rng_driver = { static int __init n2rng_init(void) { - return of_register_driver(&n2rng_driver, &of_bus_type); + return of_register_platform_driver(&n2rng_driver); } static void __exit n2rng_exit(void) { - of_unregister_driver(&n2rng_driver); + of_unregister_platform_driver(&n2rng_driver); } module_init(n2rng_init); diff --git a/drivers/char/hw_random/n2rng.h b/drivers/char/hw_random/n2rng.h index a2b81e7bfc1..4bea07f3097 100644 --- a/drivers/char/hw_random/n2rng.h +++ b/drivers/char/hw_random/n2rng.h @@ -65,7 +65,7 @@ struct n2rng_unit { }; struct n2rng { - struct of_device *op; + struct platform_device *op; unsigned long flags; #define N2RNG_FLAG_VF 0x00000001 /* Victoria Falls RNG, else N2 */ diff --git a/drivers/char/hw_random/pasemi-rng.c b/drivers/char/hw_random/pasemi-rng.c index 261ba8f22b8..a31c830ca8c 100644 --- a/drivers/char/hw_random/pasemi-rng.c +++ b/drivers/char/hw_random/pasemi-rng.c @@ -94,7 +94,7 @@ static struct hwrng pasemi_rng = { .data_read = pasemi_rng_data_read, }; -static int __devinit rng_probe(struct of_device *ofdev, +static int __devinit rng_probe(struct platform_device *ofdev, const struct of_device_id *match) { void __iomem *rng_regs; @@ -123,7 +123,7 @@ static int __devinit rng_probe(struct of_device *ofdev, return err; } -static int __devexit rng_remove(struct of_device *dev) +static int __devexit rng_remove(struct platform_device *dev) { void __iomem *rng_regs = (void __iomem *)pasemi_rng.priv; diff --git a/drivers/char/ip2/ip2main.c b/drivers/char/ip2/ip2main.c index 911e1da6def..d4b71e8d0d2 100644 --- a/drivers/char/ip2/ip2main.c +++ b/drivers/char/ip2/ip2main.c @@ -1486,7 +1486,9 @@ ip2_open( PTTY tty, struct file *pFile ) if ( tty_hung_up_p(pFile) || ( pCh->flags & ASYNC_CLOSING )) { if ( pCh->flags & ASYNC_CLOSING ) { + tty_unlock(); schedule(); + tty_lock(); } if ( tty_hung_up_p(pFile) ) { set_current_state( TASK_RUNNING ); @@ -1548,7 +1550,9 @@ ip2_open( PTTY tty, struct file *pFile ) rc = (( pCh->flags & ASYNC_HUP_NOTIFY ) ? -EAGAIN : -ERESTARTSYS); break; } + tty_unlock(); schedule(); + tty_lock(); } set_current_state( TASK_RUNNING ); remove_wait_queue(&pCh->open_wait, &wait); @@ -1646,7 +1650,7 @@ ip2_close( PTTY tty, struct file *pFile ) /* disable DSS reporting */ i2QueueCommands(PTYPE_INLINE, pCh, 100, 4, CMD_DCD_NREP, CMD_CTS_NREP, CMD_DSR_NREP, CMD_RI_NREP); - if ( !tty || (tty->termios->c_cflag & HUPCL) ) { + if (tty->termios->c_cflag & HUPCL) { i2QueueCommands(PTYPE_INLINE, pCh, 100, 2, CMD_RTSDN, CMD_DTRDN); pCh->dataSetOut &= ~(I2_DTR | I2_RTS); i2QueueCommands( PTYPE_INLINE, pCh, 100, 1, CMD_PAUSE(25)); @@ -2926,6 +2930,8 @@ ip2_ipl_ioctl (struct file *pFile, UINT cmd, ULONG arg ) if ( pCh ) { rc = copy_to_user(argp, pCh, sizeof(i2ChanStr)); + if (rc) + rc = -EFAULT; } else { rc = -ENODEV; } diff --git a/drivers/char/ipmi/ipmi_si_intf.c b/drivers/char/ipmi/ipmi_si_intf.c index 094bdc355b1..3822b4f49c8 100644 --- a/drivers/char/ipmi/ipmi_si_intf.c +++ b/drivers/char/ipmi/ipmi_si_intf.c @@ -1804,9 +1804,12 @@ static int hotmod_handler(const char *val, struct kernel_param *kp) info->irq_setup = std_irq_setup; info->slave_addr = ipmb; - if (!add_smi(info)) + if (!add_smi(info)) { if (try_smi_init(info)) cleanup_one_si(info); + } else { + kfree(info); + } } else { /* remove */ struct smi_info *e, *tmp_e; @@ -1890,9 +1893,12 @@ static __devinit void hardcode_find_bmc(void) info->irq_setup = std_irq_setup; info->slave_addr = slave_addrs[i]; - if (!add_smi(info)) + if (!add_smi(info)) { if (try_smi_init(info)) cleanup_one_si(info); + } else { + kfree(info); + } } } @@ -1965,8 +1971,8 @@ static int acpi_gpe_irq_setup(struct smi_info *info) /* * Defined at - * http://h21007.www2.hp.com/dspp/files/unprotected/devresource/ - * Docs/TechPapers/IA64/hpspmi.pdf + * http://h21007.www2.hp.com/portal/download/files + * /unprot/hpspmi.pdf */ struct SPMITable { s8 Signature[4]; @@ -2013,18 +2019,12 @@ struct SPMITable { static __devinit int try_init_spmi(struct SPMITable *spmi) { struct smi_info *info; - u8 addr_space; if (spmi->IPMIlegacy != 1) { printk(KERN_INFO PFX "Bad SPMI legacy %d\n", spmi->IPMIlegacy); return -ENODEV; } - if (spmi->addr.space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY) - addr_space = IPMI_MEM_ADDR_SPACE; - else - addr_space = IPMI_IO_ADDR_SPACE; - info = kzalloc(sizeof(*info), GFP_KERNEL); if (!info) { printk(KERN_ERR PFX "Could not allocate SI data (3)\n"); @@ -2088,7 +2088,13 @@ static __devinit int try_init_spmi(struct SPMITable *spmi) } info->io.addr_data = spmi->addr.address; - add_smi(info); + pr_info("ipmi_si: SPMI: %s %#lx regsize %d spacing %d irq %d\n", + (info->io.addr_type == IPMI_IO_ADDR_SPACE) ? "io" : "mem", + info->io.addr_data, info->io.regsize, info->io.regspacing, + info->irq); + + if (add_smi(info)) + kfree(info); return 0; } @@ -2176,6 +2182,14 @@ static int __devinit ipmi_pnp_probe(struct pnp_dev *dev, info->io.addr_data = res->start; info->io.regspacing = DEFAULT_REGSPACING; + res = pnp_get_resource(dev, + (info->io.addr_type == IPMI_IO_ADDR_SPACE) ? + IORESOURCE_IO : IORESOURCE_MEM, + 1); + if (res) { + if (res->start > info->io.addr_data) + info->io.regspacing = res->start - info->io.addr_data; + } info->io.regsize = DEFAULT_REGSPACING; info->io.regshift = 0; @@ -2196,7 +2210,10 @@ static int __devinit ipmi_pnp_probe(struct pnp_dev *dev, res, info->io.regsize, info->io.regspacing, info->irq); - return add_smi(info); + if (add_smi(info)) + goto err_free; + + return 0; err_free: kfree(info); @@ -2354,7 +2371,13 @@ static __devinit void try_init_dmi(struct dmi_ipmi_data *ipmi_data) if (info->irq) info->irq_setup = std_irq_setup; - add_smi(info); + pr_info("ipmi_si: SMBIOS: %s %#lx regsize %d spacing %d irq %d\n", + (info->io.addr_type == IPMI_IO_ADDR_SPACE) ? "io" : "mem", + info->io.addr_data, info->io.regsize, info->io.regspacing, + info->irq); + + if (add_smi(info)) + kfree(info); } static void __devinit dmi_find_bmc(void) @@ -2460,7 +2483,10 @@ static int __devinit ipmi_pci_probe(struct pci_dev *pdev, &pdev->resource[0], info->io.regsize, info->io.regspacing, info->irq); - return add_smi(info); + if (add_smi(info)) + kfree(info); + + return 0; } static void __devexit ipmi_pci_remove(struct pci_dev *pdev) @@ -2502,7 +2528,7 @@ static struct pci_driver ipmi_pci_driver = { #ifdef CONFIG_PPC_OF -static int __devinit ipmi_of_probe(struct of_device *dev, +static int __devinit ipmi_of_probe(struct platform_device *dev, const struct of_device_id *match) { struct smi_info *info; @@ -2573,10 +2599,15 @@ static int __devinit ipmi_of_probe(struct of_device *dev, dev_set_drvdata(&dev->dev, info); - return add_smi(info); + if (add_smi(info)) { + kfree(info); + return -EBUSY; + } + + return 0; } -static int __devexit ipmi_of_remove(struct of_device *dev) +static int __devexit ipmi_of_remove(struct platform_device *dev) { cleanup_one_si(dev_get_drvdata(&dev->dev)); return 0; @@ -3006,6 +3037,8 @@ static __devinit void default_find_bmc(void) info->io.addr_data); } else cleanup_one_si(info); + } else { + kfree(info); } } } @@ -3033,7 +3066,7 @@ static int add_smi(struct smi_info *new_smi) si_to_str[new_smi->si_type]); mutex_lock(&smi_infos_lock); if (!is_new_interface(new_smi)) { - printk(KERN_CONT PFX "duplicate interface\n"); + printk(KERN_CONT " duplicate interface\n"); rv = -EBUSY; goto out_err; } diff --git a/drivers/char/ipmi/ipmi_watchdog.c b/drivers/char/ipmi/ipmi_watchdog.c index 82bcdb262a3..654d566ca57 100644 --- a/drivers/char/ipmi/ipmi_watchdog.c +++ b/drivers/char/ipmi/ipmi_watchdog.c @@ -196,7 +196,7 @@ static void ipmi_unregister_watchdog(int ipmi_intf); */ static int start_now; -static int set_param_int(const char *val, struct kernel_param *kp) +static int set_param_timeout(const char *val, const struct kernel_param *kp) { char *endp; int l; @@ -215,10 +215,11 @@ static int set_param_int(const char *val, struct kernel_param *kp) return rv; } -static int get_param_int(char *buffer, struct kernel_param *kp) -{ - return sprintf(buffer, "%i", *((int *)kp->arg)); -} +static struct kernel_param_ops param_ops_timeout = { + .set = set_param_timeout, + .get = param_get_int, +}; +#define param_check_timeout param_check_int typedef int (*action_fn)(const char *intval, char *outval); @@ -227,7 +228,7 @@ static int preaction_op(const char *inval, char *outval); static int preop_op(const char *inval, char *outval); static void check_parms(void); -static int set_param_str(const char *val, struct kernel_param *kp) +static int set_param_str(const char *val, const struct kernel_param *kp) { action_fn fn = (action_fn) kp->arg; int rv = 0; @@ -251,7 +252,7 @@ static int set_param_str(const char *val, struct kernel_param *kp) return rv; } -static int get_param_str(char *buffer, struct kernel_param *kp) +static int get_param_str(char *buffer, const struct kernel_param *kp) { action_fn fn = (action_fn) kp->arg; int rv; @@ -263,7 +264,7 @@ static int get_param_str(char *buffer, struct kernel_param *kp) } -static int set_param_wdog_ifnum(const char *val, struct kernel_param *kp) +static int set_param_wdog_ifnum(const char *val, const struct kernel_param *kp) { int rv = param_set_int(val, kp); if (rv) @@ -276,27 +277,38 @@ static int set_param_wdog_ifnum(const char *val, struct kernel_param *kp) return 0; } -module_param_call(ifnum_to_use, set_param_wdog_ifnum, get_param_int, - &ifnum_to_use, 0644); +static struct kernel_param_ops param_ops_wdog_ifnum = { + .set = set_param_wdog_ifnum, + .get = param_get_int, +}; + +#define param_check_wdog_ifnum param_check_int + +static struct kernel_param_ops param_ops_str = { + .set = set_param_str, + .get = get_param_str, +}; + +module_param(ifnum_to_use, wdog_ifnum, 0644); MODULE_PARM_DESC(ifnum_to_use, "The interface number to use for the watchdog " "timer. Setting to -1 defaults to the first registered " "interface"); -module_param_call(timeout, set_param_int, get_param_int, &timeout, 0644); +module_param(timeout, timeout, 0644); MODULE_PARM_DESC(timeout, "Timeout value in seconds."); -module_param_call(pretimeout, set_param_int, get_param_int, &pretimeout, 0644); +module_param(pretimeout, timeout, 0644); MODULE_PARM_DESC(pretimeout, "Pretimeout value in seconds."); -module_param_call(action, set_param_str, get_param_str, action_op, 0644); +module_param_cb(action, ¶m_ops_str, action_op, 0644); MODULE_PARM_DESC(action, "Timeout action. One of: " "reset, none, power_cycle, power_off."); -module_param_call(preaction, set_param_str, get_param_str, preaction_op, 0644); +module_param_cb(preaction, ¶m_ops_str, preaction_op, 0644); MODULE_PARM_DESC(preaction, "Pretimeout action. One of: " "pre_none, pre_smi, pre_nmi, pre_int."); -module_param_call(preop, set_param_str, get_param_str, preop_op, 0644); +module_param_cb(preop, ¶m_ops_str, preop_op, 0644); MODULE_PARM_DESC(preop, "Pretimeout driver operation. One of: " "preop_none, preop_panic, preop_give_data."); diff --git a/drivers/char/isicom.c b/drivers/char/isicom.c index 98310e1aae3..c27e9d21fea 100644 --- a/drivers/char/isicom.c +++ b/drivers/char/isicom.c @@ -124,7 +124,6 @@ #include <linux/fs.h> #include <linux/sched.h> #include <linux/serial.h> -#include <linux/smp_lock.h> #include <linux/mm.h> #include <linux/interrupt.h> #include <linux/timer.h> @@ -872,7 +871,6 @@ static struct tty_port *isicom_find_port(struct tty_struct *tty) static int isicom_open(struct tty_struct *tty, struct file *filp) { struct isi_port *port; - struct isi_board *card; struct tty_port *tport; tport = isicom_find_port(tty); @@ -1118,8 +1116,7 @@ static int isicom_set_serial_info(struct tty_struct *tty, if (copy_from_user(&newinfo, info, sizeof(newinfo))) return -EFAULT; - lock_kernel(); - + mutex_lock(&port->port.mutex); reconfig_port = ((port->port.flags & ASYNC_SPD_MASK) != (newinfo.flags & ASYNC_SPD_MASK)); @@ -1128,7 +1125,7 @@ static int isicom_set_serial_info(struct tty_struct *tty, (newinfo.closing_wait != port->port.closing_wait) || ((newinfo.flags & ~ASYNC_USR_MASK) != (port->port.flags & ~ASYNC_USR_MASK))) { - unlock_kernel(); + mutex_unlock(&port->port.mutex); return -EPERM; } port->port.flags = ((port->port.flags & ~ASYNC_USR_MASK) | @@ -1145,7 +1142,7 @@ static int isicom_set_serial_info(struct tty_struct *tty, isicom_config_port(tty); spin_unlock_irqrestore(&port->card->card_lock, flags); } - unlock_kernel(); + mutex_unlock(&port->port.mutex); return 0; } @@ -1154,7 +1151,7 @@ static int isicom_get_serial_info(struct isi_port *port, { struct serial_struct out_info; - lock_kernel(); + mutex_lock(&port->port.mutex); memset(&out_info, 0, sizeof(out_info)); /* out_info.type = ? */ out_info.line = port - isi_ports; @@ -1164,7 +1161,7 @@ static int isicom_get_serial_info(struct isi_port *port, /* out_info.baud_base = ? */ out_info.close_delay = port->port.close_delay; out_info.closing_wait = port->port.closing_wait; - unlock_kernel(); + mutex_unlock(&port->port.mutex); if (copy_to_user(info, &out_info, sizeof(out_info))) return -EFAULT; return 0; diff --git a/drivers/char/istallion.c b/drivers/char/istallion.c index 4e395c956a0..be28391adb7 100644 --- a/drivers/char/istallion.c +++ b/drivers/char/istallion.c @@ -203,9 +203,9 @@ static int stli_shared; * the board has been detected, and whether it is actually running a slave * or not. */ -#define BST_FOUND 0x1 -#define BST_STARTED 0x2 -#define BST_PROBED 0x4 +#define BST_FOUND 0 +#define BST_STARTED 1 +#define BST_PROBED 2 /* * Define the set of port state flags. These are marked for internal @@ -816,7 +816,7 @@ static int stli_open(struct tty_struct *tty, struct file *filp) brdp = stli_brds[brdnr]; if (brdp == NULL) return -ENODEV; - if ((brdp->state & BST_STARTED) == 0) + if (!test_bit(BST_STARTED, &brdp->state)) return -ENODEV; portnr = MINOR2PORT(minordev); if (portnr > brdp->nrports) @@ -954,7 +954,7 @@ static int stli_rawopen(struct stlibrd *brdp, struct stliport *portp, unsigned l * order of opens and closes may not be preserved across shared * memory, so we must wait until it is complete. */ - wait_event_interruptible(portp->raw_wait, + wait_event_interruptible_tty(portp->raw_wait, !test_bit(ST_CLOSING, &portp->state)); if (signal_pending(current)) { return -ERESTARTSYS; @@ -989,7 +989,7 @@ static int stli_rawopen(struct stlibrd *brdp, struct stliport *portp, unsigned l set_bit(ST_OPENING, &portp->state); spin_unlock_irqrestore(&brd_lock, flags); - wait_event_interruptible(portp->raw_wait, + wait_event_interruptible_tty(portp->raw_wait, !test_bit(ST_OPENING, &portp->state)); if (signal_pending(current)) rc = -ERESTARTSYS; @@ -1020,7 +1020,7 @@ static int stli_rawclose(struct stlibrd *brdp, struct stliport *portp, unsigned * occurs on this port. */ if (wait) { - wait_event_interruptible(portp->raw_wait, + wait_event_interruptible_tty(portp->raw_wait, !test_bit(ST_CLOSING, &portp->state)); if (signal_pending(current)) { return -ERESTARTSYS; @@ -1052,7 +1052,7 @@ static int stli_rawclose(struct stlibrd *brdp, struct stliport *portp, unsigned * to come back. */ rc = 0; - wait_event_interruptible(portp->raw_wait, + wait_event_interruptible_tty(portp->raw_wait, !test_bit(ST_CLOSING, &portp->state)); if (signal_pending(current)) rc = -ERESTARTSYS; @@ -1073,6 +1073,10 @@ static int stli_rawclose(struct stlibrd *brdp, struct stliport *portp, unsigned static int stli_cmdwait(struct stlibrd *brdp, struct stliport *portp, unsigned long cmd, void *arg, int size, int copyback) { + /* + * no need for wait_event_tty because clearing ST_CMDING cannot block + * on BTM + */ wait_event_interruptible(portp->raw_wait, !test_bit(ST_CMDING, &portp->state)); if (signal_pending(current)) @@ -1846,7 +1850,7 @@ static void stli_portinfo(struct seq_file *m, struct stlibrd *brdp, struct stlip rc = stli_portcmdstats(NULL, portp); uart = "UNKNOWN"; - if (brdp->state & BST_STARTED) { + if (test_bit(BST_STARTED, &brdp->state)) { switch (stli_comstats.hwid) { case 0: uart = "2681"; break; case 1: uart = "SC26198"; break; @@ -1855,7 +1859,7 @@ static void stli_portinfo(struct seq_file *m, struct stlibrd *brdp, struct stlip } seq_printf(m, "%d: uart:%s ", portnr, uart); - if ((brdp->state & BST_STARTED) && (rc >= 0)) { + if (test_bit(BST_STARTED, &brdp->state) && rc >= 0) { char sep; seq_printf(m, "tx:%d rx:%d", (int) stli_comstats.txtotal, @@ -2355,7 +2359,7 @@ static void stli_poll(unsigned long arg) brdp = stli_brds[brdnr]; if (brdp == NULL) continue; - if ((brdp->state & BST_STARTED) == 0) + if (!test_bit(BST_STARTED, &brdp->state)) continue; spin_lock(&brd_lock); @@ -3140,7 +3144,7 @@ static int stli_initecp(struct stlibrd *brdp) } - brdp->state |= BST_FOUND; + set_bit(BST_FOUND, &brdp->state); return 0; err_unmap: iounmap(brdp->membase); @@ -3297,7 +3301,7 @@ static int stli_initonb(struct stlibrd *brdp) brdp->panels[0] = brdp->nrports; - brdp->state |= BST_FOUND; + set_bit(BST_FOUND, &brdp->state); return 0; err_unmap: iounmap(brdp->membase); @@ -3407,7 +3411,7 @@ stli_donestartup: spin_unlock_irqrestore(&brd_lock, flags); if (rc == 0) - brdp->state |= BST_STARTED; + set_bit(BST_STARTED, &brdp->state); if (! stli_timeron) { stli_timeron++; @@ -3710,7 +3714,7 @@ static int __devinit stli_pciprobe(struct pci_dev *pdev, if (retval) goto err_null; - brdp->state |= BST_PROBED; + set_bit(BST_PROBED, &brdp->state); pci_set_drvdata(pdev, brdp); EBRDENABLE(brdp); @@ -3841,7 +3845,7 @@ static int __init stli_initbrds(void) brdp = stli_brds[i]; if (brdp == NULL) continue; - if (brdp->state & BST_FOUND) { + if (test_bit(BST_FOUND, &brdp->state)) { EBRDENABLE(brdp); brdp->enable = NULL; brdp->disable = NULL; @@ -4011,6 +4015,7 @@ static int stli_getbrdstats(combrd_t __user *bp) return -ENODEV; memset(&stli_brdstats, 0, sizeof(combrd_t)); + stli_brdstats.brd = brdp->brdnr; stli_brdstats.type = brdp->brdtype; stli_brdstats.hwid = 0; @@ -4076,10 +4081,13 @@ static int stli_portcmdstats(struct tty_struct *tty, struct stliport *portp) if (brdp == NULL) return -ENODEV; - if (brdp->state & BST_STARTED) { + mutex_lock(&portp->port.mutex); + if (test_bit(BST_STARTED, &brdp->state)) { if ((rc = stli_cmdwait(brdp, portp, A_GETSTATS, - &stli_cdkstats, sizeof(asystats_t), 1)) < 0) + &stli_cdkstats, sizeof(asystats_t), 1)) < 0) { + mutex_unlock(&portp->port.mutex); return rc; + } } else { memset(&stli_cdkstats, 0, sizeof(asystats_t)); } @@ -4124,6 +4132,7 @@ static int stli_portcmdstats(struct tty_struct *tty, struct stliport *portp) stli_comstats.modem = stli_cdkstats.dcdcnt; stli_comstats.hwid = stli_cdkstats.hwid; stli_comstats.signals = stli_mktiocm(stli_cdkstats.signals); + mutex_unlock(&portp->port.mutex); return 0; } @@ -4186,15 +4195,20 @@ static int stli_clrportstats(struct stliport *portp, comstats_t __user *cp) if (!brdp) return -ENODEV; - if (brdp->state & BST_STARTED) { - if ((rc = stli_cmdwait(brdp, portp, A_CLEARSTATS, NULL, 0, 0)) < 0) + mutex_lock(&portp->port.mutex); + + if (test_bit(BST_STARTED, &brdp->state)) { + if ((rc = stli_cmdwait(brdp, portp, A_CLEARSTATS, NULL, 0, 0)) < 0) { + mutex_unlock(&portp->port.mutex); return rc; + } } memset(&stli_comstats, 0, sizeof(comstats_t)); stli_comstats.brd = portp->brdnr; stli_comstats.panel = portp->panelnr; stli_comstats.port = portp->portnr; + mutex_unlock(&portp->port.mutex); if (copy_to_user(cp, &stli_comstats, sizeof(comstats_t))) return -EFAULT; @@ -4266,8 +4280,6 @@ static long stli_memioctl(struct file *fp, unsigned int cmd, unsigned long arg) done = 0; rc = 0; - lock_kernel(); - switch (cmd) { case COM_GETPORTSTATS: rc = stli_getportstats(NULL, NULL, argp); @@ -4290,8 +4302,6 @@ static long stli_memioctl(struct file *fp, unsigned int cmd, unsigned long arg) done++; break; } - unlock_kernel(); - if (done) return rc; @@ -4308,8 +4318,6 @@ static long stli_memioctl(struct file *fp, unsigned int cmd, unsigned long arg) if (brdp->state == 0) return -ENODEV; - lock_kernel(); - switch (cmd) { case STL_BINTR: EBRDINTR(brdp); @@ -4318,10 +4326,10 @@ static long stli_memioctl(struct file *fp, unsigned int cmd, unsigned long arg) rc = stli_startbrd(brdp); break; case STL_BSTOP: - brdp->state &= ~BST_STARTED; + clear_bit(BST_STARTED, &brdp->state); break; case STL_BRESET: - brdp->state &= ~BST_STARTED; + clear_bit(BST_STARTED, &brdp->state); EBRDRESET(brdp); if (stli_shared == 0) { if (brdp->reenable != NULL) @@ -4332,7 +4340,6 @@ static long stli_memioctl(struct file *fp, unsigned int cmd, unsigned long arg) rc = -ENOIOCTLCMD; break; } - unlock_kernel(); return rc; } @@ -4378,7 +4385,8 @@ static void istallion_cleanup_isa(void) unsigned int j; for (j = 0; (j < stli_nrbrds); j++) { - if ((brdp = stli_brds[j]) == NULL || (brdp->state & BST_PROBED)) + if ((brdp = stli_brds[j]) == NULL || + test_bit(BST_PROBED, &brdp->state)) continue; stli_cleanup_ports(brdp); diff --git a/drivers/char/keyboard.c b/drivers/char/keyboard.c index 25be2102a60..a7ca75212bf 100644 --- a/drivers/char/keyboard.c +++ b/drivers/char/keyboard.c @@ -299,7 +299,7 @@ int kbd_rate(struct kbd_repeat *rep) */ static void put_queue(struct vc_data *vc, int ch) { - struct tty_struct *tty = vc->vc_tty; + struct tty_struct *tty = vc->port.tty; if (tty) { tty_insert_flip_char(tty, ch, 0); @@ -309,7 +309,7 @@ static void put_queue(struct vc_data *vc, int ch) static void puts_queue(struct vc_data *vc, char *cp) { - struct tty_struct *tty = vc->vc_tty; + struct tty_struct *tty = vc->port.tty; if (!tty) return; @@ -485,7 +485,7 @@ static void fn_show_ptregs(struct vc_data *vc) static void fn_hold(struct vc_data *vc) { - struct tty_struct *tty = vc->vc_tty; + struct tty_struct *tty = vc->port.tty; if (rep || !tty) return; @@ -563,7 +563,7 @@ static void fn_inc_console(struct vc_data *vc) static void fn_send_intr(struct vc_data *vc) { - struct tty_struct *tty = vc->vc_tty; + struct tty_struct *tty = vc->port.tty; if (!tty) return; @@ -1162,7 +1162,7 @@ static void kbd_keycode(unsigned int keycode, int down, int hw_raw) struct keyboard_notifier_param param = { .vc = vc, .value = keycode, .down = down }; int rc; - tty = vc->vc_tty; + tty = vc->port.tty; if (tty && (!tty->driver_data)) { /* No driver data? Strange. Okay we fix it then. */ diff --git a/drivers/char/mem.c b/drivers/char/mem.c index f54dab8acdc..a398ecdbd75 100644 --- a/drivers/char/mem.c +++ b/drivers/char/mem.c @@ -916,7 +916,7 @@ static int __init chr_dev_init(void) NULL, devlist[minor].name); } - return 0; + return tty_init(); } fs_initcall(chr_dev_init); diff --git a/drivers/char/misc.c b/drivers/char/misc.c index cd650ca8c67..abdafd48898 100644 --- a/drivers/char/misc.c +++ b/drivers/char/misc.c @@ -242,7 +242,7 @@ int misc_deregister(struct miscdevice *misc) { int i = DYNAMIC_MINORS - misc->minor - 1; - if (list_empty(&misc->list)) + if (WARN_ON(list_empty(&misc->list))) return -EINVAL; mutex_lock(&misc_mtx); diff --git a/drivers/char/mxser.c b/drivers/char/mxser.c index d2692d443f7..3fc89da856a 100644 --- a/drivers/char/mxser.c +++ b/drivers/char/mxser.c @@ -2193,7 +2193,7 @@ static void mxser_transmit_chars(struct tty_struct *tty, struct mxser_port *port port->mon_data.up_txcnt += (cnt - port->xmit_cnt); port->icount.tx += (cnt - port->xmit_cnt); - if (port->xmit_cnt < WAKEUP_CHARS && tty) + if (port->xmit_cnt < WAKEUP_CHARS) tty_wakeup(tty); if (port->xmit_cnt <= 0) { diff --git a/drivers/char/n_gsm.c b/drivers/char/n_gsm.c index e4089c432f1..04ef3ef0a42 100644 --- a/drivers/char/n_gsm.c +++ b/drivers/char/n_gsm.c @@ -43,7 +43,6 @@ #include <linux/sched.h> #include <linux/interrupt.h> #include <linux/tty.h> -#include <linux/timer.h> #include <linux/ctype.h> #include <linux/mm.h> #include <linux/string.h> @@ -920,7 +919,7 @@ static void gsm_dlci_data_sweep(struct gsm_mux *gsm) else len = gsm_dlci_data_output_framed(gsm, dlci); if (len < 0) - return; + break; /* DLCI empty - try the next */ if (len == 0) i++; diff --git a/drivers/char/n_hdlc.c b/drivers/char/n_hdlc.c index c68118efad8..47d32281032 100644 --- a/drivers/char/n_hdlc.c +++ b/drivers/char/n_hdlc.c @@ -598,18 +598,18 @@ static ssize_t n_hdlc_tty_read(struct tty_struct *tty, struct file *file, return -EFAULT; } - lock_kernel(); + tty_lock(); for (;;) { if (test_bit(TTY_OTHER_CLOSED, &tty->flags)) { - unlock_kernel(); + tty_unlock(); return -EIO; } n_hdlc = tty2n_hdlc (tty); if (!n_hdlc || n_hdlc->magic != HDLC_MAGIC || tty != n_hdlc->tty) { - unlock_kernel(); + tty_unlock(); return 0; } @@ -619,13 +619,13 @@ static ssize_t n_hdlc_tty_read(struct tty_struct *tty, struct file *file, /* no data */ if (file->f_flags & O_NONBLOCK) { - unlock_kernel(); + tty_unlock(); return -EAGAIN; } interruptible_sleep_on (&tty->read_wait); if (signal_pending(current)) { - unlock_kernel(); + tty_unlock(); return -EINTR; } } @@ -648,7 +648,7 @@ static ssize_t n_hdlc_tty_read(struct tty_struct *tty, struct file *file, kfree(rbuf); else n_hdlc_buf_put(&n_hdlc->rx_free_buf_list,rbuf); - unlock_kernel(); + tty_unlock(); return ret; } /* end of n_hdlc_tty_read() */ @@ -691,7 +691,7 @@ static ssize_t n_hdlc_tty_write(struct tty_struct *tty, struct file *file, count = maxframe; } - lock_kernel(); + tty_lock(); add_wait_queue(&tty->write_wait, &wait); set_current_state(TASK_INTERRUPTIBLE); @@ -731,7 +731,7 @@ static ssize_t n_hdlc_tty_write(struct tty_struct *tty, struct file *file, n_hdlc_buf_put(&n_hdlc->tx_buf_list,tbuf); n_hdlc_send_frames(n_hdlc,tty); } - unlock_kernel(); + tty_unlock(); return error; } /* end of n_hdlc_tty_write() */ diff --git a/drivers/char/n_r3964.c b/drivers/char/n_r3964.c index c1d8b54c816..a98290d7a2c 100644 --- a/drivers/char/n_r3964.c +++ b/drivers/char/n_r3964.c @@ -1067,7 +1067,7 @@ static ssize_t r3964_read(struct tty_struct *tty, struct file *file, TRACE_L("read()"); - lock_kernel(); + tty_lock(); pClient = findClient(pInfo, task_pid(current)); if (pClient) { @@ -1079,7 +1079,7 @@ static ssize_t r3964_read(struct tty_struct *tty, struct file *file, goto unlock; } /* block until there is a message: */ - wait_event_interruptible(pInfo->read_wait, + wait_event_interruptible_tty(pInfo->read_wait, (pMsg = remove_msg(pInfo, pClient))); } @@ -1109,7 +1109,7 @@ static ssize_t r3964_read(struct tty_struct *tty, struct file *file, } ret = -EPERM; unlock: - unlock_kernel(); + tty_unlock(); return ret; } @@ -1158,7 +1158,7 @@ static ssize_t r3964_write(struct tty_struct *tty, struct file *file, pHeader->locks = 0; pHeader->owner = NULL; - lock_kernel(); + tty_lock(); pClient = findClient(pInfo, task_pid(current)); if (pClient) { @@ -1177,7 +1177,7 @@ static ssize_t r3964_write(struct tty_struct *tty, struct file *file, add_tx_queue(pInfo, pHeader); trigger_transmit(pInfo); - unlock_kernel(); + tty_unlock(); return 0; } diff --git a/drivers/char/n_tty.c b/drivers/char/n_tty.c index bdae8327143..428f4fe0b5f 100644 --- a/drivers/char/n_tty.c +++ b/drivers/char/n_tty.c @@ -1102,6 +1102,11 @@ static inline void n_tty_receive_char(struct tty_struct *tty, unsigned char c) if (I_IUCLC(tty) && L_IEXTEN(tty)) c = tolower(c); + if (L_EXTPROC(tty)) { + put_tty_queue(c, tty); + return; + } + 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) && c != SUSP_CHAR(tty)) { @@ -1409,7 +1414,8 @@ static void n_tty_receive_buf(struct tty_struct *tty, const unsigned char *cp, n_tty_set_room(tty); - if (!tty->icanon && (tty->read_cnt >= tty->minimum_to_wake)) { + if ((!tty->icanon && (tty->read_cnt >= tty->minimum_to_wake)) || + L_EXTPROC(tty)) { kill_fasync(&tty->fasync, SIGIO, POLL_IN); if (waitqueue_active(&tty->read_wait)) wake_up_interruptible(&tty->read_wait); @@ -1585,7 +1591,7 @@ static int n_tty_open(struct tty_struct *tty) static inline int input_available_p(struct tty_struct *tty, int amt) { tty_flush_to_ldisc(tty); - if (tty->icanon) { + if (tty->icanon && !L_EXTPROC(tty)) { if (tty->canon_data) return 1; } else if (tty->read_cnt >= (amt ? amt : 1)) @@ -1632,6 +1638,11 @@ static int copy_from_read_buf(struct tty_struct *tty, spin_lock_irqsave(&tty->read_lock, flags); tty->read_tail = (tty->read_tail + n) & (N_TTY_BUF_SIZE-1); tty->read_cnt -= n; + /* Turn single EOF into zero-length read */ + if (L_EXTPROC(tty) && tty->icanon && n == 1) { + if (!tty->read_cnt && (*b)[n-1] == EOF_CHAR(tty)) + n--; + } spin_unlock_irqrestore(&tty->read_lock, flags); *b += n; *nr -= n; @@ -1812,7 +1823,7 @@ do_it_again: nr--; } - if (tty->icanon) { + if (tty->icanon && !L_EXTPROC(tty)) { /* N.B. avoid overrun if nr == 0 */ while (nr && tty->read_cnt) { int eol; diff --git a/drivers/char/nozomi.c b/drivers/char/nozomi.c index a6638003f53..817169cbb24 100644 --- a/drivers/char/nozomi.c +++ b/drivers/char/nozomi.c @@ -1611,6 +1611,8 @@ static int ntty_install(struct tty_driver *driver, struct tty_struct *tty) ret = tty_init_termios(tty); if (ret == 0) { tty_driver_kref_get(driver); + tty->count++; + tty->driver_data = port; driver->ttys[tty->index] = tty; } return ret; @@ -1639,7 +1641,7 @@ static int ntty_activate(struct tty_port *tport, struct tty_struct *tty) static int ntty_open(struct tty_struct *tty, struct file *filp) { - struct port *port = get_port_by_tty(tty); + struct port *port = tty->driver_data; return tty_port_open(&port->port, tty, filp); } @@ -1741,8 +1743,7 @@ static int ntty_write_room(struct tty_struct *tty) if (dc) { mutex_lock(&port->tty_sem); if (port->port.count) - room = port->fifo_ul.size - - kfifo_len(&port->fifo_ul); + room = kfifo_avail(&port->fifo_ul); mutex_unlock(&port->tty_sem); } return room; diff --git a/drivers/char/pcmcia/cm4000_cs.c b/drivers/char/pcmcia/cm4000_cs.c index e7956acf2ad..ec73d9f6d9e 100644 --- a/drivers/char/pcmcia/cm4000_cs.c +++ b/drivers/char/pcmcia/cm4000_cs.c @@ -34,7 +34,6 @@ #include <linux/uaccess.h> #include <linux/io.h> -#include <pcmcia/cs_types.h> #include <pcmcia/cs.h> #include <pcmcia/cistpl.h> #include <pcmcia/cisreg.h> @@ -422,7 +421,7 @@ static struct card_fixup card_fixups[] = { static void set_cardparameter(struct cm4000_dev *dev) { int i; - unsigned int iobase = dev->p_dev->io.BasePort1; + unsigned int iobase = dev->p_dev->resource[0]->start; u_int8_t stopbits = 0x02; /* ISO default */ DEBUGP(3, dev, "-> set_cardparameter\n"); @@ -455,7 +454,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; - unsigned int iobase = dev->p_dev->io.BasePort1; + unsigned int iobase = dev->p_dev->resource[0]->start; rc = 0; @@ -664,7 +663,7 @@ static void terminate_monitor(struct cm4000_dev *dev) static void monitor_card(unsigned long p) { struct cm4000_dev *dev = (struct cm4000_dev *) p; - unsigned int iobase = dev->p_dev->io.BasePort1; + unsigned int iobase = dev->p_dev->resource[0]->start; unsigned short s; struct ptsreq ptsreq; int i, atrc; @@ -925,7 +924,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; - unsigned int iobase = dev->p_dev->io.BasePort1; + unsigned int iobase = dev->p_dev->resource[0]->start; ssize_t rc; int i, j, k; @@ -1048,7 +1047,7 @@ static ssize_t cmm_write(struct file *filp, const char __user *buf, size_t count, loff_t *ppos) { struct cm4000_dev *dev = filp->private_data; - unsigned int iobase = dev->p_dev->io.BasePort1; + unsigned int iobase = dev->p_dev->resource[0]->start; unsigned short s; unsigned char tmp; unsigned char infolen; @@ -1401,7 +1400,7 @@ static void stop_monitor(struct cm4000_dev *dev) static long cmm_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) { struct cm4000_dev *dev = filp->private_data; - unsigned int iobase = dev->p_dev->io.BasePort1; + unsigned int iobase = dev->p_dev->resource[0]->start; struct inode *inode = filp->f_path.dentry->d_inode; struct pcmcia_device *link; int size; @@ -1752,17 +1751,12 @@ static int cm4000_config_check(struct pcmcia_device *p_dev, if (!cfg->io.nwin) return -ENODEV; - /* Get the IOaddr */ - p_dev->io.BasePort1 = cfg->io.win[0].base; - p_dev->io.NumPorts1 = cfg->io.win[0].len; - p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO; - if (!(cfg->io.flags & CISTPL_IO_8BIT)) - p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_16; - if (!(cfg->io.flags & CISTPL_IO_16BIT)) - p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_8; - p_dev->io.IOAddrLines = cfg->io.flags & CISTPL_IO_LINES_MASK; - - return pcmcia_request_io(p_dev, &p_dev->io); + p_dev->resource[0]->start = cfg->io.win[0].base; + p_dev->resource[0]->end = cfg->io.win[0].len; + p_dev->resource[0]->flags |= pcmcia_io_cfg_data_width(cfg->io.flags); + p_dev->io_lines = cfg->io.flags & CISTPL_IO_LINES_MASK; + + return pcmcia_request_io(p_dev); } static int cm4000_config(struct pcmcia_device * link, int devno) diff --git a/drivers/char/pcmcia/cm4040_cs.c b/drivers/char/pcmcia/cm4040_cs.c index c0775c844e0..815cde1d057 100644 --- a/drivers/char/pcmcia/cm4040_cs.c +++ b/drivers/char/pcmcia/cm4040_cs.c @@ -29,7 +29,6 @@ #include <asm/uaccess.h> #include <asm/io.h> -#include <pcmcia/cs_types.h> #include <pcmcia/cs.h> #include <pcmcia/cistpl.h> #include <pcmcia/cisreg.h> @@ -110,7 +109,7 @@ static inline unsigned char xinb(unsigned short port) static void cm4040_do_poll(unsigned long dummy) { struct reader_dev *dev = (struct reader_dev *) dummy; - unsigned int obs = xinb(dev->p_dev->io.BasePort1 + unsigned int obs = xinb(dev->p_dev->resource[0]->start + REG_OFFSET_BUFFER_STATUS); if ((obs & BSR_BULK_IN_FULL)) { @@ -141,7 +140,7 @@ static void cm4040_stop_poll(struct reader_dev *dev) static int wait_for_bulk_out_ready(struct reader_dev *dev) { int i, rc; - int iobase = dev->p_dev->io.BasePort1; + int iobase = dev->p_dev->resource[0]->start; for (i = 0; i < POLL_LOOP_COUNT; i++) { if ((xinb(iobase + REG_OFFSET_BUFFER_STATUS) @@ -171,7 +170,7 @@ static int wait_for_bulk_out_ready(struct reader_dev *dev) /* Write to Sync Control Register */ static int write_sync_reg(unsigned char val, struct reader_dev *dev) { - int iobase = dev->p_dev->io.BasePort1; + int iobase = dev->p_dev->resource[0]->start; int rc; rc = wait_for_bulk_out_ready(dev); @@ -189,7 +188,7 @@ static int write_sync_reg(unsigned char val, struct reader_dev *dev) static int wait_for_bulk_in_ready(struct reader_dev *dev) { int i, rc; - int iobase = dev->p_dev->io.BasePort1; + int iobase = dev->p_dev->resource[0]->start; for (i = 0; i < POLL_LOOP_COUNT; i++) { if ((xinb(iobase + REG_OFFSET_BUFFER_STATUS) @@ -219,7 +218,7 @@ static ssize_t cm4040_read(struct file *filp, char __user *buf, size_t count, loff_t *ppos) { struct reader_dev *dev = filp->private_data; - int iobase = dev->p_dev->io.BasePort1; + int iobase = dev->p_dev->resource[0]->start; size_t bytes_to_read; unsigned long i; size_t min_bytes_to_read; @@ -321,7 +320,7 @@ static ssize_t cm4040_write(struct file *filp, const char __user *buf, size_t count, loff_t *ppos) { struct reader_dev *dev = filp->private_data; - int iobase = dev->p_dev->io.BasePort1; + int iobase = dev->p_dev->resource[0]->start; ssize_t rc; int i; unsigned int bytes_to_write; @@ -528,16 +527,12 @@ static int cm4040_config_check(struct pcmcia_device *p_dev, return -ENODEV; /* Get the IOaddr */ - p_dev->io.BasePort1 = cfg->io.win[0].base; - p_dev->io.NumPorts1 = cfg->io.win[0].len; - p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO; - if (!(cfg->io.flags & CISTPL_IO_8BIT)) - p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_16; - if (!(cfg->io.flags & CISTPL_IO_16BIT)) - p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_8; - p_dev->io.IOAddrLines = cfg->io.flags & CISTPL_IO_LINES_MASK; - - rc = pcmcia_request_io(p_dev, &p_dev->io); + p_dev->resource[0]->start = cfg->io.win[0].base; + p_dev->resource[0]->end = cfg->io.win[0].len; + p_dev->resource[0]->flags |= pcmcia_io_cfg_data_width(cfg->io.flags); + p_dev->io_lines = cfg->io.flags & CISTPL_IO_LINES_MASK; + rc = pcmcia_request_io(p_dev); + dev_printk(KERN_INFO, &p_dev->dev, "pcmcia_request_io returned 0x%x\n", rc); return rc; @@ -549,10 +544,6 @@ static int reader_config(struct pcmcia_device *link, int devno) struct reader_dev *dev; int fail_rc; - link->io.BasePort2 = 0; - link->io.NumPorts2 = 0; - link->io.Attributes2 = 0; - if (pcmcia_loop_config(link, cm4040_config_check, NULL)) goto cs_release; @@ -568,8 +559,8 @@ static int reader_config(struct pcmcia_device *link, int devno) dev = link->priv; - DEBUGP(2, dev, "device " DEVICE_NAME "%d at 0x%.4x-0x%.4x\n", devno, - link->io.BasePort1, link->io.BasePort1+link->io.NumPorts1); + DEBUGP(2, dev, "device " DEVICE_NAME "%d at %pR\n", devno, + link->resource[0]); DEBUGP(2, dev, "<- reader_config (succ)\n"); return 0; diff --git a/drivers/char/pcmcia/ipwireless/main.c b/drivers/char/pcmcia/ipwireless/main.c index 63c32e3f23b..67bdb05798b 100644 --- a/drivers/char/pcmcia/ipwireless/main.c +++ b/drivers/char/pcmcia/ipwireless/main.c @@ -84,23 +84,22 @@ static int ipwireless_probe(struct pcmcia_device *p_dev, { struct ipw_dev *ipw = priv_data; struct resource *io_resource; - memreq_t memreq_attr_memory; - memreq_t memreq_common_memory; int ret; - p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO; - p_dev->io.BasePort1 = cfg->io.win[0].base; - p_dev->io.NumPorts1 = cfg->io.win[0].len; - p_dev->io.IOAddrLines = 16; + p_dev->resource[0]->flags |= IO_DATA_PATH_WIDTH_AUTO; + p_dev->resource[0]->start = cfg->io.win[0].base; + p_dev->resource[0]->end = cfg->io.win[0].len; /* 0x40 causes it to generate level mode interrupts. */ /* 0x04 enables IREQ pin. */ p_dev->conf.ConfigIndex = cfg->index | 0x44; - ret = pcmcia_request_io(p_dev, &p_dev->io); + p_dev->io_lines = 16; + ret = pcmcia_request_io(p_dev); if (ret) return ret; - io_resource = request_region(p_dev->io.BasePort1, p_dev->io.NumPorts1, + io_resource = request_region(p_dev->resource[0]->start, + resource_size(p_dev->resource[0]), IPWIRELESS_PCCARD_NAME); if (cfg->mem.nwin == 0) @@ -120,11 +119,8 @@ static int ipwireless_probe(struct pcmcia_device *p_dev, if (ret != 0) goto exit1; - memreq_common_memory.CardOffset = cfg->mem.win[0].card_addr; - memreq_common_memory.Page = 0; - ret = pcmcia_map_mem_page(p_dev, ipw->handle_common_memory, - &memreq_common_memory); + cfg->mem.win[0].card_addr); if (ret != 0) goto exit2; @@ -149,12 +145,7 @@ static int ipwireless_probe(struct pcmcia_device *p_dev, if (ret != 0) goto exit2; - memreq_attr_memory.CardOffset = 0; - memreq_attr_memory.Page = 0; - - ret = pcmcia_map_mem_page(p_dev, ipw->handle_attr_memory, - &memreq_attr_memory); - + ret = pcmcia_map_mem_page(p_dev, ipw->handle_attr_memory, 0); if (ret != 0) goto exit3; @@ -166,15 +157,12 @@ static int ipwireless_probe(struct pcmcia_device *p_dev, return 0; exit3: - pcmcia_release_window(p_dev, ipw->handle_attr_memory); exit2: if (ipw->common_memory) { release_mem_region(ipw->request_common_memory.Base, ipw->request_common_memory.Size); iounmap(ipw->common_memory); - pcmcia_release_window(p_dev, ipw->handle_common_memory); - } else - pcmcia_release_window(p_dev, ipw->handle_common_memory); + } exit1: release_resource(io_resource); pcmcia_disable_device(p_dev); @@ -197,7 +185,7 @@ static int config_ipwireless(struct ipw_dev *ipw) INIT_WORK(&ipw->work_reboot, signalled_reboot_work); - ipwireless_init_hardware_v1(ipw->hardware, link->io.BasePort1, + ipwireless_init_hardware_v1(ipw->hardware, link->resource[0]->start, ipw->attr_memory, ipw->common_memory, ipw->is_v2_card, signalled_reboot_callback, ipw); @@ -209,10 +197,7 @@ static int config_ipwireless(struct ipw_dev *ipw) printk(KERN_INFO IPWIRELESS_PCCARD_NAME ": Card type %s\n", ipw->is_v2_card ? "V2/V3" : "V1"); printk(KERN_INFO IPWIRELESS_PCCARD_NAME - ": I/O ports 0x%04x-0x%04x, irq %d\n", - (unsigned int) link->io.BasePort1, - (unsigned int) (link->io.BasePort1 + - link->io.NumPorts1 - 1), + ": I/O ports %pR, irq %d\n", link->resource[0], (unsigned int) link->irq); if (ipw->attr_memory && ipw->common_memory) printk(KERN_INFO IPWIRELESS_PCCARD_NAME @@ -250,13 +235,12 @@ exit: release_mem_region(ipw->request_attr_memory.Base, ipw->request_attr_memory.Size); iounmap(ipw->attr_memory); - pcmcia_release_window(link, ipw->handle_attr_memory); + } if (ipw->common_memory) { release_mem_region(ipw->request_common_memory.Base, ipw->request_common_memory.Size); iounmap(ipw->common_memory); - pcmcia_release_window(link, ipw->handle_common_memory); } pcmcia_disable_device(link); return -1; @@ -274,11 +258,6 @@ static void release_ipwireless(struct ipw_dev *ipw) ipw->request_attr_memory.Size); iounmap(ipw->attr_memory); } - if (ipw->common_memory) - pcmcia_release_window(ipw->link, ipw->handle_common_memory); - if (ipw->attr_memory) - pcmcia_release_window(ipw->link, ipw->handle_attr_memory); - pcmcia_disable_device(ipw->link); } diff --git a/drivers/char/pcmcia/ipwireless/main.h b/drivers/char/pcmcia/ipwireless/main.h index 96d0ef31b17..c207be87b59 100644 --- a/drivers/char/pcmcia/ipwireless/main.h +++ b/drivers/char/pcmcia/ipwireless/main.h @@ -21,7 +21,6 @@ #include <linux/sched.h> #include <linux/types.h> -#include <pcmcia/cs_types.h> #include <pcmcia/cs.h> #include <pcmcia/cistpl.h> #include <pcmcia/ds.h> diff --git a/drivers/char/pcmcia/ipwireless/tty.h b/drivers/char/pcmcia/ipwireless/tty.h index 4da6c201f72..3e163d4cab1 100644 --- a/drivers/char/pcmcia/ipwireless/tty.h +++ b/drivers/char/pcmcia/ipwireless/tty.h @@ -21,7 +21,6 @@ #include <linux/types.h> #include <linux/sched.h> -#include <pcmcia/cs_types.h> #include <pcmcia/cs.h> #include <pcmcia/cistpl.h> #include <pcmcia/ds.h> diff --git a/drivers/char/pcmcia/synclink_cs.c b/drivers/char/pcmcia/synclink_cs.c index 308903ec8bf..9ecd6bef5d3 100644 --- a/drivers/char/pcmcia/synclink_cs.c +++ b/drivers/char/pcmcia/synclink_cs.c @@ -70,7 +70,6 @@ #include <linux/workqueue.h> #include <linux/hdlc.h> -#include <pcmcia/cs_types.h> #include <pcmcia/cs.h> #include <pcmcia/cistpl.h> #include <pcmcia/cisreg.h> @@ -572,18 +571,15 @@ static int mgslpc_ioprobe(struct pcmcia_device *p_dev, unsigned int vcc, void *priv_data) { - if (cfg->io.nwin > 0) { - p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO; - if (!(cfg->io.flags & CISTPL_IO_8BIT)) - p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_16; - if (!(cfg->io.flags & CISTPL_IO_16BIT)) - p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_8; - p_dev->io.IOAddrLines = cfg->io.flags & CISTPL_IO_LINES_MASK; - p_dev->io.BasePort1 = cfg->io.win[0].base; - p_dev->io.NumPorts1 = cfg->io.win[0].len; - return pcmcia_request_io(p_dev, &p_dev->io); - } - return -ENODEV; + if (!cfg->io.nwin) + return -ENODEV; + + p_dev->resource[0]->start = cfg->io.win[0].base; + p_dev->resource[0]->end = cfg->io.win[0].len; + p_dev->resource[0]->flags |= pcmcia_io_cfg_data_width(cfg->io.flags); + p_dev->io_lines = cfg->io.flags & CISTPL_IO_LINES_MASK; + + return pcmcia_request_io(p_dev); } static int mgslpc_config(struct pcmcia_device *link) @@ -610,16 +606,15 @@ static int mgslpc_config(struct pcmcia_device *link) if (ret) goto failed; - info->io_base = link->io.BasePort1; + info->io_base = link->resource[0]->start; info->irq_level = link->irq; dev_info(&link->dev, "index 0x%02x:", link->conf.ConfigIndex); if (link->conf.Attributes & CONF_ENABLE_IRQ) printk(", irq %d", link->irq); - if (link->io.NumPorts1) - printk(", io 0x%04x-0x%04x", link->io.BasePort1, - link->io.BasePort1+link->io.NumPorts1-1); + if (link->resource[0]) + printk(", io %pR", link->resource[0]); printk("\n"); return 0; diff --git a/drivers/char/pty.c b/drivers/char/pty.c index d83a43130df..c350d01716b 100644 --- a/drivers/char/pty.c +++ b/drivers/char/pty.c @@ -62,7 +62,9 @@ static void pty_close(struct tty_struct *tty, struct file *filp) if (tty->driver == ptm_driver) devpts_pty_kill(tty->link); #endif + tty_unlock(); tty_vhangup(tty->link); + tty_lock(); } } @@ -171,6 +173,23 @@ static int pty_set_lock(struct tty_struct *tty, int __user *arg) return 0; } +/* Send a signal to the slave */ +static int pty_signal(struct tty_struct *tty, int sig) +{ + unsigned long flags; + struct pid *pgrp; + + if (tty->link) { + spin_lock_irqsave(&tty->link->ctrl_lock, flags); + pgrp = get_pid(tty->link->pgrp); + spin_unlock_irqrestore(&tty->link->ctrl_lock, flags); + + kill_pgrp(pgrp, sig, 1); + put_pid(pgrp); + } + return 0; +} + static void pty_flush_buffer(struct tty_struct *tty) { struct tty_struct *to = tty->link; @@ -321,6 +340,8 @@ static int pty_bsd_ioctl(struct tty_struct *tty, struct file *file, switch (cmd) { case TIOCSPTLCK: /* Set PT Lock (disallow slave open) */ return pty_set_lock(tty, (int __user *) arg); + case TIOCSIG: /* Send signal to other side of pty */ + return pty_signal(tty, (int) arg); } return -ENOIOCTLCMD; } @@ -476,6 +497,8 @@ static int pty_unix98_ioctl(struct tty_struct *tty, struct file *file, return pty_set_lock(tty, (int __user *)arg); case TIOCGPTN: /* Get PT Number */ return put_user(tty->index, (unsigned int __user *)arg); + case TIOCSIG: /* Send signal to other side of pty */ + return pty_signal(tty, (int) arg); } return -ENOIOCTLCMD; @@ -626,7 +649,7 @@ static const struct tty_operations pty_unix98_ops = { * allocated_ptys_lock handles the list of free pty numbers */ -static int __ptmx_open(struct inode *inode, struct file *filp) +static int ptmx_open(struct inode *inode, struct file *filp) { struct tty_struct *tty; int retval; @@ -635,11 +658,14 @@ static int __ptmx_open(struct inode *inode, struct file *filp) nonseekable_open(inode, filp); /* find a device that is not in use. */ + tty_lock(); index = devpts_new_index(inode); + tty_unlock(); if (index < 0) return index; mutex_lock(&tty_mutex); + tty_lock(); tty = tty_init_dev(ptm_driver, index, 1); mutex_unlock(&tty_mutex); @@ -649,34 +675,29 @@ static int __ptmx_open(struct inode *inode, struct file *filp) } set_bit(TTY_PTY_LOCK, &tty->flags); /* LOCK THE SLAVE */ - filp->private_data = tty; - file_move(filp, &tty->tty_files); + + tty_add_file(tty, filp); retval = devpts_pty_new(inode, tty->link); if (retval) goto out1; retval = ptm_driver->ops->open(tty, filp); - if (!retval) - return 0; + if (retval) + goto out2; out1: + tty_unlock(); + return retval; +out2: + tty_unlock(); tty_release(inode, filp); return retval; out: devpts_kill_index(inode, index); + tty_unlock(); return retval; } -static int ptmx_open(struct inode *inode, struct file *filp) -{ - int ret; - - lock_kernel(); - ret = __ptmx_open(inode, filp); - unlock_kernel(); - return ret; -} - static struct file_operations ptmx_fops; static void __init unix98_pty_init(void) diff --git a/drivers/char/riscom8.c b/drivers/char/riscom8.c index b02332a5412..af4de1fe844 100644 --- a/drivers/char/riscom8.c +++ b/drivers/char/riscom8.c @@ -47,7 +47,6 @@ #include <linux/init.h> #include <linux/delay.h> #include <linux/tty_flip.h> -#include <linux/smp_lock.h> #include <linux/spinlock.h> #include <linux/device.h> @@ -1184,6 +1183,7 @@ static int rc_set_serial_info(struct tty_struct *tty, struct riscom_port *port, if (copy_from_user(&tmp, newinfo, sizeof(tmp))) return -EFAULT; + mutex_lock(&port->port.mutex); change_speed = ((port->port.flags & ASYNC_SPD_MASK) != (tmp.flags & ASYNC_SPD_MASK)); @@ -1191,8 +1191,10 @@ static int rc_set_serial_info(struct tty_struct *tty, struct riscom_port *port, if ((tmp.close_delay != port->port.close_delay) || (tmp.closing_wait != port->port.closing_wait) || ((tmp.flags & ~ASYNC_USR_MASK) != - (port->port.flags & ~ASYNC_USR_MASK))) + (port->port.flags & ~ASYNC_USR_MASK))) { + mutex_unlock(&port->port.mutex); return -EPERM; + } port->port.flags = ((port->port.flags & ~ASYNC_USR_MASK) | (tmp.flags & ASYNC_USR_MASK)); } else { @@ -1208,6 +1210,7 @@ static int rc_set_serial_info(struct tty_struct *tty, struct riscom_port *port, rc_change_speed(tty, bp, port); spin_unlock_irqrestore(&riscom_lock, flags); } + mutex_unlock(&port->port.mutex); return 0; } @@ -1220,12 +1223,15 @@ static int rc_get_serial_info(struct riscom_port *port, memset(&tmp, 0, sizeof(tmp)); tmp.type = PORT_CIRRUS; tmp.line = port - rc_port; + + mutex_lock(&port->port.mutex); tmp.port = bp->base; tmp.irq = bp->irq; tmp.flags = port->port.flags; tmp.baud_base = (RC_OSCFREQ + CD180_TPC/2) / CD180_TPC; tmp.close_delay = port->port.close_delay * HZ/100; tmp.closing_wait = port->port.closing_wait * HZ/100; + mutex_unlock(&port->port.mutex); tmp.xmit_fifo_size = CD180_NFIFO; return copy_to_user(retinfo, &tmp, sizeof(tmp)) ? -EFAULT : 0; } @@ -1242,14 +1248,10 @@ static int rc_ioctl(struct tty_struct *tty, struct file *filp, switch (cmd) { case TIOCGSERIAL: - lock_kernel(); retval = rc_get_serial_info(port, argp); - unlock_kernel(); break; case TIOCSSERIAL: - lock_kernel(); retval = rc_set_serial_info(tty, port, argp); - unlock_kernel(); break; default: retval = -ENOIOCTLCMD; diff --git a/drivers/char/rocket.c b/drivers/char/rocket.c index 0e29a23ec4c..7c79d243acc 100644 --- a/drivers/char/rocket.c +++ b/drivers/char/rocket.c @@ -73,7 +73,6 @@ #include <linux/tty_driver.h> #include <linux/tty_flip.h> #include <linux/serial.h> -#include <linux/smp_lock.h> #include <linux/string.h> #include <linux/fcntl.h> #include <linux/ptrace.h> @@ -1017,6 +1016,7 @@ static void rp_close(struct tty_struct *tty, struct file *filp) if (tty_port_close_start(port, tty, filp) == 0) return; + mutex_lock(&port->mutex); cp = &info->channel; /* * Before we drop DTR, make sure the UART transmitter @@ -1060,9 +1060,13 @@ static void rp_close(struct tty_struct *tty, struct file *filp) info->xmit_buf = NULL; } } + spin_lock_irq(&port->lock); info->port.flags &= ~(ASYNC_INITIALIZED | ASYNC_CLOSING | ASYNC_NORMAL_ACTIVE); tty->closing = 0; + spin_unlock_irq(&port->lock); + mutex_unlock(&port->mutex); tty_port_tty_set(port, NULL); + wake_up_interruptible(&port->close_wait); complete_all(&info->close_wait); atomic_dec(&rp_num_ports_open); @@ -1210,11 +1214,13 @@ static int get_config(struct r_port *info, struct rocket_config __user *retinfo) if (!retinfo) return -EFAULT; memset(&tmp, 0, sizeof (tmp)); + mutex_lock(&info->port.mutex); tmp.line = info->line; tmp.flags = info->flags; tmp.close_delay = info->port.close_delay; tmp.closing_wait = info->port.closing_wait; tmp.port = rcktpt_io_addr[(info->line >> 5) & 3]; + mutex_unlock(&info->port.mutex); if (copy_to_user(retinfo, &tmp, sizeof (*retinfo))) return -EFAULT; @@ -1229,12 +1235,16 @@ static int set_config(struct tty_struct *tty, struct r_port *info, if (copy_from_user(&new_serial, new_info, sizeof (new_serial))) return -EFAULT; + mutex_lock(&info->port.mutex); if (!capable(CAP_SYS_ADMIN)) { - if ((new_serial.flags & ~ROCKET_USR_MASK) != (info->flags & ~ROCKET_USR_MASK)) + if ((new_serial.flags & ~ROCKET_USR_MASK) != (info->flags & ~ROCKET_USR_MASK)) { + mutex_unlock(&info->port.mutex); return -EPERM; + } info->flags = ((info->flags & ~ROCKET_USR_MASK) | (new_serial.flags & ROCKET_USR_MASK)); configure_r_port(tty, info, NULL); + mutex_unlock(&info->port.mutex); return 0; } @@ -1250,6 +1260,7 @@ static int set_config(struct tty_struct *tty, struct r_port *info, tty->alt_speed = 230400; if ((info->flags & ROCKET_SPD_MASK) == ROCKET_SPD_WARP) tty->alt_speed = 460800; + mutex_unlock(&info->port.mutex); configure_r_port(tty, info, NULL); return 0; @@ -1325,8 +1336,6 @@ static int rp_ioctl(struct tty_struct *tty, struct file *file, if (cmd != RCKP_GET_PORTS && rocket_paranoia_check(info, "rp_ioctl")) return -ENXIO; - lock_kernel(); - switch (cmd) { case RCKP_GET_STRUCT: if (copy_to_user(argp, info, sizeof (struct r_port))) @@ -1350,7 +1359,6 @@ static int rp_ioctl(struct tty_struct *tty, struct file *file, default: ret = -ENOIOCTLCMD; } - unlock_kernel(); return ret; } @@ -1471,7 +1479,6 @@ static void rp_wait_until_sent(struct tty_struct *tty, int timeout) jiffies); printk(KERN_INFO "cps=%d...\n", info->cps); #endif - lock_kernel(); while (1) { txcnt = sGetTxCnt(cp); if (!txcnt) { @@ -1499,7 +1506,6 @@ static void rp_wait_until_sent(struct tty_struct *tty, int timeout) break; } __set_current_state(TASK_RUNNING); - unlock_kernel(); #ifdef ROCKET_DEBUG_WAIT_UNTIL_SENT printk(KERN_INFO "txcnt = %d (jiff=%lu)...done\n", txcnt, jiffies); #endif @@ -1512,6 +1518,7 @@ static void rp_hangup(struct tty_struct *tty) { CHANNEL_t *cp; struct r_port *info = tty->driver_data; + unsigned long flags; if (rocket_paranoia_check(info, "rp_hangup")) return; @@ -1520,11 +1527,15 @@ static void rp_hangup(struct tty_struct *tty) printk(KERN_INFO "rp_hangup of ttyR%d...\n", info->line); #endif rp_flush_buffer(tty); - if (info->port.flags & ASYNC_CLOSING) + spin_lock_irqsave(&info->port.lock, flags); + if (info->port.flags & ASYNC_CLOSING) { + spin_unlock_irqrestore(&info->port.lock, flags); return; + } if (info->port.count) atomic_dec(&rp_num_ports_open); clear_bit((info->aiop * 8) + info->chan, (void *) &xmit_flags[info->board]); + spin_unlock_irqrestore(&info->port.lock, flags); tty_port_hangup(&info->port); @@ -1535,7 +1546,7 @@ static void rp_hangup(struct tty_struct *tty) sDisCTSFlowCtl(cp); sDisTxSoftFlowCtl(cp); sClrTxXOFF(cp); - info->port.flags &= ~ASYNC_INITIALIZED; + clear_bit(ASYNCB_INITIALIZED, &info->port.flags); wake_up_interruptible(&info->port.open_wait); } diff --git a/drivers/char/rtc.c b/drivers/char/rtc.c index 95acb8c880f..dfa8b3062fd 100644 --- a/drivers/char/rtc.c +++ b/drivers/char/rtc.c @@ -961,7 +961,7 @@ static int __init rtc_init(void) #endif #ifdef CONFIG_SPARC32 struct device_node *ebus_dp; - struct of_device *op; + struct platform_device *op; #else void *r; #ifdef RTC_IRQ diff --git a/drivers/char/selection.c b/drivers/char/selection.c index f97b9e84806..ebae344ce91 100644 --- a/drivers/char/selection.c +++ b/drivers/char/selection.c @@ -26,6 +26,7 @@ #include <linux/selection.h> #include <linux/tiocl.h> #include <linux/console.h> +#include <linux/smp_lock.h> /* Don't take this from <ctype.h>: 011-015 on the screen aren't spaces */ #define isspace(c) ((c) == ' ') @@ -312,12 +313,20 @@ int paste_selection(struct tty_struct *tty) struct tty_ldisc *ld; DECLARE_WAITQUEUE(wait, current); + /* always called with BTM from vt_ioctl */ + WARN_ON(!tty_locked()); + acquire_console_sem(); poke_blanked_console(); release_console_sem(); - ld = tty_ldisc_ref_wait(tty); - + ld = tty_ldisc_ref(tty); + if (!ld) { + tty_unlock(); + ld = tty_ldisc_ref_wait(tty); + tty_lock(); + } + add_wait_queue(&vc->paste_wait, &wait); while (sel_buffer && sel_buffer_lth > pasted) { set_current_state(TASK_INTERRUPTIBLE); diff --git a/drivers/char/serial167.c b/drivers/char/serial167.c index ecbe479c7d6..f646725bd56 100644 --- a/drivers/char/serial167.c +++ b/drivers/char/serial167.c @@ -1505,7 +1505,7 @@ cy_ioctl(struct tty_struct *tty, struct file *file, printk("cy_ioctl %s, cmd = %x arg = %lx\n", tty->name, cmd, arg); /* */ #endif - lock_kernel(); + tty_lock(); switch (cmd) { case CYGETMON: @@ -1561,7 +1561,7 @@ cy_ioctl(struct tty_struct *tty, struct file *file, default: ret_val = -ENOIOCTLCMD; } - unlock_kernel(); + tty_unlock(); #ifdef SERIAL_DEBUG_OTHER printk("cy_ioctl done\n"); @@ -1786,7 +1786,9 @@ block_til_ready(struct tty_struct *tty, struct file *filp, tty->name, info->count); /**/ #endif - schedule(); + tty_unlock(); + schedule(); + tty_lock(); } __set_current_state(TASK_RUNNING); remove_wait_queue(&info->open_wait, &wait); diff --git a/drivers/char/specialix.c b/drivers/char/specialix.c index 2c24fcdc722..9f8495b4fc8 100644 --- a/drivers/char/specialix.c +++ b/drivers/char/specialix.c @@ -1365,7 +1365,9 @@ static int block_til_ready(struct tty_struct *tty, struct file *filp, retval = -ERESTARTSYS; break; } + tty_unlock(); schedule(); + tty_lock(); } set_current_state(TASK_RUNNING); @@ -1863,8 +1865,7 @@ static int sx_set_serial_info(struct specialix_port *port, return -EFAULT; } - lock_kernel(); - + mutex_lock(&port->port.mutex); change_speed = ((port->port.flags & ASYNC_SPD_MASK) != (tmp.flags & ASYNC_SPD_MASK)); change_speed |= (tmp.custom_divisor != port->custom_divisor); @@ -1875,7 +1876,7 @@ static int sx_set_serial_info(struct specialix_port *port, ((tmp.flags & ~ASYNC_USR_MASK) != (port->port.flags & ~ASYNC_USR_MASK))) { func_exit(); - unlock_kernel(); + mutex_unlock(&port->port.mutex); return -EPERM; } port->port.flags = ((port->port.flags & ~ASYNC_USR_MASK) | @@ -1892,7 +1893,7 @@ static int sx_set_serial_info(struct specialix_port *port, sx_change_speed(bp, port); func_exit(); - unlock_kernel(); + mutex_unlock(&port->port.mutex); return 0; } @@ -1906,7 +1907,7 @@ static int sx_get_serial_info(struct specialix_port *port, func_enter(); memset(&tmp, 0, sizeof(tmp)); - lock_kernel(); + mutex_lock(&port->port.mutex); tmp.type = PORT_CIRRUS; tmp.line = port - sx_port; tmp.port = bp->base; @@ -1917,7 +1918,7 @@ static int sx_get_serial_info(struct specialix_port *port, tmp.closing_wait = port->port.closing_wait * HZ/100; tmp.custom_divisor = port->custom_divisor; tmp.xmit_fifo_size = CD186x_NFIFO; - unlock_kernel(); + mutex_unlock(&port->port.mutex); if (copy_to_user(retinfo, &tmp, sizeof(tmp))) { func_exit(); return -EFAULT; diff --git a/drivers/char/stallion.c b/drivers/char/stallion.c index 6049fd73192..f2167f8e5aa 100644 --- a/drivers/char/stallion.c +++ b/drivers/char/stallion.c @@ -807,7 +807,6 @@ static void stl_waituntilsent(struct tty_struct *tty, int timeout) timeout = HZ; tend = jiffies + timeout; - lock_kernel(); while (stl_datastate(portp)) { if (signal_pending(current)) break; @@ -815,7 +814,6 @@ static void stl_waituntilsent(struct tty_struct *tty, int timeout) if (time_after_eq(jiffies, tend)) break; } - unlock_kernel(); } /*****************************************************************************/ @@ -1029,6 +1027,8 @@ static int stl_getserial(struct stlport *portp, struct serial_struct __user *sp) pr_debug("stl_getserial(portp=%p,sp=%p)\n", portp, sp); memset(&sio, 0, sizeof(struct serial_struct)); + + mutex_lock(&portp->port.mutex); sio.line = portp->portnr; sio.port = portp->ioaddr; sio.flags = portp->port.flags; @@ -1048,6 +1048,7 @@ static int stl_getserial(struct stlport *portp, struct serial_struct __user *sp) brdp = stl_brds[portp->brdnr]; if (brdp != NULL) sio.irq = brdp->irq; + mutex_unlock(&portp->port.mutex); return copy_to_user(sp, &sio, sizeof(struct serial_struct)) ? -EFAULT : 0; } @@ -1069,12 +1070,15 @@ static int stl_setserial(struct tty_struct *tty, struct serial_struct __user *sp if (copy_from_user(&sio, sp, sizeof(struct serial_struct))) return -EFAULT; + mutex_lock(&portp->port.mutex); if (!capable(CAP_SYS_ADMIN)) { if ((sio.baud_base != portp->baud_base) || (sio.close_delay != portp->close_delay) || ((sio.flags & ~ASYNC_USR_MASK) != - (portp->port.flags & ~ASYNC_USR_MASK))) + (portp->port.flags & ~ASYNC_USR_MASK))) { + mutex_unlock(&portp->port.mutex); return -EPERM; + } } portp->port.flags = (portp->port.flags & ~ASYNC_USR_MASK) | @@ -1083,6 +1087,7 @@ static int stl_setserial(struct tty_struct *tty, struct serial_struct __user *sp portp->close_delay = sio.close_delay; portp->closing_wait = sio.closing_wait; portp->custom_divisor = sio.custom_divisor; + mutex_unlock(&portp->port.mutex); stl_setport(portp, tty->termios); return 0; } @@ -1147,8 +1152,6 @@ static int stl_ioctl(struct tty_struct *tty, struct file *file, unsigned int cmd rc = 0; - lock_kernel(); - switch (cmd) { case TIOCGSERIAL: rc = stl_getserial(portp, argp); @@ -1173,7 +1176,6 @@ static int stl_ioctl(struct tty_struct *tty, struct file *file, unsigned int cmd rc = -ENOIOCTLCMD; break; } - unlock_kernel(); return rc; } @@ -2327,6 +2329,7 @@ static int stl_getportstats(struct tty_struct *tty, struct stlport *portp, comst return -ENODEV; } + mutex_lock(&portp->port.mutex); portp->stats.state = portp->istate; portp->stats.flags = portp->port.flags; portp->stats.hwid = portp->hwid; @@ -2358,6 +2361,7 @@ static int stl_getportstats(struct tty_struct *tty, struct stlport *portp, comst (STL_TXBUFSIZE - (tail - head)); portp->stats.signals = (unsigned long) stl_getsignals(portp); + mutex_unlock(&portp->port.mutex); return copy_to_user(cp, &portp->stats, sizeof(comstats_t)) ? -EFAULT : 0; @@ -2382,10 +2386,12 @@ static int stl_clrportstats(struct stlport *portp, comstats_t __user *cp) return -ENODEV; } + mutex_lock(&portp->port.mutex); memset(&portp->stats, 0, sizeof(comstats_t)); portp->stats.brd = portp->brdnr; portp->stats.panel = portp->panelnr; portp->stats.port = portp->portnr; + mutex_unlock(&portp->port.mutex); return copy_to_user(cp, &portp->stats, sizeof(comstats_t)) ? -EFAULT : 0; } @@ -2451,7 +2457,6 @@ static long stl_memioctl(struct file *fp, unsigned int cmd, unsigned long arg) return -ENODEV; rc = 0; - lock_kernel(); switch (cmd) { case COM_GETPORTSTATS: rc = stl_getportstats(NULL, NULL, argp); @@ -2472,7 +2477,6 @@ static long stl_memioctl(struct file *fp, unsigned int cmd, unsigned long arg) rc = -ENOIOCTLCMD; break; } - unlock_kernel(); return rc; } diff --git a/drivers/char/sx.c b/drivers/char/sx.c index a81ec4fcf6f..5b24db4ff7f 100644 --- a/drivers/char/sx.c +++ b/drivers/char/sx.c @@ -1699,7 +1699,7 @@ static long sx_fw_ioctl(struct file *filp, unsigned int cmd, if (!capable(CAP_SYS_RAWIO)) return -EPERM; - lock_kernel(); + tty_lock(); sx_dprintk(SX_DEBUG_FIRMWARE, "IOCTL %x: %lx\n", cmd, arg); @@ -1848,7 +1848,7 @@ static long sx_fw_ioctl(struct file *filp, unsigned int cmd, break; } out: - unlock_kernel(); + tty_unlock(); func_exit(); return rc; } @@ -1859,7 +1859,7 @@ static int sx_break(struct tty_struct *tty, int flag) int rv; func_enter(); - lock_kernel(); + tty_lock(); if (flag) rv = sx_send_command(port, HS_START, -1, HS_IDLE_BREAK); @@ -1868,7 +1868,7 @@ static int sx_break(struct tty_struct *tty, int flag) if (rv != 1) printk(KERN_ERR "sx: couldn't send break (%x).\n", read_sx_byte(port->board, CHAN_OFFSET(port, hi_hstat))); - unlock_kernel(); + tty_unlock(); func_exit(); return 0; } @@ -1909,7 +1909,7 @@ static int sx_ioctl(struct tty_struct *tty, struct file *filp, /* func_enter2(); */ rc = 0; - lock_kernel(); + tty_lock(); switch (cmd) { case TIOCGSERIAL: rc = gs_getserial(&port->gs, argp); @@ -1921,7 +1921,7 @@ static int sx_ioctl(struct tty_struct *tty, struct file *filp, rc = -ENOIOCTLCMD; break; } - unlock_kernel(); + tty_unlock(); /* func_exit(); */ return rc; diff --git a/drivers/char/synclink.c b/drivers/char/synclink.c index 0658fc54822..a2a58004e18 100644 --- a/drivers/char/synclink.c +++ b/drivers/char/synclink.c @@ -81,7 +81,6 @@ #include <linux/mm.h> #include <linux/seq_file.h> #include <linux/slab.h> -#include <linux/smp_lock.h> #include <linux/delay.h> #include <linux/netdevice.h> #include <linux/vmalloc.h> @@ -2436,7 +2435,9 @@ static int mgsl_get_stats(struct mgsl_struct * info, struct mgsl_icount __user * if (!user_icount) { memset(&info->icount, 0, sizeof(info->icount)); } else { + mutex_lock(&info->port.mutex); COPY_TO_USER(err, user_icount, &info->icount, sizeof(struct mgsl_icount)); + mutex_unlock(&info->port.mutex); if (err) return -EFAULT; } @@ -2461,7 +2462,9 @@ static int mgsl_get_params(struct mgsl_struct * info, MGSL_PARAMS __user *user_p printk("%s(%d):mgsl_get_params(%s)\n", __FILE__,__LINE__, info->device_name); + mutex_lock(&info->port.mutex); COPY_TO_USER(err,user_params, &info->params, sizeof(MGSL_PARAMS)); + mutex_unlock(&info->port.mutex); if (err) { if ( debug_level >= DEBUG_LEVEL_INFO ) printk( "%s(%d):mgsl_get_params(%s) user buffer copy failed\n", @@ -2501,11 +2504,13 @@ static int mgsl_set_params(struct mgsl_struct * info, MGSL_PARAMS __user *new_pa return -EFAULT; } + mutex_lock(&info->port.mutex); spin_lock_irqsave(&info->irq_spinlock,flags); memcpy(&info->params,&tmp_params,sizeof(MGSL_PARAMS)); spin_unlock_irqrestore(&info->irq_spinlock,flags); mgsl_change_params(info); + mutex_unlock(&info->port.mutex); return 0; @@ -2935,7 +2940,6 @@ static int mgsl_ioctl(struct tty_struct *tty, struct file * file, unsigned int cmd, unsigned long arg) { struct mgsl_struct * info = tty->driver_data; - int ret; if (debug_level >= DEBUG_LEVEL_INFO) printk("%s(%d):mgsl_ioctl %s cmd=%08X\n", __FILE__,__LINE__, @@ -2950,10 +2954,7 @@ static int mgsl_ioctl(struct tty_struct *tty, struct file * file, return -EIO; } - lock_kernel(); - ret = mgsl_ioctl_common(info, cmd, arg); - unlock_kernel(); - return ret; + return mgsl_ioctl_common(info, cmd, arg); } static int mgsl_ioctl_common(struct mgsl_struct *info, unsigned int cmd, unsigned long arg) @@ -3109,12 +3110,14 @@ static void mgsl_close(struct tty_struct *tty, struct file * filp) if (tty_port_close_start(&info->port, tty, filp) == 0) goto cleanup; - + + mutex_lock(&info->port.mutex); if (info->port.flags & ASYNC_INITIALIZED) mgsl_wait_until_sent(tty, info->timeout); mgsl_flush_buffer(tty); tty_ldisc_flush(tty); shutdown(info); + mutex_unlock(&info->port.mutex); tty_port_close_end(&info->port, tty); info->port.tty = NULL; @@ -3162,7 +3165,6 @@ static void mgsl_wait_until_sent(struct tty_struct *tty, int timeout) * Note: use tight timings here to satisfy the NIST-PCTS. */ - lock_kernel(); if ( info->params.data_rate ) { char_time = info->timeout/(32 * 5); if (!char_time) @@ -3192,7 +3194,6 @@ static void mgsl_wait_until_sent(struct tty_struct *tty, int timeout) break; } } - unlock_kernel(); exit: if (debug_level >= DEBUG_LEVEL_INFO) @@ -3348,7 +3349,9 @@ static int block_til_ready(struct tty_struct *tty, struct file * filp, printk("%s(%d):block_til_ready blocking on %s count=%d\n", __FILE__,__LINE__, tty->driver->name, port->count ); + tty_unlock(); schedule(); + tty_lock(); } set_current_state(TASK_RUNNING); diff --git a/drivers/char/synclink_gt.c b/drivers/char/synclink_gt.c index 334cf5c8c8b..e63b830c86c 100644 --- a/drivers/char/synclink_gt.c +++ b/drivers/char/synclink_gt.c @@ -40,8 +40,8 @@ #define DBGBH(fmt) if (debug_level >= DEBUG_LEVEL_BH) printk fmt #define DBGISR(fmt) if (debug_level >= DEBUG_LEVEL_ISR) printk fmt #define DBGDATA(info, buf, size, label) if (debug_level >= DEBUG_LEVEL_DATA) trace_block((info), (buf), (size), (label)) -//#define DBGTBUF(info) dump_tbufs(info) -//#define DBGRBUF(info) dump_rbufs(info) +/*#define DBGTBUF(info) dump_tbufs(info)*/ +/*#define DBGRBUF(info) dump_rbufs(info)*/ #include <linux/module.h> @@ -62,7 +62,6 @@ #include <linux/mm.h> #include <linux/seq_file.h> #include <linux/slab.h> -#include <linux/smp_lock.h> #include <linux/netdevice.h> #include <linux/vmalloc.h> #include <linux/init.h> @@ -676,12 +675,14 @@ static int open(struct tty_struct *tty, struct file *filp) goto cleanup; } + mutex_lock(&info->port.mutex); info->port.tty->low_latency = (info->port.flags & ASYNC_LOW_LATENCY) ? 1 : 0; spin_lock_irqsave(&info->netlock, flags); if (info->netcount) { retval = -EBUSY; spin_unlock_irqrestore(&info->netlock, flags); + mutex_unlock(&info->port.mutex); goto cleanup; } info->port.count++; @@ -690,10 +691,12 @@ static int open(struct tty_struct *tty, struct file *filp) if (info->port.count == 1) { /* 1st open on this device, init hardware */ retval = startup(info); - if (retval < 0) + if (retval < 0) { + mutex_unlock(&info->port.mutex); goto cleanup; + } } - + mutex_unlock(&info->port.mutex); retval = block_til_ready(tty, filp, info); if (retval) { DBGINFO(("%s block_til_ready rc=%d\n", info->device_name, retval)); @@ -725,12 +728,14 @@ static void close(struct tty_struct *tty, struct file *filp) if (tty_port_close_start(&info->port, tty, filp) == 0) goto cleanup; + mutex_lock(&info->port.mutex); if (info->port.flags & ASYNC_INITIALIZED) wait_until_sent(tty, info->timeout); flush_buffer(tty); tty_ldisc_flush(tty); shutdown(info); + mutex_unlock(&info->port.mutex); tty_port_close_end(&info->port, tty); info->port.tty = NULL; @@ -741,17 +746,23 @@ cleanup: static void hangup(struct tty_struct *tty) { struct slgt_info *info = tty->driver_data; + unsigned long flags; if (sanity_check(info, tty->name, "hangup")) return; DBGINFO(("%s hangup\n", info->device_name)); flush_buffer(tty); + + mutex_lock(&info->port.mutex); shutdown(info); + spin_lock_irqsave(&info->port.lock, flags); info->port.count = 0; info->port.flags &= ~ASYNC_NORMAL_ACTIVE; info->port.tty = NULL; + spin_unlock_irqrestore(&info->port.lock, flags); + mutex_unlock(&info->port.mutex); wake_up_interruptible(&info->port.open_wait); } @@ -901,8 +912,6 @@ static void wait_until_sent(struct tty_struct *tty, int timeout) * Note: use tight timings here to satisfy the NIST-PCTS. */ - lock_kernel(); - if (info->params.data_rate) { char_time = info->timeout/(32 * 5); if (!char_time) @@ -920,8 +929,6 @@ static void wait_until_sent(struct tty_struct *tty, int timeout) if (timeout && time_after(jiffies, orig_jiffies + timeout)) break; } - unlock_kernel(); - exit: DBGINFO(("%s wait_until_sent exit\n", info->device_name)); } @@ -1041,8 +1048,37 @@ static int ioctl(struct tty_struct *tty, struct file *file, return -EIO; } - lock_kernel(); - + switch (cmd) { + case MGSL_IOCWAITEVENT: + return wait_mgsl_event(info, argp); + case TIOCMIWAIT: + return modem_input_wait(info,(int)arg); + case TIOCGICOUNT: + spin_lock_irqsave(&info->lock,flags); + cnow = info->icount; + spin_unlock_irqrestore(&info->lock,flags); + p_cuser = argp; + if (put_user(cnow.cts, &p_cuser->cts) || + put_user(cnow.dsr, &p_cuser->dsr) || + put_user(cnow.rng, &p_cuser->rng) || + put_user(cnow.dcd, &p_cuser->dcd) || + put_user(cnow.rx, &p_cuser->rx) || + put_user(cnow.tx, &p_cuser->tx) || + put_user(cnow.frame, &p_cuser->frame) || + put_user(cnow.overrun, &p_cuser->overrun) || + put_user(cnow.parity, &p_cuser->parity) || + put_user(cnow.brk, &p_cuser->brk) || + put_user(cnow.buf_overrun, &p_cuser->buf_overrun)) + return -EFAULT; + return 0; + case MGSL_IOCSGPIO: + return set_gpio(info, argp); + case MGSL_IOCGGPIO: + return get_gpio(info, argp); + case MGSL_IOCWAITGPIO: + return wait_gpio(info, argp); + } + mutex_lock(&info->port.mutex); switch (cmd) { case MGSL_IOCGPARAMS: ret = get_params(info, argp); @@ -1068,50 +1104,16 @@ static int ioctl(struct tty_struct *tty, struct file *file, case MGSL_IOCGSTATS: ret = get_stats(info, argp); break; - case MGSL_IOCWAITEVENT: - ret = wait_mgsl_event(info, argp); - break; - case TIOCMIWAIT: - ret = modem_input_wait(info,(int)arg); - break; case MGSL_IOCGIF: ret = get_interface(info, argp); break; case MGSL_IOCSIF: ret = set_interface(info,(int)arg); break; - case MGSL_IOCSGPIO: - ret = set_gpio(info, argp); - break; - case MGSL_IOCGGPIO: - ret = get_gpio(info, argp); - break; - case MGSL_IOCWAITGPIO: - ret = wait_gpio(info, argp); - break; - case TIOCGICOUNT: - spin_lock_irqsave(&info->lock,flags); - cnow = info->icount; - spin_unlock_irqrestore(&info->lock,flags); - p_cuser = argp; - if (put_user(cnow.cts, &p_cuser->cts) || - put_user(cnow.dsr, &p_cuser->dsr) || - put_user(cnow.rng, &p_cuser->rng) || - put_user(cnow.dcd, &p_cuser->dcd) || - put_user(cnow.rx, &p_cuser->rx) || - put_user(cnow.tx, &p_cuser->tx) || - put_user(cnow.frame, &p_cuser->frame) || - put_user(cnow.overrun, &p_cuser->overrun) || - put_user(cnow.parity, &p_cuser->parity) || - put_user(cnow.brk, &p_cuser->brk) || - put_user(cnow.buf_overrun, &p_cuser->buf_overrun)) - ret = -EFAULT; - ret = 0; - break; default: ret = -ENOIOCTLCMD; } - unlock_kernel(); + mutex_unlock(&info->port.mutex); return ret; } @@ -3244,7 +3246,9 @@ static int block_til_ready(struct tty_struct *tty, struct file *filp, } DBGINFO(("%s block_til_ready wait\n", tty->driver->name)); + tty_unlock(); schedule(); + tty_lock(); } set_current_state(TASK_RUNNING); diff --git a/drivers/char/synclinkmp.c b/drivers/char/synclinkmp.c index 2b18adc4ee1..e56caf7d82a 100644 --- a/drivers/char/synclinkmp.c +++ b/drivers/char/synclinkmp.c @@ -52,7 +52,6 @@ #include <linux/mm.h> #include <linux/seq_file.h> #include <linux/slab.h> -#include <linux/smp_lock.h> #include <linux/netdevice.h> #include <linux/vmalloc.h> #include <linux/init.h> @@ -813,13 +812,15 @@ static void close(struct tty_struct *tty, struct file *filp) if (tty_port_close_start(&info->port, tty, filp) == 0) goto cleanup; - + + mutex_lock(&info->port.mutex); if (info->port.flags & ASYNC_INITIALIZED) wait_until_sent(tty, info->timeout); flush_buffer(tty); tty_ldisc_flush(tty); shutdown(info); + mutex_unlock(&info->port.mutex); tty_port_close_end(&info->port, tty); info->port.tty = NULL; @@ -835,6 +836,7 @@ cleanup: static void hangup(struct tty_struct *tty) { SLMP_INFO *info = tty->driver_data; + unsigned long flags; if (debug_level >= DEBUG_LEVEL_INFO) printk("%s(%d):%s hangup()\n", @@ -843,12 +845,16 @@ static void hangup(struct tty_struct *tty) if (sanity_check(info, tty->name, "hangup")) return; + mutex_lock(&info->port.mutex); flush_buffer(tty); shutdown(info); + spin_lock_irqsave(&info->port.lock, flags); info->port.count = 0; info->port.flags &= ~ASYNC_NORMAL_ACTIVE; info->port.tty = NULL; + spin_unlock_irqrestore(&info->port.lock, flags); + mutex_unlock(&info->port.mutex); wake_up_interruptible(&info->port.open_wait); } @@ -1062,9 +1068,7 @@ static void wait_until_sent(struct tty_struct *tty, int timeout) if (sanity_check(info, tty->name, "wait_until_sent")) return; - lock_kernel(); - - if (!(info->port.flags & ASYNC_INITIALIZED)) + if (!test_bit(ASYNCB_INITIALIZED, &info->port.flags)) goto exit; orig_jiffies = jiffies; @@ -1094,8 +1098,10 @@ static void wait_until_sent(struct tty_struct *tty, int timeout) break; } } else { - //TODO: determine if there is something similar to USC16C32 - // TXSTATUS_ALL_SENT status + /* + * TODO: determine if there is something similar to USC16C32 + * TXSTATUS_ALL_SENT status + */ while ( info->tx_active && info->tx_enabled) { msleep_interruptible(jiffies_to_msecs(char_time)); if (signal_pending(current)) @@ -1106,7 +1112,6 @@ static void wait_until_sent(struct tty_struct *tty, int timeout) } exit: - unlock_kernel(); if (debug_level >= DEBUG_LEVEL_INFO) printk("%s(%d):%s wait_until_sent() exit\n", __FILE__,__LINE__, info->device_name ); @@ -1122,7 +1127,6 @@ static int write_room(struct tty_struct *tty) if (sanity_check(info, tty->name, "write_room")) return 0; - lock_kernel(); if (info->params.mode == MGSL_MODE_HDLC) { ret = (info->tx_active) ? 0 : HDLC_MAX_FRAME_SIZE; } else { @@ -1130,7 +1134,6 @@ static int write_room(struct tty_struct *tty) if (ret < 0) ret = 0; } - unlock_kernel(); if (debug_level >= DEBUG_LEVEL_INFO) printk("%s(%d):%s write_room()=%d\n", @@ -1251,7 +1254,7 @@ static void tx_release(struct tty_struct *tty) * * Return Value: 0 if success, otherwise error code */ -static int do_ioctl(struct tty_struct *tty, struct file *file, +static int ioctl(struct tty_struct *tty, struct file *file, unsigned int cmd, unsigned long arg) { SLMP_INFO *info = tty->driver_data; @@ -1341,16 +1344,6 @@ static int do_ioctl(struct tty_struct *tty, struct file *file, return 0; } -static int ioctl(struct tty_struct *tty, struct file *file, - unsigned int cmd, unsigned long arg) -{ - int ret; - lock_kernel(); - ret = do_ioctl(tty, file, cmd, arg); - unlock_kernel(); - return ret; -} - /* * /proc fs routines.... */ @@ -2883,7 +2876,9 @@ static int get_stats(SLMP_INFO * info, struct mgsl_icount __user *user_icount) if (!user_icount) { memset(&info->icount, 0, sizeof(info->icount)); } else { + mutex_lock(&info->port.mutex); COPY_TO_USER(err, user_icount, &info->icount, sizeof(struct mgsl_icount)); + mutex_unlock(&info->port.mutex); if (err) return -EFAULT; } @@ -2898,7 +2893,9 @@ static int get_params(SLMP_INFO * info, MGSL_PARAMS __user *user_params) printk("%s(%d):%s get_params()\n", __FILE__,__LINE__, info->device_name); + mutex_lock(&info->port.mutex); COPY_TO_USER(err,user_params, &info->params, sizeof(MGSL_PARAMS)); + mutex_unlock(&info->port.mutex); if (err) { if ( debug_level >= DEBUG_LEVEL_INFO ) printk( "%s(%d):%s get_params() user buffer copy failed\n", @@ -2926,11 +2923,13 @@ static int set_params(SLMP_INFO * info, MGSL_PARAMS __user *new_params) return -EFAULT; } + mutex_lock(&info->port.mutex); spin_lock_irqsave(&info->lock,flags); memcpy(&info->params,&tmp_params,sizeof(MGSL_PARAMS)); spin_unlock_irqrestore(&info->lock,flags); change_params(info); + mutex_unlock(&info->port.mutex); return 0; } @@ -3366,7 +3365,9 @@ static int block_til_ready(struct tty_struct *tty, struct file *filp, printk("%s(%d):%s block_til_ready() count=%d\n", __FILE__,__LINE__, tty->driver->name, port->count ); + tty_unlock(); schedule(); + tty_lock(); } set_current_state(TASK_RUNNING); diff --git a/drivers/char/sysrq.c b/drivers/char/sysrq.c index 878ac0c2cc6..ef31bb81e84 100644 --- a/drivers/char/sysrq.c +++ b/drivers/char/sysrq.c @@ -18,7 +18,6 @@ #include <linux/interrupt.h> #include <linux/mm.h> #include <linux/fs.h> -#include <linux/tty.h> #include <linux/mount.h> #include <linux/kdev_t.h> #include <linux/major.h> @@ -76,7 +75,7 @@ static int __init sysrq_always_enabled_setup(char *str) __setup("sysrq_always_enabled", sysrq_always_enabled_setup); -static void sysrq_handle_loglevel(int key, struct tty_struct *tty) +static void sysrq_handle_loglevel(int key) { int i; @@ -93,7 +92,7 @@ static struct sysrq_key_op sysrq_loglevel_op = { }; #ifdef CONFIG_VT -static void sysrq_handle_SAK(int key, struct tty_struct *tty) +static void sysrq_handle_SAK(int key) { struct work_struct *SAK_work = &vc_cons[fg_console].SAK_work; schedule_work(SAK_work); @@ -109,7 +108,7 @@ static struct sysrq_key_op sysrq_SAK_op = { #endif #ifdef CONFIG_VT -static void sysrq_handle_unraw(int key, struct tty_struct *tty) +static void sysrq_handle_unraw(int key) { struct kbd_struct *kbd = &kbd_table[fg_console]; @@ -126,7 +125,7 @@ static struct sysrq_key_op sysrq_unraw_op = { #define sysrq_unraw_op (*(struct sysrq_key_op *)NULL) #endif /* CONFIG_VT */ -static void sysrq_handle_crash(int key, struct tty_struct *tty) +static void sysrq_handle_crash(int key) { char *killer = NULL; @@ -141,7 +140,7 @@ static struct sysrq_key_op sysrq_crash_op = { .enable_mask = SYSRQ_ENABLE_DUMP, }; -static void sysrq_handle_reboot(int key, struct tty_struct *tty) +static void sysrq_handle_reboot(int key) { lockdep_off(); local_irq_enable(); @@ -154,7 +153,7 @@ static struct sysrq_key_op sysrq_reboot_op = { .enable_mask = SYSRQ_ENABLE_BOOT, }; -static void sysrq_handle_sync(int key, struct tty_struct *tty) +static void sysrq_handle_sync(int key) { emergency_sync(); } @@ -165,7 +164,7 @@ static struct sysrq_key_op sysrq_sync_op = { .enable_mask = SYSRQ_ENABLE_SYNC, }; -static void sysrq_handle_show_timers(int key, struct tty_struct *tty) +static void sysrq_handle_show_timers(int key) { sysrq_timer_list_show(); } @@ -176,7 +175,7 @@ static struct sysrq_key_op sysrq_show_timers_op = { .action_msg = "Show clockevent devices & pending hrtimers (no others)", }; -static void sysrq_handle_mountro(int key, struct tty_struct *tty) +static void sysrq_handle_mountro(int key) { emergency_remount(); } @@ -188,7 +187,7 @@ static struct sysrq_key_op sysrq_mountro_op = { }; #ifdef CONFIG_LOCKDEP -static void sysrq_handle_showlocks(int key, struct tty_struct *tty) +static void sysrq_handle_showlocks(int key) { debug_show_all_locks(); } @@ -226,7 +225,7 @@ static void sysrq_showregs_othercpus(struct work_struct *dummy) static DECLARE_WORK(sysrq_showallcpus, sysrq_showregs_othercpus); -static void sysrq_handle_showallcpus(int key, struct tty_struct *tty) +static void sysrq_handle_showallcpus(int key) { /* * Fall back to the workqueue based printing if the @@ -252,7 +251,7 @@ static struct sysrq_key_op sysrq_showallcpus_op = { }; #endif -static void sysrq_handle_showregs(int key, struct tty_struct *tty) +static void sysrq_handle_showregs(int key) { struct pt_regs *regs = get_irq_regs(); if (regs) @@ -266,7 +265,7 @@ static struct sysrq_key_op sysrq_showregs_op = { .enable_mask = SYSRQ_ENABLE_DUMP, }; -static void sysrq_handle_showstate(int key, struct tty_struct *tty) +static void sysrq_handle_showstate(int key) { show_state(); } @@ -277,7 +276,7 @@ static struct sysrq_key_op sysrq_showstate_op = { .enable_mask = SYSRQ_ENABLE_DUMP, }; -static void sysrq_handle_showstate_blocked(int key, struct tty_struct *tty) +static void sysrq_handle_showstate_blocked(int key) { show_state_filter(TASK_UNINTERRUPTIBLE); } @@ -291,7 +290,7 @@ static struct sysrq_key_op sysrq_showstate_blocked_op = { #ifdef CONFIG_TRACING #include <linux/ftrace.h> -static void sysrq_ftrace_dump(int key, struct tty_struct *tty) +static void sysrq_ftrace_dump(int key) { ftrace_dump(DUMP_ALL); } @@ -305,7 +304,7 @@ static struct sysrq_key_op sysrq_ftrace_dump_op = { #define sysrq_ftrace_dump_op (*(struct sysrq_key_op *)NULL) #endif -static void sysrq_handle_showmem(int key, struct tty_struct *tty) +static void sysrq_handle_showmem(int key) { show_mem(); } @@ -330,7 +329,7 @@ static void send_sig_all(int sig) } } -static void sysrq_handle_term(int key, struct tty_struct *tty) +static void sysrq_handle_term(int key) { send_sig_all(SIGTERM); console_loglevel = 8; @@ -349,7 +348,7 @@ static void moom_callback(struct work_struct *ignored) static DECLARE_WORK(moom_work, moom_callback); -static void sysrq_handle_moom(int key, struct tty_struct *tty) +static void sysrq_handle_moom(int key) { schedule_work(&moom_work); } @@ -361,7 +360,7 @@ static struct sysrq_key_op sysrq_moom_op = { }; #ifdef CONFIG_BLOCK -static void sysrq_handle_thaw(int key, struct tty_struct *tty) +static void sysrq_handle_thaw(int key) { emergency_thaw_all(); } @@ -373,7 +372,7 @@ static struct sysrq_key_op sysrq_thaw_op = { }; #endif -static void sysrq_handle_kill(int key, struct tty_struct *tty) +static void sysrq_handle_kill(int key) { send_sig_all(SIGKILL); console_loglevel = 8; @@ -385,7 +384,7 @@ static struct sysrq_key_op sysrq_kill_op = { .enable_mask = SYSRQ_ENABLE_SIGNAL, }; -static void sysrq_handle_unrt(int key, struct tty_struct *tty) +static void sysrq_handle_unrt(int key) { normalize_rt_tasks(); } @@ -493,7 +492,7 @@ static void __sysrq_put_key_op(int key, struct sysrq_key_op *op_p) sysrq_key_table[i] = op_p; } -void __handle_sysrq(int key, struct tty_struct *tty, int check_mask) +void __handle_sysrq(int key, bool check_mask) { struct sysrq_key_op *op_p; int orig_log_level; @@ -520,7 +519,7 @@ void __handle_sysrq(int key, struct tty_struct *tty, int check_mask) if (!check_mask || sysrq_on_mask(op_p->enable_mask)) { printk("%s\n", op_p->action_msg); console_loglevel = orig_log_level; - op_p->handler(key, tty); + op_p->handler(key); } else { printk("This sysrq operation is disabled.\n"); } @@ -545,10 +544,10 @@ void __handle_sysrq(int key, struct tty_struct *tty, int check_mask) spin_unlock_irqrestore(&sysrq_key_table_lock, flags); } -void handle_sysrq(int key, struct tty_struct *tty) +void handle_sysrq(int key) { if (sysrq_on()) - __handle_sysrq(key, tty, 1); + __handle_sysrq(key, true); } EXPORT_SYMBOL(handle_sysrq); @@ -597,7 +596,7 @@ static bool sysrq_filter(struct input_handle *handle, unsigned int type, default: if (sysrq_down && value && value != 2) - __handle_sysrq(sysrq_xlate[code], NULL, 1); + __handle_sysrq(sysrq_xlate[code], true); break; } @@ -765,7 +764,7 @@ static ssize_t write_sysrq_trigger(struct file *file, const char __user *buf, if (get_user(c, buf)) return -EFAULT; - __handle_sysrq(c, NULL, 0); + __handle_sysrq(c, false); } return count; diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c index d71f0fc34b4..613c852ee0f 100644 --- a/drivers/char/tty_io.c +++ b/drivers/char/tty_io.c @@ -136,6 +136,9 @@ LIST_HEAD(tty_drivers); /* linked list of tty drivers */ DEFINE_MUTEX(tty_mutex); EXPORT_SYMBOL(tty_mutex); +/* Spinlock to protect the tty->tty_files list */ +DEFINE_SPINLOCK(tty_files_lock); + static ssize_t tty_read(struct file *, char __user *, size_t, loff_t *); static ssize_t tty_write(struct file *, const char __user *, size_t, loff_t *); ssize_t redirected_tty_write(struct file *, const char __user *, @@ -149,6 +152,7 @@ static long tty_compat_ioctl(struct file *file, unsigned int cmd, #else #define tty_compat_ioctl NULL #endif +static int __tty_fasync(int fd, struct file *filp, int on); static int tty_fasync(int fd, struct file *filp, int on); static void release_tty(struct tty_struct *tty, int idx); static void __proc_set_tty(struct task_struct *tsk, struct tty_struct *tty); @@ -184,6 +188,41 @@ void free_tty_struct(struct tty_struct *tty) kfree(tty); } +static inline struct tty_struct *file_tty(struct file *file) +{ + return ((struct tty_file_private *)file->private_data)->tty; +} + +/* Associate a new file with the tty structure */ +void tty_add_file(struct tty_struct *tty, struct file *file) +{ + struct tty_file_private *priv; + + /* XXX: must implement proper error handling in callers */ + priv = kmalloc(sizeof(*priv), GFP_KERNEL|__GFP_NOFAIL); + + priv->tty = tty; + priv->file = file; + file->private_data = priv; + + spin_lock(&tty_files_lock); + list_add(&priv->list, &tty->tty_files); + spin_unlock(&tty_files_lock); +} + +/* Delete file from its tty */ +void tty_del_file(struct file *file) +{ + struct tty_file_private *priv = file->private_data; + + spin_lock(&tty_files_lock); + list_del(&priv->list); + spin_unlock(&tty_files_lock); + file->private_data = NULL; + kfree(priv); +} + + #define TTY_NUMBER(tty) ((tty)->index + (tty)->driver->name_base) /** @@ -234,11 +273,11 @@ static int check_tty_count(struct tty_struct *tty, const char *routine) struct list_head *p; int count = 0; - file_list_lock(); + spin_lock(&tty_files_lock); list_for_each(p, &tty->tty_files) { count++; } - file_list_unlock(); + spin_unlock(&tty_files_lock); if (tty->driver->type == TTY_DRIVER_TYPE_PTY && tty->driver->subtype == PTY_TYPE_SLAVE && tty->link && tty->link->count) @@ -316,7 +355,7 @@ struct tty_driver *tty_find_polling_driver(char *name, int *line) if (*stp == '\0') stp = NULL; - if (tty_line >= 0 && tty_line <= p->num && p->ops && + if (tty_line >= 0 && tty_line < p->num && p->ops && p->ops->poll_init && !p->ops->poll_init(p, tty_line, stp)) { res = tty_driver_kref_get(p); *line = tty_line; @@ -470,7 +509,7 @@ void tty_wakeup(struct tty_struct *tty) EXPORT_SYMBOL_GPL(tty_wakeup); /** - * do_tty_hangup - actual handler for hangup events + * __tty_hangup - actual handler for hangup events * @work: tty device * * This can be called by the "eventd" kernel thread. That is process @@ -483,7 +522,7 @@ EXPORT_SYMBOL_GPL(tty_wakeup); * remains intact. * * Locking: - * BKL + * BTM * redirect lock for undoing redirection * file list lock for manipulating list of ttys * tty_ldisc_lock from called functions @@ -491,13 +530,12 @@ EXPORT_SYMBOL_GPL(tty_wakeup); * tasklist_lock to walk task list for hangup event * ->siglock to protect ->signal/->sighand */ -static void do_tty_hangup(struct work_struct *work) +void __tty_hangup(struct tty_struct *tty) { - struct tty_struct *tty = - container_of(work, struct tty_struct, hangup_work); struct file *cons_filp = NULL; struct file *filp, *f = NULL; struct task_struct *p; + struct tty_file_private *priv; int closecount = 0, n; unsigned long flags; int refs = 0; @@ -507,28 +545,32 @@ static void do_tty_hangup(struct work_struct *work) spin_lock(&redirect_lock); - if (redirect && redirect->private_data == tty) { + if (redirect && file_tty(redirect) == tty) { f = redirect; redirect = NULL; } spin_unlock(&redirect_lock); - /* inuse_filps is protected by the single kernel lock */ - lock_kernel(); - check_tty_count(tty, "do_tty_hangup"); + tty_lock(); + + /* inuse_filps is protected by the single tty lock, + this really needs to change if we want to flush the + workqueue with the lock held */ + check_tty_count(tty, "tty_hangup"); - file_list_lock(); + spin_lock(&tty_files_lock); /* This breaks for file handles being sent over AF_UNIX sockets ? */ - list_for_each_entry(filp, &tty->tty_files, f_u.fu_list) { + list_for_each_entry(priv, &tty->tty_files, list) { + filp = priv->file; if (filp->f_op->write == redirected_tty_write) cons_filp = filp; if (filp->f_op->write != tty_write) continue; closecount++; - tty_fasync(-1, filp, 0); /* can't block */ + __tty_fasync(-1, filp, 0); /* can't block */ filp->f_op = &hung_up_tty_fops; } - file_list_unlock(); + spin_unlock(&tty_files_lock); tty_ldisc_hangup(tty); @@ -594,11 +636,21 @@ static void do_tty_hangup(struct work_struct *work) */ set_bit(TTY_HUPPED, &tty->flags); tty_ldisc_enable(tty); - unlock_kernel(); + + tty_unlock(); + if (f) fput(f); } +static void do_tty_hangup(struct work_struct *work) +{ + struct tty_struct *tty = + container_of(work, struct tty_struct, hangup_work); + + __tty_hangup(tty); +} + /** * tty_hangup - trigger a hangup event * @tty: tty to hangup @@ -634,11 +686,12 @@ void tty_vhangup(struct tty_struct *tty) printk(KERN_DEBUG "%s vhangup...\n", tty_name(tty, buf)); #endif - do_tty_hangup(&tty->hangup_work); + __tty_hangup(tty); } EXPORT_SYMBOL(tty_vhangup); + /** * tty_vhangup_self - process vhangup for own ctty * @@ -696,7 +749,8 @@ static void session_clear_tty(struct pid *session) * exiting; it is 0 if called by the ioctl TIOCNOTTY. * * Locking: - * BKL is taken for hysterical raisins + * BTM is taken for hysterical raisins, and held when + * called from no_tty(). * tty_mutex is taken to protect tty * ->siglock is taken to protect ->signal/->sighand * tasklist_lock is taken to walk process list for sessions @@ -714,10 +768,10 @@ void disassociate_ctty(int on_exit) tty = get_current_tty(); if (tty) { tty_pgrp = get_pid(tty->pgrp); - lock_kernel(); - if (on_exit && tty->driver->type != TTY_DRIVER_TYPE_PTY) - tty_vhangup(tty); - unlock_kernel(); + if (on_exit) { + if (tty->driver->type != TTY_DRIVER_TYPE_PTY) + tty_vhangup(tty); + } tty_kref_put(tty); } else if (on_exit) { struct pid *old_pgrp; @@ -774,9 +828,9 @@ void disassociate_ctty(int on_exit) void no_tty(void) { struct task_struct *tsk = current; - lock_kernel(); + tty_lock(); disassociate_ctty(0); - unlock_kernel(); + tty_unlock(); proc_clear_tty(tsk); } @@ -875,12 +929,10 @@ static ssize_t tty_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) { int i; - struct tty_struct *tty; - struct inode *inode; + struct inode *inode = file->f_path.dentry->d_inode; + struct tty_struct *tty = file_tty(file); struct tty_ldisc *ld; - tty = (struct tty_struct *)file->private_data; - inode = file->f_path.dentry->d_inode; if (tty_paranoia_check(tty, inode, "tty_read")) return -EIO; if (!tty || (test_bit(TTY_IO_ERROR, &tty->flags))) @@ -1013,19 +1065,19 @@ out: * We don't put it into the syslog queue right now maybe in the future if * really needed. * - * We must still hold the BKL and test the CLOSING flag for the moment. + * We must still hold the BTM and test the CLOSING flag for the moment. */ void tty_write_message(struct tty_struct *tty, char *msg) { if (tty) { mutex_lock(&tty->atomic_write_lock); - lock_kernel(); + tty_lock(); if (tty->ops->write && !test_bit(TTY_CLOSING, &tty->flags)) { - unlock_kernel(); + tty_unlock(); tty->ops->write(tty, msg, strlen(msg)); } else - unlock_kernel(); + tty_unlock(); tty_write_unlock(tty); } return; @@ -1051,12 +1103,11 @@ void tty_write_message(struct tty_struct *tty, char *msg) static ssize_t tty_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) { - struct tty_struct *tty; struct inode *inode = file->f_path.dentry->d_inode; + struct tty_struct *tty = file_tty(file); + struct tty_ldisc *ld; ssize_t ret; - struct tty_ldisc *ld; - tty = (struct tty_struct *)file->private_data; if (tty_paranoia_check(tty, inode, "tty_write")) return -EIO; if (!tty || !tty->ops->write || @@ -1208,18 +1259,14 @@ static int tty_driver_install_tty(struct tty_driver *driver, int ret; if (driver->ops->install) { - lock_kernel(); ret = driver->ops->install(driver, tty); - unlock_kernel(); return ret; } if (tty_init_termios(tty) == 0) { - lock_kernel(); tty_driver_kref_get(driver); tty->count++; driver->ttys[idx] = tty; - unlock_kernel(); return 0; } return -ENOMEM; @@ -1312,14 +1359,11 @@ struct tty_struct *tty_init_dev(struct tty_driver *driver, int idx, struct tty_struct *tty; int retval; - lock_kernel(); /* Check if pty master is being opened multiple times */ if (driver->subtype == PTY_TYPE_MASTER && (driver->flags & TTY_DRIVER_DEVPTS_MEM) && !first_ok) { - unlock_kernel(); return ERR_PTR(-EIO); } - unlock_kernel(); /* * First time open is complex, especially for PTY devices. @@ -1363,9 +1407,7 @@ release_mem_out: if (printk_ratelimit()) printk(KERN_INFO "tty_init_dev: ldisc open failed, " "clearing slot %d\n", idx); - lock_kernel(); release_tty(tty, idx); - unlock_kernel(); return ERR_PTR(retval); } @@ -1419,9 +1461,9 @@ static void release_one_tty(struct work_struct *work) tty_driver_kref_put(driver); module_put(driver->owner); - file_list_lock(); + spin_lock(&tty_files_lock); list_del_init(&tty->tty_files); - file_list_unlock(); + spin_unlock(&tty_files_lock); put_pid(tty->pgrp); put_pid(tty->session); @@ -1502,20 +1544,20 @@ static void release_tty(struct tty_struct *tty, int idx) int tty_release(struct inode *inode, struct file *filp) { - struct tty_struct *tty, *o_tty; + struct tty_struct *tty = file_tty(filp); + struct tty_struct *o_tty; int pty_master, tty_closing, o_tty_closing, do_sleep; int devpts; int idx; char buf[64]; - tty = (struct tty_struct *)filp->private_data; if (tty_paranoia_check(tty, inode, "tty_release_dev")) return 0; - lock_kernel(); + tty_lock(); check_tty_count(tty, "tty_release_dev"); - tty_fasync(-1, filp, 0); + __tty_fasync(-1, filp, 0); idx = tty->index; pty_master = (tty->driver->type == TTY_DRIVER_TYPE_PTY && @@ -1527,18 +1569,18 @@ int tty_release(struct inode *inode, struct file *filp) if (idx < 0 || idx >= tty->driver->num) { printk(KERN_DEBUG "tty_release_dev: bad idx when trying to " "free (%s)\n", tty->name); - unlock_kernel(); + tty_unlock(); return 0; } if (!devpts) { if (tty != tty->driver->ttys[idx]) { - unlock_kernel(); + tty_unlock(); printk(KERN_DEBUG "tty_release_dev: driver.table[%d] not tty " "for (%s)\n", idx, tty->name); return 0; } if (tty->termios != tty->driver->termios[idx]) { - unlock_kernel(); + tty_unlock(); printk(KERN_DEBUG "tty_release_dev: driver.termios[%d] not termios " "for (%s)\n", idx, tty->name); @@ -1556,21 +1598,21 @@ int tty_release(struct inode *inode, struct file *filp) if (tty->driver->other && !(tty->driver->flags & TTY_DRIVER_DEVPTS_MEM)) { if (o_tty != tty->driver->other->ttys[idx]) { - unlock_kernel(); + tty_unlock(); printk(KERN_DEBUG "tty_release_dev: other->table[%d] " "not o_tty for (%s)\n", idx, tty->name); return 0 ; } if (o_tty->termios != tty->driver->other->termios[idx]) { - unlock_kernel(); + tty_unlock(); printk(KERN_DEBUG "tty_release_dev: other->termios[%d] " "not o_termios for (%s)\n", idx, tty->name); return 0; } if (o_tty->link != tty) { - unlock_kernel(); + tty_unlock(); printk(KERN_DEBUG "tty_release_dev: bad pty pointers\n"); return 0; } @@ -1579,7 +1621,7 @@ int tty_release(struct inode *inode, struct file *filp) if (tty->ops->close) tty->ops->close(tty, filp); - unlock_kernel(); + tty_unlock(); /* * Sanity check: if tty->count is going to zero, there shouldn't be * any waiters on tty->read_wait or tty->write_wait. We test the @@ -1602,7 +1644,7 @@ int tty_release(struct inode *inode, struct file *filp) opens on /dev/tty */ mutex_lock(&tty_mutex); - lock_kernel(); + tty_lock(); tty_closing = tty->count <= 1; o_tty_closing = o_tty && (o_tty->count <= (pty_master ? 1 : 0)); @@ -1633,7 +1675,7 @@ int tty_release(struct inode *inode, struct file *filp) printk(KERN_WARNING "tty_release_dev: %s: read/write wait queue " "active!\n", tty_name(tty, buf)); - unlock_kernel(); + tty_unlock(); mutex_unlock(&tty_mutex); schedule(); } @@ -1666,8 +1708,7 @@ int tty_release(struct inode *inode, struct file *filp) * - do_tty_hangup no longer sees this file descriptor as * something that needs to be handled for hangups. */ - file_kill(filp); - filp->private_data = NULL; + tty_del_file(filp); /* * Perform some housekeeping before deciding whether to return. @@ -1698,7 +1739,7 @@ int tty_release(struct inode *inode, struct file *filp) /* check whether both sides are closing ... */ if (!tty_closing || (o_tty && !o_tty_closing)) { - unlock_kernel(); + tty_unlock(); return 0; } @@ -1718,7 +1759,7 @@ int tty_release(struct inode *inode, struct file *filp) /* Make this pty number available for reallocation */ if (devpts) devpts_kill_index(inode, idx); - unlock_kernel(); + tty_unlock(); return 0; } @@ -1760,12 +1801,12 @@ retry_open: retval = 0; mutex_lock(&tty_mutex); - lock_kernel(); + tty_lock(); if (device == MKDEV(TTYAUX_MAJOR, 0)) { tty = get_current_tty(); if (!tty) { - unlock_kernel(); + tty_unlock(); mutex_unlock(&tty_mutex); return -ENXIO; } @@ -1797,14 +1838,14 @@ retry_open: goto got_driver; } } - unlock_kernel(); + tty_unlock(); mutex_unlock(&tty_mutex); return -ENODEV; } driver = get_tty_driver(device, &index); if (!driver) { - unlock_kernel(); + tty_unlock(); mutex_unlock(&tty_mutex); return -ENODEV; } @@ -1814,7 +1855,7 @@ got_driver: tty = tty_driver_lookup_tty(driver, inode, index); if (IS_ERR(tty)) { - unlock_kernel(); + tty_unlock(); mutex_unlock(&tty_mutex); return PTR_ERR(tty); } @@ -1830,12 +1871,12 @@ got_driver: mutex_unlock(&tty_mutex); tty_driver_kref_put(driver); if (IS_ERR(tty)) { - unlock_kernel(); + tty_unlock(); return PTR_ERR(tty); } - filp->private_data = tty; - file_move(filp, &tty->tty_files); + tty_add_file(tty, filp); + check_tty_count(tty, "tty_open"); if (tty->driver->type == TTY_DRIVER_TYPE_PTY && tty->driver->subtype == PTY_TYPE_MASTER) @@ -1860,29 +1901,29 @@ got_driver: printk(KERN_DEBUG "error %d in opening %s...", retval, tty->name); #endif + tty_unlock(); /* need to call tty_release without BTM */ tty_release(inode, filp); - if (retval != -ERESTARTSYS) { - unlock_kernel(); + if (retval != -ERESTARTSYS) return retval; - } - if (signal_pending(current)) { - unlock_kernel(); + + if (signal_pending(current)) return retval; - } + schedule(); /* * Need to reset f_op in case a hangup happened. */ + tty_lock(); if (filp->f_op == &hung_up_tty_fops) filp->f_op = &tty_fops; - unlock_kernel(); + tty_unlock(); goto retry_open; } - unlock_kernel(); + tty_unlock(); mutex_lock(&tty_mutex); - lock_kernel(); + tty_lock(); spin_lock_irq(¤t->sighand->siglock); if (!noctty && current->signal->leader && @@ -1890,7 +1931,7 @@ got_driver: tty->session == NULL) __proc_set_tty(current, tty); spin_unlock_irq(¤t->sighand->siglock); - unlock_kernel(); + tty_unlock(); mutex_unlock(&tty_mutex); return 0; } @@ -1911,11 +1952,10 @@ got_driver: static unsigned int tty_poll(struct file *filp, poll_table *wait) { - struct tty_struct *tty; + struct tty_struct *tty = file_tty(filp); struct tty_ldisc *ld; int ret = 0; - tty = (struct tty_struct *)filp->private_data; if (tty_paranoia_check(tty, filp->f_path.dentry->d_inode, "tty_poll")) return 0; @@ -1926,14 +1966,12 @@ static unsigned int tty_poll(struct file *filp, poll_table *wait) return ret; } -static int tty_fasync(int fd, struct file *filp, int on) +static int __tty_fasync(int fd, struct file *filp, int on) { - struct tty_struct *tty; + struct tty_struct *tty = file_tty(filp); unsigned long flags; int retval = 0; - lock_kernel(); - tty = (struct tty_struct *)filp->private_data; if (tty_paranoia_check(tty, filp->f_path.dentry->d_inode, "tty_fasync")) goto out; @@ -1966,7 +2004,15 @@ static int tty_fasync(int fd, struct file *filp, int on) } retval = 0; out: - unlock_kernel(); + return retval; +} + +static int tty_fasync(int fd, struct file *filp, int on) +{ + int retval; + tty_lock(); + retval = __tty_fasync(fd, filp, on); + tty_unlock(); return retval; } @@ -2479,13 +2525,13 @@ EXPORT_SYMBOL(tty_pair_get_pty); */ long tty_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { - struct tty_struct *tty, *real_tty; + struct tty_struct *tty = file_tty(file); + struct tty_struct *real_tty; void __user *p = (void __user *)arg; int retval; struct tty_ldisc *ld; struct inode *inode = file->f_dentry->d_inode; - tty = (struct tty_struct *)file->private_data; if (tty_paranoia_check(tty, inode, "tty_ioctl")) return -EINVAL; @@ -2607,7 +2653,7 @@ static long tty_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { struct inode *inode = file->f_dentry->d_inode; - struct tty_struct *tty = file->private_data; + struct tty_struct *tty = file_tty(file); struct tty_ldisc *ld; int retval = -ENOIOCTLCMD; @@ -2699,7 +2745,7 @@ void __do_SAK(struct tty_struct *tty) if (!filp) continue; if (filp->f_op->read == tty_read && - filp->private_data == tty) { + file_tty(filp) == tty) { printk(KERN_NOTICE "SAK: killed process %d" " (%s): fd#%d opened to the tty\n", task_pid_nr(p), p->comm, i); @@ -3128,7 +3174,7 @@ static struct cdev tty_cdev, console_cdev; * Ok, now we can initialize the rest of the tty devices and can count * on memory allocations, interrupts etc.. */ -static int __init tty_init(void) +int __init tty_init(void) { cdev_init(&tty_cdev, &tty_fops); if (cdev_add(&tty_cdev, MKDEV(TTYAUX_MAJOR, 0), 1) || @@ -3149,4 +3195,4 @@ static int __init tty_init(void) #endif return 0; } -module_init(tty_init); + diff --git a/drivers/char/tty_ioctl.c b/drivers/char/tty_ioctl.c index 6bd5f8866c7..0c188997145 100644 --- a/drivers/char/tty_ioctl.c +++ b/drivers/char/tty_ioctl.c @@ -517,19 +517,25 @@ static void change_termios(struct tty_struct *tty, struct ktermios *new_termios) /* See if packet mode change of state. */ if (tty->link && tty->link->packet) { + int extproc = (old_termios.c_lflag & EXTPROC) | + (tty->termios->c_lflag & EXTPROC); int old_flow = ((old_termios.c_iflag & IXON) && (old_termios.c_cc[VSTOP] == '\023') && (old_termios.c_cc[VSTART] == '\021')); int new_flow = (I_IXON(tty) && STOP_CHAR(tty) == '\023' && START_CHAR(tty) == '\021'); - if (old_flow != new_flow) { + if ((old_flow != new_flow) || extproc) { spin_lock_irqsave(&tty->ctrl_lock, flags); - tty->ctrl_status &= ~(TIOCPKT_DOSTOP | TIOCPKT_NOSTOP); - if (new_flow) - tty->ctrl_status |= TIOCPKT_DOSTOP; - else - tty->ctrl_status |= TIOCPKT_NOSTOP; + if (old_flow != new_flow) { + tty->ctrl_status &= ~(TIOCPKT_DOSTOP | TIOCPKT_NOSTOP); + if (new_flow) + tty->ctrl_status |= TIOCPKT_DOSTOP; + else + tty->ctrl_status |= TIOCPKT_NOSTOP; + } + if (extproc) + tty->ctrl_status |= TIOCPKT_IOCTL; spin_unlock_irqrestore(&tty->ctrl_lock, flags); wake_up_interruptible(&tty->link->read_wait); } diff --git a/drivers/char/tty_ldisc.c b/drivers/char/tty_ldisc.c index 500e740ec5e..412f9775d19 100644 --- a/drivers/char/tty_ldisc.c +++ b/drivers/char/tty_ldisc.c @@ -440,6 +440,8 @@ static void tty_set_termios_ldisc(struct tty_struct *tty, int num) * * A helper opening method. Also a convenient debugging and check * point. + * + * Locking: always called with BTM already held. */ static int tty_ldisc_open(struct tty_struct *tty, struct tty_ldisc *ld) @@ -447,10 +449,9 @@ static int tty_ldisc_open(struct tty_struct *tty, struct tty_ldisc *ld) WARN_ON(test_and_set_bit(TTY_LDISC_OPEN, &tty->flags)); if (ld->ops->open) { int ret; - /* BKL here locks verus a hangup event */ - lock_kernel(); + /* BTM here locks versus a hangup event */ + WARN_ON(!tty_locked()); ret = ld->ops->open(tty); - unlock_kernel(); return ret; } return 0; @@ -553,7 +554,7 @@ int tty_set_ldisc(struct tty_struct *tty, int ldisc) if (IS_ERR(new_ldisc)) return PTR_ERR(new_ldisc); - lock_kernel(); + tty_lock(); /* * We need to look at the tty locking here for pty/tty pairs * when both sides try to change in parallel. @@ -567,12 +568,12 @@ int tty_set_ldisc(struct tty_struct *tty, int ldisc) */ if (tty->ldisc->ops->num == ldisc) { - unlock_kernel(); + tty_unlock(); tty_ldisc_put(new_ldisc); return 0; } - unlock_kernel(); + tty_unlock(); /* * Problem: What do we do if this blocks ? * We could deadlock here @@ -580,6 +581,7 @@ int tty_set_ldisc(struct tty_struct *tty, int ldisc) tty_wait_until_sent(tty, 0); + tty_lock(); mutex_lock(&tty->ldisc_mutex); /* @@ -589,13 +591,13 @@ int tty_set_ldisc(struct tty_struct *tty, int ldisc) while (test_bit(TTY_LDISC_CHANGING, &tty->flags)) { mutex_unlock(&tty->ldisc_mutex); + tty_unlock(); wait_event(tty_ldisc_wait, test_bit(TTY_LDISC_CHANGING, &tty->flags) == 0); + tty_lock(); mutex_lock(&tty->ldisc_mutex); } - lock_kernel(); - set_bit(TTY_LDISC_CHANGING, &tty->flags); /* @@ -607,7 +609,7 @@ int tty_set_ldisc(struct tty_struct *tty, int ldisc) o_ldisc = tty->ldisc; - unlock_kernel(); + tty_unlock(); /* * Make sure we don't change while someone holds a * reference to the line discipline. The TTY_LDISC bit @@ -632,15 +634,15 @@ int tty_set_ldisc(struct tty_struct *tty, int ldisc) flush_scheduled_work(); + tty_lock(); mutex_lock(&tty->ldisc_mutex); - lock_kernel(); if (test_bit(TTY_HUPPED, &tty->flags)) { /* We were raced by the hangup method. It will have stomped the ldisc data and closed the ldisc down */ clear_bit(TTY_LDISC_CHANGING, &tty->flags); mutex_unlock(&tty->ldisc_mutex); tty_ldisc_put(new_ldisc); - unlock_kernel(); + tty_unlock(); return -EIO; } @@ -682,7 +684,7 @@ int tty_set_ldisc(struct tty_struct *tty, int ldisc) if (o_work) schedule_delayed_work(&o_tty->buf.work, 1); mutex_unlock(&tty->ldisc_mutex); - unlock_kernel(); + tty_unlock(); return retval; } @@ -780,7 +782,20 @@ void tty_ldisc_hangup(struct tty_struct *tty) * Avoid racing set_ldisc or tty_ldisc_release */ mutex_lock(&tty->ldisc_mutex); - tty_ldisc_halt(tty); + + /* + * this is like tty_ldisc_halt, but we need to give up + * the BTM before calling cancel_delayed_work_sync, + * which may need to wait for another function taking the BTM + */ + clear_bit(TTY_LDISC, &tty->flags); + tty_unlock(); + cancel_delayed_work_sync(&tty->buf.work); + mutex_unlock(&tty->ldisc_mutex); + + tty_lock(); + mutex_lock(&tty->ldisc_mutex); + /* At this point we have a closed ldisc and we want to reopen it. We could defer this to the next open but it means auditing a lot of other paths so this is @@ -851,8 +866,10 @@ void tty_ldisc_release(struct tty_struct *tty, struct tty_struct *o_tty) * race with the set_ldisc code path. */ + tty_unlock(); tty_ldisc_halt(tty); flush_scheduled_work(); + tty_lock(); mutex_lock(&tty->ldisc_mutex); /* diff --git a/drivers/char/tty_mutex.c b/drivers/char/tty_mutex.c new file mode 100644 index 00000000000..133697540c7 --- /dev/null +++ b/drivers/char/tty_mutex.c @@ -0,0 +1,47 @@ +/* + * drivers/char/tty_lock.c + */ +#include <linux/tty.h> +#include <linux/module.h> +#include <linux/kallsyms.h> +#include <linux/semaphore.h> +#include <linux/sched.h> + +/* + * The 'big tty mutex' + * + * This mutex is taken and released by tty_lock() and tty_unlock(), + * replacing the older big kernel lock. + * It can no longer be taken recursively, and does not get + * released implicitly while sleeping. + * + * Don't use in new code. + */ +static DEFINE_MUTEX(big_tty_mutex); +struct task_struct *__big_tty_mutex_owner; +EXPORT_SYMBOL_GPL(__big_tty_mutex_owner); + +/* + * Getting the big tty mutex. + */ +void __lockfunc tty_lock(void) +{ + struct task_struct *task = current; + + WARN_ON(__big_tty_mutex_owner == task); + + mutex_lock(&big_tty_mutex); + __big_tty_mutex_owner = task; +} +EXPORT_SYMBOL(tty_lock); + +void __lockfunc tty_unlock(void) +{ + struct task_struct *task = current; + + WARN_ON(__big_tty_mutex_owner != task); + __big_tty_mutex_owner = NULL; + + mutex_unlock(&big_tty_mutex); +} +EXPORT_SYMBOL(tty_unlock); diff --git a/drivers/char/tty_port.c b/drivers/char/tty_port.c index a3bd1d0b66c..33d37d230f8 100644 --- a/drivers/char/tty_port.c +++ b/drivers/char/tty_port.c @@ -231,7 +231,7 @@ int tty_port_block_til_ready(struct tty_port *port, /* block if port is in the process of being closed */ if (tty_hung_up_p(filp) || port->flags & ASYNC_CLOSING) { - wait_event_interruptible(port->close_wait, + wait_event_interruptible_tty(port->close_wait, !(port->flags & ASYNC_CLOSING)); if (port->flags & ASYNC_HUP_NOTIFY) return -EAGAIN; @@ -294,7 +294,9 @@ int tty_port_block_til_ready(struct tty_port *port, retval = -ERESTARTSYS; break; } + tty_unlock(); schedule(); + tty_lock(); } finish_wait(&port->open_wait, &wait); diff --git a/drivers/char/vc_screen.c b/drivers/char/vc_screen.c index c1791a63d99..bcce46c96b8 100644 --- a/drivers/char/vc_screen.c +++ b/drivers/char/vc_screen.c @@ -463,10 +463,10 @@ vcs_open(struct inode *inode, struct file *filp) unsigned int currcons = iminor(inode) & 127; int ret = 0; - lock_kernel(); + tty_lock(); if(currcons && !vc_cons_allocated(currcons-1)) ret = -ENXIO; - unlock_kernel(); + tty_unlock(); return ret; } diff --git a/drivers/char/vt.c b/drivers/char/vt.c index 7cdb6ee569c..281aada7b4a 100644 --- a/drivers/char/vt.c +++ b/drivers/char/vt.c @@ -104,6 +104,8 @@ #include <linux/io.h> #include <asm/system.h> #include <linux/uaccess.h> +#include <linux/kdb.h> +#include <linux/ctype.h> #define MAX_NR_CON_DRIVER 16 @@ -187,10 +189,16 @@ static DECLARE_WORK(console_work, console_callback); * fg_console is the current virtual console, * last_console is the last used one, * want_console is the console we want to switch to, + * saved_* variants are for save/restore around kernel debugger enter/leave */ int fg_console; int last_console; int want_console = -1; +static int saved_fg_console; +static int saved_last_console; +static int saved_want_console; +static int saved_vc_mode; +static int saved_console_blanked; /* * For each existing display, we have a pointer to console currently visible @@ -280,8 +288,12 @@ static inline unsigned short *screenpos(struct vc_data *vc, int offset, int view return p; } +/* Called from the keyboard irq path.. */ static inline void scrolldelta(int lines) { + /* FIXME */ + /* scrolldelta needs some kind of consistency lock, but the BKL was + and still is not protecting versus the scheduled back end */ scrollback_delta += lines; schedule_console_callback(); } @@ -698,7 +710,10 @@ void redraw_screen(struct vc_data *vc, int is_switch) update_attr(vc); clear_buffer_attributes(vc); } - if (update && vc->vc_mode != KD_GRAPHICS) + + /* Forcibly update if we're panicing */ + if ((update && vc->vc_mode != KD_GRAPHICS) || + vt_force_oops_output(vc)) do_update_region(vc, vc->vc_origin, vc->vc_screenbuf_size / 2); } set_cursor(vc); @@ -736,6 +751,7 @@ static void visual_init(struct vc_data *vc, int num, int init) vc->vc_hi_font_mask = 0; vc->vc_complement_mask = 0; vc->vc_can_do_color = 0; + vc->vc_panic_force_write = false; vc->vc_sw->con_init(vc, init); if (!vc->vc_complement_mask) vc->vc_complement_mask = vc->vc_can_do_color ? 0x7700 : 0x0800; @@ -768,6 +784,7 @@ int vc_allocate(unsigned int currcons) /* return 0 on success */ if (!vc) return -ENOMEM; vc_cons[currcons].d = vc; + tty_port_init(&vc->port); INIT_WORK(&vc_cons[currcons].SAK_work, vc_SAK); visual_init(vc, currcons, 1); if (!*vc->vc_uni_pagedir_loc) @@ -831,9 +848,10 @@ static int vc_do_resize(struct tty_struct *tty, struct vc_data *vc, unsigned int cols, unsigned int lines) { unsigned long old_origin, new_origin, new_scr_end, rlth, rrem, err = 0; + unsigned long end; unsigned int old_cols, old_rows, old_row_size, old_screen_size; unsigned int new_cols, new_rows, new_row_size, new_screen_size; - unsigned int end, user; + unsigned int user; unsigned short *newscreen; WARN_CONSOLE_UNLOCKED(); @@ -888,22 +906,16 @@ static int vc_do_resize(struct tty_struct *tty, struct vc_data *vc, * bottom of buffer */ old_origin += (old_rows - new_rows) * old_row_size; - end = vc->vc_scr_end; } else { /* * Cursor is in no man's land, copy 1/2 screenful * from the top and bottom of cursor position */ old_origin += (vc->vc_y - new_rows/2) * old_row_size; - end = old_origin + (old_row_size * new_rows); } - } else - /* - * Cursor near the top, copy contents from the top of buffer - */ - end = (old_rows > new_rows) ? old_origin + - (old_row_size * new_rows) : - vc->vc_scr_end; + } + + end = old_origin + old_row_size * min(old_rows, new_rows); update_attr(vc); @@ -956,12 +968,12 @@ static int vc_do_resize(struct tty_struct *tty, struct vc_data *vc, * Resize a virtual console as seen from the console end of things. We * use the common vc_do_resize methods to update the structures. The * caller must hold the console sem to protect console internals and - * vc->vc_tty + * vc->port.tty */ int vc_resize(struct vc_data *vc, unsigned int cols, unsigned int rows) { - return vc_do_resize(vc->vc_tty, vc, cols, rows); + return vc_do_resize(vc->port.tty, vc, cols, rows); } /** @@ -1789,8 +1801,8 @@ static void do_con_trol(struct tty_struct *tty, struct vc_data *vc, int c) vc->vc_state = ESnormal; return; case ESpalette: - if ( (c>='0'&&c<='9') || (c>='A'&&c<='F') || (c>='a'&&c<='f') ) { - vc->vc_par[vc->vc_npar++] = (c > '9' ? (c & 0xDF) - 'A' + 10 : c - '0'); + if (isxdigit(c)) { + vc->vc_par[vc->vc_npar++] = hex_to_bin(c); if (vc->vc_npar == 7) { int i = vc->vc_par[0] * 3, j = 1; vc->vc_palette[i] = 16 * vc->vc_par[j++]; @@ -2498,7 +2510,7 @@ static void vt_console_print(struct console *co, const char *b, unsigned count) goto quit; } - if (vc->vc_mode != KD_TEXT) + if (vc->vc_mode != KD_TEXT && !vt_force_oops_output(vc)) goto quit; /* undraw cursor first */ @@ -2604,8 +2616,6 @@ int tioclinux(struct tty_struct *tty, unsigned long arg) return -EFAULT; ret = 0; - lock_kernel(); - switch (type) { case TIOCL_SETSEL: @@ -2680,7 +2690,6 @@ int tioclinux(struct tty_struct *tty, unsigned long arg) ret = -EINVAL; break; } - unlock_kernel(); return ret; } @@ -2793,12 +2802,12 @@ static int con_open(struct tty_struct *tty, struct file *filp) struct vc_data *vc = vc_cons[currcons].d; /* Still being freed */ - if (vc->vc_tty) { + if (vc->port.tty) { release_console_sem(); return -ERESTARTSYS; } tty->driver_data = vc; - vc->vc_tty = tty; + vc->port.tty = tty; if (!tty->winsize.ws_row && !tty->winsize.ws_col) { tty->winsize.ws_row = vc_cons[currcons].d->vc_rows; @@ -2826,7 +2835,7 @@ static void con_shutdown(struct tty_struct *tty) struct vc_data *vc = tty->driver_data; BUG_ON(vc == NULL); acquire_console_sem(); - vc->vc_tty = NULL; + vc->port.tty = NULL; release_console_sem(); tty_shutdown(tty); } @@ -2908,6 +2917,7 @@ static int __init con_init(void) for (currcons = 0; currcons < MIN_NR_CONSOLES; currcons++) { vc_cons[currcons].d = vc = kzalloc(sizeof(struct vc_data), GFP_NOWAIT); INIT_WORK(&vc_cons[currcons].SAK_work, vc_SAK); + tty_port_init(&vc->port); visual_init(vc, currcons, 1); vc->vc_screenbuf = kzalloc(vc->vc_screenbuf_size, GFP_NOWAIT); vc_init(vc, vc->vc_rows, vc->vc_cols, @@ -3414,6 +3424,80 @@ int con_is_bound(const struct consw *csw) EXPORT_SYMBOL(con_is_bound); /** + * con_debug_enter - prepare the console for the kernel debugger + * @sw: console driver + * + * Called when the console is taken over by the kernel debugger, this + * function needs to save the current console state, then put the console + * into a state suitable for the kernel debugger. + * + * RETURNS: + * Zero on success, nonzero if a failure occurred when trying to prepare + * the console for the debugger. + */ +int con_debug_enter(struct vc_data *vc) +{ + int ret = 0; + + saved_fg_console = fg_console; + saved_last_console = last_console; + saved_want_console = want_console; + saved_vc_mode = vc->vc_mode; + saved_console_blanked = console_blanked; + vc->vc_mode = KD_TEXT; + console_blanked = 0; + if (vc->vc_sw->con_debug_enter) + ret = vc->vc_sw->con_debug_enter(vc); +#ifdef CONFIG_KGDB_KDB + /* Set the initial LINES variable if it is not already set */ + if (vc->vc_rows < 999) { + int linecount; + char lns[4]; + const char *setargs[3] = { + "set", + "LINES", + lns, + }; + if (kdbgetintenv(setargs[0], &linecount)) { + snprintf(lns, 4, "%i", vc->vc_rows); + kdb_set(2, setargs); + } + } +#endif /* CONFIG_KGDB_KDB */ + return ret; +} +EXPORT_SYMBOL_GPL(con_debug_enter); + +/** + * con_debug_leave - restore console state + * @sw: console driver + * + * Restore the console state to what it was before the kernel debugger + * was invoked. + * + * RETURNS: + * Zero on success, nonzero if a failure occurred when trying to restore + * the console. + */ +int con_debug_leave(void) +{ + struct vc_data *vc; + int ret = 0; + + fg_console = saved_fg_console; + last_console = saved_last_console; + want_console = saved_want_console; + console_blanked = saved_console_blanked; + vc_cons[fg_console].d->vc_mode = saved_vc_mode; + + vc = vc_cons[fg_console].d; + if (vc->vc_sw->con_debug_leave) + ret = vc->vc_sw->con_debug_leave(vc); + return ret; +} +EXPORT_SYMBOL_GPL(con_debug_leave); + +/** * register_con_driver - register console driver to console layer * @csw: console driver * @first: the first console to take over, minimum value is 0 @@ -3703,7 +3787,8 @@ void do_unblank_screen(int leaving_gfx) return; } vc = vc_cons[fg_console].d; - if (vc->vc_mode != KD_TEXT) + /* Try to unblank in oops case too */ + if (vc->vc_mode != KD_TEXT && !vt_force_oops_output(vc)) return; /* but leave console_blanked != 0 */ if (blankinterval) { @@ -3712,7 +3797,7 @@ void do_unblank_screen(int leaving_gfx) } console_blanked = 0; - if (vc->vc_sw->con_blank(vc, 0, leaving_gfx)) + if (vc->vc_sw->con_blank(vc, 0, leaving_gfx) || vt_force_oops_output(vc)) /* Low-level driver cannot restore -> do it ourselves */ update_screen(vc); if (console_blank_hook) diff --git a/drivers/char/vt_ioctl.c b/drivers/char/vt_ioctl.c index cb19dbc5213..2bbeaaea46e 100644 --- a/drivers/char/vt_ioctl.c +++ b/drivers/char/vt_ioctl.c @@ -133,7 +133,7 @@ static void vt_event_wait(struct vt_event_wait *vw) list_add(&vw->list, &vt_events); spin_unlock_irqrestore(&vt_event_lock, flags); /* Wait for it to pass */ - wait_event_interruptible(vt_event_waitqueue, vw->done); + wait_event_interruptible_tty(vt_event_waitqueue, vw->done); /* Dequeue it */ spin_lock_irqsave(&vt_event_lock, flags); list_del(&vw->list); @@ -509,7 +509,7 @@ int vt_ioctl(struct tty_struct *tty, struct file * file, console = vc->vc_num; - lock_kernel(); + tty_lock(); if (!vc_cons_allocated(console)) { /* impossible? */ ret = -ENOIOCTLCMD; @@ -1336,7 +1336,7 @@ int vt_ioctl(struct tty_struct *tty, struct file * file, ret = -ENOIOCTLCMD; } out: - unlock_kernel(); + tty_unlock(); return ret; eperm: ret = -EPERM; @@ -1369,7 +1369,7 @@ void vc_SAK(struct work_struct *work) acquire_console_sem(); vc = vc_con->d; if (vc) { - tty = vc->vc_tty; + tty = vc->port.tty; /* * SAK should also work in all raw modes and reset * them properly. @@ -1503,7 +1503,7 @@ long vt_compat_ioctl(struct tty_struct *tty, struct file * file, console = vc->vc_num; - lock_kernel(); + tty_lock(); if (!vc_cons_allocated(console)) { /* impossible? */ ret = -ENOIOCTLCMD; @@ -1571,11 +1571,11 @@ long vt_compat_ioctl(struct tty_struct *tty, struct file * file, goto fallback; } out: - unlock_kernel(); + tty_unlock(); return ret; fallback: - unlock_kernel(); + tty_unlock(); return vt_ioctl(tty, file, cmd, arg); } @@ -1761,10 +1761,13 @@ int vt_move_to_console(unsigned int vt, int alloc) return -EIO; } release_console_sem(); + tty_lock(); if (vt_waitactive(vt + 1)) { pr_debug("Suspend: Can't switch VCs."); + tty_unlock(); return -EINTR; } + tty_unlock(); return prev; } diff --git a/drivers/char/xilinx_hwicap/xilinx_hwicap.c b/drivers/char/xilinx_hwicap/xilinx_hwicap.c index ed8a9cec2a0..b663d573aad 100644 --- a/drivers/char/xilinx_hwicap/xilinx_hwicap.c +++ b/drivers/char/xilinx_hwicap/xilinx_hwicap.c @@ -94,6 +94,7 @@ #ifdef CONFIG_OF /* For open firmware. */ +#include <linux/of_address.h> #include <linux/of_device.h> #include <linux/of_platform.h> #endif @@ -761,7 +762,7 @@ static struct platform_driver hwicap_platform_driver = { #if defined(CONFIG_OF) static int __devinit -hwicap_of_probe(struct of_device *op, const struct of_device_id *match) +hwicap_of_probe(struct platform_device *op, const struct of_device_id *match) { struct resource res; const unsigned int *id; @@ -798,7 +799,7 @@ hwicap_of_probe(struct of_device *op, const struct of_device_id *match) regs); } -static int __devexit hwicap_of_remove(struct of_device *op) +static int __devexit hwicap_of_remove(struct platform_device *op) { return hwicap_remove(&op->dev); } |