diff options
Diffstat (limited to 'drivers/char')
77 files changed, 2890 insertions, 3485 deletions
diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig index d0ac944e169..700ff967945 100644 --- a/drivers/char/Kconfig +++ b/drivers/char/Kconfig @@ -8,7 +8,7 @@ config VT bool "Virtual terminal" if EMBEDDED depends on !S390 select INPUT - default y if !VIOCONS + default y ---help--- If you say Y here, you will get support for terminal devices with display and keyboard devices. These are called "virtual" because you @@ -350,7 +350,7 @@ config STALDRV config STALLION tristate "Stallion EasyIO or EC8/32 support" - depends on STALDRV && BROKEN_ON_SMP && (ISA || EISA || PCI) + depends on STALDRV && (ISA || EISA || PCI) help If you have an EasyIO or EasyConnection 8/32 multiport Stallion card, then this is for you; say Y. Make sure to read @@ -361,7 +361,7 @@ config STALLION config ISTALLION tristate "Stallion EC8/64, ONboard, Brumby support" - depends on STALDRV && BROKEN_ON_SMP && (ISA || EISA || PCI) + depends on STALDRV && (ISA || EISA || PCI) help If you have an EasyConnection 8/64, ONboard, Brumby or Stallion serial multiport card, say Y here. Make sure to read diff --git a/drivers/char/Makefile b/drivers/char/Makefile index 8a161c30e1d..1a4247dccac 100644 --- a/drivers/char/Makefile +++ b/drivers/char/Makefile @@ -7,7 +7,7 @@ # FONTMAPFILE = cp437.uni -obj-y += mem.o random.o tty_io.o n_tty.o tty_ioctl.o tty_ldisc.o +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-$(CONFIG_LEGACY_PTYS) += pty.o obj-$(CONFIG_UNIX98_PTYS) += pty.o @@ -55,7 +55,6 @@ obj-$(CONFIG_RAW_DRIVER) += raw.o obj-$(CONFIG_SGI_SNSC) += snsc.o snsc_event.o obj-$(CONFIG_MSPEC) += mspec.o obj-$(CONFIG_MMTIMER) += mmtimer.o -obj-$(CONFIG_VIOCONS) += viocons.o obj-$(CONFIG_VIOTAPE) += viotape.o obj-$(CONFIG_HVCS) += hvcs.o obj-$(CONFIG_IBM_BSR) += bsr.o diff --git a/drivers/char/agp/agp.h b/drivers/char/agp/agp.h index 81e14bea54b..46f50753117 100644 --- a/drivers/char/agp/agp.h +++ b/drivers/char/agp/agp.h @@ -116,7 +116,9 @@ struct agp_bridge_driver { struct agp_memory *(*alloc_by_type) (size_t, int); void (*free_by_type)(struct agp_memory *); void *(*agp_alloc_page)(struct agp_bridge_data *); + int (*agp_alloc_pages)(struct agp_bridge_data *, struct agp_memory *, size_t); void (*agp_destroy_page)(void *, int flags); + void (*agp_destroy_pages)(struct agp_memory *); int (*agp_type_to_mask_type) (struct agp_bridge_data *, int); void (*chipset_flush)(struct agp_bridge_data *); }; @@ -148,6 +150,9 @@ struct agp_bridge_data { char minor_version; struct list_head list; u32 apbase_config; + /* list of agp_memory mapped to the aperture */ + struct list_head mapped_list; + spinlock_t mapped_lock; }; #define KB(x) ((x) * 1024) @@ -274,7 +279,10 @@ int agp_generic_remove_memory(struct agp_memory *mem, off_t pg_start, int type); struct agp_memory *agp_generic_alloc_by_type(size_t page_count, int type); void agp_generic_free_by_type(struct agp_memory *curr); void *agp_generic_alloc_page(struct agp_bridge_data *bridge); +int agp_generic_alloc_pages(struct agp_bridge_data *agp_bridge, + struct agp_memory *memory, size_t page_count); void agp_generic_destroy_page(void *addr, int flags); +void agp_generic_destroy_pages(struct agp_memory *memory); void agp_free_key(int key); int agp_num_entries(void); u32 agp_collect_device_status(struct agp_bridge_data *bridge, u32 mode, u32 command); diff --git a/drivers/char/agp/ali-agp.c b/drivers/char/agp/ali-agp.c index 1ffb381130c..31dcd9142d5 100644 --- a/drivers/char/agp/ali-agp.c +++ b/drivers/char/agp/ali-agp.c @@ -110,7 +110,8 @@ static int ali_configure(void) nlvm_addr+= agp_bridge->gart_bus_addr; nlvm_addr|=(agp_bridge->gart_bus_addr>>12); - printk(KERN_INFO PFX "nlvm top &base = %8x\n",nlvm_addr); + dev_info(&agp_bridge->dev->dev, "nlvm top &base = %8x\n", + nlvm_addr); } #endif @@ -315,8 +316,8 @@ static int __devinit agp_ali_probe(struct pci_dev *pdev, goto found; } - printk(KERN_ERR PFX "Unsupported ALi chipset (device id: %04x)\n", - pdev->device); + dev_err(&pdev->dev, "unsupported ALi chipset [%04x/%04x])\n", + pdev->vendor, pdev->device); return -ENODEV; @@ -361,8 +362,7 @@ found: bridge->driver = &ali_generic_bridge; } - printk(KERN_INFO PFX "Detected ALi %s chipset\n", - devs[j].chipset_name); + dev_info(&pdev->dev, "ALi %s chipset\n", devs[j].chipset_name); /* Fill in the mode register */ pci_read_config_dword(pdev, diff --git a/drivers/char/agp/alpha-agp.c b/drivers/char/agp/alpha-agp.c index 5da89f6c6c2..5ea4da8e995 100644 --- a/drivers/char/agp/alpha-agp.c +++ b/drivers/char/agp/alpha-agp.c @@ -143,7 +143,9 @@ struct agp_bridge_driver alpha_core_agp_driver = { .alloc_by_type = agp_generic_alloc_by_type, .free_by_type = agp_generic_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 = agp_generic_type_to_mask_type, }; diff --git a/drivers/char/agp/amd-k7-agp.c b/drivers/char/agp/amd-k7-agp.c index 39a0718bc61..603a986e96a 100644 --- a/drivers/char/agp/amd-k7-agp.c +++ b/drivers/char/agp/amd-k7-agp.c @@ -386,7 +386,9 @@ static const struct agp_bridge_driver amd_irongate_driver = { .alloc_by_type = agp_generic_alloc_by_type, .free_by_type = agp_generic_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 = agp_generic_type_to_mask_type, }; @@ -419,8 +421,8 @@ static int __devinit agp_amdk7_probe(struct pci_dev *pdev, return -ENODEV; j = ent - agp_amdk7_pci_table; - printk(KERN_INFO PFX "Detected AMD %s chipset\n", - amd_agp_device_ids[j].chipset_name); + dev_info(&pdev->dev, "AMD %s chipset\n", + amd_agp_device_ids[j].chipset_name); bridge = agp_alloc_bridge(); if (!bridge) @@ -442,7 +444,7 @@ static int __devinit agp_amdk7_probe(struct pci_dev *pdev, while (!cap_ptr) { gfxcard = pci_get_class(PCI_CLASS_DISPLAY_VGA<<8, gfxcard); if (!gfxcard) { - printk (KERN_INFO PFX "Couldn't find an AGP VGA controller.\n"); + dev_info(&pdev->dev, "no AGP VGA controller\n"); return -ENODEV; } cap_ptr = pci_find_capability(gfxcard, PCI_CAP_ID_AGP); @@ -453,7 +455,7 @@ static int __devinit agp_amdk7_probe(struct pci_dev *pdev, (if necessary at all). */ if (gfxcard->vendor == PCI_VENDOR_ID_NVIDIA) { agp_bridge->flags |= AGP_ERRATA_1X; - printk (KERN_INFO PFX "AMD 751 chipset with NVidia GeForce detected. Forcing to 1X due to errata.\n"); + dev_info(&pdev->dev, "AMD 751 chipset with NVidia GeForce; forcing 1X due to errata\n"); } pci_dev_put(gfxcard); } @@ -469,7 +471,7 @@ static int __devinit agp_amdk7_probe(struct pci_dev *pdev, agp_bridge->flags = AGP_ERRATA_FASTWRITES; agp_bridge->flags |= AGP_ERRATA_SBA; agp_bridge->flags |= AGP_ERRATA_1X; - printk (KERN_INFO PFX "AMD 761 chipset with errata detected - disabling AGP fast writes & SBA and forcing to 1X.\n"); + dev_info(&pdev->dev, "AMD 761 chipset with errata; disabling AGP fast writes & SBA and forcing to 1X\n"); } } diff --git a/drivers/char/agp/amd64-agp.c b/drivers/char/agp/amd64-agp.c index 481ffe87c71..2812ee2b165 100644 --- a/drivers/char/agp/amd64-agp.c +++ b/drivers/char/agp/amd64-agp.c @@ -34,6 +34,7 @@ static struct resource *aperture_resource; static int __initdata agp_try_unsupported = 1; +static int agp_bridges_found; static void amd64_tlbflush(struct agp_memory *temp) { @@ -223,7 +224,9 @@ static const struct agp_bridge_driver amd_8151_driver = { .alloc_by_type = agp_generic_alloc_by_type, .free_by_type = agp_generic_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 = agp_generic_type_to_mask_type, }; @@ -293,12 +296,13 @@ static __devinit int fix_northbridge(struct pci_dev *nb, struct pci_dev *agp, * so let double check that order, and lets trust the AMD NB settings */ if (order >=0 && aper + (32ULL<<(20 + order)) > 0x100000000ULL) { - printk(KERN_INFO "Aperture size %u MB is not right, using settings from NB\n", - 32 << order); + dev_info(&agp->dev, "aperture size %u MB is not right, using settings from NB\n", + 32 << order); order = nb_order; } - printk(KERN_INFO PFX "Aperture from AGP @ %Lx size %u MB\n", aper, 32 << order); + dev_info(&agp->dev, "aperture from AGP @ %Lx size %u MB\n", + aper, 32 << order); if (order < 0 || !agp_aperture_valid(aper, (32*1024*1024)<<order)) return -1; @@ -319,10 +323,10 @@ static __devinit int cache_nbs (struct pci_dev *pdev, u32 cap_ptr) for (i = 0; i < num_k8_northbridges; i++) { struct pci_dev *dev = k8_northbridges[i]; if (fix_northbridge(dev, pdev, cap_ptr) < 0) { - printk(KERN_ERR PFX "No usable aperture found.\n"); + dev_err(&dev->dev, "no usable aperture found\n"); #ifdef __x86_64__ /* should port this to i386 */ - printk(KERN_ERR PFX "Consider rebooting with iommu=memaper=2 to get a good aperture.\n"); + dev_err(&dev->dev, "consider rebooting with iommu=memaper=2 to get a good aperture\n"); #endif return -1; } @@ -345,14 +349,14 @@ static void __devinit amd8151_init(struct pci_dev *pdev, struct agp_bridge_data default: revstring="??"; break; } - printk (KERN_INFO PFX "Detected AMD 8151 AGP Bridge rev %s\n", revstring); + dev_info(&pdev->dev, "AMD 8151 AGP Bridge rev %s\n", revstring); /* * Work around errata. * Chips before B2 stepping incorrectly reporting v3.5 */ if (pdev->revision < 0x13) { - printk (KERN_INFO PFX "Correcting AGP revision (reports 3.5, is really 3.0)\n"); + dev_info(&pdev->dev, "correcting AGP revision (reports 3.5, is really 3.0)\n"); bridge->major_version = 3; bridge->minor_version = 0; } @@ -375,11 +379,11 @@ static int __devinit uli_agp_init(struct pci_dev *pdev) struct pci_dev *dev1; int i; unsigned size = amd64_fetch_size(); - printk(KERN_INFO "Setting up ULi AGP.\n"); + + dev_info(&pdev->dev, "setting up ULi AGP\n"); dev1 = pci_get_slot (pdev->bus,PCI_DEVFN(0,0)); if (dev1 == NULL) { - printk(KERN_INFO PFX "Detected a ULi chipset, " - "but could not fine the secondary device.\n"); + dev_info(&pdev->dev, "can't find ULi secondary device\n"); return -ENODEV; } @@ -388,7 +392,7 @@ static int __devinit uli_agp_init(struct pci_dev *pdev) break; if (i == ARRAY_SIZE(uli_sizes)) { - printk(KERN_INFO PFX "No ULi size found for %d\n", size); + dev_info(&pdev->dev, "no ULi size found for %d\n", size); return -ENODEV; } @@ -433,13 +437,11 @@ static int nforce3_agp_init(struct pci_dev *pdev) int i; unsigned size = amd64_fetch_size(); - printk(KERN_INFO PFX "Setting up Nforce3 AGP.\n"); + dev_info(&pdev->dev, "setting up Nforce3 AGP\n"); dev1 = pci_get_slot(pdev->bus, PCI_DEVFN(11, 0)); if (dev1 == NULL) { - printk(KERN_INFO PFX "agpgart: Detected an NVIDIA " - "nForce3 chipset, but could not find " - "the secondary device.\n"); + dev_info(&pdev->dev, "can't find Nforce3 secondary device\n"); return -ENODEV; } @@ -448,7 +450,7 @@ static int nforce3_agp_init(struct pci_dev *pdev) break; if (i == ARRAY_SIZE(nforce3_sizes)) { - printk(KERN_INFO PFX "No NForce3 size found for %d\n", size); + dev_info(&pdev->dev, "no NForce3 size found for %d\n", size); return -ENODEV; } @@ -462,7 +464,7 @@ static int nforce3_agp_init(struct pci_dev *pdev) /* if x86-64 aperture base is beyond 4G, exit here */ if ( (apbase & 0x7fff) >> (32 - 25) ) { - printk(KERN_INFO PFX "aperture base > 4G\n"); + dev_info(&pdev->dev, "aperture base > 4G\n"); return -ENODEV; } @@ -489,6 +491,7 @@ static int __devinit agp_amd64_probe(struct pci_dev *pdev, { struct agp_bridge_data *bridge; u8 cap_ptr; + int err; cap_ptr = pci_find_capability(pdev, PCI_CAP_ID_AGP); if (!cap_ptr) @@ -504,7 +507,8 @@ static int __devinit agp_amd64_probe(struct pci_dev *pdev, pdev->device == PCI_DEVICE_ID_AMD_8151_0) { amd8151_init(pdev, bridge); } else { - printk(KERN_INFO PFX "Detected AGP bridge %x\n", pdev->devfn); + dev_info(&pdev->dev, "AGP bridge [%04x/%04x]\n", + pdev->vendor, pdev->device); } bridge->driver = &amd_8151_driver; @@ -536,7 +540,12 @@ static int __devinit agp_amd64_probe(struct pci_dev *pdev, } pci_set_drvdata(pdev, bridge); - return agp_add_bridge(bridge); + err = agp_add_bridge(bridge); + if (err < 0) + return err; + + agp_bridges_found++; + return 0; } static void __devexit agp_amd64_remove(struct pci_dev *pdev) @@ -713,7 +722,11 @@ int __init agp_amd64_init(void) if (agp_off) return -EINVAL; - if (pci_register_driver(&agp_amd64_pci_driver) < 0) { + err = pci_register_driver(&agp_amd64_pci_driver); + if (err < 0) + return err; + + if (agp_bridges_found == 0) { struct pci_dev *dev; if (!agp_try_unsupported && !agp_try_unsupported_boot) { printk(KERN_INFO PFX "No supported AGP bridge found.\n"); diff --git a/drivers/char/agp/ati-agp.c b/drivers/char/agp/ati-agp.c index 3a4566c0d84..ae2791b926b 100644 --- a/drivers/char/agp/ati-agp.c +++ b/drivers/char/agp/ati-agp.c @@ -418,7 +418,9 @@ static const struct agp_bridge_driver ati_generic_bridge = { .alloc_by_type = agp_generic_alloc_by_type, .free_by_type = agp_generic_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 = agp_generic_type_to_mask_type, }; @@ -486,8 +488,8 @@ static int __devinit agp_ati_probe(struct pci_dev *pdev, goto found; } - printk(KERN_ERR PFX - "Unsupported Ati chipset (device id: %04x)\n", pdev->device); + dev_err(&pdev->dev, "unsupported Ati chipset [%04x/%04x])\n", + pdev->vendor, pdev->device); return -ENODEV; found: @@ -500,8 +502,7 @@ found: bridge->driver = &ati_generic_bridge; - printk(KERN_INFO PFX "Detected Ati %s chipset\n", - devs[j].chipset_name); + dev_info(&pdev->dev, "Ati %s chipset\n", devs[j].chipset_name); /* Fill in the mode register */ pci_read_config_dword(pdev, diff --git a/drivers/char/agp/backend.c b/drivers/char/agp/backend.c index 1ec87104e68..3a3cc03d401 100644 --- a/drivers/char/agp/backend.c +++ b/drivers/char/agp/backend.c @@ -144,7 +144,8 @@ static int agp_backend_initialize(struct agp_bridge_data *bridge) void *addr = bridge->driver->agp_alloc_page(bridge); if (!addr) { - printk(KERN_ERR PFX "unable to get memory for scratch page.\n"); + dev_err(&bridge->dev->dev, + "can't get memory for scratch page\n"); return -ENOMEM; } @@ -155,13 +156,13 @@ static int agp_backend_initialize(struct agp_bridge_data *bridge) size_value = bridge->driver->fetch_size(); if (size_value == 0) { - printk(KERN_ERR PFX "unable to determine aperture size.\n"); + dev_err(&bridge->dev->dev, "can't determine aperture size\n"); rc = -EINVAL; goto err_out; } if (bridge->driver->create_gatt_table(bridge)) { - printk(KERN_ERR PFX - "unable to get memory for graphics translation table.\n"); + dev_err(&bridge->dev->dev, + "can't get memory for graphics translation table\n"); rc = -ENOMEM; goto err_out; } @@ -169,7 +170,8 @@ static int agp_backend_initialize(struct agp_bridge_data *bridge) bridge->key_list = vmalloc(PAGE_SIZE * 4); if (bridge->key_list == NULL) { - printk(KERN_ERR PFX "error allocating memory for key lists.\n"); + dev_err(&bridge->dev->dev, + "can't allocate memory for key lists\n"); rc = -ENOMEM; goto err_out; } @@ -179,10 +181,12 @@ static int agp_backend_initialize(struct agp_bridge_data *bridge) memset(bridge->key_list, 0, PAGE_SIZE * 4); if (bridge->driver->configure()) { - printk(KERN_ERR PFX "error configuring host chipset.\n"); + dev_err(&bridge->dev->dev, "error configuring host chipset\n"); rc = -EINVAL; goto err_out; } + INIT_LIST_HEAD(&bridge->mapped_list); + spin_lock_init(&bridge->mapped_lock); return 0; @@ -269,25 +273,27 @@ int agp_add_bridge(struct agp_bridge_data *bridge) /* Grab reference on the chipset driver. */ if (!try_module_get(bridge->driver->owner)) { - printk (KERN_INFO PFX "Couldn't lock chipset driver.\n"); + dev_info(&bridge->dev->dev, "can't lock chipset driver\n"); return -EINVAL; } error = agp_backend_initialize(bridge); if (error) { - printk (KERN_INFO PFX "agp_backend_initialize() failed.\n"); + dev_info(&bridge->dev->dev, + "agp_backend_initialize() failed\n"); goto err_out; } if (list_empty(&agp_bridges)) { error = agp_frontend_initialize(); if (error) { - printk (KERN_INFO PFX "agp_frontend_initialize() failed.\n"); + dev_info(&bridge->dev->dev, + "agp_frontend_initialize() failed\n"); goto frontend_err; } - printk(KERN_INFO PFX "AGP aperture is %dM @ 0x%lx\n", - bridge->driver->fetch_size(), bridge->gart_bus_addr); + dev_info(&bridge->dev->dev, "AGP aperture is %dM @ 0x%lx\n", + bridge->driver->fetch_size(), bridge->gart_bus_addr); } diff --git a/drivers/char/agp/efficeon-agp.c b/drivers/char/agp/efficeon-agp.c index 8ca6f262ef8..453543a1f29 100644 --- a/drivers/char/agp/efficeon-agp.c +++ b/drivers/char/agp/efficeon-agp.c @@ -335,7 +335,9 @@ static const struct agp_bridge_driver efficeon_driver = { .alloc_by_type = agp_generic_alloc_by_type, .free_by_type = agp_generic_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 = agp_generic_type_to_mask_type, }; diff --git a/drivers/char/agp/generic.c b/drivers/char/agp/generic.c index eaa1a355bb3..10d6cbd7c05 100644 --- a/drivers/char/agp/generic.c +++ b/drivers/char/agp/generic.c @@ -201,14 +201,22 @@ void agp_free_memory(struct agp_memory *curr) return; } if (curr->page_count != 0) { - for (i = 0; i < curr->page_count; i++) { - curr->memory[i] = (unsigned long)gart_to_virt(curr->memory[i]); - curr->bridge->driver->agp_destroy_page((void *)curr->memory[i], - AGP_PAGE_DESTROY_UNMAP); - } - for (i = 0; i < curr->page_count; i++) { - curr->bridge->driver->agp_destroy_page((void *)curr->memory[i], - AGP_PAGE_DESTROY_FREE); + if (curr->bridge->driver->agp_destroy_pages) { + curr->bridge->driver->agp_destroy_pages(curr); + } else { + + for (i = 0; i < curr->page_count; i++) { + curr->memory[i] = (unsigned long)gart_to_virt( + curr->memory[i]); + curr->bridge->driver->agp_destroy_page( + (void *)curr->memory[i], + AGP_PAGE_DESTROY_UNMAP); + } + for (i = 0; i < curr->page_count; i++) { + curr->bridge->driver->agp_destroy_page( + (void *)curr->memory[i], + AGP_PAGE_DESTROY_FREE); + } } } agp_free_key(curr->key); @@ -264,6 +272,15 @@ struct agp_memory *agp_allocate_memory(struct agp_bridge_data *bridge, if (new == NULL) return NULL; + if (bridge->driver->agp_alloc_pages) { + if (bridge->driver->agp_alloc_pages(bridge, new, page_count)) { + agp_free_memory(new); + return NULL; + } + new->bridge = bridge; + return new; + } + for (i = 0; i < page_count; i++) { void *addr = bridge->driver->agp_alloc_page(bridge); @@ -429,6 +446,10 @@ int agp_bind_memory(struct agp_memory *curr, off_t pg_start) curr->is_bound = true; curr->pg_start = pg_start; + spin_lock(&agp_bridge->mapped_lock); + list_add(&curr->mapped_list, &agp_bridge->mapped_list); + spin_unlock(&agp_bridge->mapped_lock); + return 0; } EXPORT_SYMBOL(agp_bind_memory); @@ -461,10 +482,34 @@ int agp_unbind_memory(struct agp_memory *curr) curr->is_bound = false; curr->pg_start = 0; + spin_lock(&curr->bridge->mapped_lock); + list_del(&curr->mapped_list); + spin_unlock(&curr->bridge->mapped_lock); return 0; } EXPORT_SYMBOL(agp_unbind_memory); +/** + * agp_rebind_emmory - Rewrite the entire GATT, useful on resume + */ +int agp_rebind_memory(void) +{ + struct agp_memory *curr; + int ret_val = 0; + + spin_lock(&agp_bridge->mapped_lock); + list_for_each_entry(curr, &agp_bridge->mapped_list, mapped_list) { + ret_val = curr->bridge->driver->insert_memory(curr, + curr->pg_start, + curr->type); + if (ret_val != 0) + break; + } + spin_unlock(&agp_bridge->mapped_lock); + return ret_val; +} +EXPORT_SYMBOL(agp_rebind_memory); + /* End - Routines for handling swapping of agp_memory into the GATT */ @@ -771,8 +816,8 @@ void agp_device_command(u32 bridge_agpstat, bool agp_v3) if (!agp) continue; - printk(KERN_INFO PFX "Putting AGP V%d device at %s into %dx mode\n", - agp_v3 ? 3 : 2, pci_name(device), mode); + dev_info(&device->dev, "putting AGP V%d device into %dx mode\n", + agp_v3 ? 3 : 2, mode); pci_write_config_dword(device, agp + PCI_AGP_COMMAND, bridge_agpstat); } } @@ -800,10 +845,8 @@ void agp_generic_enable(struct agp_bridge_data *bridge, u32 requested_mode) get_agp_version(agp_bridge); - printk(KERN_INFO PFX "Found an AGP %d.%d compliant device at %s.\n", - agp_bridge->major_version, - agp_bridge->minor_version, - pci_name(agp_bridge->dev)); + dev_info(&agp_bridge->dev->dev, "AGP %d.%d bridge\n", + agp_bridge->major_version, agp_bridge->minor_version); pci_read_config_dword(agp_bridge->dev, agp_bridge->capndx + PCI_AGP_STATUS, &bridge_agpstat); @@ -832,8 +875,7 @@ void agp_generic_enable(struct agp_bridge_data *bridge, u32 requested_mode) pci_write_config_dword(bridge->dev, bridge->capndx+AGPCTRL, temp); - printk(KERN_INFO PFX "Device is in legacy mode," - " falling back to 2.x\n"); + dev_info(&bridge->dev->dev, "bridge is in legacy mode, falling back to 2.x\n"); } } @@ -1178,6 +1220,39 @@ EXPORT_SYMBOL(agp_generic_alloc_user); * against a maximum value. */ +int agp_generic_alloc_pages(struct agp_bridge_data *bridge, struct agp_memory *mem, size_t num_pages) +{ + struct page * page; + int i, ret = -ENOMEM; + + for (i = 0; i < num_pages; i++) { + page = alloc_page(GFP_KERNEL | GFP_DMA32); + /* agp_free_memory() needs gart address */ + if (page == NULL) + goto out; + +#ifndef CONFIG_X86 + map_page_into_agp(page); +#endif + get_page(page); + atomic_inc(&agp_bridge->current_memory_agp); + + /* set_memory_array_uc() needs virtual address */ + mem->memory[i] = (unsigned long)page_address(page); + mem->page_count++; + } + +#ifdef CONFIG_X86 + set_memory_array_uc(mem->memory, num_pages); +#endif + ret = 0; +out: + for (i = 0; i < mem->page_count; i++) + mem->memory[i] = virt_to_gart((void *)mem->memory[i]); + return ret; +} +EXPORT_SYMBOL(agp_generic_alloc_pages); + void *agp_generic_alloc_page(struct agp_bridge_data *bridge) { struct page * page; @@ -1194,6 +1269,37 @@ void *agp_generic_alloc_page(struct agp_bridge_data *bridge) } EXPORT_SYMBOL(agp_generic_alloc_page); +void agp_generic_destroy_pages(struct agp_memory *mem) +{ + int i; + void *addr; + struct page *page; + + if (!mem) + return; + + for (i = 0; i < mem->page_count; i++) + mem->memory[i] = (unsigned long)gart_to_virt(mem->memory[i]); + +#ifdef CONFIG_X86 + set_memory_array_wb(mem->memory, mem->page_count); +#endif + + for (i = 0; i < mem->page_count; i++) { + addr = (void *)mem->memory[i]; + page = virt_to_page(addr); + +#ifndef CONFIG_X86 + unmap_page_from_agp(page); +#endif + + put_page(page); + free_page((unsigned long)addr); + atomic_dec(&agp_bridge->current_memory_agp); + mem->memory[i] = 0; + } +} +EXPORT_SYMBOL(agp_generic_destroy_pages); void agp_generic_destroy_page(void *addr, int flags) { diff --git a/drivers/char/agp/hp-agp.c b/drivers/char/agp/hp-agp.c index 80d7317f85c..183ac3fe44f 100644 --- a/drivers/char/agp/hp-agp.c +++ b/drivers/char/agp/hp-agp.c @@ -435,7 +435,9 @@ const struct agp_bridge_driver hp_zx1_driver = { .alloc_by_type = agp_generic_alloc_by_type, .free_by_type = agp_generic_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 = agp_generic_type_to_mask_type, .cant_use_aperture = true, }; diff --git a/drivers/char/agp/i460-agp.c b/drivers/char/agp/i460-agp.c index e587eebebc6..10da687d131 100644 --- a/drivers/char/agp/i460-agp.c +++ b/drivers/char/agp/i460-agp.c @@ -575,7 +575,9 @@ const struct agp_bridge_driver intel_i460_driver = { .insert_memory = i460_insert_memory_small_io_page, .remove_memory = i460_remove_memory_small_io_page, .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, #endif .alloc_by_type = agp_generic_alloc_by_type, .free_by_type = agp_generic_free_by_type, diff --git a/drivers/char/agp/intel-agp.c b/drivers/char/agp/intel-agp.c index df702642ab8..043e36628d6 100644 --- a/drivers/char/agp/intel-agp.c +++ b/drivers/char/agp/intel-agp.c @@ -32,8 +32,8 @@ #define PCI_DEVICE_ID_INTEL_Q35_IG 0x29B2 #define PCI_DEVICE_ID_INTEL_Q33_HB 0x29D0 #define PCI_DEVICE_ID_INTEL_Q33_IG 0x29D2 -#define PCI_DEVICE_ID_INTEL_IGD_HB 0x2A40 -#define PCI_DEVICE_ID_INTEL_IGD_IG 0x2A42 +#define PCI_DEVICE_ID_INTEL_GM45_HB 0x2A40 +#define PCI_DEVICE_ID_INTEL_GM45_IG 0x2A42 #define PCI_DEVICE_ID_INTEL_IGD_E_HB 0x2E00 #define PCI_DEVICE_ID_INTEL_IGD_E_IG 0x2E02 #define PCI_DEVICE_ID_INTEL_Q45_HB 0x2E10 @@ -55,7 +55,7 @@ agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82965G_HB || \ agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82965GM_HB || \ agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_82965GME_HB || \ - agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_IGD_HB) + agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_GM45_HB) #define IS_G33 (agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_G33_HB || \ agp_bridge->dev->device == PCI_DEVICE_ID_INTEL_Q35_HB || \ @@ -161,7 +161,7 @@ static int intel_i810_fetch_size(void) values = A_SIZE_FIX(agp_bridge->driver->aperture_sizes); if ((smram_miscc & I810_GMS) == I810_GMS_DISABLE) { - printk(KERN_WARNING PFX "i810 is disabled\n"); + dev_warn(&agp_bridge->dev->dev, "i810 is disabled\n"); return 0; } if ((smram_miscc & I810_GFX_MEM_WIN_SIZE) == I810_GFX_MEM_WIN_32M) { @@ -193,7 +193,8 @@ static int intel_i810_configure(void) intel_private.registers = ioremap(temp, 128 * 4096); if (!intel_private.registers) { - printk(KERN_ERR PFX "Unable to remap memory.\n"); + dev_err(&intel_private.pcidev->dev, + "can't remap memory\n"); return -ENOMEM; } } @@ -201,7 +202,8 @@ static int intel_i810_configure(void) if ((readl(intel_private.registers+I810_DRAM_CTL) & I810_DRAM_ROW_0) == I810_DRAM_ROW_0_SDRAM) { /* This will need to be dynamically assigned */ - printk(KERN_INFO PFX "detected 4MB dedicated video ram.\n"); + dev_info(&intel_private.pcidev->dev, + "detected 4MB dedicated video ram\n"); intel_private.num_dcache_entries = 1024; } pci_read_config_dword(intel_private.pcidev, I810_GMADDR, &temp); @@ -500,8 +502,8 @@ static void intel_i830_init_gtt_entries(void) size = 1024 + 512; break; default: - printk(KERN_INFO PFX "Unknown page table size, " - "assuming 512KB\n"); + dev_info(&intel_private.pcidev->dev, + "unknown page table size, assuming 512KB\n"); size = 512; } size += 4; /* add in BIOS popup space */ @@ -515,8 +517,8 @@ static void intel_i830_init_gtt_entries(void) size = 2048; break; default: - printk(KERN_INFO PFX "Unknown page table size 0x%x, " - "assuming 512KB\n", + dev_info(&agp_bridge->dev->dev, + "unknown page table size 0x%x, assuming 512KB\n", (gmch_ctrl & G33_PGETBL_SIZE_MASK)); size = 512; } @@ -627,11 +629,11 @@ static void intel_i830_init_gtt_entries(void) } } if (gtt_entries > 0) - printk(KERN_INFO PFX "Detected %dK %s memory.\n", + dev_info(&agp_bridge->dev->dev, "detected %dK %s memory\n", gtt_entries / KB(1), local ? "local" : "stolen"); else - printk(KERN_INFO PFX - "No pre-allocated video memory detected.\n"); + dev_info(&agp_bridge->dev->dev, + "no pre-allocated video memory detected\n"); gtt_entries /= KB(4); intel_private.gtt_entries = gtt_entries; @@ -801,10 +803,12 @@ static int intel_i830_insert_entries(struct agp_memory *mem, off_t pg_start, num_entries = A_SIZE_FIX(temp)->num_entries; if (pg_start < intel_private.gtt_entries) { - printk(KERN_DEBUG PFX "pg_start == 0x%.8lx,intel_private.gtt_entries == 0x%.8x\n", - pg_start, intel_private.gtt_entries); + dev_printk(KERN_DEBUG, &intel_private.pcidev->dev, + "pg_start == 0x%.8lx, intel_private.gtt_entries == 0x%.8x\n", + pg_start, intel_private.gtt_entries); - printk(KERN_INFO PFX "Trying to insert into local/stolen memory\n"); + dev_info(&intel_private.pcidev->dev, + "trying to insert into local/stolen memory\n"); goto out_err; } @@ -851,7 +855,8 @@ static int intel_i830_remove_entries(struct agp_memory *mem, off_t pg_start, return 0; if (pg_start < intel_private.gtt_entries) { - printk(KERN_INFO PFX "Trying to disable local/stolen memory\n"); + dev_info(&intel_private.pcidev->dev, + "trying to disable local/stolen memory\n"); return -EINVAL; } @@ -957,7 +962,7 @@ static void intel_i9xx_setup_flush(void) if (intel_private.ifp_resource.start) { intel_private.i9xx_flush_page = ioremap_nocache(intel_private.ifp_resource.start, PAGE_SIZE); if (!intel_private.i9xx_flush_page) - printk(KERN_INFO "unable to ioremap flush page - no chipset flushing"); + dev_info(&intel_private.pcidev->dev, "can't ioremap flush page - no chipset flushing"); } } @@ -1028,10 +1033,12 @@ static int intel_i915_insert_entries(struct agp_memory *mem, off_t pg_start, num_entries = A_SIZE_FIX(temp)->num_entries; if (pg_start < intel_private.gtt_entries) { - printk(KERN_DEBUG PFX "pg_start == 0x%.8lx,intel_private.gtt_entries == 0x%.8x\n", - pg_start, intel_private.gtt_entries); + dev_printk(KERN_DEBUG, &intel_private.pcidev->dev, + "pg_start == 0x%.8lx, intel_private.gtt_entries == 0x%.8x\n", + pg_start, intel_private.gtt_entries); - printk(KERN_INFO PFX "Trying to insert into local/stolen memory\n"); + dev_info(&intel_private.pcidev->dev, + "trying to insert into local/stolen memory\n"); goto out_err; } @@ -1078,7 +1085,8 @@ static int intel_i915_remove_entries(struct agp_memory *mem, off_t pg_start, return 0; if (pg_start < intel_private.gtt_entries) { - printk(KERN_INFO PFX "Trying to disable local/stolen memory\n"); + dev_info(&intel_private.pcidev->dev, + "trying to disable local/stolen memory\n"); return -EINVAL; } @@ -1182,7 +1190,7 @@ static unsigned long intel_i965_mask_memory(struct agp_bridge_data *bridge, static void intel_i965_get_gtt_range(int *gtt_offset, int *gtt_size) { switch (agp_bridge->dev->device) { - case PCI_DEVICE_ID_INTEL_IGD_HB: + case PCI_DEVICE_ID_INTEL_GM45_HB: case PCI_DEVICE_ID_INTEL_IGD_E_HB: case PCI_DEVICE_ID_INTEL_Q45_HB: case PCI_DEVICE_ID_INTEL_G45_HB: @@ -1379,7 +1387,7 @@ static int intel_815_configure(void) /* the Intel 815 chipset spec. says that bits 29-31 in the * ATTBASE register are reserved -> try not to write them */ if (agp_bridge->gatt_bus_addr & INTEL_815_ATTBASE_MASK) { - printk(KERN_EMERG PFX "gatt bus addr too high"); + dev_emerg(&agp_bridge->dev->dev, "gatt bus addr too high"); return -EINVAL; } @@ -1703,7 +1711,9 @@ static const struct agp_bridge_driver intel_generic_driver = { .alloc_by_type = agp_generic_alloc_by_type, .free_by_type = agp_generic_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 = agp_generic_type_to_mask_type, }; @@ -1728,7 +1738,9 @@ static const struct agp_bridge_driver intel_810_driver = { .alloc_by_type = intel_i810_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 = agp_generic_type_to_mask_type, }; @@ -1752,7 +1764,9 @@ static const struct agp_bridge_driver intel_815_driver = { .alloc_by_type = agp_generic_alloc_by_type, .free_by_type = agp_generic_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 = agp_generic_type_to_mask_type, }; @@ -1777,7 +1791,9 @@ static const struct agp_bridge_driver intel_830_driver = { .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_i830_type_to_mask_type, .chipset_flush = intel_i830_chipset_flush, }; @@ -1802,7 +1818,9 @@ static const struct agp_bridge_driver intel_820_driver = { .alloc_by_type = agp_generic_alloc_by_type, .free_by_type = agp_generic_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 = agp_generic_type_to_mask_type, }; @@ -1826,7 +1844,9 @@ static const struct agp_bridge_driver intel_830mp_driver = { .alloc_by_type = agp_generic_alloc_by_type, .free_by_type = agp_generic_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 = agp_generic_type_to_mask_type, }; @@ -1850,7 +1870,9 @@ static const struct agp_bridge_driver intel_840_driver = { .alloc_by_type = agp_generic_alloc_by_type, .free_by_type = agp_generic_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 = agp_generic_type_to_mask_type, }; @@ -1874,7 +1896,9 @@ static const struct agp_bridge_driver intel_845_driver = { .alloc_by_type = agp_generic_alloc_by_type, .free_by_type = agp_generic_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 = agp_generic_type_to_mask_type, .chipset_flush = intel_i830_chipset_flush, }; @@ -1899,7 +1923,9 @@ static const struct agp_bridge_driver intel_850_driver = { .alloc_by_type = agp_generic_alloc_by_type, .free_by_type = agp_generic_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 = agp_generic_type_to_mask_type, }; @@ -1923,7 +1949,9 @@ static const struct agp_bridge_driver intel_860_driver = { .alloc_by_type = agp_generic_alloc_by_type, .free_by_type = agp_generic_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 = agp_generic_type_to_mask_type, }; @@ -1948,7 +1976,9 @@ static const struct agp_bridge_driver intel_915_driver = { .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_i830_type_to_mask_type, .chipset_flush = intel_i915_chipset_flush, }; @@ -1974,7 +2004,9 @@ static const struct agp_bridge_driver intel_i965_driver = { .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_i830_type_to_mask_type, .chipset_flush = intel_i915_chipset_flush, }; @@ -1999,7 +2031,9 @@ static const struct agp_bridge_driver intel_7505_driver = { .alloc_by_type = agp_generic_alloc_by_type, .free_by_type = agp_generic_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 = agp_generic_type_to_mask_type, }; @@ -2024,7 +2058,9 @@ static const struct agp_bridge_driver intel_g33_driver = { .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_i830_type_to_mask_type, .chipset_flush = intel_i915_chipset_flush, }; @@ -2117,8 +2153,8 @@ static const struct intel_driver_description { NULL, &intel_g33_driver }, { PCI_DEVICE_ID_INTEL_Q33_HB, PCI_DEVICE_ID_INTEL_Q33_IG, 0, "Q33", NULL, &intel_g33_driver }, - { PCI_DEVICE_ID_INTEL_IGD_HB, PCI_DEVICE_ID_INTEL_IGD_IG, 0, - "Intel Integrated Graphics Device", NULL, &intel_i965_driver }, + { PCI_DEVICE_ID_INTEL_GM45_HB, PCI_DEVICE_ID_INTEL_GM45_IG, 0, + "Mobile Intel? GM45 Express", NULL, &intel_i965_driver }, { PCI_DEVICE_ID_INTEL_IGD_E_HB, PCI_DEVICE_ID_INTEL_IGD_E_IG, 0, "Intel Integrated Graphics Device", NULL, &intel_i965_driver }, { PCI_DEVICE_ID_INTEL_Q45_HB, PCI_DEVICE_ID_INTEL_Q45_IG, 0, @@ -2163,8 +2199,8 @@ static int __devinit agp_intel_probe(struct pci_dev *pdev, if (intel_agp_chipsets[i].name == NULL) { if (cap_ptr) - printk(KERN_WARNING PFX "Unsupported Intel chipset" - "(device id: %04x)\n", pdev->device); + dev_warn(&pdev->dev, "unsupported Intel chipset [%04x/%04x]\n", + pdev->vendor, pdev->device); agp_put_bridge(bridge); return -ENODEV; } @@ -2172,9 +2208,8 @@ static int __devinit agp_intel_probe(struct pci_dev *pdev, if (bridge->driver == NULL) { /* bridge has no AGP and no IGD detected */ if (cap_ptr) - printk(KERN_WARNING PFX "Failed to find bridge device " - "(chip_id: %04x)\n", - intel_agp_chipsets[i].gmch_chip_id); + dev_warn(&pdev->dev, "can't find bridge device (chip_id: %04x)\n", + intel_agp_chipsets[i].gmch_chip_id); agp_put_bridge(bridge); return -ENODEV; } @@ -2183,8 +2218,7 @@ static int __devinit agp_intel_probe(struct pci_dev *pdev, bridge->capndx = cap_ptr; bridge->dev_private_data = &intel_private; - printk(KERN_INFO PFX "Detected an Intel %s Chipset.\n", - intel_agp_chipsets[i].name); + dev_info(&pdev->dev, "Intel %s Chipset\n", intel_agp_chipsets[i].name); /* * The following fixes the case where the BIOS has "forgotten" to @@ -2194,7 +2228,7 @@ static int __devinit agp_intel_probe(struct pci_dev *pdev, r = &pdev->resource[0]; if (!r->start && r->end) { if (pci_assign_resource(pdev, 0)) { - printk(KERN_ERR PFX "could not assign resource 0\n"); + dev_err(&pdev->dev, "can't assign resource 0\n"); agp_put_bridge(bridge); return -ENODEV; } @@ -2206,7 +2240,7 @@ static int __devinit agp_intel_probe(struct pci_dev *pdev, * 20030610 - hamish@zot.org */ if (pci_enable_device(pdev)) { - printk(KERN_ERR PFX "Unable to Enable PCI device\n"); + dev_err(&pdev->dev, "can't enable PCI device\n"); agp_put_bridge(bridge); return -ENODEV; } @@ -2238,6 +2272,7 @@ static void __devexit agp_intel_remove(struct pci_dev *pdev) static int agp_intel_resume(struct pci_dev *pdev) { struct agp_bridge_data *bridge = pci_get_drvdata(pdev); + int ret_val; pci_restore_state(pdev); @@ -2265,6 +2300,10 @@ static int agp_intel_resume(struct pci_dev *pdev) else if (bridge->driver == &intel_i965_driver) intel_i915_configure(); + ret_val = agp_rebind_memory(); + if (ret_val != 0) + return ret_val; + return 0; } #endif @@ -2315,7 +2354,7 @@ static struct pci_device_id agp_intel_pci_table[] = { ID(PCI_DEVICE_ID_INTEL_G33_HB), ID(PCI_DEVICE_ID_INTEL_Q35_HB), ID(PCI_DEVICE_ID_INTEL_Q33_HB), - ID(PCI_DEVICE_ID_INTEL_IGD_HB), + ID(PCI_DEVICE_ID_INTEL_GM45_HB), ID(PCI_DEVICE_ID_INTEL_IGD_E_HB), ID(PCI_DEVICE_ID_INTEL_Q45_HB), ID(PCI_DEVICE_ID_INTEL_G45_HB), diff --git a/drivers/char/agp/isoch.c b/drivers/char/agp/isoch.c index 3f9ccde6237..c73385cc4b8 100644 --- a/drivers/char/agp/isoch.c +++ b/drivers/char/agp/isoch.c @@ -153,7 +153,7 @@ static int agp_3_5_isochronous_node_enable(struct agp_bridge_data *bridge, /* Check if this configuration has any chance of working */ if (tot_bw > target.maxbw) { - printk(KERN_ERR PFX "isochronous bandwidth required " + dev_err(&td->dev, "isochronous bandwidth required " "by AGP 3.0 devices exceeds that which is supported by " "the AGP 3.0 bridge!\n"); ret = -ENODEV; @@ -188,7 +188,7 @@ static int agp_3_5_isochronous_node_enable(struct agp_bridge_data *bridge, /* Exit if the minimal ISOCH_N allocation among the masters is more * than the target can handle. */ if (tot_n > target.n) { - printk(KERN_ERR PFX "number of isochronous " + dev_err(&td->dev, "number of isochronous " "transactions per period required by AGP 3.0 devices " "exceeds that which is supported by the AGP 3.0 " "bridge!\n"); @@ -229,7 +229,7 @@ static int agp_3_5_isochronous_node_enable(struct agp_bridge_data *bridge, /* Exit if the minimal RQ needs of the masters exceeds what the target * can provide. */ if (tot_rq > rq_isoch) { - printk(KERN_ERR PFX "number of request queue slots " + dev_err(&td->dev, "number of request queue slots " "required by the isochronous bandwidth requested by " "AGP 3.0 devices exceeds the number provided by the " "AGP 3.0 bridge!\n"); @@ -359,8 +359,9 @@ int agp_3_5_enable(struct agp_bridge_data *bridge) case 0x0001: /* Unclassified device */ /* Don't know what this is, but log it for investigation. */ if (mcapndx != 0) { - printk (KERN_INFO PFX "Wacky, found unclassified AGP device. %x:%x\n", - dev->vendor, dev->device); + dev_info(&td->dev, "wacky, found unclassified AGP device %s [%04x/%04x]\n", + pci_name(dev), + dev->vendor, dev->device); } continue; @@ -407,17 +408,18 @@ int agp_3_5_enable(struct agp_bridge_data *bridge) } if (mcapndx == 0) { - printk(KERN_ERR PFX "woah! Non-AGP device " - "found on the secondary bus of an AGP 3.5 bridge!\n"); + dev_err(&td->dev, "woah! Non-AGP device %s on " + "secondary bus of AGP 3.5 bridge!\n", + pci_name(dev)); ret = -ENODEV; goto free_and_exit; } mmajor = (ncapid >> AGP_MAJOR_VERSION_SHIFT) & 0xf; if (mmajor < 3) { - printk(KERN_ERR PFX "woah! AGP 2.0 device " - "found on the secondary bus of an AGP 3.5 " - "bridge operating with AGP 3.0 electricals!\n"); + dev_err(&td->dev, "woah! AGP 2.0 device %s on " + "secondary bus of AGP 3.5 bridge operating " + "with AGP 3.0 electricals!\n", pci_name(dev)); ret = -ENODEV; goto free_and_exit; } @@ -427,10 +429,10 @@ int agp_3_5_enable(struct agp_bridge_data *bridge) pci_read_config_dword(dev, cur->capndx+AGPSTAT, &mstatus); if (((mstatus >> 3) & 0x1) == 0) { - printk(KERN_ERR PFX "woah! AGP 3.x device " - "not operating in AGP 3.x mode found on the " - "secondary bus of an AGP 3.5 bridge operating " - "with AGP 3.0 electricals!\n"); + dev_err(&td->dev, "woah! AGP 3.x device %s not " + "operating in AGP 3.x mode on secondary bus " + "of AGP 3.5 bridge operating with AGP 3.0 " + "electricals!\n", pci_name(dev)); ret = -ENODEV; goto free_and_exit; } @@ -444,9 +446,9 @@ int agp_3_5_enable(struct agp_bridge_data *bridge) if (isoch) { ret = agp_3_5_isochronous_node_enable(bridge, dev_list, ndevs); if (ret) { - printk(KERN_INFO PFX "Something bad happened setting " - "up isochronous xfers. Falling back to " - "non-isochronous xfer mode.\n"); + dev_info(&td->dev, "something bad happened setting " + "up isochronous xfers; falling back to " + "non-isochronous xfer mode\n"); } else { goto free_and_exit; } @@ -466,4 +468,3 @@ free_and_exit: get_out: return ret; } - diff --git a/drivers/char/agp/nvidia-agp.c b/drivers/char/agp/nvidia-agp.c index eaceb61ba2d..dc70d377181 100644 --- a/drivers/char/agp/nvidia-agp.c +++ b/drivers/char/agp/nvidia-agp.c @@ -312,7 +312,9 @@ static const struct agp_bridge_driver nvidia_driver = { .alloc_by_type = agp_generic_alloc_by_type, .free_by_type = agp_generic_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 = agp_generic_type_to_mask_type, }; diff --git a/drivers/char/agp/parisc-agp.c b/drivers/char/agp/parisc-agp.c index 8c42dcc5958..f2492ecf082 100644 --- a/drivers/char/agp/parisc-agp.c +++ b/drivers/char/agp/parisc-agp.c @@ -224,7 +224,9 @@ static const struct agp_bridge_driver parisc_agp_driver = { .alloc_by_type = agp_generic_alloc_by_type, .free_by_type = agp_generic_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 = agp_generic_type_to_mask_type, .cant_use_aperture = true, }; diff --git a/drivers/char/agp/sis-agp.c b/drivers/char/agp/sis-agp.c index b6791846809..6c3837a0184 100644 --- a/drivers/char/agp/sis-agp.c +++ b/drivers/char/agp/sis-agp.c @@ -79,10 +79,8 @@ static void sis_delayed_enable(struct agp_bridge_data *bridge, u32 mode) u32 command; int rate; - printk(KERN_INFO PFX "Found an AGP %d.%d compliant device at %s.\n", - agp_bridge->major_version, - agp_bridge->minor_version, - pci_name(agp_bridge->dev)); + dev_info(&agp_bridge->dev->dev, "AGP %d.%d bridge\n", + agp_bridge->major_version, agp_bridge->minor_version); pci_read_config_dword(agp_bridge->dev, agp_bridge->capndx + PCI_AGP_STATUS, &command); command = agp_collect_device_status(bridge, mode, command); @@ -94,8 +92,8 @@ static void sis_delayed_enable(struct agp_bridge_data *bridge, u32 mode) if (!agp) continue; - printk(KERN_INFO PFX "Putting AGP V3 device at %s into %dx mode\n", - pci_name(device), rate); + dev_info(&agp_bridge->dev->dev, "putting AGP V3 device at %s into %dx mode\n", + pci_name(device), rate); pci_write_config_dword(device, agp + PCI_AGP_COMMAND, command); @@ -105,7 +103,7 @@ static void sis_delayed_enable(struct agp_bridge_data *bridge, u32 mode) * cannot be configured */ if (device->device == bridge->dev->device) { - printk(KERN_INFO PFX "SiS delay workaround: giving bridge time to recover.\n"); + dev_info(&agp_bridge->dev->dev, "SiS delay workaround: giving bridge time to recover\n"); msleep(10); } } @@ -142,7 +140,9 @@ static struct agp_bridge_driver sis_driver = { .alloc_by_type = agp_generic_alloc_by_type, .free_by_type = agp_generic_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 = agp_generic_type_to_mask_type, }; @@ -190,7 +190,8 @@ static int __devinit agp_sis_probe(struct pci_dev *pdev, return -ENODEV; - printk(KERN_INFO PFX "Detected SiS chipset - id:%i\n", pdev->device); + dev_info(&pdev->dev, "SiS chipset [%04x/%04x]\n", + pdev->vendor, pdev->device); bridge = agp_alloc_bridge(); if (!bridge) return -ENOMEM; @@ -242,7 +243,7 @@ static struct pci_device_id agp_sis_pci_table[] = { .class = (PCI_CLASS_BRIDGE_HOST << 8), .class_mask = ~0, .vendor = PCI_VENDOR_ID_SI, - .device = PCI_DEVICE_ID_SI_5591_AGP, + .device = PCI_DEVICE_ID_SI_5591, .subvendor = PCI_ANY_ID, .subdevice = PCI_ANY_ID, }, diff --git a/drivers/char/agp/sworks-agp.c b/drivers/char/agp/sworks-agp.c index 0e054c13449..6224df8b7f0 100644 --- a/drivers/char/agp/sworks-agp.c +++ b/drivers/char/agp/sworks-agp.c @@ -241,7 +241,8 @@ static void serverworks_tlbflush(struct agp_memory *temp) while (readb(serverworks_private.registers+SVWRKS_POSTFLUSH) == 1) { cpu_relax(); if (time_after(jiffies, timeout)) { - printk(KERN_ERR PFX "TLB post flush took more than 3 seconds\n"); + dev_err(&serverworks_private.svrwrks_dev->dev, + "TLB post flush took more than 3 seconds\n"); break; } } @@ -251,7 +252,8 @@ static void serverworks_tlbflush(struct agp_memory *temp) while (readl(serverworks_private.registers+SVWRKS_DIRFLUSH) == 1) { cpu_relax(); if (time_after(jiffies, timeout)) { - printk(KERN_ERR PFX "TLB Dir flush took more than 3 seconds\n"); + dev_err(&serverworks_private.svrwrks_dev->dev, + "TLB Dir flush took more than 3 seconds\n"); break; } } @@ -271,7 +273,7 @@ static int serverworks_configure(void) temp = (temp & PCI_BASE_ADDRESS_MEM_MASK); serverworks_private.registers = (volatile u8 __iomem *) ioremap(temp, 4096); if (!serverworks_private.registers) { - printk (KERN_ERR PFX "Unable to ioremap() memory.\n"); + dev_err(&agp_bridge->dev->dev, "can't ioremap(%#x)\n", temp); return -ENOMEM; } @@ -435,7 +437,9 @@ static const struct agp_bridge_driver sworks_driver = { .alloc_by_type = agp_generic_alloc_by_type, .free_by_type = agp_generic_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 = agp_generic_type_to_mask_type, }; @@ -451,7 +455,7 @@ static int __devinit agp_serverworks_probe(struct pci_dev *pdev, switch (pdev->device) { case 0x0006: - printk (KERN_ERR PFX "ServerWorks CNB20HE is unsupported due to lack of documentation.\n"); + dev_err(&pdev->dev, "ServerWorks CNB20HE is unsupported due to lack of documentation\n"); return -ENODEV; case PCI_DEVICE_ID_SERVERWORKS_HE: @@ -461,8 +465,8 @@ static int __devinit agp_serverworks_probe(struct pci_dev *pdev, default: if (cap_ptr) - printk(KERN_ERR PFX "Unsupported Serverworks chipset " - "(device id: %04x)\n", pdev->device); + dev_err(&pdev->dev, "unsupported Serverworks chipset " + "[%04x/%04x]\n", pdev->vendor, pdev->device); return -ENODEV; } @@ -470,8 +474,7 @@ static int __devinit agp_serverworks_probe(struct pci_dev *pdev, bridge_dev = pci_get_bus_and_slot((unsigned int)pdev->bus->number, PCI_DEVFN(0, 1)); if (!bridge_dev) { - printk(KERN_INFO PFX "Detected a Serverworks chipset " - "but could not find the secondary device.\n"); + dev_info(&pdev->dev, "can't find secondary device\n"); return -ENODEV; } @@ -482,8 +485,8 @@ static int __devinit agp_serverworks_probe(struct pci_dev *pdev, if (temp & PCI_BASE_ADDRESS_MEM_TYPE_64) { pci_read_config_dword(pdev, SVWRKS_APSIZE + 4, &temp2); if (temp2 != 0) { - printk(KERN_INFO PFX "Detected 64 bit aperture address, " - "but top bits are not zero. Disabling agp\n"); + dev_info(&pdev->dev, "64 bit aperture address, " + "but top bits are not zero; disabling AGP\n"); return -ENODEV; } serverworks_private.mm_addr_ofs = 0x18; @@ -495,8 +498,8 @@ static int __devinit agp_serverworks_probe(struct pci_dev *pdev, pci_read_config_dword(pdev, serverworks_private.mm_addr_ofs + 4, &temp2); if (temp2 != 0) { - printk(KERN_INFO PFX "Detected 64 bit MMIO address, " - "but top bits are not zero. Disabling agp\n"); + dev_info(&pdev->dev, "64 bit MMIO address, but top " + "bits are not zero; disabling AGP\n"); return -ENODEV; } } diff --git a/drivers/char/agp/uninorth-agp.c b/drivers/char/agp/uninorth-agp.c index d2fa3cfca02..0f004b65ec0 100644 --- a/drivers/char/agp/uninorth-agp.c +++ b/drivers/char/agp/uninorth-agp.c @@ -46,8 +46,8 @@ static int uninorth_fetch_size(void) break; if (i == agp_bridge->driver->num_aperture_sizes) { - printk(KERN_ERR PFX "Invalid aperture size, using" - " default\n"); + dev_err(&agp_bridge->dev->dev, "invalid aperture size, " + "using default\n"); size = 0; aperture = NULL; } @@ -108,8 +108,8 @@ static int uninorth_configure(void) current_size = A_SIZE_32(agp_bridge->current_size); - printk(KERN_INFO PFX "configuring for size idx: %d\n", - current_size->size_value); + dev_info(&agp_bridge->dev->dev, "configuring for size idx: %d\n", + current_size->size_value); /* aperture size and gatt addr */ pci_write_config_dword(agp_bridge->dev, @@ -197,8 +197,9 @@ static int u3_insert_memory(struct agp_memory *mem, off_t pg_start, int type) gp = (u32 *) &agp_bridge->gatt_table[pg_start]; for (i = 0; i < mem->page_count; ++i) { if (gp[i]) { - printk("u3_insert_memory: entry 0x%x occupied (%x)\n", - i, gp[i]); + dev_info(&agp_bridge->dev->dev, + "u3_insert_memory: entry 0x%x occupied (%x)\n", + i, gp[i]); return -EBUSY; } } @@ -276,8 +277,8 @@ static void uninorth_agp_enable(struct agp_bridge_data *bridge, u32 mode) &scratch); } while ((scratch & PCI_AGP_COMMAND_AGP) == 0 && ++timeout < 1000); if ((scratch & PCI_AGP_COMMAND_AGP) == 0) - printk(KERN_ERR PFX "failed to write UniNorth AGP" - " command register\n"); + dev_err(&bridge->dev->dev, "can't write UniNorth AGP " + "command register\n"); if (uninorth_rev >= 0x30) { /* This is an AGP V3 */ @@ -330,8 +331,8 @@ static int agp_uninorth_suspend(struct pci_dev *pdev) pci_read_config_dword(device, agp + PCI_AGP_COMMAND, &cmd); if (!(cmd & PCI_AGP_COMMAND_AGP)) continue; - printk("uninorth-agp: disabling AGP on device %s\n", - pci_name(device)); + dev_info(&pdev->dev, "disabling AGP on device %s\n", + pci_name(device)); cmd &= ~PCI_AGP_COMMAND_AGP; pci_write_config_dword(device, agp + PCI_AGP_COMMAND, cmd); } @@ -341,8 +342,7 @@ static int agp_uninorth_suspend(struct pci_dev *pdev) pci_read_config_dword(pdev, agp + PCI_AGP_COMMAND, &cmd); bridge->dev_private_data = (void *)(long)cmd; if (cmd & PCI_AGP_COMMAND_AGP) { - printk("uninorth-agp: disabling AGP on bridge %s\n", - pci_name(pdev)); + dev_info(&pdev->dev, "disabling AGP on bridge\n"); cmd &= ~PCI_AGP_COMMAND_AGP; pci_write_config_dword(pdev, agp + PCI_AGP_COMMAND, cmd); } @@ -509,7 +509,9 @@ const struct agp_bridge_driver uninorth_agp_driver = { .alloc_by_type = agp_generic_alloc_by_type, .free_by_type = agp_generic_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 = agp_generic_type_to_mask_type, .cant_use_aperture = true, }; @@ -534,7 +536,9 @@ const struct agp_bridge_driver u3_agp_driver = { .alloc_by_type = agp_generic_alloc_by_type, .free_by_type = agp_generic_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 = agp_generic_type_to_mask_type, .cant_use_aperture = true, .needs_scratch_page = true, @@ -591,14 +595,14 @@ static int __devinit agp_uninorth_probe(struct pci_dev *pdev, /* probe for known chipsets */ for (j = 0; devs[j].chipset_name != NULL; ++j) { if (pdev->device == devs[j].device_id) { - printk(KERN_INFO PFX "Detected Apple %s chipset\n", - devs[j].chipset_name); + dev_info(&pdev->dev, "Apple %s chipset\n", + devs[j].chipset_name); goto found; } } - printk(KERN_ERR PFX "Unsupported Apple chipset (device id: %04x).\n", - pdev->device); + dev_err(&pdev->dev, "unsupported Apple chipset [%04x/%04x]\n", + pdev->vendor, pdev->device); return -ENODEV; found: diff --git a/drivers/char/agp/via-agp.c b/drivers/char/agp/via-agp.c index 7b36476dff4..9f4d49e1b59 100644 --- a/drivers/char/agp/via-agp.c +++ b/drivers/char/agp/via-agp.c @@ -190,7 +190,9 @@ static const struct agp_bridge_driver via_agp3_driver = { .alloc_by_type = agp_generic_alloc_by_type, .free_by_type = agp_generic_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 = agp_generic_type_to_mask_type, }; @@ -214,7 +216,9 @@ static const struct agp_bridge_driver via_driver = { .alloc_by_type = agp_generic_alloc_by_type, .free_by_type = agp_generic_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 = agp_generic_type_to_mask_type, }; diff --git a/drivers/char/amiserial.c b/drivers/char/amiserial.c index 3530ff417a5..98821f97583 100644 --- a/drivers/char/amiserial.c +++ b/drivers/char/amiserial.c @@ -837,9 +837,6 @@ static int rs_put_char(struct tty_struct *tty, unsigned char ch) struct async_struct *info; unsigned long flags; - if (!tty) - return 0; - info = tty->driver_data; if (serial_paranoia_check(info, tty->name, "rs_put_char")) @@ -892,9 +889,6 @@ static int rs_write(struct tty_struct * tty, const unsigned char *buf, int count struct async_struct *info; unsigned long flags; - if (!tty) - return 0; - info = tty->driver_data; if (serial_paranoia_check(info, tty->name, "rs_write")) @@ -1254,7 +1248,7 @@ static int rs_break(struct tty_struct *tty, int break_state) unsigned long flags; if (serial_paranoia_check(info, tty->name, "rs_break")) - return; + return -EINVAL; local_irq_save(flags); if (break_state == -1) diff --git a/drivers/char/applicom.c b/drivers/char/applicom.c index 31d08b641f5..b899d9182c7 100644 --- a/drivers/char/applicom.c +++ b/drivers/char/applicom.c @@ -712,8 +712,7 @@ static int ac_ioctl(struct inode *inode, struct file *file, unsigned int cmd, un IndexCard = adgl->num_card-1; - if(cmd != 0 && cmd != 6 && - ((IndexCard >= MAX_BOARD) || !apbs[IndexCard].RamIO)) { + if(cmd != 6 && ((IndexCard >= MAX_BOARD) || !apbs[IndexCard].RamIO)) { static int warncount = 10; if (warncount) { printk( KERN_WARNING "APPLICOM driver IOCTL, bad board number %d\n",(int)IndexCard+1); @@ -832,8 +831,7 @@ static int ac_ioctl(struct inode *inode, struct file *file, unsigned int cmd, un } break; default: - printk(KERN_INFO "APPLICOM driver ioctl, unknown function code %d\n",cmd) ; - ret = -EINVAL; + ret = -ENOTTY; break; } Dummy = readb(apbs[IndexCard].RamIO + VERS); diff --git a/drivers/char/cyclades.c b/drivers/char/cyclades.c index fe6d774fe2e..5e5b1dc1a0a 100644 --- a/drivers/char/cyclades.c +++ b/drivers/char/cyclades.c @@ -4993,12 +4993,14 @@ static int __devinit cy_pci_probe(struct pci_dev *pdev, device_id == PCI_DEVICE_ID_CYCLOM_Y_Hi) { card_name = "Cyclom-Y"; - addr0 = pci_iomap(pdev, 0, CyPCI_Yctl); + addr0 = ioremap_nocache(pci_resource_start(pdev, 0), + CyPCI_Yctl); if (addr0 == NULL) { dev_err(&pdev->dev, "can't remap ctl region\n"); goto err_reg; } - addr2 = pci_iomap(pdev, 2, CyPCI_Ywin); + addr2 = ioremap_nocache(pci_resource_start(pdev, 2), + CyPCI_Ywin); if (addr2 == NULL) { dev_err(&pdev->dev, "can't remap base region\n"); goto err_unmap; @@ -5013,7 +5015,8 @@ static int __devinit cy_pci_probe(struct pci_dev *pdev, } else if (device_id == PCI_DEVICE_ID_CYCLOM_Z_Hi) { struct RUNTIME_9060 __iomem *ctl_addr; - ctl_addr = addr0 = pci_iomap(pdev, 0, CyPCI_Zctl); + ctl_addr = addr0 = ioremap_nocache(pci_resource_start(pdev, 0), + CyPCI_Zctl); if (addr0 == NULL) { dev_err(&pdev->dev, "can't remap ctl region\n"); goto err_reg; @@ -5026,8 +5029,8 @@ static int __devinit cy_pci_probe(struct pci_dev *pdev, mailbox = (u32)readl(&ctl_addr->mail_box_0); - addr2 = pci_iomap(pdev, 2, mailbox == ZE_V1 ? - CyPCI_Ze_win : CyPCI_Zwin); + addr2 = ioremap_nocache(pci_resource_start(pdev, 2), + mailbox == ZE_V1 ? CyPCI_Ze_win : CyPCI_Zwin); if (addr2 == NULL) { dev_err(&pdev->dev, "can't remap base region\n"); goto err_unmap; @@ -5159,9 +5162,9 @@ err_null: cy_card[card_no].base_addr = NULL; free_irq(irq, &cy_card[card_no]); err_unmap: - pci_iounmap(pdev, addr0); + iounmap(addr0); if (addr2) - pci_iounmap(pdev, addr2); + iounmap(addr2); err_reg: pci_release_regions(pdev); err_dis: @@ -5186,9 +5189,9 @@ static void __devexit cy_pci_remove(struct pci_dev *pdev) cy_writew(cinfo->ctl_addr + 0x68, readw(cinfo->ctl_addr + 0x68) & ~0x0900); - pci_iounmap(pdev, cinfo->base_addr); + iounmap(cinfo->base_addr); if (cinfo->ctl_addr) - pci_iounmap(pdev, cinfo->ctl_addr); + iounmap(cinfo->ctl_addr); if (cinfo->irq #ifndef CONFIG_CYZ_INTR && !IS_CYC_Z(*cinfo) diff --git a/drivers/char/ds1620.c b/drivers/char/ds1620.c index 34275c6f1da..74e9cd81b5b 100644 --- a/drivers/char/ds1620.c +++ b/drivers/char/ds1620.c @@ -10,7 +10,7 @@ #include <linux/init.h> #include <linux/smp_lock.h> -#include <asm/hardware.h> +#include <mach/hardware.h> #include <asm/mach-types.h> #include <asm/uaccess.h> #include <asm/therm.h> diff --git a/drivers/char/efirtc.c b/drivers/char/efirtc.c index 67fbd7aab5d..34d15d54823 100644 --- a/drivers/char/efirtc.c +++ b/drivers/char/efirtc.c @@ -37,7 +37,6 @@ #include <linux/rtc.h> #include <linux/proc_fs.h> #include <linux/efi.h> -#include <linux/smp_lock.h> #include <linux/uaccess.h> #include <asm/system.h> diff --git a/drivers/char/epca.c b/drivers/char/epca.c index 456e4ede049..4998b2761e8 100644 --- a/drivers/char/epca.c +++ b/drivers/char/epca.c @@ -1376,6 +1376,7 @@ static void post_fep_init(unsigned int crd) unsigned long flags; u16 tseg, rseg; + tty_port_init(&ch->port); ch->brdchan = bc; ch->mailbox = gd; INIT_WORK(&ch->tqueue, do_softint); @@ -1510,10 +1511,6 @@ static void post_fep_init(unsigned int crd) ch->fepstopca = 0; ch->close_delay = 50; - ch->port.count = 0; - ch->port.blocked_open = 0; - init_waitqueue_head(&ch->port.open_wait); - init_waitqueue_head(&ch->port.close_wait); spin_unlock_irqrestore(&epca_lock, flags); } diff --git a/drivers/char/generic_serial.c b/drivers/char/generic_serial.c index 19d3afb0e50..c6090f84a2e 100644 --- a/drivers/char/generic_serial.c +++ b/drivers/char/generic_serial.c @@ -54,8 +54,6 @@ int gs_put_char(struct tty_struct * tty, unsigned char ch) func_enter (); - if (!tty) return 0; - port = tty->driver_data; if (!port) return 0; @@ -97,8 +95,6 @@ int gs_write(struct tty_struct * tty, func_enter (); - if (!tty) return 0; - port = tty->driver_data; if (!port) return 0; @@ -185,7 +181,6 @@ static int gs_real_chars_in_buffer(struct tty_struct *tty) struct gs_port *port; func_enter (); - if (!tty) return 0; port = tty->driver_data; if (!port->rd) return 0; @@ -274,8 +269,6 @@ void gs_flush_buffer(struct tty_struct *tty) func_enter (); - if (!tty) return; - port = tty->driver_data; if (!port) return; @@ -296,8 +289,6 @@ void gs_flush_chars(struct tty_struct * tty) func_enter (); - if (!tty) return; - port = tty->driver_data; if (!port) return; @@ -321,8 +312,6 @@ void gs_stop(struct tty_struct * tty) func_enter (); - if (!tty) return; - port = tty->driver_data; if (!port) return; @@ -341,8 +330,6 @@ void gs_start(struct tty_struct * tty) { struct gs_port *port; - if (!tty) return; - port = tty->driver_data; if (!port) return; @@ -393,8 +380,6 @@ void gs_hangup(struct tty_struct *tty) func_enter (); - if (!tty) return; - port = tty->driver_data; tty = port->port.tty; if (!tty) @@ -426,8 +411,6 @@ int gs_block_til_ready(void *port_, struct file * filp) tty = port->port.tty; - if (!tty) return 0; - gs_dprintk (GS_DEBUG_BTR, "Entering gs_block_till_ready.\n"); /* * If the device is in the middle of being closed, then block @@ -523,8 +506,6 @@ void gs_close(struct tty_struct * tty, struct file * filp) func_enter (); - if (!tty) return; - port = (struct gs_port *) tty->driver_data; if (!port) return; @@ -621,8 +602,6 @@ void gs_set_termios (struct tty_struct * tty, func_enter(); - if (!tty) return; - port = tty->driver_data; if (!port) return; diff --git a/drivers/char/hpet.c b/drivers/char/hpet.c index b3f5dbc6d88..f3cfb4c7612 100644 --- a/drivers/char/hpet.c +++ b/drivers/char/hpet.c @@ -53,6 +53,11 @@ #define HPET_RANGE_SIZE 1024 /* from HPET spec */ + +/* WARNING -- don't get confused. These macros are never used + * to write the (single) counter, and rarely to read it. + * They're badly named; to fix, someday. + */ #if BITS_PER_LONG == 64 #define write_counter(V, MC) writeq(V, MC) #define read_counter(MC) readq(MC) @@ -77,7 +82,7 @@ static struct clocksource clocksource_hpet = { .rating = 250, .read = read_hpet, .mask = CLOCKSOURCE_MASK(64), - .mult = 0, /*to be caluclated*/ + .mult = 0, /* to be calculated */ .shift = 10, .flags = CLOCK_SOURCE_IS_CONTINUOUS, }; @@ -86,8 +91,6 @@ static struct clocksource *hpet_clocksource; /* A lock for concurrent access by app and isr hpet activity. */ static DEFINE_SPINLOCK(hpet_lock); -/* A lock for concurrent intermodule access to hpet and isr hpet activity. */ -static DEFINE_SPINLOCK(hpet_task_lock); #define HPET_DEV_NAME (7) @@ -99,7 +102,6 @@ struct hpet_dev { unsigned long hd_irqdata; wait_queue_head_t hd_waitqueue; struct fasync_struct *hd_async_queue; - struct hpet_task *hd_task; unsigned int hd_flags; unsigned int hd_irq; unsigned int hd_hdwirq; @@ -173,11 +175,6 @@ static irqreturn_t hpet_interrupt(int irq, void *data) writel(isr, &devp->hd_hpet->hpet_isr); spin_unlock(&hpet_lock); - spin_lock(&hpet_task_lock); - if (devp->hd_task) - devp->hd_task->ht_func(devp->hd_task->ht_data); - spin_unlock(&hpet_task_lock); - wake_up_interruptible(&devp->hd_waitqueue); kill_fasync(&devp->hd_async_queue, SIGIO, POLL_IN); @@ -185,6 +182,67 @@ static irqreturn_t hpet_interrupt(int irq, void *data) return IRQ_HANDLED; } +static void hpet_timer_set_irq(struct hpet_dev *devp) +{ + unsigned long v; + int irq, gsi; + struct hpet_timer __iomem *timer; + + spin_lock_irq(&hpet_lock); + if (devp->hd_hdwirq) { + spin_unlock_irq(&hpet_lock); + return; + } + + timer = devp->hd_timer; + + /* we prefer level triggered mode */ + v = readl(&timer->hpet_config); + if (!(v & Tn_INT_TYPE_CNF_MASK)) { + v |= Tn_INT_TYPE_CNF_MASK; + writel(v, &timer->hpet_config); + } + spin_unlock_irq(&hpet_lock); + + v = (readq(&timer->hpet_config) & Tn_INT_ROUTE_CAP_MASK) >> + Tn_INT_ROUTE_CAP_SHIFT; + + /* + * In PIC mode, skip IRQ0-4, IRQ6-9, IRQ12-15 which is always used by + * legacy device. In IO APIC mode, we skip all the legacy IRQS. + */ + if (acpi_irq_model == ACPI_IRQ_MODEL_PIC) + v &= ~0xf3df; + else + v &= ~0xffff; + + for (irq = find_first_bit(&v, HPET_MAX_IRQ); irq < HPET_MAX_IRQ; + irq = find_next_bit(&v, HPET_MAX_IRQ, 1 + irq)) { + + if (irq >= NR_IRQS) { + irq = HPET_MAX_IRQ; + break; + } + + gsi = acpi_register_gsi(irq, ACPI_LEVEL_SENSITIVE, + ACPI_ACTIVE_LOW); + if (gsi > 0) + break; + + /* FIXME: Setup interrupt source table */ + } + + if (irq < HPET_MAX_IRQ) { + spin_lock_irq(&hpet_lock); + v = readl(&timer->hpet_config); + v |= irq << Tn_INT_ROUTE_CNF_SHIFT; + writel(v, &timer->hpet_config); + devp->hd_hdwirq = gsi; + spin_unlock_irq(&hpet_lock); + } + return; +} + static int hpet_open(struct inode *inode, struct file *file) { struct hpet_dev *devp; @@ -199,8 +257,7 @@ static int hpet_open(struct inode *inode, struct file *file) for (devp = NULL, hpetp = hpets; hpetp && !devp; hpetp = hpetp->hp_next) for (i = 0; i < hpetp->hp_ntimer; i++) - if (hpetp->hp_dev[i].hd_flags & HPET_OPEN - || hpetp->hp_dev[i].hd_task) + if (hpetp->hp_dev[i].hd_flags & HPET_OPEN) continue; else { devp = &hpetp->hp_dev[i]; @@ -219,6 +276,8 @@ static int hpet_open(struct inode *inode, struct file *file) spin_unlock_irq(&hpet_lock); unlock_kernel(); + hpet_timer_set_irq(devp); + return 0; } @@ -441,7 +500,11 @@ static int hpet_ioctl_ieon(struct hpet_dev *devp) devp->hd_irq = irq; t = devp->hd_ireqfreq; v = readq(&timer->hpet_config); - g = v | Tn_INT_ENB_CNF_MASK; + + /* 64-bit comparators are not yet supported through the ioctls, + * so force this into 32-bit mode if it supports both modes + */ + g = v | Tn_32MODE_CNF_MASK | Tn_INT_ENB_CNF_MASK; if (devp->hd_flags & HPET_PERIODIC) { write_counter(t, &timer->hpet_compare); @@ -451,6 +514,12 @@ static int hpet_ioctl_ieon(struct hpet_dev *devp) v |= Tn_VAL_SET_CNF_MASK; writeq(v, &timer->hpet_config); local_irq_save(flags); + + /* NOTE: what we modify here is a hidden accumulator + * register supported by periodic-capable comparators. + * We never want to modify the (single) counter; that + * would affect all the comparators. + */ m = read_counter(&hpet->hpet_mc); write_counter(t + m + hpetp->hp_delta, &timer->hpet_compare); } else { @@ -604,57 +673,6 @@ static int hpet_is_known(struct hpet_data *hdp) return 0; } -static inline int hpet_tpcheck(struct hpet_task *tp) -{ - struct hpet_dev *devp; - struct hpets *hpetp; - - devp = tp->ht_opaque; - - if (!devp) - return -ENXIO; - - for (hpetp = hpets; hpetp; hpetp = hpetp->hp_next) - if (devp >= hpetp->hp_dev - && devp < (hpetp->hp_dev + hpetp->hp_ntimer) - && devp->hd_hpet == hpetp->hp_hpet) - return 0; - - return -ENXIO; -} - -#if 0 -int hpet_unregister(struct hpet_task *tp) -{ - struct hpet_dev *devp; - struct hpet_timer __iomem *timer; - int err; - - if ((err = hpet_tpcheck(tp))) - return err; - - spin_lock_irq(&hpet_task_lock); - spin_lock(&hpet_lock); - - devp = tp->ht_opaque; - if (devp->hd_task != tp) { - spin_unlock(&hpet_lock); - spin_unlock_irq(&hpet_task_lock); - return -ENXIO; - } - - timer = devp->hd_timer; - writeq((readq(&timer->hpet_config) & ~Tn_INT_ENB_CNF_MASK), - &timer->hpet_config); - devp->hd_flags &= ~(HPET_IE | HPET_PERIODIC); - devp->hd_task = NULL; - spin_unlock(&hpet_lock); - spin_unlock_irq(&hpet_task_lock); - - return 0; -} -#endif /* 0 */ - static ctl_table hpet_table[] = { { .ctl_name = CTL_UNNUMBERED, @@ -746,6 +764,7 @@ int hpet_alloc(struct hpet_data *hdp) static struct hpets *last = NULL; unsigned long period; unsigned long long temp; + u32 remainder; /* * hpet_alloc can be called by platform dependent code. @@ -809,9 +828,13 @@ int hpet_alloc(struct hpet_data *hdp) printk("%s %d", i > 0 ? "," : "", hdp->hd_irq[i]); printk("\n"); - printk(KERN_INFO "hpet%u: %u %d-bit timers, %Lu Hz\n", - hpetp->hp_which, hpetp->hp_ntimer, - cap & HPET_COUNTER_SIZE_MASK ? 64 : 32, hpetp->hp_tick_freq); + temp = hpetp->hp_tick_freq; + remainder = do_div(temp, 1000000); + printk(KERN_INFO + "hpet%u: %u comparators, %d-bit %u.%06u MHz counter\n", + hpetp->hp_which, hpetp->hp_ntimer, + cap & HPET_COUNTER_SIZE_MASK ? 64 : 32, + (unsigned) temp, remainder); mcfg = readq(&hpet->hpet_config); if ((mcfg & HPET_ENABLE_CNF_MASK) == 0) { @@ -874,8 +897,6 @@ static acpi_status hpet_resources(struct acpi_resource *res, void *data) hdp->hd_address = ioremap(addr.minimum, addr.address_length); if (hpet_is_known(hdp)) { - printk(KERN_DEBUG "%s: 0x%lx is busy\n", - __func__, hdp->hd_phys_address); iounmap(hdp->hd_address); return AE_ALREADY_EXISTS; } @@ -891,8 +912,6 @@ static acpi_status hpet_resources(struct acpi_resource *res, void *data) HPET_RANGE_SIZE); if (hpet_is_known(hdp)) { - printk(KERN_DEBUG "%s: 0x%lx is busy\n", - __func__, hdp->hd_phys_address); iounmap(hdp->hd_address); return AE_ALREADY_EXISTS; } diff --git a/drivers/char/hvc_console.c b/drivers/char/hvc_console.c index 02aac104842..ec7aded0a2d 100644 --- a/drivers/char/hvc_console.c +++ b/drivers/char/hvc_console.c @@ -322,11 +322,10 @@ static int hvc_open(struct tty_struct *tty, struct file * filp) hp->tty = tty; - if (hp->ops->notifier_add) - rc = hp->ops->notifier_add(hp, hp->data); - spin_unlock_irqrestore(&hp->lock, flags); + if (hp->ops->notifier_add) + rc = hp->ops->notifier_add(hp, hp->data); /* * If the notifier fails we return an error. The tty layer @@ -820,11 +819,11 @@ static int hvc_init(void) hvc_driver = drv; return 0; -put_tty: - put_tty_driver(hvc_driver); stop_thread: kthread_stop(hvc_task); hvc_task = NULL; +put_tty: + put_tty_driver(drv); out: return err; } diff --git a/drivers/char/hvc_console.h b/drivers/char/hvc_console.h index d9ce1091562..9790201718a 100644 --- a/drivers/char/hvc_console.h +++ b/drivers/char/hvc_console.h @@ -6,7 +6,7 @@ * Ryan S. Arnold <rsa@us.ibm.com> * * hvc_console header information: - * moved here from include/asm-powerpc/hvconsole.h + * moved here from arch/powerpc/include/asm/hvconsole.h * and drivers/char/hvc_console.c * * This program is free software; you can redistribute it and/or modify diff --git a/drivers/char/hvc_xen.c b/drivers/char/hvc_xen.c index 6b70aa66a58..538ceea5e7d 100644 --- a/drivers/char/hvc_xen.c +++ b/drivers/char/hvc_xen.c @@ -108,8 +108,8 @@ static int __init xen_init(void) { struct hvc_struct *hp; - if (!is_running_on_xen() || - is_initial_xendomain() || + if (!xen_pv_domain() || + xen_initial_domain() || !xen_start_info->console.domU.evtchn) return -ENODEV; @@ -142,7 +142,7 @@ static void __exit xen_fini(void) static int xen_cons_init(void) { - if (!is_running_on_xen()) + if (!xen_pv_domain()) return 0; hvc_instantiate(HVC_COOKIE, 0, &hvc_ops); diff --git a/drivers/char/hvcs.c b/drivers/char/hvcs.c index 786d518e947..473d9b14439 100644 --- a/drivers/char/hvcs.c +++ b/drivers/char/hvcs.c @@ -114,7 +114,7 @@ * the hvcs_final_close() function in order to get it out of the spinlock. * Rearranged hvcs_close(). Cleaned up some printks and did some housekeeping * on the changelog. Removed local CLC_LENGTH and used HVCS_CLC_LENGTH from - * include/asm-powerpc/hvcserver.h + * arch/powerepc/include/asm/hvcserver.h * * 1.3.2 -> 1.3.3 Replaced yield() in hvcs_close() with tty_wait_until_sent() to * prevent possible lockup with realtime scheduling as similarily pointed out by diff --git a/drivers/char/hw_random/ixp4xx-rng.c b/drivers/char/hw_random/ixp4xx-rng.c index bab43ca32ac..263567f5f39 100644 --- a/drivers/char/hw_random/ixp4xx-rng.c +++ b/drivers/char/hw_random/ixp4xx-rng.c @@ -23,7 +23,7 @@ #include <linux/hw_random.h> #include <asm/io.h> -#include <asm/hardware.h> +#include <mach/hardware.h> static int ixp4xx_rng_data_read(struct hwrng *rng, u32 *buffer) diff --git a/drivers/char/hw_random/n2-drv.c b/drivers/char/hw_random/n2-drv.c index 5220f541df2..8859aeac2d2 100644 --- a/drivers/char/hw_random/n2-drv.c +++ b/drivers/char/hw_random/n2-drv.c @@ -736,7 +736,7 @@ static int __devexit n2rng_remove(struct of_device *op) return 0; } -static struct of_device_id n2rng_match[] = { +static const struct of_device_id n2rng_match[] = { { .name = "random-number-generator", .compatible = "SUNW,n2-rng", diff --git a/drivers/char/hw_random/via-rng.c b/drivers/char/hw_random/via-rng.c index f7feae4ebb5..128202e18fc 100644 --- a/drivers/char/hw_random/via-rng.c +++ b/drivers/char/hw_random/via-rng.c @@ -31,6 +31,7 @@ #include <asm/io.h> #include <asm/msr.h> #include <asm/cpufeature.h> +#include <asm/i387.h> #define PFX KBUILD_MODNAME ": " @@ -67,16 +68,23 @@ enum { * Another possible performance boost may come from simply buffering * until we have 4 bytes, thus returning a u32 at a time, * instead of the current u8-at-a-time. + * + * Padlock instructions can generate a spurious DNA fault, so + * we have to call them in the context of irq_ts_save/restore() */ static inline u32 xstore(u32 *addr, u32 edx_in) { u32 eax_out; + int ts_state; + + ts_state = irq_ts_save(); asm(".byte 0x0F,0xA7,0xC0 /* xstore %%edi (addr=%0) */" :"=m"(*addr), "=a"(eax_out) :"D"(addr), "d"(edx_in)); + irq_ts_restore(ts_state); return eax_out; } diff --git a/drivers/char/ip2/Makefile b/drivers/char/ip2/Makefile index 939618f62fe..bc397d92b49 100644 --- a/drivers/char/ip2/Makefile +++ b/drivers/char/ip2/Makefile @@ -4,5 +4,5 @@ obj-$(CONFIG_COMPUTONE) += ip2.o -ip2-objs := ip2base.o ip2main.o +ip2-objs := ip2main.o diff --git a/drivers/char/ip2/i2ellis.c b/drivers/char/ip2/i2ellis.c index 3601017f58c..29db44de399 100644 --- a/drivers/char/ip2/i2ellis.c +++ b/drivers/char/ip2/i2ellis.c @@ -69,38 +69,6 @@ static DEFINE_RWLOCK(Dl_spinlock); //======================================================= //****************************************************************************** -// Function: iiEllisInit() -// Parameters: None -// -// Returns: Nothing -// -// Description: -// -// This routine performs any required initialization of the iiEllis subsystem. -// -//****************************************************************************** -static void -iiEllisInit(void) -{ -} - -//****************************************************************************** -// Function: iiEllisCleanup() -// Parameters: None -// -// Returns: Nothing -// -// Description: -// -// This routine performs any required cleanup of the iiEllis subsystem. -// -//****************************************************************************** -static void -iiEllisCleanup(void) -{ -} - -//****************************************************************************** // Function: iiSetAddress(pB, address, delay) // Parameters: pB - pointer to the board structure // address - the purported I/O address of the board diff --git a/drivers/char/ip2/i2ellis.h b/drivers/char/ip2/i2ellis.h index c88a64e527a..fb6df245601 100644 --- a/drivers/char/ip2/i2ellis.h +++ b/drivers/char/ip2/i2ellis.h @@ -511,7 +511,6 @@ typedef void (*delayFunc_t)(unsigned int); // // Initialization of a board & structure is in four (five!) parts: // -// 0) iiEllisInit() - Initialize iiEllis subsystem. // 1) iiSetAddress() - Define the board address & delay function for a board. // 2) iiReset() - Reset the board (provided it exists) // -- Note you may do this to several boards -- @@ -523,7 +522,6 @@ typedef void (*delayFunc_t)(unsigned int); // loadware. To change loadware, you must begin again with step 2, resetting // the board again (step 1 not needed). -static void iiEllisInit(void); static int iiSetAddress(i2eBordStrPtr, int, delayFunc_t ); static int iiReset(i2eBordStrPtr); static int iiResetDelay(i2eBordStrPtr); diff --git a/drivers/char/ip2/ip2base.c b/drivers/char/ip2/ip2base.c deleted file mode 100644 index 8155e247c04..00000000000 --- a/drivers/char/ip2/ip2base.c +++ /dev/null @@ -1,108 +0,0 @@ -// ip2.c -// This is a dummy module to make the firmware available when needed -// and allows it to be unloaded when not. Rumor is the __initdata -// macro doesn't always works on all platforms so we use this kludge. -// If not compiled as a module it just makes fip_firm avaliable then -// __initdata should work as advertized -// - -#include <linux/module.h> -#include <linux/init.h> -#include <linux/wait.h> - -#ifndef __init -#define __init -#endif -#ifndef __initfunc -#define __initfunc(a) a -#endif -#ifndef __initdata -#define __initdata -#endif - -#include "ip2types.h" - -int -ip2_loadmain(int *, int *); // ref into ip2main.c - -/* Note: Add compiled in defaults to these arrays, not to the structure - in ip2.h any longer. That structure WILL get overridden - by these values, or command line values, or insmod values!!! =mhw= -*/ -static int io[IP2_MAX_BOARDS]= { 0, 0, 0, 0 }; -static int irq[IP2_MAX_BOARDS] = { -1, -1, -1, -1 }; - -static int poll_only = 0; - -MODULE_AUTHOR("Doug McNash"); -MODULE_DESCRIPTION("Computone IntelliPort Plus Driver"); -module_param_array(irq, int, NULL, 0); -MODULE_PARM_DESC(irq,"Interrupts for IntelliPort Cards"); -module_param_array(io, int, NULL, 0); -MODULE_PARM_DESC(io,"I/O ports for IntelliPort Cards"); -module_param(poll_only, bool, 0); -MODULE_PARM_DESC(poll_only,"Do not use card interrupts"); - - -static int __init ip2_init(void) -{ - if( poll_only ) { - /* Hard lock the interrupts to zero */ - irq[0] = irq[1] = irq[2] = irq[3] = 0; - } - - return ip2_loadmain(io, irq); -} -module_init(ip2_init); - -MODULE_LICENSE("GPL"); - -#ifndef MODULE -/****************************************************************************** - * ip2_setup: - * str: kernel command line string - * - * Can't autoprobe the boards so user must specify configuration on - * kernel command line. Sane people build it modular but the others - * come here. - * - * Alternating pairs of io,irq for up to 4 boards. - * ip2=io0,irq0,io1,irq1,io2,irq2,io3,irq3 - * - * io=0 => No board - * io=1 => PCI - * io=2 => EISA - * else => ISA I/O address - * - * irq=0 or invalid for ISA will revert to polling mode - * - * Any value = -1, do not overwrite compiled in value. - * - ******************************************************************************/ -static int __init ip2_setup(char *str) -{ - int ints[10]; /* 4 boards, 2 parameters + 2 */ - int i, j; - - str = get_options (str, ARRAY_SIZE(ints), ints); - - for( i = 0, j = 1; i < 4; i++ ) { - if( j > ints[0] ) { - break; - } - if( ints[j] >= 0 ) { - io[i] = ints[j]; - } - j++; - if( j > ints[0] ) { - break; - } - if( ints[j] >= 0 ) { - irq[i] = ints[j]; - } - j++; - } - return 1; -} -__setup("ip2=", ip2_setup); -#endif /* !MODULE */ diff --git a/drivers/char/ip2/ip2main.c b/drivers/char/ip2/ip2main.c index 689f9dcd3b8..6774572d375 100644 --- a/drivers/char/ip2/ip2main.c +++ b/drivers/char/ip2/ip2main.c @@ -150,15 +150,12 @@ static int ip2_read_proc(char *, char **, off_t, int, int *, void * ); /*************/ /* String constants to identify ourselves */ -static char *pcName = "Computone IntelliPort Plus multiport driver"; -static char *pcVersion = "1.2.14"; +static const char pcName[] = "Computone IntelliPort Plus multiport driver"; +static const char pcVersion[] = "1.2.14"; /* String constants for port names */ -static char *pcDriver_name = "ip2"; -static char *pcIpl = "ip2ipl"; - -// cheezy kludge or genius - you decide? -int ip2_loadmain(int *, int *); +static const char pcDriver_name[] = "ip2"; +static const char pcIpl[] = "ip2ipl"; /***********************/ /* Function Prototypes */ @@ -240,8 +237,8 @@ static const struct file_operations ip2_ipl = { .open = ip2_ipl_open, }; -static unsigned long irq_counter = 0; -static unsigned long bh_counter = 0; +static unsigned long irq_counter; +static unsigned long bh_counter; // Use immediate queue to service interrupts #define USE_IQI @@ -252,7 +249,6 @@ static unsigned long bh_counter = 0; */ #define POLL_TIMEOUT (jiffies + 1) static DEFINE_TIMER(PollTimer, ip2_poll, 0, 0); -static char TimerOn; #ifdef IP2DEBUG_TRACE /* Trace (debug) buffer data */ @@ -268,8 +264,8 @@ static int tracewrap; /**********/ #if defined(MODULE) && defined(IP2DEBUG_OPEN) -#define DBG_CNT(s) printk(KERN_DEBUG "(%s): [%x] refc=%d, ttyc=%d, modc=%x -> %s\n", \ - tty->name,(pCh->flags),ip2_tty_driver->refcount, \ +#define DBG_CNT(s) printk(KERN_DEBUG "(%s): [%x] ttyc=%d, modc=%x -> %s\n", \ + tty->name,(pCh->flags), \ tty->count,/*GET_USE_COUNT(module)*/0,s) #else #define DBG_CNT(s) @@ -287,8 +283,9 @@ static int tracewrap; MODULE_AUTHOR("Doug McNash"); MODULE_DESCRIPTION("Computone IntelliPort Plus Driver"); +MODULE_LICENSE("GPL"); -static int poll_only = 0; +static int poll_only; static int Eisa_irq; static int Eisa_slot; @@ -297,34 +294,46 @@ static int iindx; static char rirqs[IP2_MAX_BOARDS]; static int Valid_Irqs[] = { 3, 4, 5, 7, 10, 11, 12, 15, 0}; +/* Note: Add compiled in defaults to these arrays, not to the structure + in ip2.h any longer. That structure WILL get overridden + by these values, or command line values, or insmod values!!! =mhw= +*/ +static int io[IP2_MAX_BOARDS]; +static int irq[IP2_MAX_BOARDS] = { -1, -1, -1, -1 }; + +MODULE_AUTHOR("Doug McNash"); +MODULE_DESCRIPTION("Computone IntelliPort Plus Driver"); +module_param_array(irq, int, NULL, 0); +MODULE_PARM_DESC(irq, "Interrupts for IntelliPort Cards"); +module_param_array(io, int, NULL, 0); +MODULE_PARM_DESC(io, "I/O ports for IntelliPort Cards"); +module_param(poll_only, bool, 0); +MODULE_PARM_DESC(poll_only, "Do not use card interrupts"); + /* for sysfs class support */ static struct class *ip2_class; -// Some functions to keep track of what irq's we have +/* Some functions to keep track of what irqs we have */ -static int -is_valid_irq(int irq) +static int __init is_valid_irq(int irq) { int *i = Valid_Irqs; - while ((*i != 0) && (*i != irq)) { + while (*i != 0 && *i != irq) i++; - } - return (*i); + + return *i; } -static void -mark_requested_irq( char irq ) +static void __init mark_requested_irq(char irq) { rirqs[iindx++] = irq; } -#ifdef MODULE -static int -clear_requested_irq( char irq ) +static int __exit clear_requested_irq(char irq) { int i; - for ( i = 0; i < IP2_MAX_BOARDS; ++i ) { + for (i = 0; i < IP2_MAX_BOARDS; ++i) { if (rirqs[i] == irq) { rirqs[i] = 0; return 1; @@ -332,17 +341,15 @@ clear_requested_irq( char irq ) } return 0; } -#endif -static int -have_requested_irq( char irq ) +static int have_requested_irq(char irq) { - // array init to zeros so 0 irq will not be requested as a side effect + /* array init to zeros so 0 irq will not be requested as a side + * effect */ int i; - for ( i = 0; i < IP2_MAX_BOARDS; ++i ) { + for (i = 0; i < IP2_MAX_BOARDS; ++i) if (rirqs[i] == irq) return 1; - } return 0; } @@ -361,53 +368,45 @@ have_requested_irq( char irq ) /* handle subsequent installations of the driver. All memory allocated by the */ /* driver should be returned since it may be unloaded from memory. */ /******************************************************************************/ -#ifdef MODULE -void __exit -ip2_cleanup_module(void) +static void __exit ip2_cleanup_module(void) { int err; int i; -#ifdef IP2DEBUG_INIT - printk (KERN_DEBUG "Unloading %s: version %s\n", pcName, pcVersion ); -#endif - /* Stop poll timer if we had one. */ - if ( TimerOn ) { - del_timer ( &PollTimer ); - TimerOn = 0; - } + del_timer_sync(&PollTimer); /* Reset the boards we have. */ - for( i = 0; i < IP2_MAX_BOARDS; ++i ) { - if ( i2BoardPtrTable[i] ) { - iiReset( i2BoardPtrTable[i] ); - } - } + for (i = 0; i < IP2_MAX_BOARDS; i++) + if (i2BoardPtrTable[i]) + iiReset(i2BoardPtrTable[i]); /* The following is done at most once, if any boards were installed. */ - for ( i = 0; i < IP2_MAX_BOARDS; ++i ) { - if ( i2BoardPtrTable[i] ) { - iiResetDelay( i2BoardPtrTable[i] ); + for (i = 0; i < IP2_MAX_BOARDS; i++) { + if (i2BoardPtrTable[i]) { + iiResetDelay(i2BoardPtrTable[i]); /* free io addresses and Tibet */ - release_region( ip2config.addr[i], 8 ); + release_region(ip2config.addr[i], 8); device_destroy(ip2_class, MKDEV(IP2_IPL_MAJOR, 4 * i)); - device_destroy(ip2_class, MKDEV(IP2_IPL_MAJOR, 4 * i + 1)); + device_destroy(ip2_class, MKDEV(IP2_IPL_MAJOR, + 4 * i + 1)); } /* Disable and remove interrupt handler. */ - if ( (ip2config.irq[i] > 0) && have_requested_irq(ip2config.irq[i]) ) { - free_irq ( ip2config.irq[i], (void *)&pcName); - clear_requested_irq( ip2config.irq[i]); + if (ip2config.irq[i] > 0 && + have_requested_irq(ip2config.irq[i])) { + free_irq(ip2config.irq[i], (void *)&pcName); + clear_requested_irq(ip2config.irq[i]); } } class_destroy(ip2_class); - if ( ( err = tty_unregister_driver ( ip2_tty_driver ) ) ) { - printk(KERN_ERR "IP2: failed to unregister tty driver (%d)\n", err); - } + err = tty_unregister_driver(ip2_tty_driver); + if (err) + printk(KERN_ERR "IP2: failed to unregister tty driver (%d)\n", + err); put_tty_driver(ip2_tty_driver); unregister_chrdev(IP2_IPL_MAJOR, pcIpl); remove_proc_entry("ip2mem", NULL); - // free memory + /* free memory */ for (i = 0; i < IP2_MAX_BOARDS; i++) { void *pB; #ifdef CONFIG_PCI @@ -417,24 +416,18 @@ ip2_cleanup_module(void) ip2config.pci_dev[i] = NULL; } #endif - if ((pB = i2BoardPtrTable[i]) != 0 ) { - kfree ( pB ); + pB = i2BoardPtrTable[i]; + if (pB != NULL) { + kfree(pB); i2BoardPtrTable[i] = NULL; } - if ((DevTableMem[i]) != NULL ) { - kfree ( DevTableMem[i] ); + if (DevTableMem[i] != NULL) { + kfree(DevTableMem[i]); DevTableMem[i] = NULL; } } - - /* Cleanup the iiEllis subsystem. */ - iiEllisCleanup(); -#ifdef IP2DEBUG_INIT - printk (KERN_DEBUG "IP2 Unloaded\n" ); -#endif } module_exit(ip2_cleanup_module); -#endif /* MODULE */ static const struct tty_operations ip2_ops = { .open = ip2_open, @@ -494,139 +487,168 @@ static const struct firmware *ip2_request_firmware(void) return fw; } -int -ip2_loadmain(int *iop, int *irqp) +#ifndef MODULE +/****************************************************************************** + * ip2_setup: + * str: kernel command line string + * + * Can't autoprobe the boards so user must specify configuration on + * kernel command line. Sane people build it modular but the others + * come here. + * + * Alternating pairs of io,irq for up to 4 boards. + * ip2=io0,irq0,io1,irq1,io2,irq2,io3,irq3 + * + * io=0 => No board + * io=1 => PCI + * io=2 => EISA + * else => ISA I/O address + * + * irq=0 or invalid for ISA will revert to polling mode + * + * Any value = -1, do not overwrite compiled in value. + * + ******************************************************************************/ +static int __init ip2_setup(char *str) +{ + int j, ints[10]; /* 4 boards, 2 parameters + 2 */ + unsigned int i; + + str = get_options(str, ARRAY_SIZE(ints), ints); + + for (i = 0, j = 1; i < 4; i++) { + if (j > ints[0]) + break; + if (ints[j] >= 0) + io[i] = ints[j]; + j++; + if (j > ints[0]) + break; + if (ints[j] >= 0) + irq[i] = ints[j]; + j++; + } + return 1; +} +__setup("ip2=", ip2_setup); +#endif /* !MODULE */ + +static int __init ip2_loadmain(void) { int i, j, box; int err = 0; - static int loaded; i2eBordStrPtr pB = NULL; int rc = -1; - static struct pci_dev *pci_dev_i = NULL; + struct pci_dev *pdev = NULL; const struct firmware *fw = NULL; - ip2trace (ITRC_NO_PORT, ITRC_INIT, ITRC_ENTER, 0 ); + if (poll_only) { + /* Hard lock the interrupts to zero */ + irq[0] = irq[1] = irq[2] = irq[3] = poll_only = 0; + } + + ip2trace(ITRC_NO_PORT, ITRC_INIT, ITRC_ENTER, 0); /* process command line arguments to modprobe or insmod i.e. iop & irqp */ /* irqp and iop should ALWAYS be specified now... But we check them individually just to be sure, anyways... */ - for ( i = 0; i < IP2_MAX_BOARDS; ++i ) { - if (iop) { - ip2config.addr[i] = iop[i]; - if (irqp) { - if( irqp[i] >= 0 ) { - ip2config.irq[i] = irqp[i]; - } else { - ip2config.irq[i] = 0; - } - // This is a little bit of a hack. If poll_only=1 on command - // line back in ip2.c OR all IRQs on all specified boards are - // explicitly set to 0, then drop to poll only mode and override - // PCI or EISA interrupts. This superceeds the old hack of - // triggering if all interrupts were zero (like da default). - // Still a hack but less prone to random acts of terrorism. - // - // What we really should do, now that the IRQ default is set - // to -1, is to use 0 as a hard coded, do not probe. - // - // /\/\|=mhw=|\/\/ - poll_only |= irqp[i]; - } - } + for (i = 0; i < IP2_MAX_BOARDS; ++i) { + ip2config.addr[i] = io[i]; + if (irq[i] >= 0) + ip2config.irq[i] = irq[i]; + else + ip2config.irq[i] = 0; + /* This is a little bit of a hack. If poll_only=1 on command + line back in ip2.c OR all IRQs on all specified boards are + explicitly set to 0, then drop to poll only mode and override + PCI or EISA interrupts. This superceeds the old hack of + triggering if all interrupts were zero (like da default). + Still a hack but less prone to random acts of terrorism. + + What we really should do, now that the IRQ default is set + to -1, is to use 0 as a hard coded, do not probe. + + /\/\|=mhw=|\/\/ + */ + poll_only |= irq[i]; } poll_only = !poll_only; /* Announce our presence */ - printk( KERN_INFO "%s version %s\n", pcName, pcVersion ); - - // ip2 can be unloaded and reloaded for no good reason - // we can't let that happen here or bad things happen - // second load hoses board but not system - fixme later - if (loaded) { - printk( KERN_INFO "Still loaded\n" ); - return 0; - } - loaded++; + printk(KERN_INFO "%s version %s\n", pcName, pcVersion); ip2_tty_driver = alloc_tty_driver(IP2_MAX_PORTS); if (!ip2_tty_driver) return -ENOMEM; - /* Initialise the iiEllis subsystem. */ - iiEllisInit(); - - /* Initialize arrays. */ - memset( i2BoardPtrTable, 0, sizeof i2BoardPtrTable ); - memset( DevTable, 0, sizeof DevTable ); - /* Initialise all the boards we can find (up to the maximum). */ - for ( i = 0; i < IP2_MAX_BOARDS; ++i ) { - switch ( ip2config.addr[i] ) { + for (i = 0; i < IP2_MAX_BOARDS; ++i) { + switch (ip2config.addr[i]) { case 0: /* skip this slot even if card is present */ break; default: /* ISA */ /* ISA address must be specified */ - if ( (ip2config.addr[i] < 0x100) || (ip2config.addr[i] > 0x3f8) ) { - printk ( KERN_ERR "IP2: Bad ISA board %d address %x\n", - i, ip2config.addr[i] ); + if (ip2config.addr[i] < 0x100 || + ip2config.addr[i] > 0x3f8) { + printk(KERN_ERR "IP2: Bad ISA board %d " + "address %x\n", i, + ip2config.addr[i]); ip2config.addr[i] = 0; - } else { - ip2config.type[i] = ISA; - - /* Check for valid irq argument, set for polling if invalid */ - if (ip2config.irq[i] && !is_valid_irq(ip2config.irq[i])) { - printk(KERN_ERR "IP2: Bad IRQ(%d) specified\n",ip2config.irq[i]); - ip2config.irq[i] = 0;// 0 is polling and is valid in that sense - } + break; + } + ip2config.type[i] = ISA; + + /* Check for valid irq argument, set for polling if + * invalid */ + if (ip2config.irq[i] && + !is_valid_irq(ip2config.irq[i])) { + printk(KERN_ERR "IP2: Bad IRQ(%d) specified\n", + ip2config.irq[i]); + /* 0 is polling and is valid in that sense */ + ip2config.irq[i] = 0; } break; case PCI: #ifdef CONFIG_PCI - { - int status; + { + u32 addr; + int status; - pci_dev_i = pci_get_device(PCI_VENDOR_ID_COMPUTONE, - PCI_DEVICE_ID_COMPUTONE_IP2EX, pci_dev_i); - if (pci_dev_i != NULL) { - unsigned int addr; - - if (pci_enable_device(pci_dev_i)) { - printk( KERN_ERR "IP2: can't enable PCI device at %s\n", - pci_name(pci_dev_i)); - break; - } - ip2config.type[i] = PCI; - ip2config.pci_dev[i] = pci_dev_get(pci_dev_i); - status = - pci_read_config_dword(pci_dev_i, PCI_BASE_ADDRESS_1, &addr); - if ( addr & 1 ) { - ip2config.addr[i]=(USHORT)(addr&0xfffe); - } else { - printk( KERN_ERR "IP2: PCI I/O address error\n"); - } + pdev = pci_get_device(PCI_VENDOR_ID_COMPUTONE, + PCI_DEVICE_ID_COMPUTONE_IP2EX, pdev); + if (pdev == NULL) { + ip2config.addr[i] = 0; + printk(KERN_ERR "IP2: PCI board %d not " + "found\n", i); + break; + } -// If the PCI BIOS assigned it, lets try and use it. If we -// can't acquire it or it screws up, deal with it then. - -// if (!is_valid_irq(pci_irq)) { -// printk( KERN_ERR "IP2: Bad PCI BIOS IRQ(%d)\n",pci_irq); -// pci_irq = 0; -// } - ip2config.irq[i] = pci_dev_i->irq; - } else { // ann error - ip2config.addr[i] = 0; - printk(KERN_ERR "IP2: PCI board %d not found\n", i); - } + if (pci_enable_device(pdev)) { + dev_err(&pdev->dev, "can't enable device\n"); + break; } + ip2config.type[i] = PCI; + ip2config.pci_dev[i] = pci_dev_get(pdev); + status = pci_read_config_dword(pdev, PCI_BASE_ADDRESS_1, + &addr); + if (addr & 1) + ip2config.addr[i] = (USHORT)(addr & 0xfffe); + else + dev_err(&pdev->dev, "I/O address error\n"); + + ip2config.irq[i] = pdev->irq; + } #else - printk( KERN_ERR "IP2: PCI card specified but PCI support not\n"); - printk( KERN_ERR "IP2: configured in this kernel.\n"); - printk( KERN_ERR "IP2: Recompile kernel with CONFIG_PCI defined!\n"); + printk(KERN_ERR "IP2: PCI card specified but PCI " + "support not enabled.\n"); + printk(KERN_ERR "IP2: Recompile kernel with CONFIG_PCI " + "defined!\n"); #endif /* CONFIG_PCI */ break; case EISA: - if ( (ip2config.addr[i] = find_eisa_board( Eisa_slot + 1 )) != 0) { + ip2config.addr[i] = find_eisa_board(Eisa_slot + 1); + if (ip2config.addr[i] != 0) { /* Eisa_irq set as side effect, boo */ ip2config.type[i] = EISA; } @@ -634,31 +656,32 @@ ip2_loadmain(int *iop, int *irqp) break; } /* switch */ } /* for */ - if (pci_dev_i) - pci_dev_put(pci_dev_i); + pci_dev_put(pdev); - for ( i = 0; i < IP2_MAX_BOARDS; ++i ) { - if ( ip2config.addr[i] ) { + for (i = 0; i < IP2_MAX_BOARDS; ++i) { + if (ip2config.addr[i]) { pB = kzalloc(sizeof(i2eBordStr), GFP_KERNEL); if (pB) { i2BoardPtrTable[i] = pB; - iiSetAddress( pB, ip2config.addr[i], ii2DelayTimer ); - iiReset( pB ); - } else { - printk(KERN_ERR "IP2: board memory allocation error\n"); - } + iiSetAddress(pB, ip2config.addr[i], + ii2DelayTimer); + iiReset(pB); + } else + printk(KERN_ERR "IP2: board memory allocation " + "error\n"); } } - for ( i = 0; i < IP2_MAX_BOARDS; ++i ) { - if ( ( pB = i2BoardPtrTable[i] ) != NULL ) { - iiResetDelay( pB ); + for (i = 0; i < IP2_MAX_BOARDS; ++i) { + pB = i2BoardPtrTable[i]; + if (pB != NULL) { + iiResetDelay(pB); break; } } - for ( i = 0; i < IP2_MAX_BOARDS; ++i ) { + for (i = 0; i < IP2_MAX_BOARDS; ++i) { /* We don't want to request the firmware unless we have at least one board */ - if ( i2BoardPtrTable[i] != NULL ) { + if (i2BoardPtrTable[i] != NULL) { if (!fw) fw = ip2_request_firmware(); if (!fw) @@ -669,7 +692,7 @@ ip2_loadmain(int *iop, int *irqp) if (fw) release_firmware(fw); - ip2trace (ITRC_NO_PORT, ITRC_INIT, 2, 0 ); + ip2trace(ITRC_NO_PORT, ITRC_INIT, 2, 0); ip2_tty_driver->owner = THIS_MODULE; ip2_tty_driver->name = "ttyF"; @@ -680,20 +703,23 @@ ip2_loadmain(int *iop, int *irqp) ip2_tty_driver->subtype = SERIAL_TYPE_NORMAL; ip2_tty_driver->init_termios = tty_std_termios; ip2_tty_driver->init_termios.c_cflag = B9600|CS8|CREAD|HUPCL|CLOCAL; - ip2_tty_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV; + ip2_tty_driver->flags = TTY_DRIVER_REAL_RAW | + TTY_DRIVER_DYNAMIC_DEV; tty_set_operations(ip2_tty_driver, &ip2_ops); - ip2trace (ITRC_NO_PORT, ITRC_INIT, 3, 0 ); + ip2trace(ITRC_NO_PORT, ITRC_INIT, 3, 0); - /* Register the tty devices. */ - if ( ( err = tty_register_driver ( ip2_tty_driver ) ) ) { - printk(KERN_ERR "IP2: failed to register tty driver (%d)\n", err); + err = tty_register_driver(ip2_tty_driver); + if (err) { + printk(KERN_ERR "IP2: failed to register tty driver\n"); put_tty_driver(ip2_tty_driver); - return -EINVAL; - } else - /* Register the IPL driver. */ - if ( ( err = register_chrdev ( IP2_IPL_MAJOR, pcIpl, &ip2_ipl ) ) ) { - printk(KERN_ERR "IP2: failed to register IPL device (%d)\n", err ); + return err; /* leaking resources */ + } + + err = register_chrdev(IP2_IPL_MAJOR, pcIpl, &ip2_ipl); + if (err) { + printk(KERN_ERR "IP2: failed to register IPL device (%d)\n", + err); } else { /* create the sysfs class */ ip2_class = class_create(THIS_MODULE, "ip2"); @@ -705,84 +731,86 @@ ip2_loadmain(int *iop, int *irqp) /* Register the read_procmem thing */ if (!proc_create("ip2mem",0,NULL,&ip2mem_proc_fops)) { printk(KERN_ERR "IP2: failed to register read_procmem\n"); - } else { + return -EIO; /* leaking resources */ + } - ip2trace (ITRC_NO_PORT, ITRC_INIT, 4, 0 ); - /* Register the interrupt handler or poll handler, depending upon the - * specified interrupt. - */ + ip2trace(ITRC_NO_PORT, ITRC_INIT, 4, 0); + /* Register the interrupt handler or poll handler, depending upon the + * specified interrupt. + */ - for( i = 0; i < IP2_MAX_BOARDS; ++i ) { - if ( 0 == ip2config.addr[i] ) { - continue; - } + for (i = 0; i < IP2_MAX_BOARDS; ++i) { + if (ip2config.addr[i] == 0) + continue; - if ( NULL != ( pB = i2BoardPtrTable[i] ) ) { - device_create_drvdata(ip2_class, NULL, - MKDEV(IP2_IPL_MAJOR, 4 * i), - NULL, "ipl%d", i); - device_create_drvdata(ip2_class, NULL, - MKDEV(IP2_IPL_MAJOR, 4 * i + 1), - NULL, "stat%d", i); - - for ( box = 0; box < ABS_MAX_BOXES; ++box ) - { - for ( j = 0; j < ABS_BIGGEST_BOX; ++j ) - { - if ( pB->i2eChannelMap[box] & (1 << j) ) - { - tty_register_device(ip2_tty_driver, - j + ABS_BIGGEST_BOX * - (box+i*ABS_MAX_BOXES), NULL); - } - } - } - } + pB = i2BoardPtrTable[i]; + if (pB != NULL) { + device_create_drvdata(ip2_class, NULL, + MKDEV(IP2_IPL_MAJOR, 4 * i), + NULL, "ipl%d", i); + device_create_drvdata(ip2_class, NULL, + MKDEV(IP2_IPL_MAJOR, 4 * i + 1), + NULL, "stat%d", i); + + for (box = 0; box < ABS_MAX_BOXES; box++) + for (j = 0; j < ABS_BIGGEST_BOX; j++) + if (pB->i2eChannelMap[box] & (1 << j)) + tty_register_device( + ip2_tty_driver, + j + ABS_BIGGEST_BOX * + (box+i*ABS_MAX_BOXES), + NULL); + } - if (poll_only) { -// Poll only forces driver to only use polling and -// to ignore the probed PCI or EISA interrupts. - ip2config.irq[i] = CIR_POLL; - } - if ( ip2config.irq[i] == CIR_POLL ) { + if (poll_only) { + /* Poll only forces driver to only use polling and + to ignore the probed PCI or EISA interrupts. */ + ip2config.irq[i] = CIR_POLL; + } + if (ip2config.irq[i] == CIR_POLL) { retry: - if (!TimerOn) { - PollTimer.expires = POLL_TIMEOUT; - add_timer ( &PollTimer ); - TimerOn = 1; - printk( KERN_INFO "IP2: polling\n"); - } - } else { - if (have_requested_irq(ip2config.irq[i])) - continue; - rc = request_irq( ip2config.irq[i], ip2_interrupt, - IP2_SA_FLAGS | (ip2config.type[i] == PCI ? IRQF_SHARED : 0), - pcName, i2BoardPtrTable[i]); - if (rc) { - printk(KERN_ERR "IP2: an request_irq failed: error %d\n",rc); - ip2config.irq[i] = CIR_POLL; - printk( KERN_INFO "IP2: Polling %ld/sec.\n", - (POLL_TIMEOUT - jiffies)); - goto retry; - } - mark_requested_irq(ip2config.irq[i]); - /* Initialise the interrupt handler bottom half (aka slih). */ + if (!timer_pending(&PollTimer)) { + mod_timer(&PollTimer, POLL_TIMEOUT); + printk(KERN_INFO "IP2: polling\n"); } - } - for( i = 0; i < IP2_MAX_BOARDS; ++i ) { - if ( i2BoardPtrTable[i] ) { - set_irq( i, ip2config.irq[i] ); /* set and enable board interrupt */ + } else { + if (have_requested_irq(ip2config.irq[i])) + continue; + rc = request_irq(ip2config.irq[i], ip2_interrupt, + IP2_SA_FLAGS | + (ip2config.type[i] == PCI ? IRQF_SHARED : 0), + pcName, i2BoardPtrTable[i]); + if (rc) { + printk(KERN_ERR "IP2: request_irq failed: " + "error %d\n", rc); + ip2config.irq[i] = CIR_POLL; + printk(KERN_INFO "IP2: Polling %ld/sec.\n", + (POLL_TIMEOUT - jiffies)); + goto retry; } + mark_requested_irq(ip2config.irq[i]); + /* Initialise the interrupt handler bottom half + * (aka slih). */ } } - ip2trace (ITRC_NO_PORT, ITRC_INIT, ITRC_RETURN, 0 ); - goto out; + + for (i = 0; i < IP2_MAX_BOARDS; ++i) { + if (i2BoardPtrTable[i]) { + /* set and enable board interrupt */ + set_irq(i, ip2config.irq[i]); + } + } + + ip2trace(ITRC_NO_PORT, ITRC_INIT, ITRC_RETURN, 0); + + return 0; out_chrdev: unregister_chrdev(IP2_IPL_MAJOR, "ip2"); -out: + /* unregister and put tty here */ return err; } +module_init(ip2_loadmain); /******************************************************************************/ /* Function: ip2_init_board() */ @@ -1199,9 +1227,8 @@ ip2_polled_interrupt(void) { int i; i2eBordStrPtr pB; - const int irq = 0; - ip2trace (ITRC_NO_PORT, ITRC_INTR, 99, 1, irq ); + ip2trace(ITRC_NO_PORT, ITRC_INTR, 99, 1, 0); /* Service just the boards on the list using this irq */ for( i = 0; i < i2nBoards; ++i ) { @@ -1210,9 +1237,8 @@ ip2_polled_interrupt(void) // Only process those boards which match our IRQ. // IRQ = 0 for polled boards, we won't poll "IRQ" boards - if ( pB && (pB->i2eUsingIrq == irq) ) { + if (pB && pB->i2eUsingIrq == 0) ip2_irq_work(pB); - } } ++irq_counter; @@ -1250,16 +1276,12 @@ ip2_poll(unsigned long arg) { ip2trace (ITRC_NO_PORT, ITRC_INTR, 100, 0 ); - TimerOn = 0; // it's the truth but not checked in service - // Just polled boards, IRQ = 0 will hit all non-interrupt boards. // It will NOT poll boards handled by hard interrupts. // The issue of queued BH interrupts is handled in ip2_interrupt(). ip2_polled_interrupt(); - PollTimer.expires = POLL_TIMEOUT; - add_timer( &PollTimer ); - TimerOn = 1; + mod_timer(&PollTimer, POLL_TIMEOUT); ip2trace (ITRC_NO_PORT, ITRC_INTR, ITRC_RETURN, 0 ); } @@ -2871,7 +2893,7 @@ ip2_ipl_ioctl (struct file *pFile, UINT cmd, ULONG arg ) case 13: switch ( cmd ) { case 64: /* Driver - ip2stat */ - rc = put_user(ip2_tty_driver->refcount, pIndex++ ); + rc = put_user(-1, pIndex++ ); rc = put_user(irq_counter, pIndex++ ); rc = put_user(bh_counter, pIndex++ ); break; diff --git a/drivers/char/ipmi/ipmi_si_intf.c b/drivers/char/ipmi/ipmi_si_intf.c index 192688344ed..8e8afb6141f 100644 --- a/drivers/char/ipmi/ipmi_si_intf.c +++ b/drivers/char/ipmi/ipmi_si_intf.c @@ -66,8 +66,8 @@ #include <linux/ctype.h> #ifdef CONFIG_PPC_OF -#include <asm/of_device.h> -#include <asm/of_platform.h> +#include <linux/of_device.h> +#include <linux/of_platform.h> #endif #define PFX "ipmi_si: " @@ -2695,15 +2695,13 @@ static __devinit void default_find_bmc(void) for (i = 0; ; i++) { if (!ipmi_defaults[i].port) break; - - info = kzalloc(sizeof(*info), GFP_KERNEL); - if (!info) - return; - #ifdef CONFIG_PPC_MERGE if (check_legacy_ioport(ipmi_defaults[i].port)) continue; #endif + info = kzalloc(sizeof(*info), GFP_KERNEL); + if (!info) + return; info->addr_source = NULL; diff --git a/drivers/char/isicom.c b/drivers/char/isicom.c index 8f7cc190b62..7d30ee1d3fc 100644 --- a/drivers/char/isicom.c +++ b/drivers/char/isicom.c @@ -421,17 +421,16 @@ static void isicom_tx(unsigned long _data) if (retries >= 100) goto unlock; + tty = tty_port_tty_get(&port->port); + if (tty == NULL) + goto put_unlock; + for (; count > 0; count--, port++) { /* port not active or tx disabled to force flow control */ if (!(port->port.flags & ASYNC_INITIALIZED) || !(port->status & ISI_TXOK)) continue; - tty = port->port.tty; - - if (tty == NULL) - continue; - txcount = min_t(short, TX_SIZE, port->xmit_cnt); if (txcount <= 0 || tty->stopped || tty->hw_stopped) continue; @@ -489,6 +488,8 @@ static void isicom_tx(unsigned long _data) tty_wakeup(tty); } +put_unlock: + tty_kref_put(tty); unlock: spin_unlock_irqrestore(&isi_card[card].card_lock, flags); /* schedule another tx for hopefully in about 10ms */ @@ -547,7 +548,7 @@ static irqreturn_t isicom_interrupt(int irq, void *dev_id) return IRQ_HANDLED; } - tty = port->port.tty; + tty = tty_port_tty_get(&port->port); if (tty == NULL) { word_count = byte_count >> 1; while (byte_count > 1) { @@ -588,7 +589,7 @@ static irqreturn_t isicom_interrupt(int irq, void *dev_id) } if (port->port.flags & ASYNC_CTS_FLOW) { - if (port->port.tty->hw_stopped) { + if (tty->hw_stopped) { if (header & ISI_CTS) { port->port.tty->hw_stopped = 0; /* start tx ing */ @@ -597,7 +598,7 @@ static irqreturn_t isicom_interrupt(int irq, void *dev_id) tty_wakeup(tty); } } else if (!(header & ISI_CTS)) { - port->port.tty->hw_stopped = 1; + tty->hw_stopped = 1; /* stop tx ing */ port->status &= ~(ISI_TXOK | ISI_CTS); } @@ -660,24 +661,21 @@ static irqreturn_t isicom_interrupt(int irq, void *dev_id) } outw(0x0000, base+0x04); /* enable interrupts */ spin_unlock(&card->card_lock); + tty_kref_put(tty); return IRQ_HANDLED; } -static void isicom_config_port(struct isi_port *port) +static void isicom_config_port(struct tty_struct *tty) { + struct isi_port *port = tty->driver_data; struct isi_board *card = port->card; - struct tty_struct *tty; unsigned long baud; unsigned long base = card->base; u16 channel_setup, channel = port->channel, shift_count = card->shift_count; unsigned char flow_ctrl; - tty = port->port.tty; - - if (tty == NULL) - return; /* FIXME: Switch to new tty baud API */ baud = C_BAUD(tty); if (baud & CBAUDEX) { @@ -690,7 +688,7 @@ static void isicom_config_port(struct isi_port *port) /* 1,2,3,4 => 57.6, 115.2, 230, 460 kbps resp. */ if (baud < 1 || baud > 4) - port->port.tty->termios->c_cflag &= ~CBAUDEX; + tty->termios->c_cflag &= ~CBAUDEX; else baud += 15; } @@ -797,8 +795,9 @@ static inline void isicom_setup_board(struct isi_board *bp) spin_unlock_irqrestore(&bp->card_lock, flags); } -static int isicom_setup_port(struct isi_port *port) +static int isicom_setup_port(struct tty_struct *tty) { + struct isi_port *port = tty->driver_data; struct isi_board *card = port->card; unsigned long flags; @@ -808,8 +807,7 @@ static int isicom_setup_port(struct isi_port *port) return -ENOMEM; spin_lock_irqsave(&card->card_lock, flags); - if (port->port.tty) - clear_bit(TTY_IO_ERROR, &port->port.tty->flags); + clear_bit(TTY_IO_ERROR, &tty->flags); if (port->port.count == 1) card->count++; @@ -823,7 +821,7 @@ static int isicom_setup_port(struct isi_port *port) InterruptTheCard(card->base); } - isicom_config_port(port); + isicom_config_port(tty); port->port.flags |= ASYNC_INITIALIZED; spin_unlock_irqrestore(&card->card_lock, flags); @@ -934,8 +932,8 @@ static int isicom_open(struct tty_struct *tty, struct file *filp) port->port.count++; tty->driver_data = port; - port->port.tty = tty; - error = isicom_setup_port(port); + tty_port_tty_set(&port->port, tty); + error = isicom_setup_port(tty); if (error == 0) error = block_til_ready(tty, filp, port); return error; @@ -955,15 +953,17 @@ static void isicom_shutdown_port(struct isi_port *port) struct isi_board *card = port->card; struct tty_struct *tty; - tty = port->port.tty; + tty = tty_port_tty_get(&port->port); - if (!(port->port.flags & ASYNC_INITIALIZED)) + if (!(port->port.flags & ASYNC_INITIALIZED)) { + tty_kref_put(tty); return; + } tty_port_free_xmit_buf(&port->port); port->port.flags &= ~ASYNC_INITIALIZED; /* 3rd October 2000 : Vinayak P Risbud */ - port->port.tty = NULL; + tty_port_tty_set(&port->port, NULL); /*Fix done by Anil .S on 30-04-2001 remote login through isi port has dtr toggle problem @@ -1243,9 +1243,10 @@ static int isicom_tiocmset(struct tty_struct *tty, struct file *file, return 0; } -static int isicom_set_serial_info(struct isi_port *port, - struct serial_struct __user *info) +static int isicom_set_serial_info(struct tty_struct *tty, + struct serial_struct __user *info) { + struct isi_port *port = tty->driver_data; struct serial_struct newinfo; int reconfig_port; @@ -1276,7 +1277,7 @@ static int isicom_set_serial_info(struct isi_port *port, if (reconfig_port) { unsigned long flags; spin_lock_irqsave(&port->card->card_lock, flags); - isicom_config_port(port); + isicom_config_port(tty); spin_unlock_irqrestore(&port->card->card_lock, flags); } unlock_kernel(); @@ -1318,7 +1319,7 @@ static int isicom_ioctl(struct tty_struct *tty, struct file *filp, return isicom_get_serial_info(port, argp); case TIOCSSERIAL: - return isicom_set_serial_info(port, argp); + return isicom_set_serial_info(tty, argp); default: return -ENOIOCTLCMD; @@ -1341,7 +1342,7 @@ static void isicom_set_termios(struct tty_struct *tty, return; spin_lock_irqsave(&port->card->card_lock, flags); - isicom_config_port(port); + isicom_config_port(tty); spin_unlock_irqrestore(&port->card->card_lock, flags); if ((old_termios->c_cflag & CRTSCTS) && @@ -1419,7 +1420,7 @@ static void isicom_hangup(struct tty_struct *tty) port->port.count = 0; port->port.flags &= ~ASYNC_NORMAL_ACTIVE; - port->port.tty = NULL; + tty_port_tty_set(&port->port, NULL); wake_up_interruptible(&port->port.open_wait); } diff --git a/drivers/char/istallion.c b/drivers/char/istallion.c index 843a2afaf20..505d7a1f6b8 100644 --- a/drivers/char/istallion.c +++ b/drivers/char/istallion.c @@ -623,24 +623,25 @@ static int stli_memioctl(struct inode *ip, struct file *fp, unsigned int cmd, un static void stli_brdpoll(struct stlibrd *brdp, cdkhdr_t __iomem *hdrp); static void stli_poll(unsigned long arg); static int stli_hostcmd(struct stlibrd *brdp, struct stliport *portp); -static int stli_initopen(struct stlibrd *brdp, struct stliport *portp); +static int stli_initopen(struct tty_struct *tty, struct stlibrd *brdp, struct stliport *portp); static int stli_rawopen(struct stlibrd *brdp, struct stliport *portp, unsigned long arg, int wait); static int stli_rawclose(struct stlibrd *brdp, struct stliport *portp, unsigned long arg, int wait); -static int stli_waitcarrier(struct stlibrd *brdp, struct stliport *portp, struct file *filp); -static int stli_setport(struct stliport *portp); +static int stli_waitcarrier(struct tty_struct *tty, struct stlibrd *brdp, + struct stliport *portp, struct file *filp); +static int stli_setport(struct tty_struct *tty); static int stli_cmdwait(struct stlibrd *brdp, struct stliport *portp, unsigned long cmd, void *arg, int size, int copyback); static void stli_sendcmd(struct stlibrd *brdp, struct stliport *portp, unsigned long cmd, void *arg, int size, int copyback); static void __stli_sendcmd(struct stlibrd *brdp, struct stliport *portp, unsigned long cmd, void *arg, int size, int copyback); static void stli_dodelaycmd(struct stliport *portp, cdkctrl_t __iomem *cp); -static void stli_mkasyport(struct stliport *portp, asyport_t *pp, struct ktermios *tiosp); +static void stli_mkasyport(struct tty_struct *tty, struct stliport *portp, asyport_t *pp, struct ktermios *tiosp); static void stli_mkasysigs(asysigs_t *sp, int dtr, int rts); static long stli_mktiocm(unsigned long sigvalue); static void stli_read(struct stlibrd *brdp, struct stliport *portp); static int stli_getserial(struct stliport *portp, struct serial_struct __user *sp); -static int stli_setserial(struct stliport *portp, struct serial_struct __user *sp); +static int stli_setserial(struct tty_struct *tty, struct serial_struct __user *sp); static int stli_getbrdstats(combrd_t __user *bp); -static int stli_getportstats(struct stliport *portp, comstats_t __user *cp); -static int stli_portcmdstats(struct stliport *portp); +static int stli_getportstats(struct tty_struct *tty, struct stliport *portp, comstats_t __user *cp); +static int stli_portcmdstats(struct tty_struct *tty, struct stliport *portp); static int stli_clrportstats(struct stliport *portp, comstats_t __user *cp); static int stli_getportstruct(struct stliport __user *arg); static int stli_getbrdstruct(struct stlibrd __user *arg); @@ -731,12 +732,16 @@ static void stli_cleanup_ports(struct stlibrd *brdp) { struct stliport *portp; unsigned int j; + struct tty_struct *tty; for (j = 0; j < STL_MAXPORTS; j++) { portp = brdp->ports[j]; if (portp != NULL) { - if (portp->port.tty != NULL) - tty_hangup(portp->port.tty); + tty = tty_port_tty_get(&portp->port); + if (tty != NULL) { + tty_hangup(tty); + tty_kref_put(tty); + } kfree(portp); } } @@ -824,7 +829,7 @@ static int stli_open(struct tty_struct *tty, struct file *filp) * requires several commands to the board we will need to wait for any * other open that is already initializing the port. */ - portp->port.tty = tty; + tty_port_tty_set(&portp->port, tty); tty->driver_data = portp; portp->port.count++; @@ -835,7 +840,7 @@ static int stli_open(struct tty_struct *tty, struct file *filp) if ((portp->port.flags & ASYNC_INITIALIZED) == 0) { set_bit(ST_INITIALIZING, &portp->state); - if ((rc = stli_initopen(brdp, portp)) >= 0) { + if ((rc = stli_initopen(tty, brdp, portp)) >= 0) { portp->port.flags |= ASYNC_INITIALIZED; clear_bit(TTY_IO_ERROR, &tty->flags); } @@ -864,7 +869,7 @@ static int stli_open(struct tty_struct *tty, struct file *filp) * then also we might have to wait for carrier. */ if (!(filp->f_flags & O_NONBLOCK)) { - if ((rc = stli_waitcarrier(brdp, portp, filp)) != 0) + if ((rc = stli_waitcarrier(tty, brdp, portp, filp)) != 0) return rc; } portp->port.flags |= ASYNC_NORMAL_ACTIVE; @@ -930,7 +935,7 @@ static void stli_close(struct tty_struct *tty, struct file *filp) stli_flushbuffer(tty); tty->closing = 0; - portp->port.tty = NULL; + tty_port_tty_set(&portp->port, NULL); if (portp->openwaitcnt) { if (portp->close_delay) @@ -952,9 +957,9 @@ static void stli_close(struct tty_struct *tty, struct file *filp) * this still all happens pretty quickly. */ -static int stli_initopen(struct stlibrd *brdp, struct stliport *portp) +static int stli_initopen(struct tty_struct *tty, + struct stlibrd *brdp, struct stliport *portp) { - struct tty_struct *tty; asynotify_t nt; asyport_t aport; int rc; @@ -969,10 +974,7 @@ static int stli_initopen(struct stlibrd *brdp, struct stliport *portp) sizeof(asynotify_t), 0)) < 0) return rc; - tty = portp->port.tty; - if (tty == NULL) - return -ENODEV; - stli_mkasyport(portp, &aport, tty->termios); + stli_mkasyport(tty, portp, &aport, tty->termios); if ((rc = stli_cmdwait(brdp, portp, A_SETPORT, &aport, sizeof(asyport_t), 0)) < 0) return rc; @@ -1161,22 +1163,21 @@ static int stli_cmdwait(struct stlibrd *brdp, struct stliport *portp, unsigned l * waiting for the command to complete - so must have user context. */ -static int stli_setport(struct stliport *portp) +static int stli_setport(struct tty_struct *tty) { + struct stliport *portp = tty->driver_data; struct stlibrd *brdp; asyport_t aport; if (portp == NULL) return -ENODEV; - if (portp->port.tty == NULL) - return -ENODEV; if (portp->brdnr >= stli_nrbrds) return -ENODEV; brdp = stli_brds[portp->brdnr]; if (brdp == NULL) return -ENODEV; - stli_mkasyport(portp, &aport, portp->port.tty->termios); + stli_mkasyport(tty, portp, &aport, tty->termios); return(stli_cmdwait(brdp, portp, A_SETPORT, &aport, sizeof(asyport_t), 0)); } @@ -1187,7 +1188,8 @@ static int stli_setport(struct stliport *portp) * maybe because if we are clocal then we don't need to wait... */ -static int stli_waitcarrier(struct stlibrd *brdp, struct stliport *portp, struct file *filp) +static int stli_waitcarrier(struct tty_struct *tty, struct stlibrd *brdp, + struct stliport *portp, struct file *filp) { unsigned long flags; int rc, doclocal; @@ -1195,7 +1197,7 @@ static int stli_waitcarrier(struct stlibrd *brdp, struct stliport *portp, struct rc = 0; doclocal = 0; - if (portp->port.tty->termios->c_cflag & CLOCAL) + if (tty->termios->c_cflag & CLOCAL) doclocal++; spin_lock_irqsave(&stli_lock, flags); @@ -1373,8 +1375,6 @@ static void stli_flushchars(struct tty_struct *tty) stli_txcookrealsize = 0; stli_txcooktty = NULL; - if (tty == NULL) - return; if (cooktty == NULL) return; if (tty != cooktty) @@ -1572,10 +1572,11 @@ static int stli_getserial(struct stliport *portp, struct serial_struct __user *s * just quietly ignore any requests to change irq, etc. */ -static int stli_setserial(struct stliport *portp, struct serial_struct __user *sp) +static int stli_setserial(struct tty_struct *tty, struct serial_struct __user *sp) { struct serial_struct sio; int rc; + struct stliport *portp = tty->driver_data; if (copy_from_user(&sio, sp, sizeof(struct serial_struct))) return -EFAULT; @@ -1594,7 +1595,7 @@ static int stli_setserial(struct stliport *portp, struct serial_struct __user *s portp->closing_wait = sio.closing_wait; portp->custom_divisor = sio.custom_divisor; - if ((rc = stli_setport(portp)) < 0) + if ((rc = stli_setport(tty)) < 0) return rc; return 0; } @@ -1685,17 +1686,17 @@ static int stli_ioctl(struct tty_struct *tty, struct file *file, unsigned int cm rc = stli_getserial(portp, argp); break; case TIOCSSERIAL: - rc = stli_setserial(portp, argp); + rc = stli_setserial(tty, argp); break; case STL_GETPFLAG: rc = put_user(portp->pflag, (unsigned __user *)argp); break; case STL_SETPFLAG: if ((rc = get_user(portp->pflag, (unsigned __user *)argp)) == 0) - stli_setport(portp); + stli_setport(tty); break; case COM_GETPORTSTATS: - rc = stli_getportstats(portp, argp); + rc = stli_getportstats(tty, portp, argp); break; case COM_CLRPORTSTATS: rc = stli_clrportstats(portp, argp); @@ -1729,8 +1730,6 @@ static void stli_settermios(struct tty_struct *tty, struct ktermios *old) struct ktermios *tiosp; asyport_t aport; - if (tty == NULL) - return; portp = tty->driver_data; if (portp == NULL) return; @@ -1742,7 +1741,7 @@ static void stli_settermios(struct tty_struct *tty, struct ktermios *old) tiosp = tty->termios; - stli_mkasyport(portp, &aport, tiosp); + stli_mkasyport(tty, portp, &aport, tiosp); stli_cmdwait(brdp, portp, A_SETPORT, &aport, sizeof(asyport_t), 0); stli_mkasysigs(&portp->asig, ((tiosp->c_cflag & CBAUD) ? 1 : 0), -1); stli_cmdwait(brdp, portp, A_SETSIGNALS, &portp->asig, @@ -1854,7 +1853,7 @@ static void stli_hangup(struct tty_struct *tty) clear_bit(ST_TXBUSY, &portp->state); clear_bit(ST_RXSTOP, &portp->state); set_bit(TTY_IO_ERROR, &tty->flags); - portp->port.tty = NULL; + tty_port_tty_set(&portp->port, NULL); portp->port.flags &= ~ASYNC_NORMAL_ACTIVE; portp->port.count = 0; spin_unlock_irqrestore(&stli_lock, flags); @@ -1935,8 +1934,6 @@ static void stli_waituntilsent(struct tty_struct *tty, int timeout) struct stliport *portp; unsigned long tend; - if (tty == NULL) - return; portp = tty->driver_data; if (portp == NULL) return; @@ -1998,7 +1995,7 @@ static int stli_portinfo(struct stlibrd *brdp, struct stliport *portp, int portn char *sp, *uart; int rc, cnt; - rc = stli_portcmdstats(portp); + rc = stli_portcmdstats(NULL, portp); uart = "UNKNOWN"; if (brdp->state & BST_STARTED) { @@ -2188,7 +2185,7 @@ static void stli_read(struct stlibrd *brdp, struct stliport *portp) if (test_bit(ST_RXSTOP, &portp->state)) return; - tty = portp->port.tty; + tty = tty_port_tty_get(&portp->port); if (tty == NULL) return; @@ -2230,6 +2227,7 @@ static void stli_read(struct stlibrd *brdp, struct stliport *portp) set_bit(ST_RXING, &portp->state); tty_schedule_flip(tty); + tty_kref_put(tty); } /*****************************************************************************/ @@ -2362,7 +2360,7 @@ static int stli_hostcmd(struct stlibrd *brdp, struct stliport *portp) if (ap->notify) { nt = ap->changed; ap->notify = 0; - tty = portp->port.tty; + tty = tty_port_tty_get(&portp->port); if (nt.signal & SG_DCD) { oldsigs = portp->sigs; @@ -2399,6 +2397,7 @@ static int stli_hostcmd(struct stlibrd *brdp, struct stliport *portp) tty_schedule_flip(tty); } } + tty_kref_put(tty); if (nt.data & DT_RXBUSY) { donerx++; @@ -2535,14 +2534,15 @@ static void stli_poll(unsigned long arg) * the slave. */ -static void stli_mkasyport(struct stliport *portp, asyport_t *pp, struct ktermios *tiosp) +static void stli_mkasyport(struct tty_struct *tty, struct stliport *portp, + asyport_t *pp, struct ktermios *tiosp) { memset(pp, 0, sizeof(asyport_t)); /* * Start of by setting the baud, char size, parity and stop bit info. */ - pp->baudout = tty_get_baud_rate(portp->port.tty); + pp->baudout = tty_get_baud_rate(tty); if ((tiosp->c_cflag & CBAUD) == B38400) { if ((portp->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI) pp->baudout = 57600; @@ -2695,7 +2695,7 @@ static int stli_initports(struct stlibrd *brdp) printk("STALLION: failed to allocate port structure\n"); continue; } - + tty_port_init(&portp->port); portp->magic = STLI_PORTMAGIC; portp->portnr = i; portp->brdnr = brdp->brdnr; @@ -4220,7 +4220,7 @@ static struct stliport *stli_getport(unsigned int brdnr, unsigned int panelnr, * what port to get stats for (used through board control device). */ -static int stli_portcmdstats(struct stliport *portp) +static int stli_portcmdstats(struct tty_struct *tty, struct stliport *portp) { unsigned long flags; struct stlibrd *brdp; @@ -4249,15 +4249,15 @@ static int stli_portcmdstats(struct stliport *portp) stli_comstats.flags = portp->port.flags; spin_lock_irqsave(&brd_lock, flags); - if (portp->port.tty != NULL) { - if (portp->port.tty->driver_data == portp) { - stli_comstats.ttystate = portp->port.tty->flags; + if (tty != NULL) { + if (portp->port.tty == tty) { + stli_comstats.ttystate = tty->flags; stli_comstats.rxbuffered = -1; - if (portp->port.tty->termios != NULL) { - stli_comstats.cflags = portp->port.tty->termios->c_cflag; - stli_comstats.iflags = portp->port.tty->termios->c_iflag; - stli_comstats.oflags = portp->port.tty->termios->c_oflag; - stli_comstats.lflags = portp->port.tty->termios->c_lflag; + if (tty->termios != NULL) { + stli_comstats.cflags = tty->termios->c_cflag; + stli_comstats.iflags = tty->termios->c_iflag; + stli_comstats.oflags = tty->termios->c_oflag; + stli_comstats.lflags = tty->termios->c_lflag; } } } @@ -4294,7 +4294,8 @@ static int stli_portcmdstats(struct stliport *portp) * what port to get stats for (used through board control device). */ -static int stli_getportstats(struct stliport *portp, comstats_t __user *cp) +static int stli_getportstats(struct tty_struct *tty, struct stliport *portp, + comstats_t __user *cp) { struct stlibrd *brdp; int rc; @@ -4312,7 +4313,7 @@ static int stli_getportstats(struct stliport *portp, comstats_t __user *cp) if (!brdp) return -ENODEV; - if ((rc = stli_portcmdstats(portp)) < 0) + if ((rc = stli_portcmdstats(tty, portp)) < 0) return rc; return copy_to_user(cp, &stli_comstats, sizeof(comstats_t)) ? @@ -4427,7 +4428,7 @@ static int stli_memioctl(struct inode *ip, struct file *fp, unsigned int cmd, un switch (cmd) { case COM_GETPORTSTATS: - rc = stli_getportstats(NULL, argp); + rc = stli_getportstats(NULL, NULL, argp); done++; break; case COM_CLRPORTSTATS: diff --git a/drivers/char/moxa.c b/drivers/char/moxa.c index d3d7864e0c1..5df4003ad87 100644 --- a/drivers/char/moxa.c +++ b/drivers/char/moxa.c @@ -205,7 +205,7 @@ static int moxa_tiocmset(struct tty_struct *tty, struct file *file, static void moxa_poll(unsigned long); static void moxa_set_tty_param(struct tty_struct *, struct ktermios *); static void moxa_setup_empty_event(struct tty_struct *); -static void moxa_shut_down(struct moxa_port *); +static void moxa_shut_down(struct tty_struct *); /* * moxa board interface functions: */ @@ -217,7 +217,7 @@ static void MoxaPortLineCtrl(struct moxa_port *, int, int); static void MoxaPortFlowCtrl(struct moxa_port *, int, int, int, int, int); static int MoxaPortLineStatus(struct moxa_port *); static void MoxaPortFlushData(struct moxa_port *, int); -static int MoxaPortWriteData(struct moxa_port *, const unsigned char *, int); +static int MoxaPortWriteData(struct tty_struct *, const unsigned char *, int); static int MoxaPortReadData(struct moxa_port *); static int MoxaPortTxQueue(struct moxa_port *); static int MoxaPortRxQueue(struct moxa_port *); @@ -332,6 +332,7 @@ static int moxa_ioctl(struct tty_struct *tty, struct file *file, for (i = 0; i < MAX_BOARDS; i++) { p = moxa_boards[i].ports; for (j = 0; j < MAX_PORTS_PER_BOARD; j++, p++, argm++) { + struct tty_struct *ttyp; memset(&tmp, 0, sizeof(tmp)); if (!moxa_boards[i].ready) goto copy; @@ -344,10 +345,12 @@ static int moxa_ioctl(struct tty_struct *tty, struct file *file, if (status & 4) tmp.dcd = 1; - if (!p->port.tty || !p->port.tty->termios) + ttyp = tty_port_tty_get(&p->port); + if (!ttyp || !ttyp->termios) tmp.cflag = p->cflag; else - tmp.cflag = p->port.tty->termios->c_cflag; + tmp.cflag = ttyp->termios->c_cflag; + tty_kref_put(tty); copy: if (copy_to_user(argm, &tmp, sizeof(tmp))) { mutex_unlock(&moxa_openlock); @@ -880,8 +883,14 @@ static void moxa_board_deinit(struct moxa_board_conf *brd) /* pci hot-un-plug support */ for (a = 0; a < brd->numPorts; a++) - if (brd->ports[a].port.flags & ASYNC_INITIALIZED) - tty_hangup(brd->ports[a].port.tty); + if (brd->ports[a].port.flags & ASYNC_INITIALIZED) { + struct tty_struct *tty = tty_port_tty_get( + &brd->ports[a].port); + if (tty) { + tty_hangup(tty); + tty_kref_put(tty); + } + } while (1) { opened = 0; for (a = 0; a < brd->numPorts; a++) @@ -1096,13 +1105,14 @@ static void __exit moxa_exit(void) module_init(moxa_init); module_exit(moxa_exit); -static void moxa_close_port(struct moxa_port *ch) +static void moxa_close_port(struct tty_struct *tty) { - moxa_shut_down(ch); + struct moxa_port *ch = tty->driver_data; + moxa_shut_down(tty); MoxaPortFlushData(ch, 2); ch->port.flags &= ~ASYNC_NORMAL_ACTIVE; - ch->port.tty->driver_data = NULL; - ch->port.tty = NULL; + tty->driver_data = NULL; + tty_port_tty_set(&ch->port, NULL); } static int moxa_block_till_ready(struct tty_struct *tty, struct file *filp, @@ -1161,7 +1171,7 @@ static int moxa_open(struct tty_struct *tty, struct file *filp) ch = &brd->ports[port % MAX_PORTS_PER_BOARD]; ch->port.count++; tty->driver_data = ch; - ch->port.tty = tty; + tty_port_tty_set(&ch->port, tty); if (!(ch->port.flags & ASYNC_INITIALIZED)) { ch->statusflags = 0; moxa_set_tty_param(tty, tty->termios); @@ -1179,7 +1189,7 @@ static int moxa_open(struct tty_struct *tty, struct file *filp) if (retval) { if (ch->port.count) /* 0 means already hung up... */ if (--ch->port.count == 0) - moxa_close_port(ch); + moxa_close_port(tty); } else ch->port.flags |= ASYNC_NORMAL_ACTIVE; mutex_unlock(&moxa_openlock); @@ -1219,7 +1229,7 @@ static void moxa_close(struct tty_struct *tty, struct file *filp) tty_wait_until_sent(tty, 30 * HZ); /* 30 seconds timeout */ } - moxa_close_port(ch); + moxa_close_port(tty); unlock: mutex_unlock(&moxa_openlock); } @@ -1234,7 +1244,7 @@ static int moxa_write(struct tty_struct *tty, return 0; spin_lock_bh(&moxa_lock); - len = MoxaPortWriteData(ch, buf, count); + len = MoxaPortWriteData(tty, buf, count); spin_unlock_bh(&moxa_lock); ch->statusflags |= LOWWAIT; @@ -1409,7 +1419,7 @@ static void moxa_hangup(struct tty_struct *tty) return; } ch->port.count = 0; - moxa_close_port(ch); + moxa_close_port(tty); mutex_unlock(&moxa_openlock); wake_up_interruptible(&ch->port.open_wait); @@ -1417,11 +1427,14 @@ static void moxa_hangup(struct tty_struct *tty) static void moxa_new_dcdstate(struct moxa_port *p, u8 dcd) { + struct tty_struct *tty; dcd = !!dcd; - if (dcd != p->DCDState && p->port.tty && C_CLOCAL(p->port.tty)) { - if (!dcd) - tty_hangup(p->port.tty); + if (dcd != p->DCDState) { + tty = tty_port_tty_get(&p->port); + if (tty && C_CLOCAL(tty) && !dcd) + tty_hangup(tty); + tty_kref_put(tty); } p->DCDState = dcd; } @@ -1429,7 +1442,7 @@ static void moxa_new_dcdstate(struct moxa_port *p, u8 dcd) static int moxa_poll_port(struct moxa_port *p, unsigned int handle, u16 __iomem *ip) { - struct tty_struct *tty = p->port.tty; + struct tty_struct *tty = tty_port_tty_get(&p->port); void __iomem *ofsAddr; unsigned int inited = p->port.flags & ASYNC_INITIALIZED; u16 intr; @@ -1476,6 +1489,7 @@ static int moxa_poll_port(struct moxa_port *p, unsigned int handle, tty_insert_flip_char(tty, 0, TTY_BREAK); tty_schedule_flip(tty); } + tty_kref_put(tty); if (intr & IntrLine) moxa_new_dcdstate(p, readb(ofsAddr + FlagStat) & DCD_state); @@ -1560,9 +1574,9 @@ static void moxa_setup_empty_event(struct tty_struct *tty) spin_unlock_bh(&moxa_lock); } -static void moxa_shut_down(struct moxa_port *ch) +static void moxa_shut_down(struct tty_struct *tty) { - struct tty_struct *tp = ch->port.tty; + struct moxa_port *ch = tty->driver_data; if (!(ch->port.flags & ASYNC_INITIALIZED)) return; @@ -1572,7 +1586,7 @@ static void moxa_shut_down(struct moxa_port *ch) /* * If we're a modem control device and HUPCL is on, drop RTS & DTR. */ - if (C_HUPCL(tp)) + if (C_HUPCL(tty)) MoxaPortLineCtrl(ch, 0, 0); spin_lock_bh(&moxa_lock); @@ -1953,9 +1967,10 @@ static int MoxaPortLineStatus(struct moxa_port *port) return val; } -static int MoxaPortWriteData(struct moxa_port *port, +static int MoxaPortWriteData(struct tty_struct *tty, const unsigned char *buffer, int len) { + struct moxa_port *port = tty->driver_data; void __iomem *baseAddr, *ofsAddr, *ofs; unsigned int c, total; u16 head, tail, tx_mask, spage, epage; diff --git a/drivers/char/mxser.c b/drivers/char/mxser.c index e30575e8764..8beef50f95a 100644 --- a/drivers/char/mxser.c +++ b/drivers/char/mxser.c @@ -610,15 +610,13 @@ static int mxser_block_til_ready(struct tty_struct *tty, struct file *filp, return 0; } -static int mxser_set_baud(struct mxser_port *info, long newspd) +static int mxser_set_baud(struct tty_struct *tty, long newspd) { + struct mxser_port *info = tty->driver_data; int quot = 0, baud; unsigned char cval; - if (!info->port.tty || !info->port.tty->termios) - return -1; - - if (!(info->ioaddr)) + if (!info->ioaddr) return -1; if (newspd > info->max_baud) @@ -626,13 +624,13 @@ static int mxser_set_baud(struct mxser_port *info, long newspd) if (newspd == 134) { quot = 2 * info->baud_base / 269; - tty_encode_baud_rate(info->port.tty, 134, 134); + tty_encode_baud_rate(tty, 134, 134); } else if (newspd) { quot = info->baud_base / newspd; if (quot == 0) quot = 1; baud = info->baud_base/quot; - tty_encode_baud_rate(info->port.tty, baud, baud); + tty_encode_baud_rate(tty, baud, baud); } else { quot = 0; } @@ -658,7 +656,7 @@ static int mxser_set_baud(struct mxser_port *info, long newspd) outb(cval, info->ioaddr + UART_LCR); /* reset DLAB */ #ifdef BOTHER - if (C_BAUD(info->port.tty) == BOTHER) { + if (C_BAUD(tty) == BOTHER) { quot = info->baud_base % newspd; quot *= 8; if (quot % newspd > newspd / 2) { @@ -679,21 +677,20 @@ static int mxser_set_baud(struct mxser_port *info, long newspd) * This routine is called to set the UART divisor registers to match * the specified baud rate for a serial port. */ -static int mxser_change_speed(struct mxser_port *info, - struct ktermios *old_termios) +static int mxser_change_speed(struct tty_struct *tty, + struct ktermios *old_termios) { + struct mxser_port *info = tty->driver_data; unsigned cflag, cval, fcr; int ret = 0; unsigned char status; - if (!info->port.tty || !info->port.tty->termios) - return ret; - cflag = info->port.tty->termios->c_cflag; - if (!(info->ioaddr)) + cflag = tty->termios->c_cflag; + if (!info->ioaddr) return ret; - if (mxser_set_baud_method[info->port.tty->index] == 0) - mxser_set_baud(info, tty_get_baud_rate(info->port.tty)); + if (mxser_set_baud_method[tty->index] == 0) + mxser_set_baud(tty, tty_get_baud_rate(tty)); /* byte size and parity */ switch (cflag & CSIZE) { @@ -762,9 +759,9 @@ static int mxser_change_speed(struct mxser_port *info, info->MCR |= UART_MCR_AFE; } else { status = inb(info->ioaddr + UART_MSR); - if (info->port.tty->hw_stopped) { + if (tty->hw_stopped) { if (status & UART_MSR_CTS) { - info->port.tty->hw_stopped = 0; + tty->hw_stopped = 0; if (info->type != PORT_16550A && !info->board->chip_flag) { outb(info->IER & ~UART_IER_THRI, @@ -774,11 +771,11 @@ static int mxser_change_speed(struct mxser_port *info, outb(info->IER, info->ioaddr + UART_IER); } - tty_wakeup(info->port.tty); + tty_wakeup(tty); } } else { if (!(status & UART_MSR_CTS)) { - info->port.tty->hw_stopped = 1; + tty->hw_stopped = 1; if ((info->type != PORT_16550A) && (!info->board->chip_flag)) { info->IER &= ~UART_IER_THRI; @@ -804,21 +801,21 @@ static int mxser_change_speed(struct mxser_port *info, * Set up parity check flag */ info->read_status_mask = UART_LSR_OE | UART_LSR_THRE | UART_LSR_DR; - if (I_INPCK(info->port.tty)) + if (I_INPCK(tty)) info->read_status_mask |= UART_LSR_FE | UART_LSR_PE; - if (I_BRKINT(info->port.tty) || I_PARMRK(info->port.tty)) + if (I_BRKINT(tty) || I_PARMRK(tty)) info->read_status_mask |= UART_LSR_BI; info->ignore_status_mask = 0; - if (I_IGNBRK(info->port.tty)) { + if (I_IGNBRK(tty)) { info->ignore_status_mask |= UART_LSR_BI; info->read_status_mask |= UART_LSR_BI; /* * If we're ignore parity and break indicators, ignore * overruns too. (For real raw support). */ - if (I_IGNPAR(info->port.tty)) { + if (I_IGNPAR(tty)) { info->ignore_status_mask |= UART_LSR_OE | UART_LSR_PE | @@ -830,16 +827,16 @@ static int mxser_change_speed(struct mxser_port *info, } } if (info->board->chip_flag) { - mxser_set_must_xon1_value(info->ioaddr, START_CHAR(info->port.tty)); - mxser_set_must_xoff1_value(info->ioaddr, STOP_CHAR(info->port.tty)); - if (I_IXON(info->port.tty)) { + mxser_set_must_xon1_value(info->ioaddr, START_CHAR(tty)); + mxser_set_must_xoff1_value(info->ioaddr, STOP_CHAR(tty)); + if (I_IXON(tty)) { mxser_enable_must_rx_software_flow_control( info->ioaddr); } else { mxser_disable_must_rx_software_flow_control( info->ioaddr); } - if (I_IXOFF(info->port.tty)) { + if (I_IXOFF(tty)) { mxser_enable_must_tx_software_flow_control( info->ioaddr); } else { @@ -855,7 +852,8 @@ static int mxser_change_speed(struct mxser_port *info, return ret; } -static void mxser_check_modem_status(struct mxser_port *port, int status) +static void mxser_check_modem_status(struct tty_struct *tty, + struct mxser_port *port, int status) { /* update input line counters */ if (status & UART_MSR_TERI) @@ -874,10 +872,11 @@ static void mxser_check_modem_status(struct mxser_port *port, int status) wake_up_interruptible(&port->port.open_wait); } + tty = tty_port_tty_get(&port->port); if (port->port.flags & ASYNC_CTS_FLOW) { - if (port->port.tty->hw_stopped) { + if (tty->hw_stopped) { if (status & UART_MSR_CTS) { - port->port.tty->hw_stopped = 0; + tty->hw_stopped = 0; if ((port->type != PORT_16550A) && (!port->board->chip_flag)) { @@ -887,11 +886,11 @@ static void mxser_check_modem_status(struct mxser_port *port, int status) outb(port->IER, port->ioaddr + UART_IER); } - tty_wakeup(port->port.tty); + tty_wakeup(tty); } } else { if (!(status & UART_MSR_CTS)) { - port->port.tty->hw_stopped = 1; + tty->hw_stopped = 1; if (port->type != PORT_16550A && !port->board->chip_flag) { port->IER &= ~UART_IER_THRI; @@ -903,8 +902,9 @@ static void mxser_check_modem_status(struct mxser_port *port, int status) } } -static int mxser_startup(struct mxser_port *info) +static int mxser_startup(struct tty_struct *tty) { + struct mxser_port *info = tty->driver_data; unsigned long page; unsigned long flags; @@ -921,8 +921,7 @@ static int mxser_startup(struct mxser_port *info) } if (!info->ioaddr || !info->type) { - if (info->port.tty) - set_bit(TTY_IO_ERROR, &info->port.tty->flags); + set_bit(TTY_IO_ERROR, &tty->flags); free_page(page); spin_unlock_irqrestore(&info->slock, flags); return 0; @@ -952,8 +951,8 @@ static int mxser_startup(struct mxser_port *info) if (inb(info->ioaddr + UART_LSR) == 0xff) { spin_unlock_irqrestore(&info->slock, flags); if (capable(CAP_SYS_ADMIN)) { - if (info->port.tty) - set_bit(TTY_IO_ERROR, &info->port.tty->flags); + if (tty) + set_bit(TTY_IO_ERROR, &tty->flags); return 0; } else return -ENODEV; @@ -991,14 +990,13 @@ static int mxser_startup(struct mxser_port *info) (void) inb(info->ioaddr + UART_IIR); (void) inb(info->ioaddr + UART_MSR); - if (info->port.tty) - clear_bit(TTY_IO_ERROR, &info->port.tty->flags); + clear_bit(TTY_IO_ERROR, &tty->flags); info->xmit_cnt = info->xmit_head = info->xmit_tail = 0; /* * and set the speed of the serial port */ - mxser_change_speed(info, NULL); + mxser_change_speed(tty, NULL); info->port.flags |= ASYNC_INITIALIZED; spin_unlock_irqrestore(&info->slock, flags); @@ -1009,8 +1007,9 @@ static int mxser_startup(struct mxser_port *info) * This routine will shutdown a serial port; interrupts maybe disabled, and * DTR is dropped if the hangup on close termio flag is on. */ -static void mxser_shutdown(struct mxser_port *info) +static void mxser_shutdown(struct tty_struct *tty) { + struct mxser_port *info = tty->driver_data; unsigned long flags; if (!(info->port.flags & ASYNC_INITIALIZED)) @@ -1035,7 +1034,7 @@ static void mxser_shutdown(struct mxser_port *info) info->IER = 0; outb(0x00, info->ioaddr + UART_IER); - if (!info->port.tty || (info->port.tty->termios->c_cflag & HUPCL)) + if (tty->termios->c_cflag & HUPCL) info->MCR &= ~(UART_MCR_DTR | UART_MCR_RTS); outb(info->MCR, info->ioaddr + UART_MCR); @@ -1051,8 +1050,7 @@ static void mxser_shutdown(struct mxser_port *info) /* read data port to reset things */ (void) inb(info->ioaddr + UART_RX); - if (info->port.tty) - set_bit(TTY_IO_ERROR, &info->port.tty->flags); + set_bit(TTY_IO_ERROR, &tty->flags); info->port.flags &= ~ASYNC_INITIALIZED; @@ -1084,14 +1082,14 @@ static int mxser_open(struct tty_struct *tty, struct file *filp) return -ENODEV; tty->driver_data = info; - info->port.tty = tty; + tty_port_tty_set(&info->port, tty); /* * Start up serial port */ spin_lock_irqsave(&info->slock, flags); info->port.count++; spin_unlock_irqrestore(&info->slock, flags); - retval = mxser_startup(info); + retval = mxser_startup(tty); if (retval) return retval; @@ -1209,13 +1207,13 @@ static void mxser_close(struct tty_struct *tty, struct file *filp) break; } } - mxser_shutdown(info); + mxser_shutdown(tty); mxser_flush_buffer(tty); tty_ldisc_flush(tty); tty->closing = 0; - info->port.tty = NULL; + tty_port_tty_set(&info->port, NULL); if (info->port.blocked_open) { if (info->port.close_delay) schedule_timeout_interruptible(info->port.close_delay); @@ -1337,12 +1335,13 @@ static int mxser_chars_in_buffer(struct tty_struct *tty) * friends of mxser_ioctl() * ------------------------------------------------------------ */ -static int mxser_get_serial_info(struct mxser_port *info, +static int mxser_get_serial_info(struct tty_struct *tty, struct serial_struct __user *retinfo) { + struct mxser_port *info = tty->driver_data; struct serial_struct tmp = { .type = info->type, - .line = info->port.tty->index, + .line = tty->index, .port = info->ioaddr, .irq = info->board->irq, .flags = info->port.flags, @@ -1357,9 +1356,10 @@ static int mxser_get_serial_info(struct mxser_port *info, return 0; } -static int mxser_set_serial_info(struct mxser_port *info, +static int mxser_set_serial_info(struct tty_struct *tty, struct serial_struct __user *new_info) { + struct mxser_port *info = tty->driver_data; struct serial_struct new_serial; speed_t baud; unsigned long sl_flags; @@ -1393,14 +1393,14 @@ static int mxser_set_serial_info(struct mxser_port *info, (new_serial.flags & ASYNC_FLAGS)); info->port.close_delay = new_serial.close_delay * HZ / 100; info->port.closing_wait = new_serial.closing_wait * HZ / 100; - info->port.tty->low_latency = - (info->port.flags & ASYNC_LOW_LATENCY) ? 1 : 0; + tty->low_latency = (info->port.flags & ASYNC_LOW_LATENCY) + ? 1 : 0; if ((info->port.flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST && (new_serial.baud_base != info->baud_base || new_serial.custom_divisor != info->custom_divisor)) { baud = new_serial.baud_base / new_serial.custom_divisor; - tty_encode_baud_rate(info->port.tty, baud, baud); + tty_encode_baud_rate(tty, baud, baud); } } @@ -1411,11 +1411,11 @@ static int mxser_set_serial_info(struct mxser_port *info, if (info->port.flags & ASYNC_INITIALIZED) { if (flags != (info->port.flags & ASYNC_SPD_MASK)) { spin_lock_irqsave(&info->slock, sl_flags); - mxser_change_speed(info, NULL); + mxser_change_speed(tty, NULL); spin_unlock_irqrestore(&info->slock, sl_flags); } } else - retval = mxser_startup(info); + retval = mxser_startup(tty); return retval; } @@ -1461,7 +1461,7 @@ static int mxser_tiocmget(struct tty_struct *tty, struct file *file) spin_lock_irqsave(&info->slock, flags); status = inb(info->ioaddr + UART_MSR); if (status & UART_MSR_ANY_DELTA) - mxser_check_modem_status(info, status); + mxser_check_modem_status(tty, info, status); spin_unlock_irqrestore(&info->slock, flags); return ((control & UART_MCR_RTS) ? TIOCM_RTS : 0) | ((control & UART_MCR_DTR) ? TIOCM_DTR : 0) | @@ -1606,14 +1606,17 @@ static int __init mxser_read_register(int port, unsigned short *regs) static int mxser_ioctl_special(unsigned int cmd, void __user *argp) { struct mxser_port *port; + struct tty_struct *tty; int result, status; unsigned int i, j; int ret = 0; switch (cmd) { case MOXA_GET_MAJOR: - printk(KERN_WARNING "mxser: '%s' uses deprecated ioctl %x, fix " - "your userspace\n", current->comm, cmd); + if (printk_ratelimit()) + printk(KERN_WARNING "mxser: '%s' uses deprecated ioctl " + "%x (GET_MAJOR), fix your userspace\n", + current->comm, cmd); return put_user(ttymajor, (int __user *)argp); case MOXA_CHKPORTENABLE: @@ -1641,12 +1644,14 @@ static int mxser_ioctl_special(unsigned int cmd, void __user *argp) if (!port->ioaddr) goto copy; + + tty = tty_port_tty_get(&port->port); - if (!port->port.tty || !port->port.tty->termios) + if (!tty || !tty->termios) ms.cflag = port->normal_termios.c_cflag; else - ms.cflag = port->port.tty->termios->c_cflag; - + ms.cflag = tty->termios->c_cflag; + tty_kref_put(tty); status = inb(port->ioaddr + UART_MSR); if (status & UART_MSR_DCD) ms.dcd = 1; @@ -1702,15 +1707,18 @@ static int mxser_ioctl_special(unsigned int cmd, void __user *argp) me->up_txcnt[p] = port->mon_data.up_txcnt; me->modem_status[p] = port->mon_data.modem_status; - me->baudrate[p] = tty_get_baud_rate(port->port.tty); + tty = tty_port_tty_get(&port->port); - if (!port->port.tty || !port->port.tty->termios) { + if (!tty || !tty->termios) { cflag = port->normal_termios.c_cflag; iflag = port->normal_termios.c_iflag; + me->baudrate[p] = tty_termios_baud_rate(&port->normal_termios); } else { - cflag = port->port.tty->termios->c_cflag; - iflag = port->port.tty->termios->c_iflag; + cflag = tty->termios->c_cflag; + iflag = tty->termios->c_iflag; + me->baudrate[p] = tty_get_baud_rate(tty); } + tty_kref_put(tty); me->databits[p] = cflag & CSIZE; me->stopbits[p] = cflag & CSTOPB; @@ -1820,12 +1828,12 @@ static int mxser_ioctl(struct tty_struct *tty, struct file *file, switch (cmd) { case TIOCGSERIAL: lock_kernel(); - retval = mxser_get_serial_info(info, argp); + retval = mxser_get_serial_info(tty, argp); unlock_kernel(); return retval; case TIOCSSERIAL: lock_kernel(); - retval = mxser_set_serial_info(info, argp); + retval = mxser_set_serial_info(tty, argp); unlock_kernel(); return retval; case TIOCSERGETLSR: /* Get line status register */ @@ -1894,7 +1902,7 @@ static int mxser_ioctl(struct tty_struct *tty, struct file *file, lock_kernel(); status = mxser_get_msr(info->ioaddr, 1, tty->index); - mxser_check_modem_status(info, status); + mxser_check_modem_status(tty, info, status); mcr = inb(info->ioaddr + UART_MCR); if (mcr & MOXA_MUST_MCR_XON_FLAG) @@ -1907,7 +1915,7 @@ static int mxser_ioctl(struct tty_struct *tty, struct file *file, else info->mon_data.hold_reason |= NPPI_NOTIFY_XOFFXENT; - if (info->port.tty->hw_stopped) + if (tty->hw_stopped) info->mon_data.hold_reason |= NPPI_NOTIFY_CTSHOLD; else info->mon_data.hold_reason &= ~NPPI_NOTIFY_CTSHOLD; @@ -1956,7 +1964,7 @@ static void mxser_stoprx(struct tty_struct *tty) } } - if (info->port.tty->termios->c_cflag & CRTSCTS) { + if (tty->termios->c_cflag & CRTSCTS) { info->MCR &= ~UART_MCR_RTS; outb(info->MCR, info->ioaddr + UART_MCR); } @@ -1993,7 +2001,7 @@ static void mxser_unthrottle(struct tty_struct *tty) } } - if (info->port.tty->termios->c_cflag & CRTSCTS) { + if (tty->termios->c_cflag & CRTSCTS) { info->MCR |= UART_MCR_RTS; outb(info->MCR, info->ioaddr + UART_MCR); } @@ -2038,7 +2046,7 @@ static void mxser_set_termios(struct tty_struct *tty, struct ktermios *old_termi unsigned long flags; spin_lock_irqsave(&info->slock, flags); - mxser_change_speed(info, old_termios); + mxser_change_speed(tty, old_termios); spin_unlock_irqrestore(&info->slock, flags); if ((old_termios->c_cflag & CRTSCTS) && @@ -2136,10 +2144,10 @@ static void mxser_hangup(struct tty_struct *tty) struct mxser_port *info = tty->driver_data; mxser_flush_buffer(tty); - mxser_shutdown(info); + mxser_shutdown(tty); info->port.count = 0; info->port.flags &= ~ASYNC_NORMAL_ACTIVE; - info->port.tty = NULL; + tty_port_tty_set(&info->port, NULL); wake_up_interruptible(&info->port.open_wait); } @@ -2162,9 +2170,9 @@ static int mxser_rs_break(struct tty_struct *tty, int break_state) return 0; } -static void mxser_receive_chars(struct mxser_port *port, int *status) +static void mxser_receive_chars(struct tty_struct *tty, + struct mxser_port *port, int *status) { - struct tty_struct *tty = port->port.tty; unsigned char ch, gdl; int ignored = 0; int cnt = 0; @@ -2172,9 +2180,8 @@ static void mxser_receive_chars(struct mxser_port *port, int *status) int max = 256; recv_room = tty->receive_room; - if ((recv_room == 0) && (!port->ldisc_stop_rx)) + if (recv_room == 0 && !port->ldisc_stop_rx) mxser_stoprx(tty); - if (port->board->chip_flag != MOXA_OTHER_UART) { if (*status & UART_LSR_SPECIAL) @@ -2251,7 +2258,7 @@ intr_old: } while (*status & UART_LSR_DR); end_intr: - mxvar_log.rxcnt[port->port.tty->index] += cnt; + mxvar_log.rxcnt[tty->index] += cnt; port->mon_data.rxcnt += cnt; port->mon_data.up_rxcnt += cnt; @@ -2265,14 +2272,14 @@ end_intr: spin_lock(&port->slock); } -static void mxser_transmit_chars(struct mxser_port *port) +static void mxser_transmit_chars(struct tty_struct *tty, struct mxser_port *port) { int count, cnt; if (port->x_char) { outb(port->x_char, port->ioaddr + UART_TX); port->x_char = 0; - mxvar_log.txcnt[port->port.tty->index]++; + mxvar_log.txcnt[tty->index]++; port->mon_data.txcnt++; port->mon_data.up_txcnt++; port->icount.tx++; @@ -2282,8 +2289,8 @@ static void mxser_transmit_chars(struct mxser_port *port) if (port->port.xmit_buf == NULL) return; - if ((port->xmit_cnt <= 0) || port->port.tty->stopped || - (port->port.tty->hw_stopped && + if (port->xmit_cnt <= 0 || tty->stopped || + (tty->hw_stopped && (port->type != PORT_16550A) && (!port->board->chip_flag))) { port->IER &= ~UART_IER_THRI; @@ -2300,14 +2307,14 @@ static void mxser_transmit_chars(struct mxser_port *port) if (--port->xmit_cnt <= 0) break; } while (--count > 0); - mxvar_log.txcnt[port->port.tty->index] += (cnt - port->xmit_cnt); + mxvar_log.txcnt[tty->index] += (cnt - port->xmit_cnt); port->mon_data.txcnt += (cnt - port->xmit_cnt); port->mon_data.up_txcnt += (cnt - port->xmit_cnt); port->icount.tx += (cnt - port->xmit_cnt); - if (port->xmit_cnt < WAKEUP_CHARS) - tty_wakeup(port->port.tty); + if (port->xmit_cnt < WAKEUP_CHARS && tty) + tty_wakeup(tty); if (port->xmit_cnt <= 0) { port->IER &= ~UART_IER_THRI; @@ -2326,6 +2333,7 @@ static irqreturn_t mxser_interrupt(int irq, void *dev_id) int max, irqbits, bits, msr; unsigned int int_cnt, pass_counter = 0; int handled = IRQ_NONE; + struct tty_struct *tty; for (i = 0; i < MXSER_BOARDS; i++) if (dev_id == &mxser_boards[i]) { @@ -2358,13 +2366,15 @@ static irqreturn_t mxser_interrupt(int irq, void *dev_id) if (iir & UART_IIR_NO_INT) break; iir &= MOXA_MUST_IIR_MASK; - if (!port->port.tty || + tty = tty_port_tty_get(&port->port); + if (!tty || (port->port.flags & ASYNC_CLOSING) || !(port->port.flags & ASYNC_INITIALIZED)) { status = inb(port->ioaddr + UART_LSR); outb(0x27, port->ioaddr + UART_FCR); inb(port->ioaddr + UART_MSR); + tty_kref_put(tty); break; } @@ -2385,27 +2395,28 @@ static irqreturn_t mxser_interrupt(int irq, void *dev_id) iir == MOXA_MUST_IIR_RDA || iir == MOXA_MUST_IIR_RTO || iir == MOXA_MUST_IIR_LSR) - mxser_receive_chars(port, + mxser_receive_chars(tty, port, &status); } else { status &= port->read_status_mask; if (status & UART_LSR_DR) - mxser_receive_chars(port, + mxser_receive_chars(tty, port, &status); } msr = inb(port->ioaddr + UART_MSR); if (msr & UART_MSR_ANY_DELTA) - mxser_check_modem_status(port, msr); + mxser_check_modem_status(tty, port, msr); if (port->board->chip_flag) { if (iir == 0x02 && (status & UART_LSR_THRE)) - mxser_transmit_chars(port); + mxser_transmit_chars(tty, port); } else { if (status & UART_LSR_THRE) - mxser_transmit_chars(port); + mxser_transmit_chars(tty, port); } + tty_kref_put(tty); } while (int_cnt++ < MXSER_ISR_PASS_LIMIT); spin_unlock(&port->slock); } diff --git a/drivers/char/n_hdlc.c b/drivers/char/n_hdlc.c index 69ec6399c71..bacb3e2872a 100644 --- a/drivers/char/n_hdlc.c +++ b/drivers/char/n_hdlc.c @@ -764,7 +764,7 @@ static int n_hdlc_tty_ioctl(struct tty_struct *tty, struct file *file, break; default: - error = n_tty_ioctl (tty, file, cmd, arg); + error = n_tty_ioctl_helper(tty, file, cmd, arg); break; } return error; diff --git a/drivers/char/n_r3964.c b/drivers/char/n_r3964.c index ae377aa473b..4a8215a89ad 100644 --- a/drivers/char/n_r3964.c +++ b/drivers/char/n_r3964.c @@ -372,14 +372,8 @@ static void remove_from_rx_queue(struct r3964_info *pInfo, static void put_char(struct r3964_info *pInfo, unsigned char ch) { struct tty_struct *tty = pInfo->tty; - - if (tty == NULL) - return; - /* FIXME: put_char should not be called from an IRQ */ - if (tty->ops->put_char) { - tty->ops->put_char(tty, ch); - } + tty_put_char(tty, ch); pInfo->bcc ^= ch; } diff --git a/drivers/char/n_tty.c b/drivers/char/n_tty.c index 708c2b1dbe5..efbfe961265 100644 --- a/drivers/char/n_tty.c +++ b/drivers/char/n_tty.c @@ -26,7 +26,7 @@ * * 2002/03/18 Implemented n_tty_wakeup to send SIGIO POLL_OUTs to * waiting writing processes-Sapan Bhatia <sapan@corewars.org>. - * Also fixed a bug in BLOCKING mode where write_chan returns + * Also fixed a bug in BLOCKING mode where n_tty_write returns * EAGAIN */ @@ -99,6 +99,7 @@ static inline int tty_put_user(struct tty_struct *tty, unsigned char x, static void n_tty_set_room(struct tty_struct *tty) { + /* tty->read_cnt is not read locked ? */ int left = N_TTY_BUF_SIZE - tty->read_cnt - 1; /* @@ -121,6 +122,16 @@ static void put_tty_queue_nolock(unsigned char c, struct tty_struct *tty) } } +/** + * put_tty_queue - add character to tty + * @c: character + * @tty: tty device + * + * Add a character to the tty read_buf queue. This is done under the + * read_lock to serialize character addition and also to protect us + * against parallel reads or flushes + */ + static void put_tty_queue(unsigned char c, struct tty_struct *tty) { unsigned long flags; @@ -137,14 +148,11 @@ static void put_tty_queue(unsigned char c, struct tty_struct *tty) * check_unthrottle - allow new receive data * @tty; tty device * - * Check whether to call the driver.unthrottle function. - * We test the TTY_THROTTLED bit first so that it always - * indicates the current state. The decision about whether - * it is worth allowing more input has been taken by the caller. + * Check whether to call the driver unthrottle functions + * * Can sleep, may be called under the atomic_read_lock mutex but * this is not guaranteed. */ - static void check_unthrottle(struct tty_struct *tty) { if (tty->count) @@ -158,6 +166,8 @@ static void check_unthrottle(struct tty_struct *tty) * Reset the read buffer counters, clear the flags, * and make sure the driver is unthrottled. Called * from n_tty_open() and n_tty_flush_buffer(). + * + * Locking: tty_read_lock for read fields. */ static void reset_buffer_flags(struct tty_struct *tty) { @@ -181,7 +191,7 @@ static void reset_buffer_flags(struct tty_struct *tty) * at hangup) or when the N_TTY line discipline internally has to * clean the pending queue (for example some signals). * - * Locking: ctrl_lock + * Locking: ctrl_lock, read_lock. */ static void n_tty_flush_buffer(struct tty_struct *tty) @@ -207,6 +217,8 @@ static void n_tty_flush_buffer(struct tty_struct *tty) * * Report the number of characters buffered to be delivered to user * at this instant in time. + * + * Locking: read_lock */ static ssize_t n_tty_chars_in_buffer(struct tty_struct *tty) @@ -346,7 +358,7 @@ static int opost(unsigned char c, struct tty_struct *tty) * the simple cases normally found and helps to generate blocks of * symbols for the console driver and thus improve performance. * - * Called from write_chan under the tty layer write lock. Relies + * Called from n_tty_write under the tty layer write lock. Relies * on lock_kernel for the tty->column state. */ @@ -410,6 +422,8 @@ break_out: * * Echo user input back onto the screen. This must be called only when * L_ECHO(tty) is true. Called from the driver receive_buf path. + * + * Relies on BKL for tty column locking */ static void echo_char(unsigned char c, struct tty_struct *tty) @@ -422,6 +436,12 @@ static void echo_char(unsigned char c, struct tty_struct *tty) opost(c, tty); } +/** + * finsh_erasing - complete erase + * @tty: tty doing the erase + * + * Relies on BKL for tty column locking + */ static inline void finish_erasing(struct tty_struct *tty) { if (tty->erasing) { @@ -439,6 +459,8 @@ static inline void finish_erasing(struct tty_struct *tty) * Perform erase and necessary output when an erase character is * present in the stream from the driver layer. Handles the complexities * of UTF-8 multibyte symbols. + * + * Locking: read_lock for tty buffers, BKL for column/erasing state */ static void eraser(unsigned char c, struct tty_struct *tty) @@ -447,6 +469,7 @@ static void eraser(unsigned char c, struct tty_struct *tty) int head, seen_alnums, cnt; unsigned long flags; + /* FIXME: locking needed ? */ if (tty->read_head == tty->canon_head) { /* opost('\a', tty); */ /* what do you think? */ return; @@ -481,6 +504,7 @@ static void eraser(unsigned char c, struct tty_struct *tty) } seen_alnums = 0; + /* FIXME: Locking ?? */ while (tty->read_head != tty->canon_head) { head = tty->read_head; @@ -583,6 +607,8 @@ static void eraser(unsigned char c, struct tty_struct *tty) * may caus terminal flushing to take place according to the termios * settings and character used. Called from the driver receive_buf * path so serialized. + * + * Locking: ctrl_lock, read_lock (both via flush buffer) */ static inline void isig(int sig, struct tty_struct *tty, int flush) @@ -1007,12 +1033,26 @@ int is_ignored(int sig) * and is protected from re-entry by the tty layer. The user is * guaranteed that this function will not be re-entered or in progress * when the ldisc is closed. + * + * Locking: Caller holds tty->termios_mutex */ static void n_tty_set_termios(struct tty_struct *tty, struct ktermios *old) { - if (!tty) - return; + int canon_change = 1; + BUG_ON(!tty); + + if (old) + canon_change = (old->c_lflag ^ tty->termios->c_lflag) & ICANON; + if (canon_change) { + memset(&tty->read_flags, 0, sizeof tty->read_flags); + tty->canon_head = tty->read_tail; + tty->canon_data = 0; + tty->erasing = 0; + } + + if (canon_change && !L_ICANON(tty) && tty->read_cnt) + wake_up_interruptible(&tty->read_wait); tty->icanon = (L_ICANON(tty) != 0); if (test_bit(TTY_HW_COOK_IN, &tty->flags)) { @@ -1143,7 +1183,7 @@ static inline int input_available_p(struct tty_struct *tty, int amt) * @b: user data * @nr: size of data * - * Helper function to speed up read_chan. It is only called when + * Helper function to speed up n_tty_read. It is only called when * ICANON is off; it copies characters straight from the tty queue to * user space directly. It can be profitably called twice; once to * drain the space from the tail pointer to the (physical) end of the @@ -1210,7 +1250,7 @@ static int job_control(struct tty_struct *tty, struct file *file) if (file->f_op->write != redirected_tty_write && current->signal->tty == tty) { if (!tty->pgrp) - printk(KERN_ERR "read_chan: no tty->pgrp!\n"); + printk(KERN_ERR "n_tty_read: no tty->pgrp!\n"); else if (task_pgrp(current) != tty->pgrp) { if (is_ignored(SIGTTIN) || is_current_pgrp_orphaned()) @@ -1225,7 +1265,7 @@ static int job_control(struct tty_struct *tty, struct file *file) /** - * read_chan - read function for tty + * n_tty_read - read function for tty * @tty: tty device * @file: file object * @buf: userspace buffer pointer @@ -1239,7 +1279,7 @@ static int job_control(struct tty_struct *tty, struct file *file) * This code must be sure never to sleep through a hangup. */ -static ssize_t read_chan(struct tty_struct *tty, struct file *file, +static ssize_t n_tty_read(struct tty_struct *tty, struct file *file, unsigned char __user *buf, size_t nr) { unsigned char __user *b = buf; @@ -1254,10 +1294,7 @@ static ssize_t read_chan(struct tty_struct *tty, struct file *file, do_it_again: - if (!tty->read_buf) { - printk(KERN_ERR "n_tty_read_chan: read_buf == NULL?!?\n"); - return -EIO; - } + BUG_ON(!tty->read_buf); c = job_control(tty, file); if (c < 0) @@ -1444,7 +1481,7 @@ do_it_again: } /** - * write_chan - write function for tty + * n_tty_write - write function for tty * @tty: tty device * @file: file object * @buf: userspace buffer pointer @@ -1458,7 +1495,7 @@ do_it_again: * This code must be sure never to sleep through a hangup. */ -static ssize_t write_chan(struct tty_struct *tty, struct file *file, +static ssize_t n_tty_write(struct tty_struct *tty, struct file *file, const unsigned char *buf, size_t nr) { const unsigned char *b = buf; @@ -1532,7 +1569,7 @@ break_out: } /** - * normal_poll - poll method for N_TTY + * n_tty_poll - poll method for N_TTY * @tty: terminal device * @file: file accessing it * @wait: poll table @@ -1545,7 +1582,7 @@ break_out: * Called without the kernel lock held - fine */ -static unsigned int normal_poll(struct tty_struct *tty, struct file *file, +static unsigned int n_tty_poll(struct tty_struct *tty, struct file *file, poll_table *wait) { unsigned int mask = 0; @@ -1573,6 +1610,44 @@ static unsigned int normal_poll(struct tty_struct *tty, struct file *file, return mask; } +static unsigned long inq_canon(struct tty_struct *tty) +{ + int nr, head, tail; + + if (!tty->canon_data) + return 0; + head = tty->canon_head; + tail = tty->read_tail; + nr = (head - tail) & (N_TTY_BUF_SIZE-1); + /* Skip EOF-chars.. */ + while (head != tail) { + if (test_bit(tail, tty->read_flags) && + tty->read_buf[tail] == __DISABLED_CHAR) + nr--; + tail = (tail+1) & (N_TTY_BUF_SIZE-1); + } + return nr; +} + +static int n_tty_ioctl(struct tty_struct *tty, struct file *file, + unsigned int cmd, unsigned long arg) +{ + int retval; + + switch (cmd) { + case TIOCOUTQ: + return put_user(tty_chars_in_buffer(tty), (int __user *) arg); + case TIOCINQ: + /* FIXME: Locking */ + retval = tty->read_cnt; + if (L_ICANON(tty)) + retval = inq_canon(tty); + return put_user(retval, (unsigned int __user *) arg); + default: + return n_tty_ioctl_helper(tty, file, cmd, arg); + } +} + struct tty_ldisc_ops tty_ldisc_N_TTY = { .magic = TTY_LDISC_MAGIC, .name = "n_tty", @@ -1580,11 +1655,11 @@ struct tty_ldisc_ops tty_ldisc_N_TTY = { .close = n_tty_close, .flush_buffer = n_tty_flush_buffer, .chars_in_buffer = n_tty_chars_in_buffer, - .read = read_chan, - .write = write_chan, + .read = n_tty_read, + .write = n_tty_write, .ioctl = n_tty_ioctl, .set_termios = n_tty_set_termios, - .poll = normal_poll, + .poll = n_tty_poll, .receive_buf = n_tty_receive_buf, .write_wakeup = n_tty_write_wakeup }; diff --git a/drivers/char/nozomi.c b/drivers/char/nozomi.c index 66a0f931c66..9a34a193528 100644 --- a/drivers/char/nozomi.c +++ b/drivers/char/nozomi.c @@ -1599,7 +1599,10 @@ static int ntty_open(struct tty_struct *tty, struct file *file) return 0; } -/* Called when the userspace process close the tty, /dev/noz*. */ +/* Called when the userspace process close the tty, /dev/noz*. Also + called immediately if ntty_open fails in which case tty->driver_data + will be NULL an we exit by the first return */ + static void ntty_close(struct tty_struct *tty, struct file *file) { struct nozomi *dc = get_dc_by_tty(tty); diff --git a/drivers/char/pcmcia/ipwireless/tty.c b/drivers/char/pcmcia/ipwireless/tty.c index b1414507997..569f2f7743a 100644 --- a/drivers/char/pcmcia/ipwireless/tty.c +++ b/drivers/char/pcmcia/ipwireless/tty.c @@ -29,7 +29,6 @@ #include <linux/tty_driver.h> #include <linux/tty_flip.h> #include <linux/uaccess.h> -#include <linux/version.h> #include "tty.h" #include "network.h" @@ -277,6 +276,7 @@ static int ipw_write_room(struct tty_struct *linux_tty) struct ipw_tty *tty = linux_tty->driver_data; int room; + /* FIXME: Exactly how is the tty object locked here .. */ if (!tty) return -ENODEV; @@ -398,6 +398,7 @@ static int set_control_lines(struct ipw_tty *tty, unsigned int set, static int ipw_tiocmget(struct tty_struct *linux_tty, struct file *file) { struct ipw_tty *tty = linux_tty->driver_data; + /* FIXME: Exactly how is the tty object locked here .. */ if (!tty) return -ENODEV; @@ -413,6 +414,7 @@ ipw_tiocmset(struct tty_struct *linux_tty, struct file *file, unsigned int set, unsigned int clear) { struct ipw_tty *tty = linux_tty->driver_data; + /* FIXME: Exactly how is the tty object locked here .. */ if (!tty) return -ENODEV; @@ -434,6 +436,8 @@ static int ipw_ioctl(struct tty_struct *linux_tty, struct file *file, if (!tty->open_count) return -EINVAL; + /* FIXME: Exactly how is the tty object locked here .. */ + switch (cmd) { case TIOCGSERIAL: return ipwireless_get_serial_info(tty, (void __user *) arg); @@ -468,13 +472,6 @@ static int ipw_ioctl(struct tty_struct *linux_tty, struct file *file, } return 0; - case TCGETS: - case TCGETA: - return n_tty_ioctl(linux_tty, file, cmd, arg); - - case TCFLSH: - return n_tty_ioctl(linux_tty, file, cmd, arg); - case FIONREAD: { int val = 0; @@ -483,10 +480,11 @@ static int ipw_ioctl(struct tty_struct *linux_tty, struct file *file, return -EFAULT; } return 0; + case TCFLSH: + return tty_perform_flush(linux_tty, arg); } } - - return -ENOIOCTLCMD; + return tty_mode_ioctl(linux_tty, file, cmd , arg); } static int add_tty(dev_node_t *nodesp, int j, @@ -589,6 +587,8 @@ void ipwireless_tty_free(struct ipw_tty *tty) tty_hangup(ttyj->linux_tty); /* Wait till the tty_hangup has completed */ flush_scheduled_work(); + /* FIXME: Exactly how is the tty object locked here + against a parallel ioctl etc */ mutex_lock(&ttyj->ipw_tty_mutex); } while (ttyj->open_count) diff --git a/drivers/char/pcmcia/synclink_cs.c b/drivers/char/pcmcia/synclink_cs.c index 05bf9c55ecc..9a626e50b79 100644 --- a/drivers/char/pcmcia/synclink_cs.c +++ b/drivers/char/pcmcia/synclink_cs.c @@ -232,7 +232,6 @@ typedef struct _mgslpc_info { /* SPPP/Cisco HDLC device parts */ int netcount; - int dosyncppp; spinlock_t netlock; #if SYNCLINK_GENERIC_HDLC @@ -459,13 +458,11 @@ static int ttymajor=0; static int debug_level = 0; static int maxframe[MAX_DEVICE_COUNT] = {0,}; -static int dosyncppp[MAX_DEVICE_COUNT] = {1,1,1,1}; module_param(break_on_load, bool, 0); module_param(ttymajor, int, 0); module_param(debug_level, int, 0); module_param_array(maxframe, int, NULL, 0); -module_param_array(dosyncppp, int, NULL, 0); MODULE_LICENSE("GPL"); @@ -2915,7 +2912,6 @@ static void mgslpc_add_device(MGSLPC_INFO *info) if (info->line < MAX_DEVICE_COUNT) { if (maxframe[info->line]) info->max_frame_size = maxframe[info->line]; - info->dosyncppp = dosyncppp[info->line]; } mgslpc_device_count++; diff --git a/drivers/char/pty.c b/drivers/char/pty.c index 76b27932d22..6d4582712b1 100644 --- a/drivers/char/pty.c +++ b/drivers/char/pty.c @@ -8,10 +8,12 @@ * Added TTY_DO_WRITE_WAKEUP to enable n_tty to send POLL_OUT to * waiting writers -- Sapan Bhatia <sapan@corewars.org> * - * + * When reading this code see also fs/devpts. In particular note that the + * driver_data field is used by the devpts side as a binding to the devpts + * inode. */ -#include <linux/module.h> /* For EXPORT_SYMBOL */ +#include <linux/module.h> #include <linux/errno.h> #include <linux/interrupt.h> @@ -23,26 +25,25 @@ #include <linux/mm.h> #include <linux/init.h> #include <linux/sysctl.h> - -#include <asm/uaccess.h> -#include <asm/system.h> +#include <linux/device.h> +#include <linux/uaccess.h> #include <linux/bitops.h> #include <linux/devpts_fs.h> +#include <asm/system.h> + /* These are global because they are accessed in tty_io.c */ #ifdef CONFIG_UNIX98_PTYS struct tty_driver *ptm_driver; static struct tty_driver *pts_driver; #endif -static void pty_close(struct tty_struct * tty, struct file * filp) +static void pty_close(struct tty_struct *tty, struct file *filp) { - if (!tty) - return; - if (tty->driver->subtype == PTY_TYPE_MASTER) { - if (tty->count > 1) - printk("master pty_close: count = %d!!\n", tty->count); - } else { + BUG_ON(!tty); + if (tty->driver->subtype == PTY_TYPE_MASTER) + WARN_ON(tty->count > 1); + else { if (tty->count > 2) return; } @@ -59,7 +60,7 @@ static void pty_close(struct tty_struct * tty, struct file * filp) set_bit(TTY_OTHER_CLOSED, &tty->flags); #ifdef CONFIG_UNIX98_PTYS if (tty->driver == ptm_driver) - devpts_pty_kill(tty->index); + devpts_pty_kill(tty->link); #endif tty_vhangup(tty->link); } @@ -69,13 +70,13 @@ static void pty_close(struct tty_struct * tty, struct file * filp) * The unthrottle routine is called by the line discipline to signal * that it can receive more characters. For PTY's, the TTY_THROTTLED * flag is always set, to force the line discipline to always call the - * unthrottle routine when there are fewer than TTY_THRESHOLD_UNTHROTTLE + * unthrottle routine when there are fewer than TTY_THRESHOLD_UNTHROTTLE * characters in the queue. This is necessary since each time this * happens, we need to wake up any sleeping processes that could be * (1) trying to send data to the pty, or (2) waiting in wait_until_sent() * for the pty buffer to be drained. */ -static void pty_unthrottle(struct tty_struct * tty) +static void pty_unthrottle(struct tty_struct *tty) { struct tty_struct *o_tty = tty->link; @@ -87,7 +88,7 @@ static void pty_unthrottle(struct tty_struct * tty) } /* - * WSH 05/24/97: modified to + * WSH 05/24/97: modified to * (1) use space in tty->flip instead of a shared temp buffer * The flip buffers aren't being used for a pty, so there's lots * of space available. The buffer is protected by a per-pty @@ -100,7 +101,8 @@ static void pty_unthrottle(struct tty_struct * tty) * not our partners. We can't just take the other one blindly without * risking deadlocks. */ -static int pty_write(struct tty_struct * tty, const unsigned char *buf, int count) +static int pty_write(struct tty_struct *tty, const unsigned char *buf, + int count) { struct tty_struct *to = tty->link; int c; @@ -112,7 +114,7 @@ static int pty_write(struct tty_struct * tty, const unsigned char *buf, int coun if (c > count) c = count; to->ldisc.ops->receive_buf(to, buf, NULL, c); - + return c; } @@ -128,17 +130,17 @@ static int pty_write_room(struct tty_struct *tty) /* * WSH 05/24/97: Modified for asymmetric MASTER/SLAVE behavior - * The chars_in_buffer() value is used by the ldisc select() function + * The chars_in_buffer() value is used by the ldisc select() function * to hold off writing when chars_in_buffer > WAKEUP_CHARS (== 256). * The pty driver chars_in_buffer() Master/Slave must behave differently: * * The Master side needs to allow typed-ahead commands to accumulate * while being canonicalized, so we report "our buffer" as empty until * some threshold is reached, and then report the count. (Any count > - * WAKEUP_CHARS is regarded by select() as "full".) To avoid deadlock - * the count returned must be 0 if no canonical data is available to be + * WAKEUP_CHARS is regarded by select() as "full".) To avoid deadlock + * the count returned must be 0 if no canonical data is available to be * read. (The N_TTY ldisc.chars_in_buffer now knows this.) - * + * * The Slave side passes all characters in raw mode to the Master side's * buffer where they can be read immediately, so in this case we can * return the true count in the buffer. @@ -155,21 +157,22 @@ static int pty_chars_in_buffer(struct tty_struct *tty) /* The ldisc must report 0 if no characters available to be read */ count = to->ldisc.ops->chars_in_buffer(to); - if (tty->driver->subtype == PTY_TYPE_SLAVE) return count; + if (tty->driver->subtype == PTY_TYPE_SLAVE) + return count; - /* Master side driver ... if the other side's read buffer is less than + /* Master side driver ... if the other side's read buffer is less than * half full, return 0 to allow writers to proceed; otherwise return - * the count. This leaves a comfortable margin to avoid overflow, + * the count. This leaves a comfortable margin to avoid overflow, * and still allows half a buffer's worth of typed-ahead commands. */ - return ((count < N_TTY_BUF_SIZE/2) ? 0 : count); + return (count < N_TTY_BUF_SIZE/2) ? 0 : count; } /* Set the lock flag on a pty */ -static int pty_set_lock(struct tty_struct *tty, int __user * arg) +static int pty_set_lock(struct tty_struct *tty, int __user *arg) { int val; - if (get_user(val,arg)) + if (get_user(val, arg)) return -EFAULT; if (val) set_bit(TTY_PTY_LOCK, &tty->flags); @@ -182,13 +185,13 @@ static void pty_flush_buffer(struct tty_struct *tty) { struct tty_struct *to = tty->link; unsigned long flags; - + if (!to) return; - + if (to->ldisc.ops->flush_buffer) to->ldisc.ops->flush_buffer(to); - + if (to->packet) { spin_lock_irqsave(&tty->ctrl_lock, flags); tty->ctrl_status |= TIOCPKT_FLUSHWRITE; @@ -197,7 +200,7 @@ static void pty_flush_buffer(struct tty_struct *tty) } } -static int pty_open(struct tty_struct *tty, struct file * filp) +static int pty_open(struct tty_struct *tty, struct file *filp) { int retval = -ENODEV; @@ -220,13 +223,65 @@ out: return retval; } -static void pty_set_termios(struct tty_struct *tty, struct ktermios *old_termios) +static void pty_set_termios(struct tty_struct *tty, + struct ktermios *old_termios) +{ + tty->termios->c_cflag &= ~(CSIZE | PARENB); + tty->termios->c_cflag |= (CS8 | CREAD); +} + +static int pty_install(struct tty_driver *driver, struct tty_struct *tty) { - tty->termios->c_cflag &= ~(CSIZE | PARENB); - tty->termios->c_cflag |= (CS8 | CREAD); + struct tty_struct *o_tty; + int idx = tty->index; + int retval; + + o_tty = alloc_tty_struct(); + if (!o_tty) + return -ENOMEM; + if (!try_module_get(driver->other->owner)) { + /* This cannot in fact currently happen */ + free_tty_struct(o_tty); + return -ENOMEM; + } + initialize_tty_struct(o_tty, driver->other, idx); + + /* We always use new tty termios data so we can do this + the easy way .. */ + retval = tty_init_termios(tty); + if (retval) + goto free_mem_out; + + retval = tty_init_termios(o_tty); + if (retval) { + tty_free_termios(tty); + goto free_mem_out; + } + + /* + * Everything allocated ... set up the o_tty structure. + */ + driver->other->ttys[idx] = o_tty; + tty_driver_kref_get(driver->other); + if (driver->subtype == PTY_TYPE_MASTER) + o_tty->count++; + /* Establish the links in both directions */ + tty->link = o_tty; + o_tty->link = tty; + + tty_driver_kref_get(driver); + tty->count++; + driver->ttys[idx] = tty; + return 0; +free_mem_out: + module_put(o_tty->driver->owner); + free_tty_struct(o_tty); + return -ENOMEM; } + static const struct tty_operations pty_ops = { + .install = pty_install, .open = pty_open, .close = pty_close, .write = pty_write, @@ -329,8 +384,11 @@ static inline void legacy_pty_init(void) { } * Otherwise one can eat up all kernel memory by opening /dev/ptmx repeatedly. */ int pty_limit = NR_UNIX98_PTY_DEFAULT; -static int pty_limit_min = 0; +static int pty_limit_min; static int pty_limit_max = NR_UNIX98_PTY_MAX; +static int pty_count; + +static struct cdev ptmx_cdev; static struct ctl_table pty_table[] = { { @@ -348,6 +406,7 @@ static struct ctl_table pty_table[] = { .procname = "nr", .maxlen = sizeof(int), .mode = 0444, + .data = &pty_count, .proc_handler = &proc_dointvec, }, { .ctl_name = 0 @@ -388,7 +447,127 @@ static int pty_unix98_ioctl(struct tty_struct *tty, struct file *file, return -ENOIOCTLCMD; } +/** + * ptm_unix98_lookup - find a pty master + * @driver: ptm driver + * @idx: tty index + * + * Look up a pty master device. Called under the tty_mutex for now. + * This provides our locking. + */ + +static struct tty_struct *ptm_unix98_lookup(struct tty_driver *driver, + struct inode *ptm_inode, int idx) +{ + struct tty_struct *tty = devpts_get_tty(ptm_inode, idx); + if (tty) + tty = tty->link; + return tty; +} + +/** + * pts_unix98_lookup - find a pty slave + * @driver: pts driver + * @idx: tty index + * + * Look up a pty master device. Called under the tty_mutex for now. + * This provides our locking. + */ + +static struct tty_struct *pts_unix98_lookup(struct tty_driver *driver, + struct inode *pts_inode, int idx) +{ + struct tty_struct *tty = devpts_get_tty(pts_inode, idx); + /* Master must be open before slave */ + if (!tty) + return ERR_PTR(-EIO); + return tty; +} + +static void pty_unix98_shutdown(struct tty_struct *tty) +{ + /* We have our own method as we don't use the tty index */ + kfree(tty->termios); +} + +/* We have no need to install and remove our tty objects as devpts does all + the work for us */ + +static int pty_unix98_install(struct tty_driver *driver, struct tty_struct *tty) +{ + struct tty_struct *o_tty; + int idx = tty->index; + + o_tty = alloc_tty_struct(); + if (!o_tty) + return -ENOMEM; + if (!try_module_get(driver->other->owner)) { + /* This cannot in fact currently happen */ + free_tty_struct(o_tty); + return -ENOMEM; + } + initialize_tty_struct(o_tty, driver->other, idx); + + tty->termios = kzalloc(sizeof(struct ktermios[2]), GFP_KERNEL); + if (tty->termios == NULL) + goto free_mem_out; + *tty->termios = driver->init_termios; + tty->termios_locked = tty->termios + 1; + + o_tty->termios = kzalloc(sizeof(struct ktermios[2]), GFP_KERNEL); + if (o_tty->termios == NULL) + goto free_mem_out; + *o_tty->termios = driver->other->init_termios; + o_tty->termios_locked = o_tty->termios + 1; + + tty_driver_kref_get(driver->other); + if (driver->subtype == PTY_TYPE_MASTER) + o_tty->count++; + /* Establish the links in both directions */ + tty->link = o_tty; + o_tty->link = tty; + /* + * All structures have been allocated, so now we install them. + * Failures after this point use release_tty to clean up, so + * there's no need to null out the local pointers. + */ + tty_driver_kref_get(driver); + tty->count++; + pty_count++; + return 0; +free_mem_out: + kfree(o_tty->termios); + module_put(o_tty->driver->owner); + free_tty_struct(o_tty); + kfree(tty->termios); + return -ENOMEM; +} + +static void pty_unix98_remove(struct tty_driver *driver, struct tty_struct *tty) +{ + pty_count--; +} + +static const struct tty_operations ptm_unix98_ops = { + .lookup = ptm_unix98_lookup, + .install = pty_unix98_install, + .remove = pty_unix98_remove, + .open = pty_open, + .close = pty_close, + .write = pty_write, + .write_room = pty_write_room, + .flush_buffer = pty_flush_buffer, + .chars_in_buffer = pty_chars_in_buffer, + .unthrottle = pty_unthrottle, + .set_termios = pty_set_termios, + .ioctl = pty_unix98_ioctl, + .shutdown = pty_unix98_shutdown +}; + static const struct tty_operations pty_unix98_ops = { + .lookup = pts_unix98_lookup, + .install = pty_unix98_install, + .remove = pty_unix98_remove, .open = pty_open, .close = pty_close, .write = pty_write, @@ -397,9 +576,73 @@ static const struct tty_operations pty_unix98_ops = { .chars_in_buffer = pty_chars_in_buffer, .unthrottle = pty_unthrottle, .set_termios = pty_set_termios, - .ioctl = pty_unix98_ioctl + .shutdown = pty_unix98_shutdown }; +/** + * ptmx_open - open a unix 98 pty master + * @inode: inode of device file + * @filp: file pointer to tty + * + * Allocate a unix98 pty master device from the ptmx driver. + * + * Locking: tty_mutex protects the init_dev work. tty->count should + * protect the rest. + * allocated_ptys_lock handles the list of free pty numbers + */ + +static int __ptmx_open(struct inode *inode, struct file *filp) +{ + struct tty_struct *tty; + int retval; + int index; + + nonseekable_open(inode, filp); + + /* find a device that is not in use. */ + index = devpts_new_index(inode); + if (index < 0) + return index; + + mutex_lock(&tty_mutex); + tty = tty_init_dev(ptm_driver, index, 1); + mutex_unlock(&tty_mutex); + + if (IS_ERR(tty)) { + retval = PTR_ERR(tty); + goto out; + } + + set_bit(TTY_PTY_LOCK, &tty->flags); /* LOCK THE SLAVE */ + filp->private_data = tty; + file_move(filp, &tty->tty_files); + + retval = devpts_pty_new(inode, tty->link); + if (retval) + goto out1; + + retval = ptm_driver->ops->open(tty, filp); + if (!retval) + return 0; +out1: + tty_release_dev(filp); + return retval; +out: + devpts_kill_index(inode, index); + 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) { @@ -427,7 +670,7 @@ static void __init unix98_pty_init(void) ptm_driver->flags = TTY_DRIVER_RESET_TERMIOS | TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV | TTY_DRIVER_DEVPTS_MEM; ptm_driver->other = pts_driver; - tty_set_operations(ptm_driver, &pty_unix98_ops); + tty_set_operations(ptm_driver, &ptm_unix98_ops); pts_driver->owner = THIS_MODULE; pts_driver->driver_name = "pty_slave"; @@ -443,16 +686,26 @@ static void __init unix98_pty_init(void) pts_driver->flags = TTY_DRIVER_RESET_TERMIOS | TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV | TTY_DRIVER_DEVPTS_MEM; pts_driver->other = ptm_driver; - tty_set_operations(pts_driver, &pty_ops); - + tty_set_operations(pts_driver, &pty_unix98_ops); + if (tty_register_driver(ptm_driver)) panic("Couldn't register Unix98 ptm driver"); if (tty_register_driver(pts_driver)) panic("Couldn't register Unix98 pts driver"); - pty_table[1].data = &ptm_driver->refcount; register_sysctl_table(pty_root_table); + + /* Now create the /dev/ptmx special device */ + tty_default_fops(&ptmx_fops); + ptmx_fops.open = ptmx_open; + + cdev_init(&ptmx_cdev, &ptmx_fops); + if (cdev_add(&ptmx_cdev, MKDEV(TTYAUX_MAJOR, 2), 1) || + register_chrdev_region(MKDEV(TTYAUX_MAJOR, 2), 1, "/dev/ptmx") < 0) + panic("Couldn't register /dev/ptmx driver\n"); + device_create(tty_class, NULL, MKDEV(TTYAUX_MAJOR, 2), NULL, "ptmx"); } + #else static inline void unix98_pty_init(void) { } #endif diff --git a/drivers/char/random.c b/drivers/char/random.c index e0d0e371909..6af435b8986 100644 --- a/drivers/char/random.c +++ b/drivers/char/random.c @@ -407,7 +407,7 @@ struct entropy_store { /* read-write data: */ spinlock_t lock; unsigned add_ptr; - int entropy_count; + int entropy_count; /* Must at no time exceed ->POOLBITS! */ int input_rotate; }; @@ -520,6 +520,7 @@ static void mix_pool_bytes(struct entropy_store *r, const void *in, int bytes) static void credit_entropy_bits(struct entropy_store *r, int nbits) { unsigned long flags; + int entropy_count; if (!nbits) return; @@ -527,20 +528,20 @@ static void credit_entropy_bits(struct entropy_store *r, int nbits) spin_lock_irqsave(&r->lock, flags); DEBUG_ENT("added %d entropy credits to %s\n", nbits, r->name); - r->entropy_count += nbits; - if (r->entropy_count < 0) { + entropy_count = r->entropy_count; + entropy_count += nbits; + if (entropy_count < 0) { DEBUG_ENT("negative entropy/overflow\n"); - r->entropy_count = 0; - } else if (r->entropy_count > r->poolinfo->POOLBITS) - r->entropy_count = r->poolinfo->POOLBITS; + entropy_count = 0; + } else if (entropy_count > r->poolinfo->POOLBITS) + entropy_count = r->poolinfo->POOLBITS; + r->entropy_count = entropy_count; /* should we wake readers? */ - if (r == &input_pool && - r->entropy_count >= random_read_wakeup_thresh) { + if (r == &input_pool && entropy_count >= random_read_wakeup_thresh) { wake_up_interruptible(&random_read_wait); kill_fasync(&fasync, SIGIO, POLL_IN); } - spin_unlock_irqrestore(&r->lock, flags); } @@ -660,10 +661,10 @@ void add_disk_randomness(struct gendisk *disk) if (!disk || !disk->random) return; /* first major is 1, so we get >= 0x200 here */ - DEBUG_ENT("disk event %d:%d\n", disk->major, disk->first_minor); + DEBUG_ENT("disk event %d:%d\n", + MAJOR(disk_devt(disk)), MINOR(disk_devt(disk))); - add_timer_randomness(disk->random, - 0x100 + MKDEV(disk->major, disk->first_minor)); + add_timer_randomness(disk->random, 0x100 + disk_devt(disk)); } #endif @@ -1571,6 +1572,7 @@ u32 secure_ipv4_port_ephemeral(__be32 saddr, __be32 daddr, __be16 dport) return half_md4_transform(hash, keyptr->secret); } +EXPORT_SYMBOL_GPL(secure_ipv4_port_ephemeral); #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) u32 secure_ipv6_port_ephemeral(const __be32 *saddr, const __be32 *daddr, diff --git a/drivers/char/rtc.c b/drivers/char/rtc.c index d9799e2bcfb..b47710c1788 100644 --- a/drivers/char/rtc.c +++ b/drivers/char/rtc.c @@ -78,7 +78,6 @@ #include <linux/wait.h> #include <linux/bcd.h> #include <linux/delay.h> -#include <linux/smp_lock.h> #include <linux/uaccess.h> #include <asm/current.h> @@ -89,12 +88,12 @@ #endif #ifdef CONFIG_SPARC32 -#include <linux/pci.h> -#include <linux/jiffies.h> -#include <asm/ebus.h> +#include <linux/of.h> +#include <linux/of_device.h> +#include <asm/io.h> static unsigned long rtc_port; -static int rtc_irq = PCI_IRQ_NONE; +static int rtc_irq; #endif #ifdef CONFIG_HPET_RTC_IRQ @@ -974,8 +973,8 @@ static int __init rtc_init(void) char *guess = NULL; #endif #ifdef CONFIG_SPARC32 - struct linux_ebus *ebus; - struct linux_ebus_device *edev; + struct device_node *ebus_dp; + struct of_device *op; #else void *r; #ifdef RTC_IRQ @@ -984,12 +983,16 @@ static int __init rtc_init(void) #endif #ifdef CONFIG_SPARC32 - for_each_ebus(ebus) { - for_each_ebusdev(edev, ebus) { - if (strcmp(edev->prom_node->name, "rtc") == 0) { - rtc_port = edev->resource[0].start; - rtc_irq = edev->irqs[0]; - goto found; + for_each_node_by_name(ebus_dp, "ebus") { + struct device_node *dp; + for (dp = ebus_dp; dp; dp = dp->sibling) { + if (!strcmp(dp->name, "rtc")) { + op = of_find_device_by_node(dp); + if (op) { + rtc_port = op->resource[0].start; + rtc_irq = op->irqs[0]; + goto found; + } } } } @@ -998,7 +1001,7 @@ static int __init rtc_init(void) return -EIO; found: - if (rtc_irq == PCI_IRQ_NONE) { + if (!rtc_irq) { rtc_has_irq = 0; goto no_irq; } diff --git a/drivers/char/stallion.c b/drivers/char/stallion.c index 19db1eb87c2..8b8f07a7f50 100644 --- a/drivers/char/stallion.c +++ b/drivers/char/stallion.c @@ -405,9 +405,9 @@ static unsigned int stl_baudrates[] = { static int stl_memioctl(struct inode *ip, struct file *fp, unsigned int cmd, unsigned long arg); static int stl_brdinit(struct stlbrd *brdp); -static int stl_getportstats(struct stlport *portp, comstats_t __user *cp); +static int stl_getportstats(struct tty_struct *tty, struct stlport *portp, comstats_t __user *cp); static int stl_clrportstats(struct stlport *portp, comstats_t __user *cp); -static int stl_waitcarrier(struct stlport *portp, struct file *filp); +static int stl_waitcarrier(struct tty_struct *tty, struct stlport *portp, struct file *filp); /* * CD1400 uart specific handling functions. @@ -612,8 +612,9 @@ static struct class *stallion_class; static void stl_cd_change(struct stlport *portp) { unsigned int oldsigs = portp->sigs; + struct tty_struct *tty = tty_port_tty_get(&portp->port); - if (!portp->port.tty) + if (!tty) return; portp->sigs = stl_getsignals(portp); @@ -623,7 +624,8 @@ static void stl_cd_change(struct stlport *portp) if ((oldsigs & TIOCM_CD) && ((portp->sigs & TIOCM_CD) == 0)) if (portp->port.flags & ASYNC_CHECK_CD) - tty_hangup(portp->port.tty); + tty_hangup(tty); + tty_kref_put(tty); } /* @@ -734,7 +736,7 @@ static int stl_open(struct tty_struct *tty, struct file *filp) * On the first open of the device setup the port hardware, and * initialize the per port data structure. */ - portp->port.tty = tty; + tty_port_tty_set(&portp->port, tty); tty->driver_data = portp; portp->port.count++; @@ -774,7 +776,7 @@ static int stl_open(struct tty_struct *tty, struct file *filp) * then also we might have to wait for carrier. */ if (!(filp->f_flags & O_NONBLOCK)) - if ((rc = stl_waitcarrier(portp, filp)) != 0) + if ((rc = stl_waitcarrier(tty, portp, filp)) != 0) return rc; portp->port.flags |= ASYNC_NORMAL_ACTIVE; @@ -789,7 +791,8 @@ static int stl_open(struct tty_struct *tty, struct file *filp) * maybe because if we are clocal then we don't need to wait... */ -static int stl_waitcarrier(struct stlport *portp, struct file *filp) +static int stl_waitcarrier(struct tty_struct *tty, struct stlport *portp, + struct file *filp) { unsigned long flags; int rc, doclocal; @@ -801,7 +804,7 @@ static int stl_waitcarrier(struct stlport *portp, struct file *filp) spin_lock_irqsave(&stallion_lock, flags); - if (portp->port.tty->termios->c_cflag & CLOCAL) + if (tty->termios->c_cflag & CLOCAL) doclocal++; portp->openwaitcnt++; @@ -846,8 +849,6 @@ static void stl_flushbuffer(struct tty_struct *tty) pr_debug("stl_flushbuffer(tty=%p)\n", tty); - if (tty == NULL) - return; portp = tty->driver_data; if (portp == NULL) return; @@ -865,8 +866,6 @@ static void stl_waituntilsent(struct tty_struct *tty, int timeout) pr_debug("stl_waituntilsent(tty=%p,timeout=%d)\n", tty, timeout); - if (tty == NULL) - return; portp = tty->driver_data; if (portp == NULL) return; @@ -949,7 +948,7 @@ static void stl_close(struct tty_struct *tty, struct file *filp) tty_ldisc_flush(tty); tty->closing = 0; - portp->port.tty = NULL; + tty_port_tty_set(&portp->port, NULL); if (portp->openwaitcnt) { if (portp->close_delay) @@ -1033,8 +1032,6 @@ static int stl_putchar(struct tty_struct *tty, unsigned char ch) pr_debug("stl_putchar(tty=%p,ch=%x)\n", tty, ch); - if (tty == NULL) - return -EINVAL; portp = tty->driver_data; if (portp == NULL) return -EINVAL; @@ -1070,8 +1067,6 @@ static void stl_flushchars(struct tty_struct *tty) pr_debug("stl_flushchars(tty=%p)\n", tty); - if (tty == NULL) - return; portp = tty->driver_data; if (portp == NULL) return; @@ -1090,8 +1085,6 @@ static int stl_writeroom(struct tty_struct *tty) pr_debug("stl_writeroom(tty=%p)\n", tty); - if (tty == NULL) - return 0; portp = tty->driver_data; if (portp == NULL) return 0; @@ -1122,8 +1115,6 @@ static int stl_charsinbuffer(struct tty_struct *tty) pr_debug("stl_charsinbuffer(tty=%p)\n", tty); - if (tty == NULL) - return 0; portp = tty->driver_data; if (portp == NULL) return 0; @@ -1183,8 +1174,9 @@ static int stl_getserial(struct stlport *portp, struct serial_struct __user *sp) * just quietly ignore any requests to change irq, etc. */ -static int stl_setserial(struct stlport *portp, struct serial_struct __user *sp) +static int stl_setserial(struct tty_struct *tty, struct serial_struct __user *sp) { + struct stlport * portp = tty->driver_data; struct serial_struct sio; pr_debug("stl_setserial(portp=%p,sp=%p)\n", portp, sp); @@ -1205,7 +1197,7 @@ static int stl_setserial(struct stlport *portp, struct serial_struct __user *sp) portp->close_delay = sio.close_delay; portp->closing_wait = sio.closing_wait; portp->custom_divisor = sio.custom_divisor; - stl_setport(portp, portp->port.tty->termios); + stl_setport(portp, tty->termios); return 0; } @@ -1215,8 +1207,6 @@ static int stl_tiocmget(struct tty_struct *tty, struct file *file) { struct stlport *portp; - if (tty == NULL) - return -ENODEV; portp = tty->driver_data; if (portp == NULL) return -ENODEV; @@ -1232,8 +1222,6 @@ static int stl_tiocmset(struct tty_struct *tty, struct file *file, struct stlport *portp; int rts = -1, dtr = -1; - if (tty == NULL) - return -ENODEV; portp = tty->driver_data; if (portp == NULL) return -ENODEV; @@ -1262,8 +1250,6 @@ static int stl_ioctl(struct tty_struct *tty, struct file *file, unsigned int cmd pr_debug("stl_ioctl(tty=%p,file=%p,cmd=%x,arg=%lx)\n", tty, file, cmd, arg); - if (tty == NULL) - return -ENODEV; portp = tty->driver_data; if (portp == NULL) return -ENODEV; @@ -1282,10 +1268,10 @@ static int stl_ioctl(struct tty_struct *tty, struct file *file, unsigned int cmd rc = stl_getserial(portp, argp); break; case TIOCSSERIAL: - rc = stl_setserial(portp, argp); + rc = stl_setserial(tty, argp); break; case COM_GETPORTSTATS: - rc = stl_getportstats(portp, argp); + rc = stl_getportstats(tty, portp, argp); break; case COM_CLRPORTSTATS: rc = stl_clrportstats(portp, argp); @@ -1317,8 +1303,6 @@ static void stl_start(struct tty_struct *tty) pr_debug("stl_start(tty=%p)\n", tty); - if (tty == NULL) - return; portp = tty->driver_data; if (portp == NULL) return; @@ -1334,8 +1318,6 @@ static void stl_settermios(struct tty_struct *tty, struct ktermios *old) pr_debug("stl_settermios(tty=%p,old=%p)\n", tty, old); - if (tty == NULL) - return; portp = tty->driver_data; if (portp == NULL) return; @@ -1369,8 +1351,6 @@ static void stl_throttle(struct tty_struct *tty) pr_debug("stl_throttle(tty=%p)\n", tty); - if (tty == NULL) - return; portp = tty->driver_data; if (portp == NULL) return; @@ -1389,8 +1369,6 @@ static void stl_unthrottle(struct tty_struct *tty) pr_debug("stl_unthrottle(tty=%p)\n", tty); - if (tty == NULL) - return; portp = tty->driver_data; if (portp == NULL) return; @@ -1410,8 +1388,6 @@ static void stl_stop(struct tty_struct *tty) pr_debug("stl_stop(tty=%p)\n", tty); - if (tty == NULL) - return; portp = tty->driver_data; if (portp == NULL) return; @@ -1432,8 +1408,6 @@ static void stl_hangup(struct tty_struct *tty) pr_debug("stl_hangup(tty=%p)\n", tty); - if (tty == NULL) - return; portp = tty->driver_data; if (portp == NULL) return; @@ -1452,7 +1426,7 @@ static void stl_hangup(struct tty_struct *tty) portp->tx.head = NULL; portp->tx.tail = NULL; } - portp->port.tty = NULL; + tty_port_tty_set(&portp->port, NULL); portp->port.flags &= ~ASYNC_NORMAL_ACTIVE; portp->port.count = 0; wake_up_interruptible(&portp->port.open_wait); @@ -1466,8 +1440,6 @@ static int stl_breakctl(struct tty_struct *tty, int state) pr_debug("stl_breakctl(tty=%p,state=%d)\n", tty, state); - if (tty == NULL) - return -EINVAL; portp = tty->driver_data; if (portp == NULL) return -EINVAL; @@ -1484,8 +1456,6 @@ static void stl_sendxchar(struct tty_struct *tty, char ch) pr_debug("stl_sendxchar(tty=%p,ch=%x)\n", tty, ch); - if (tty == NULL) - return; portp = tty->driver_data; if (portp == NULL) return; @@ -1805,7 +1775,7 @@ static int __devinit stl_initports(struct stlbrd *brdp, struct stlpanel *panelp) "(size=%Zd)\n", sizeof(struct stlport)); break; } - + tty_port_init(&portp->port); portp->magic = STL_PORTMAGIC; portp->portnr = i; portp->brdnr = panelp->brdnr; @@ -1832,6 +1802,7 @@ static void stl_cleanup_panels(struct stlbrd *brdp) struct stlpanel *panelp; struct stlport *portp; unsigned int j, k; + struct tty_struct *tty; for (j = 0; j < STL_MAXPANELS; j++) { panelp = brdp->panels[j]; @@ -1841,8 +1812,11 @@ static void stl_cleanup_panels(struct stlbrd *brdp) portp = panelp->ports[k]; if (portp == NULL) continue; - if (portp->port.tty != NULL) - stl_hangup(portp->port.tty); + tty = tty_port_tty_get(&portp->port); + if (tty != NULL) { + stl_hangup(tty); + tty_kref_put(tty); + } kfree(portp->tx.buf); kfree(portp); } @@ -2498,7 +2472,7 @@ static struct stlport *stl_getport(int brdnr, int panelnr, int portnr) * what port to get stats for (used through board control device). */ -static int stl_getportstats(struct stlport *portp, comstats_t __user *cp) +static int stl_getportstats(struct tty_struct *tty, struct stlport *portp, comstats_t __user *cp) { comstats_t stl_comstats; unsigned char *head, *tail; @@ -2525,18 +2499,17 @@ static int stl_getportstats(struct stlport *portp, comstats_t __user *cp) portp->stats.rxbuffered = 0; spin_lock_irqsave(&stallion_lock, flags); - if (portp->port.tty != NULL) - if (portp->port.tty->driver_data == portp) { - portp->stats.ttystate = portp->port.tty->flags; - /* No longer available as a statistic */ - portp->stats.rxbuffered = 1; /*portp->port.tty->flip.count; */ - if (portp->port.tty->termios != NULL) { - portp->stats.cflags = portp->port.tty->termios->c_cflag; - portp->stats.iflags = portp->port.tty->termios->c_iflag; - portp->stats.oflags = portp->port.tty->termios->c_oflag; - portp->stats.lflags = portp->port.tty->termios->c_lflag; - } + if (tty != NULL && portp->port.tty == tty) { + portp->stats.ttystate = tty->flags; + /* No longer available as a statistic */ + portp->stats.rxbuffered = 1; /*tty->flip.count; */ + if (tty->termios != NULL) { + portp->stats.cflags = tty->termios->c_cflag; + portp->stats.iflags = tty->termios->c_iflag; + portp->stats.oflags = tty->termios->c_oflag; + portp->stats.lflags = tty->termios->c_lflag; } + } spin_unlock_irqrestore(&stallion_lock, flags); head = portp->tx.head; @@ -2640,7 +2613,7 @@ static int stl_memioctl(struct inode *ip, struct file *fp, unsigned int cmd, uns switch (cmd) { case COM_GETPORTSTATS: - rc = stl_getportstats(NULL, argp); + rc = stl_getportstats(NULL, NULL, argp); break; case COM_CLRPORTSTATS: rc = stl_clrportstats(NULL, argp); @@ -3243,7 +3216,7 @@ static void stl_cd1400flowctrl(struct stlport *portp, int state) if (portp == NULL) return; - tty = portp->port.tty; + tty = tty_port_tty_get(&portp->port); if (tty == NULL) return; @@ -3288,6 +3261,7 @@ static void stl_cd1400flowctrl(struct stlport *portp, int state) BRDDISABLE(portp->brdnr); spin_unlock_irqrestore(&brd_lock, flags); + tty_kref_put(tty); } /*****************************************************************************/ @@ -3305,7 +3279,7 @@ static void stl_cd1400sendflow(struct stlport *portp, int state) if (portp == NULL) return; - tty = portp->port.tty; + tty = tty_port_tty_get(&portp->port); if (tty == NULL) return; @@ -3325,6 +3299,7 @@ static void stl_cd1400sendflow(struct stlport *portp, int state) } BRDDISABLE(portp->brdnr); spin_unlock_irqrestore(&brd_lock, flags); + tty_kref_put(tty); } /*****************************************************************************/ @@ -3478,6 +3453,7 @@ static void stl_cd1400txisr(struct stlpanel *panelp, int ioaddr) int len, stlen; char *head, *tail; unsigned char ioack, srer; + struct tty_struct *tty; pr_debug("stl_cd1400txisr(panelp=%p,ioaddr=%x)\n", panelp, ioaddr); @@ -3504,8 +3480,11 @@ static void stl_cd1400txisr(struct stlpanel *panelp, int ioaddr) if ((len == 0) || ((len < STL_TXBUFLOW) && (test_bit(ASYI_TXLOW, &portp->istate) == 0))) { set_bit(ASYI_TXLOW, &portp->istate); - if (portp->port.tty) - tty_wakeup(portp->port.tty); + tty = tty_port_tty_get(&portp->port); + if (tty) { + tty_wakeup(tty); + tty_kref_put(tty); + } } if (len == 0) { @@ -3569,7 +3548,7 @@ static void stl_cd1400rxisr(struct stlpanel *panelp, int ioaddr) return; } portp = panelp->ports[(ioack >> 3)]; - tty = portp->port.tty; + tty = tty_port_tty_get(&portp->port); if ((ioack & ACK_TYPMASK) == ACK_TYPRXGOOD) { outb((RDCR + portp->uartaddr), ioaddr); @@ -3633,10 +3612,12 @@ static void stl_cd1400rxisr(struct stlpanel *panelp, int ioaddr) } } else { printk("STALLION: bad RX interrupt ack value=%x\n", ioack); + tty_kref_put(tty); return; } stl_rxalldone: + tty_kref_put(tty); outb((EOSRR + portp->uartaddr), ioaddr); outb(0, (ioaddr + EREG_DATA)); } @@ -4175,7 +4156,7 @@ static void stl_sc26198flowctrl(struct stlport *portp, int state) if (portp == NULL) return; - tty = portp->port.tty; + tty = tty_port_tty_get(&portp->port); if (tty == NULL) return; @@ -4226,6 +4207,7 @@ static void stl_sc26198flowctrl(struct stlport *portp, int state) BRDDISABLE(portp->brdnr); spin_unlock_irqrestore(&brd_lock, flags); + tty_kref_put(tty); } /*****************************************************************************/ @@ -4244,7 +4226,7 @@ static void stl_sc26198sendflow(struct stlport *portp, int state) if (portp == NULL) return; - tty = portp->port.tty; + tty = tty_port_tty_get(&portp->port); if (tty == NULL) return; @@ -4269,6 +4251,7 @@ static void stl_sc26198sendflow(struct stlport *portp, int state) } BRDDISABLE(portp->brdnr); spin_unlock_irqrestore(&brd_lock, flags); + tty_kref_put(tty); } /*****************************************************************************/ @@ -4408,6 +4391,7 @@ static void stl_sc26198intr(struct stlpanel *panelp, unsigned int iobase) static void stl_sc26198txisr(struct stlport *portp) { + struct tty_struct *tty; unsigned int ioaddr; unsigned char mr0; int len, stlen; @@ -4422,8 +4406,11 @@ static void stl_sc26198txisr(struct stlport *portp) if ((len == 0) || ((len < STL_TXBUFLOW) && (test_bit(ASYI_TXLOW, &portp->istate) == 0))) { set_bit(ASYI_TXLOW, &portp->istate); - if (portp->port.tty) - tty_wakeup(portp->port.tty); + tty = tty_port_tty_get(&portp->port); + if (tty) { + tty_wakeup(tty); + tty_kref_put(tty); + } } if (len == 0) { @@ -4476,7 +4463,7 @@ static void stl_sc26198rxisr(struct stlport *portp, unsigned int iack) pr_debug("stl_sc26198rxisr(portp=%p,iack=%x)\n", portp, iack); - tty = portp->port.tty; + tty = tty_port_tty_get(&portp->port); ioaddr = portp->ioaddr; outb(GIBCR, (ioaddr + XP_ADDR)); len = inb(ioaddr + XP_DATA) + 1; @@ -4515,6 +4502,7 @@ static void stl_sc26198rxisr(struct stlport *portp, unsigned int iack) stl_sc26198txunflow(portp, tty); } } + tty_kref_put(tty); } /*****************************************************************************/ @@ -4528,7 +4516,7 @@ static void stl_sc26198rxbadch(struct stlport *portp, unsigned char status, char struct tty_struct *tty; unsigned int ioaddr; - tty = portp->port.tty; + tty = tty_port_tty_get(&portp->port); ioaddr = portp->ioaddr; if (status & SR_RXPARITY) @@ -4566,6 +4554,7 @@ static void stl_sc26198rxbadch(struct stlport *portp, unsigned char status, char if (status == 0) portp->stats.rxtotal++; } + tty_kref_put(tty); } /*****************************************************************************/ diff --git a/drivers/char/sx.c b/drivers/char/sx.c index c385206f9db..5b8d7a1aa3e 100644 --- a/drivers/char/sx.c +++ b/drivers/char/sx.c @@ -2504,7 +2504,7 @@ static void __devexit sx_remove_card(struct sx_board *board, del_timer(&board->timer); if (pdev) { #ifdef CONFIG_PCI - pci_iounmap(pdev, board->base); + pci_iounmap(pdev, board->base2); pci_release_region(pdev, IS_CF_BOARD(board) ? 3 : 2); #endif } else { @@ -2703,7 +2703,7 @@ static int __devinit sx_pci_probe(struct pci_dev *pdev, return 0; err_unmap: - pci_iounmap(pdev, board->base); + pci_iounmap(pdev, board->base2); err_reg: pci_release_region(pdev, reg); err_flag: diff --git a/drivers/char/synclink.c b/drivers/char/synclink.c index ef6706f0906..500f5176b6b 100644 --- a/drivers/char/synclink.c +++ b/drivers/char/synclink.c @@ -304,7 +304,6 @@ struct mgsl_struct { /* generic HDLC device parts */ int netcount; - int dosyncppp; spinlock_t netlock; #if SYNCLINK_GENERIC_HDLC @@ -868,7 +867,6 @@ static int irq[MAX_ISA_DEVICES]; static int dma[MAX_ISA_DEVICES]; static int debug_level; static int maxframe[MAX_TOTAL_DEVICES]; -static int dosyncppp[MAX_TOTAL_DEVICES]; static int txdmabufs[MAX_TOTAL_DEVICES]; static int txholdbufs[MAX_TOTAL_DEVICES]; @@ -879,7 +877,6 @@ module_param_array(irq, int, NULL, 0); module_param_array(dma, int, NULL, 0); module_param(debug_level, int, 0); module_param_array(maxframe, int, NULL, 0); -module_param_array(dosyncppp, int, NULL, 0); module_param_array(txdmabufs, int, NULL, 0); module_param_array(txholdbufs, int, NULL, 0); @@ -4258,7 +4255,6 @@ static void mgsl_add_device( struct mgsl_struct *info ) if (info->line < MAX_TOTAL_DEVICES) { if (maxframe[info->line]) info->max_frame_size = maxframe[info->line]; - info->dosyncppp = dosyncppp[info->line]; if (txdmabufs[info->line]) { info->num_tx_dma_buffers = txdmabufs[info->line]; diff --git a/drivers/char/synclink_gt.c b/drivers/char/synclink_gt.c index 3e9058993e4..08911ed6649 100644 --- a/drivers/char/synclink_gt.c +++ b/drivers/char/synclink_gt.c @@ -47,7 +47,6 @@ #include <linux/module.h> -#include <linux/version.h> #include <linux/errno.h> #include <linux/signal.h> #include <linux/sched.h> @@ -128,17 +127,14 @@ static int slgt_device_count; static int ttymajor; static int debug_level; static int maxframe[MAX_DEVICES]; -static int dosyncppp[MAX_DEVICES]; module_param(ttymajor, int, 0); module_param(debug_level, int, 0); module_param_array(maxframe, int, NULL, 0); -module_param_array(dosyncppp, int, NULL, 0); MODULE_PARM_DESC(ttymajor, "TTY major device number override: 0=auto assigned"); MODULE_PARM_DESC(debug_level, "Debug syslog output: 0=disabled, 1 to 5=increasing detail"); MODULE_PARM_DESC(maxframe, "Maximum frame size used by device (4096 to 65535)"); -MODULE_PARM_DESC(dosyncppp, "Enable synchronous net device, 0=disable 1=enable"); /* * tty support and callbacks @@ -349,7 +345,6 @@ struct slgt_info { /* SPPP/Cisco HDLC device parts */ int netcount; - int dosyncppp; spinlock_t netlock; #if SYNCLINK_GENERIC_HDLC struct net_device *netdev; @@ -3405,7 +3400,6 @@ static void add_device(struct slgt_info *info) if (info->line < MAX_DEVICES) { if (maxframe[info->line]) info->max_frame_size = maxframe[info->line]; - info->dosyncppp = dosyncppp[info->line]; } slgt_device_count++; diff --git a/drivers/char/synclinkmp.c b/drivers/char/synclinkmp.c index c0490cbd0db..6bdb44f7bec 100644 --- a/drivers/char/synclinkmp.c +++ b/drivers/char/synclinkmp.c @@ -270,7 +270,6 @@ typedef struct _synclinkmp_info { /* SPPP/Cisco HDLC device parts */ int netcount; - int dosyncppp; spinlock_t netlock; #if SYNCLINK_GENERIC_HDLC @@ -469,13 +468,11 @@ static int ttymajor = 0; */ static int debug_level = 0; static int maxframe[MAX_DEVICES] = {0,}; -static int dosyncppp[MAX_DEVICES] = {0,}; module_param(break_on_load, bool, 0); module_param(ttymajor, int, 0); module_param(debug_level, int, 0); module_param_array(maxframe, int, NULL, 0); -module_param_array(dosyncppp, int, NULL, 0); static char *driver_name = "SyncLink MultiPort driver"; static char *driver_version = "$Revision: 4.38 $"; @@ -3752,7 +3749,6 @@ static void add_device(SLMP_INFO *info) if (info->line < MAX_DEVICES) { if (maxframe[info->line]) info->max_frame_size = maxframe[info->line]; - info->dosyncppp = dosyncppp[info->line]; } synclinkmp_device_count++; diff --git a/drivers/char/tpm/Kconfig b/drivers/char/tpm/Kconfig index 3738cfa209f..f5fc64f89c5 100644 --- a/drivers/char/tpm/Kconfig +++ b/drivers/char/tpm/Kconfig @@ -6,6 +6,7 @@ menuconfig TCG_TPM tristate "TPM Hardware Support" depends on HAS_IOMEM depends on EXPERIMENTAL + select SECURITYFS ---help--- If you have a TPM security chip in your system, which implements the Trusted Computing Group's specification, diff --git a/drivers/char/tpm/tpm.c b/drivers/char/tpm/tpm.c index ae766d86845..1fee7034a38 100644 --- a/drivers/char/tpm/tpm.c +++ b/drivers/char/tpm/tpm.c @@ -954,72 +954,63 @@ EXPORT_SYMBOL_GPL(tpm_store_cancel); /* * Device file system interface to the TPM + * + * It's assured that the chip will be opened just once, + * by the check of is_open variable, which is protected + * by driver_lock. */ int tpm_open(struct inode *inode, struct file *file) { - int rc = 0, minor = iminor(inode); + int minor = iminor(inode); struct tpm_chip *chip = NULL, *pos; - lock_kernel(); - spin_lock(&driver_lock); - - list_for_each_entry(pos, &tpm_chip_list, list) { + rcu_read_lock(); + list_for_each_entry_rcu(pos, &tpm_chip_list, list) { if (pos->vendor.miscdev.minor == minor) { chip = pos; + get_device(chip->dev); break; } } + rcu_read_unlock(); - if (chip == NULL) { - rc = -ENODEV; - goto err_out; - } + if (!chip) + return -ENODEV; - if (chip->num_opens) { + if (test_and_set_bit(0, &chip->is_open)) { dev_dbg(chip->dev, "Another process owns this TPM\n"); - rc = -EBUSY; - goto err_out; + put_device(chip->dev); + return -EBUSY; } - chip->num_opens++; - get_device(chip->dev); - - spin_unlock(&driver_lock); - chip->data_buffer = kmalloc(TPM_BUFSIZE * sizeof(u8), GFP_KERNEL); if (chip->data_buffer == NULL) { - chip->num_opens--; + clear_bit(0, &chip->is_open); put_device(chip->dev); - unlock_kernel(); return -ENOMEM; } atomic_set(&chip->data_pending, 0); file->private_data = chip; - unlock_kernel(); return 0; - -err_out: - spin_unlock(&driver_lock); - unlock_kernel(); - return rc; } EXPORT_SYMBOL_GPL(tpm_open); +/* + * Called on file close + */ int tpm_release(struct inode *inode, struct file *file) { struct tpm_chip *chip = file->private_data; + del_singleshot_timer_sync(&chip->user_read_timer); flush_scheduled_work(); - spin_lock(&driver_lock); file->private_data = NULL; - del_singleshot_timer_sync(&chip->user_read_timer); atomic_set(&chip->data_pending, 0); - chip->num_opens--; - put_device(chip->dev); kfree(chip->data_buffer); - spin_unlock(&driver_lock); + clear_bit(0, &chip->is_open); + put_device(chip->dev); return 0; } EXPORT_SYMBOL_GPL(tpm_release); @@ -1093,13 +1084,11 @@ void tpm_remove_hardware(struct device *dev) } spin_lock(&driver_lock); - - list_del(&chip->list); - + list_del_rcu(&chip->list); spin_unlock(&driver_lock); + synchronize_rcu(); misc_deregister(&chip->vendor.miscdev); - sysfs_remove_group(&dev->kobj, chip->vendor.attr_group); tpm_bios_log_teardown(chip->bios_dir); @@ -1144,25 +1133,33 @@ int tpm_pm_resume(struct device *dev) } EXPORT_SYMBOL_GPL(tpm_pm_resume); +/* In case vendor provided release function, call it too.*/ + +void tpm_dev_vendor_release(struct tpm_chip *chip) +{ + if (chip->vendor.release) + chip->vendor.release(chip->dev); + + clear_bit(chip->dev_num, dev_mask); + kfree(chip->vendor.miscdev.name); +} +EXPORT_SYMBOL_GPL(tpm_dev_vendor_release); + + /* * Once all references to platform device are down to 0, * release all allocated structures. - * In case vendor provided release function, - * call it too. */ static void tpm_dev_release(struct device *dev) { struct tpm_chip *chip = dev_get_drvdata(dev); - if (chip->vendor.release) - chip->vendor.release(dev); + tpm_dev_vendor_release(chip); chip->release(dev); - - clear_bit(chip->dev_num, dev_mask); - kfree(chip->vendor.miscdev.name); kfree(chip); } +EXPORT_SYMBOL_GPL(tpm_dev_release); /* * Called from tpm_<specific>.c probe function only for devices @@ -1171,8 +1168,8 @@ static void tpm_dev_release(struct device *dev) * upon errant exit from this function specific probe function should call * pci_disable_device */ -struct tpm_chip *tpm_register_hardware(struct device *dev, const struct tpm_vendor_specific - *entry) +struct tpm_chip *tpm_register_hardware(struct device *dev, + const struct tpm_vendor_specific *entry) { #define DEVNAME_SIZE 7 @@ -1231,21 +1228,20 @@ struct tpm_chip *tpm_register_hardware(struct device *dev, const struct tpm_vend return NULL; } - spin_lock(&driver_lock); - - list_add(&chip->list, &tpm_chip_list); - - spin_unlock(&driver_lock); - if (sysfs_create_group(&dev->kobj, chip->vendor.attr_group)) { - list_del(&chip->list); misc_deregister(&chip->vendor.miscdev); put_device(chip->dev); + return NULL; } chip->bios_dir = tpm_bios_log_setup(devname); + /* Make chip available */ + spin_lock(&driver_lock); + list_add_rcu(&chip->list, &tpm_chip_list); + spin_unlock(&driver_lock); + return chip; } EXPORT_SYMBOL_GPL(tpm_register_hardware); diff --git a/drivers/char/tpm/tpm.h b/drivers/char/tpm/tpm.h index e885148b4cf..8e30df4a438 100644 --- a/drivers/char/tpm/tpm.h +++ b/drivers/char/tpm/tpm.h @@ -90,7 +90,7 @@ struct tpm_chip { struct device *dev; /* Device stuff */ int dev_num; /* /dev/tpm# */ - int num_opens; /* only one allowed */ + unsigned long is_open; /* only one allowed */ int time_expired; /* Data passed to and from the tpm via the read/write calls */ @@ -132,6 +132,7 @@ extern struct tpm_chip* tpm_register_hardware(struct device *, const struct tpm_vendor_specific *); extern int tpm_open(struct inode *, struct file *); extern int tpm_release(struct inode *, struct file *); +extern void tpm_dev_vendor_release(struct tpm_chip *); extern ssize_t tpm_write(struct file *, const char __user *, size_t, loff_t *); extern ssize_t tpm_read(struct file *, char __user *, size_t, loff_t *); diff --git a/drivers/char/tpm/tpm_tis.c b/drivers/char/tpm/tpm_tis.c index ed1879c0dd8..717af7ad1bd 100644 --- a/drivers/char/tpm/tpm_tis.c +++ b/drivers/char/tpm/tpm_tis.c @@ -630,12 +630,23 @@ static struct pnp_device_id tpm_pnp_tbl[] __devinitdata = { {"", 0} /* Terminator */ }; +static __devexit void tpm_tis_pnp_remove(struct pnp_dev *dev) +{ + struct tpm_chip *chip = pnp_get_drvdata(dev); + + tpm_dev_vendor_release(chip); + + kfree(chip); +} + + static struct pnp_driver tis_pnp_driver = { .name = "tpm_tis", .id_table = tpm_pnp_tbl, .probe = tpm_tis_pnp_init, .suspend = tpm_tis_pnp_suspend, .resume = tpm_tis_pnp_resume, + .remove = tpm_tis_pnp_remove, }; #define TIS_HID_USR_IDX sizeof(tpm_pnp_tbl)/sizeof(struct pnp_device_id) -2 @@ -683,6 +694,7 @@ static void __exit cleanup_tis(void) spin_lock(&tis_lock); list_for_each_entry_safe(i, j, &tis_chips, list) { chip = to_tpm_chip(i); + tpm_remove_hardware(chip->dev); iowrite32(~TPM_GLOBAL_INT_ENABLE & ioread32(chip->vendor.iobase + TPM_INT_ENABLE(chip->vendor. @@ -694,9 +706,9 @@ static void __exit cleanup_tis(void) free_irq(chip->vendor.irq, chip); iounmap(i->iobase); list_del(&i->list); - tpm_remove_hardware(chip->dev); } spin_unlock(&tis_lock); + if (force) { platform_device_unregister(pdev); driver_unregister(&tis_drv); diff --git a/drivers/char/tty_audit.c b/drivers/char/tty_audit.c index 3582f43345a..5787249934c 100644 --- a/drivers/char/tty_audit.c +++ b/drivers/char/tty_audit.c @@ -93,7 +93,7 @@ static void tty_audit_buf_push(struct task_struct *tsk, uid_t loginuid, get_task_comm(name, tsk); audit_log_untrustedstring(ab, name); audit_log_format(ab, " data="); - audit_log_n_untrustedstring(ab, buf->data, buf->valid); + audit_log_n_hex(ab, buf->data, buf->valid); audit_log_end(ab); } buf->valid = 0; diff --git a/drivers/char/tty_buffer.c b/drivers/char/tty_buffer.c new file mode 100644 index 00000000000..810ee25d66a --- /dev/null +++ b/drivers/char/tty_buffer.c @@ -0,0 +1,511 @@ +/* + * Tty buffer allocation management + */ + +#include <linux/types.h> +#include <linux/errno.h> +#include <linux/tty.h> +#include <linux/tty_driver.h> +#include <linux/tty_flip.h> +#include <linux/timer.h> +#include <linux/string.h> +#include <linux/slab.h> +#include <linux/sched.h> +#include <linux/init.h> +#include <linux/wait.h> +#include <linux/bitops.h> +#include <linux/delay.h> +#include <linux/module.h> + +/** + * tty_buffer_free_all - free buffers used by a tty + * @tty: tty to free from + * + * Remove all the buffers pending on a tty whether queued with data + * or in the free ring. Must be called when the tty is no longer in use + * + * Locking: none + */ + +void tty_buffer_free_all(struct tty_struct *tty) +{ + struct tty_buffer *thead; + while ((thead = tty->buf.head) != NULL) { + tty->buf.head = thead->next; + kfree(thead); + } + while ((thead = tty->buf.free) != NULL) { + tty->buf.free = thead->next; + kfree(thead); + } + tty->buf.tail = NULL; + tty->buf.memory_used = 0; +} + +/** + * tty_buffer_alloc - allocate a tty buffer + * @tty: tty device + * @size: desired size (characters) + * + * Allocate a new tty buffer to hold the desired number of characters. + * Return NULL if out of memory or the allocation would exceed the + * per device queue + * + * Locking: Caller must hold tty->buf.lock + */ + +static struct tty_buffer *tty_buffer_alloc(struct tty_struct *tty, size_t size) +{ + struct tty_buffer *p; + + if (tty->buf.memory_used + size > 65536) + return NULL; + p = kmalloc(sizeof(struct tty_buffer) + 2 * size, GFP_ATOMIC); + if (p == NULL) + return NULL; + p->used = 0; + p->size = size; + p->next = NULL; + p->commit = 0; + p->read = 0; + p->char_buf_ptr = (char *)(p->data); + p->flag_buf_ptr = (unsigned char *)p->char_buf_ptr + size; + tty->buf.memory_used += size; + return p; +} + +/** + * tty_buffer_free - free a tty buffer + * @tty: tty owning the buffer + * @b: the buffer to free + * + * Free a tty buffer, or add it to the free list according to our + * internal strategy + * + * Locking: Caller must hold tty->buf.lock + */ + +static void tty_buffer_free(struct tty_struct *tty, struct tty_buffer *b) +{ + /* Dumb strategy for now - should keep some stats */ + tty->buf.memory_used -= b->size; + WARN_ON(tty->buf.memory_used < 0); + + if (b->size >= 512) + kfree(b); + else { + b->next = tty->buf.free; + tty->buf.free = b; + } +} + +/** + * __tty_buffer_flush - flush full tty buffers + * @tty: tty to flush + * + * flush all the buffers containing receive data. Caller must + * hold the buffer lock and must have ensured no parallel flush to + * ldisc is running. + * + * Locking: Caller must hold tty->buf.lock + */ + +static void __tty_buffer_flush(struct tty_struct *tty) +{ + struct tty_buffer *thead; + + while ((thead = tty->buf.head) != NULL) { + tty->buf.head = thead->next; + tty_buffer_free(tty, thead); + } + tty->buf.tail = NULL; +} + +/** + * tty_buffer_flush - flush full tty buffers + * @tty: tty to flush + * + * flush all the buffers containing receive data. If the buffer is + * being processed by flush_to_ldisc then we defer the processing + * to that function + * + * Locking: none + */ + +void tty_buffer_flush(struct tty_struct *tty) +{ + unsigned long flags; + spin_lock_irqsave(&tty->buf.lock, flags); + + /* If the data is being pushed to the tty layer then we can't + process it here. Instead set a flag and the flush_to_ldisc + path will process the flush request before it exits */ + if (test_bit(TTY_FLUSHING, &tty->flags)) { + set_bit(TTY_FLUSHPENDING, &tty->flags); + spin_unlock_irqrestore(&tty->buf.lock, flags); + wait_event(tty->read_wait, + test_bit(TTY_FLUSHPENDING, &tty->flags) == 0); + return; + } else + __tty_buffer_flush(tty); + spin_unlock_irqrestore(&tty->buf.lock, flags); +} + +/** + * tty_buffer_find - find a free tty buffer + * @tty: tty owning the buffer + * @size: characters wanted + * + * Locate an existing suitable tty buffer or if we are lacking one then + * allocate a new one. We round our buffers off in 256 character chunks + * to get better allocation behaviour. + * + * Locking: Caller must hold tty->buf.lock + */ + +static struct tty_buffer *tty_buffer_find(struct tty_struct *tty, size_t size) +{ + struct tty_buffer **tbh = &tty->buf.free; + while ((*tbh) != NULL) { + struct tty_buffer *t = *tbh; + if (t->size >= size) { + *tbh = t->next; + t->next = NULL; + t->used = 0; + t->commit = 0; + t->read = 0; + tty->buf.memory_used += t->size; + return t; + } + tbh = &((*tbh)->next); + } + /* Round the buffer size out */ + size = (size + 0xFF) & ~0xFF; + return tty_buffer_alloc(tty, size); + /* Should possibly check if this fails for the largest buffer we + have queued and recycle that ? */ +} + +/** + * tty_buffer_request_room - grow tty buffer if needed + * @tty: tty structure + * @size: size desired + * + * Make at least size bytes of linear space available for the tty + * buffer. If we fail return the size we managed to find. + * + * Locking: Takes tty->buf.lock + */ +int tty_buffer_request_room(struct tty_struct *tty, size_t size) +{ + struct tty_buffer *b, *n; + int left; + unsigned long flags; + + spin_lock_irqsave(&tty->buf.lock, flags); + + /* OPTIMISATION: We could keep a per tty "zero" sized buffer to + remove this conditional if its worth it. This would be invisible + to the callers */ + if ((b = tty->buf.tail) != NULL) + left = b->size - b->used; + else + left = 0; + + if (left < size) { + /* This is the slow path - looking for new buffers to use */ + if ((n = tty_buffer_find(tty, size)) != NULL) { + if (b != NULL) { + b->next = n; + b->commit = b->used; + } else + tty->buf.head = n; + tty->buf.tail = n; + } else + size = left; + } + + spin_unlock_irqrestore(&tty->buf.lock, flags); + return size; +} +EXPORT_SYMBOL_GPL(tty_buffer_request_room); + +/** + * tty_insert_flip_string - Add characters to the tty buffer + * @tty: tty structure + * @chars: characters + * @size: size + * + * Queue a series of bytes to the tty buffering. All the characters + * passed are marked as without error. Returns the number added. + * + * Locking: Called functions may take tty->buf.lock + */ + +int tty_insert_flip_string(struct tty_struct *tty, const unsigned char *chars, + size_t size) +{ + int copied = 0; + do { + int space = tty_buffer_request_room(tty, size - copied); + struct tty_buffer *tb = tty->buf.tail; + /* If there is no space then tb may be NULL */ + if (unlikely(space == 0)) + break; + memcpy(tb->char_buf_ptr + tb->used, chars, space); + memset(tb->flag_buf_ptr + tb->used, TTY_NORMAL, space); + tb->used += space; + copied += space; + chars += space; + /* There is a small chance that we need to split the data over + several buffers. If this is the case we must loop */ + } while (unlikely(size > copied)); + return copied; +} +EXPORT_SYMBOL(tty_insert_flip_string); + +/** + * tty_insert_flip_string_flags - Add characters to the tty buffer + * @tty: tty structure + * @chars: characters + * @flags: flag bytes + * @size: size + * + * Queue a series of bytes to the tty buffering. For each character + * the flags array indicates the status of the character. Returns the + * number added. + * + * Locking: Called functions may take tty->buf.lock + */ + +int tty_insert_flip_string_flags(struct tty_struct *tty, + const unsigned char *chars, const char *flags, size_t size) +{ + int copied = 0; + do { + int space = tty_buffer_request_room(tty, size - copied); + struct tty_buffer *tb = tty->buf.tail; + /* If there is no space then tb may be NULL */ + if (unlikely(space == 0)) + break; + memcpy(tb->char_buf_ptr + tb->used, chars, space); + memcpy(tb->flag_buf_ptr + tb->used, flags, space); + tb->used += space; + copied += space; + chars += space; + flags += space; + /* There is a small chance that we need to split the data over + several buffers. If this is the case we must loop */ + } while (unlikely(size > copied)); + return copied; +} +EXPORT_SYMBOL(tty_insert_flip_string_flags); + +/** + * tty_schedule_flip - push characters to ldisc + * @tty: tty to push from + * + * Takes any pending buffers and transfers their ownership to the + * ldisc side of the queue. It then schedules those characters for + * processing by the line discipline. + * + * Locking: Takes tty->buf.lock + */ + +void tty_schedule_flip(struct tty_struct *tty) +{ + unsigned long flags; + spin_lock_irqsave(&tty->buf.lock, flags); + if (tty->buf.tail != NULL) + tty->buf.tail->commit = tty->buf.tail->used; + spin_unlock_irqrestore(&tty->buf.lock, flags); + schedule_delayed_work(&tty->buf.work, 1); +} +EXPORT_SYMBOL(tty_schedule_flip); + +/** + * tty_prepare_flip_string - make room for characters + * @tty: tty + * @chars: return pointer for character write area + * @size: desired size + * + * Prepare a block of space in the buffer for data. Returns the length + * available and buffer pointer to the space which is now allocated and + * accounted for as ready for normal characters. This is used for drivers + * that need their own block copy routines into the buffer. There is no + * guarantee the buffer is a DMA target! + * + * Locking: May call functions taking tty->buf.lock + */ + +int tty_prepare_flip_string(struct tty_struct *tty, unsigned char **chars, + size_t size) +{ + int space = tty_buffer_request_room(tty, size); + if (likely(space)) { + struct tty_buffer *tb = tty->buf.tail; + *chars = tb->char_buf_ptr + tb->used; + memset(tb->flag_buf_ptr + tb->used, TTY_NORMAL, space); + tb->used += space; + } + return space; +} +EXPORT_SYMBOL_GPL(tty_prepare_flip_string); + +/** + * tty_prepare_flip_string_flags - make room for characters + * @tty: tty + * @chars: return pointer for character write area + * @flags: return pointer for status flag write area + * @size: desired size + * + * Prepare a block of space in the buffer for data. Returns the length + * available and buffer pointer to the space which is now allocated and + * accounted for as ready for characters. This is used for drivers + * that need their own block copy routines into the buffer. There is no + * guarantee the buffer is a DMA target! + * + * Locking: May call functions taking tty->buf.lock + */ + +int tty_prepare_flip_string_flags(struct tty_struct *tty, + unsigned char **chars, char **flags, size_t size) +{ + int space = tty_buffer_request_room(tty, size); + if (likely(space)) { + struct tty_buffer *tb = tty->buf.tail; + *chars = tb->char_buf_ptr + tb->used; + *flags = tb->flag_buf_ptr + tb->used; + tb->used += space; + } + return space; +} +EXPORT_SYMBOL_GPL(tty_prepare_flip_string_flags); + + + +/** + * flush_to_ldisc + * @work: tty structure passed from work queue. + * + * This routine is called out of the software interrupt to flush data + * from the buffer chain to the line discipline. + * + * Locking: holds tty->buf.lock to guard buffer list. Drops the lock + * while invoking the line discipline receive_buf method. The + * receive_buf method is single threaded for each tty instance. + */ + +static void flush_to_ldisc(struct work_struct *work) +{ + struct tty_struct *tty = + container_of(work, struct tty_struct, buf.work.work); + unsigned long flags; + struct tty_ldisc *disc; + struct tty_buffer *tbuf, *head; + char *char_buf; + unsigned char *flag_buf; + + disc = tty_ldisc_ref(tty); + if (disc == NULL) /* !TTY_LDISC */ + return; + + spin_lock_irqsave(&tty->buf.lock, flags); + /* So we know a flush is running */ + set_bit(TTY_FLUSHING, &tty->flags); + head = tty->buf.head; + if (head != NULL) { + tty->buf.head = NULL; + for (;;) { + int count = head->commit - head->read; + if (!count) { + if (head->next == NULL) + break; + tbuf = head; + head = head->next; + tty_buffer_free(tty, tbuf); + continue; + } + /* Ldisc or user is trying to flush the buffers + we are feeding to the ldisc, stop feeding the + line discipline as we want to empty the queue */ + if (test_bit(TTY_FLUSHPENDING, &tty->flags)) + break; + if (!tty->receive_room) { + schedule_delayed_work(&tty->buf.work, 1); + break; + } + if (count > tty->receive_room) + count = tty->receive_room; + char_buf = head->char_buf_ptr + head->read; + flag_buf = head->flag_buf_ptr + head->read; + head->read += count; + spin_unlock_irqrestore(&tty->buf.lock, flags); + disc->ops->receive_buf(tty, char_buf, + flag_buf, count); + spin_lock_irqsave(&tty->buf.lock, flags); + } + /* Restore the queue head */ + tty->buf.head = head; + } + /* We may have a deferred request to flush the input buffer, + if so pull the chain under the lock and empty the queue */ + if (test_bit(TTY_FLUSHPENDING, &tty->flags)) { + __tty_buffer_flush(tty); + clear_bit(TTY_FLUSHPENDING, &tty->flags); + wake_up(&tty->read_wait); + } + clear_bit(TTY_FLUSHING, &tty->flags); + spin_unlock_irqrestore(&tty->buf.lock, flags); + + tty_ldisc_deref(disc); +} + +/** + * tty_flip_buffer_push - terminal + * @tty: tty to push + * + * Queue a push of the terminal flip buffers to the line discipline. This + * function must not be called from IRQ context if tty->low_latency is set. + * + * In the event of the queue being busy for flipping the work will be + * held off and retried later. + * + * Locking: tty buffer lock. Driver locks in low latency mode. + */ + +void tty_flip_buffer_push(struct tty_struct *tty) +{ + unsigned long flags; + spin_lock_irqsave(&tty->buf.lock, flags); + if (tty->buf.tail != NULL) + tty->buf.tail->commit = tty->buf.tail->used; + spin_unlock_irqrestore(&tty->buf.lock, flags); + + if (tty->low_latency) + flush_to_ldisc(&tty->buf.work.work); + else + schedule_delayed_work(&tty->buf.work, 1); +} +EXPORT_SYMBOL(tty_flip_buffer_push); + +/** + * tty_buffer_init - prepare a tty buffer structure + * @tty: tty to initialise + * + * Set up the initial state of the buffer management for a tty device. + * Must be called before the other tty buffer functions are used. + * + * Locking: none + */ + +void tty_buffer_init(struct tty_struct *tty) +{ + spin_lock_init(&tty->buf.lock); + tty->buf.head = NULL; + tty->buf.tail = NULL; + tty->buf.free = NULL; + tty->buf.memory_used = 0; + INIT_DELAYED_WORK(&tty->buf.work, flush_to_ldisc); +} + diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c index e1b46bc7e43..7053d633369 100644 --- a/drivers/char/tty_io.c +++ b/drivers/char/tty_io.c @@ -49,7 +49,7 @@ * implement CONFIG_VT and generalize console device interface. * -- Marko Kohtala <Marko.Kohtala@hut.fi>, March 97 * - * Rewrote init_dev and release_dev to eliminate races. + * Rewrote tty_init_dev and tty_release_dev to eliminate races. * -- Bill Hawes <whawes@star.net>, June 97 * * Added devfs support. @@ -136,13 +136,6 @@ LIST_HEAD(tty_drivers); /* linked list of tty drivers */ DEFINE_MUTEX(tty_mutex); EXPORT_SYMBOL(tty_mutex); -#ifdef CONFIG_UNIX98_PTYS -extern struct tty_driver *ptm_driver; /* Unix98 pty masters; for /dev/ptmx */ -static int ptmx_open(struct inode *, struct file *); -#endif - -static void initialize_tty_struct(struct tty_struct *tty); - 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 *, @@ -171,13 +164,11 @@ static void proc_set_tty(struct task_struct *tsk, struct tty_struct *tty); * Locking: none */ -static struct tty_struct *alloc_tty_struct(void) +struct tty_struct *alloc_tty_struct(void) { return kzalloc(sizeof(struct tty_struct), GFP_KERNEL); } -static void tty_buffer_free_all(struct tty_struct *); - /** * free_tty_struct - free a disused tty * @tty: tty struct to free @@ -187,7 +178,7 @@ static void tty_buffer_free_all(struct tty_struct *); * Locking: none. Must be called after tty is definitely unused */ -static inline void free_tty_struct(struct tty_struct *tty) +void free_tty_struct(struct tty_struct *tty) { kfree(tty->write_buf); tty_buffer_free_all(tty); @@ -263,398 +254,6 @@ static int check_tty_count(struct tty_struct *tty, const char *routine) return 0; } -/* - * Tty buffer allocation management - */ - -/** - * tty_buffer_free_all - free buffers used by a tty - * @tty: tty to free from - * - * Remove all the buffers pending on a tty whether queued with data - * or in the free ring. Must be called when the tty is no longer in use - * - * Locking: none - */ - -static void tty_buffer_free_all(struct tty_struct *tty) -{ - struct tty_buffer *thead; - while ((thead = tty->buf.head) != NULL) { - tty->buf.head = thead->next; - kfree(thead); - } - while ((thead = tty->buf.free) != NULL) { - tty->buf.free = thead->next; - kfree(thead); - } - tty->buf.tail = NULL; - tty->buf.memory_used = 0; -} - -/** - * tty_buffer_init - prepare a tty buffer structure - * @tty: tty to initialise - * - * Set up the initial state of the buffer management for a tty device. - * Must be called before the other tty buffer functions are used. - * - * Locking: none - */ - -static void tty_buffer_init(struct tty_struct *tty) -{ - spin_lock_init(&tty->buf.lock); - tty->buf.head = NULL; - tty->buf.tail = NULL; - tty->buf.free = NULL; - tty->buf.memory_used = 0; -} - -/** - * tty_buffer_alloc - allocate a tty buffer - * @tty: tty device - * @size: desired size (characters) - * - * Allocate a new tty buffer to hold the desired number of characters. - * Return NULL if out of memory or the allocation would exceed the - * per device queue - * - * Locking: Caller must hold tty->buf.lock - */ - -static struct tty_buffer *tty_buffer_alloc(struct tty_struct *tty, size_t size) -{ - struct tty_buffer *p; - - if (tty->buf.memory_used + size > 65536) - return NULL; - p = kmalloc(sizeof(struct tty_buffer) + 2 * size, GFP_ATOMIC); - if (p == NULL) - return NULL; - p->used = 0; - p->size = size; - p->next = NULL; - p->commit = 0; - p->read = 0; - p->char_buf_ptr = (char *)(p->data); - p->flag_buf_ptr = (unsigned char *)p->char_buf_ptr + size; - tty->buf.memory_used += size; - return p; -} - -/** - * tty_buffer_free - free a tty buffer - * @tty: tty owning the buffer - * @b: the buffer to free - * - * Free a tty buffer, or add it to the free list according to our - * internal strategy - * - * Locking: Caller must hold tty->buf.lock - */ - -static void tty_buffer_free(struct tty_struct *tty, struct tty_buffer *b) -{ - /* Dumb strategy for now - should keep some stats */ - tty->buf.memory_used -= b->size; - WARN_ON(tty->buf.memory_used < 0); - - if (b->size >= 512) - kfree(b); - else { - b->next = tty->buf.free; - tty->buf.free = b; - } -} - -/** - * __tty_buffer_flush - flush full tty buffers - * @tty: tty to flush - * - * flush all the buffers containing receive data. Caller must - * hold the buffer lock and must have ensured no parallel flush to - * ldisc is running. - * - * Locking: Caller must hold tty->buf.lock - */ - -static void __tty_buffer_flush(struct tty_struct *tty) -{ - struct tty_buffer *thead; - - while ((thead = tty->buf.head) != NULL) { - tty->buf.head = thead->next; - tty_buffer_free(tty, thead); - } - tty->buf.tail = NULL; -} - -/** - * tty_buffer_flush - flush full tty buffers - * @tty: tty to flush - * - * flush all the buffers containing receive data. If the buffer is - * being processed by flush_to_ldisc then we defer the processing - * to that function - * - * Locking: none - */ - -static void tty_buffer_flush(struct tty_struct *tty) -{ - unsigned long flags; - spin_lock_irqsave(&tty->buf.lock, flags); - - /* If the data is being pushed to the tty layer then we can't - process it here. Instead set a flag and the flush_to_ldisc - path will process the flush request before it exits */ - if (test_bit(TTY_FLUSHING, &tty->flags)) { - set_bit(TTY_FLUSHPENDING, &tty->flags); - spin_unlock_irqrestore(&tty->buf.lock, flags); - wait_event(tty->read_wait, - test_bit(TTY_FLUSHPENDING, &tty->flags) == 0); - return; - } else - __tty_buffer_flush(tty); - spin_unlock_irqrestore(&tty->buf.lock, flags); -} - -/** - * tty_buffer_find - find a free tty buffer - * @tty: tty owning the buffer - * @size: characters wanted - * - * Locate an existing suitable tty buffer or if we are lacking one then - * allocate a new one. We round our buffers off in 256 character chunks - * to get better allocation behaviour. - * - * Locking: Caller must hold tty->buf.lock - */ - -static struct tty_buffer *tty_buffer_find(struct tty_struct *tty, size_t size) -{ - struct tty_buffer **tbh = &tty->buf.free; - while ((*tbh) != NULL) { - struct tty_buffer *t = *tbh; - if (t->size >= size) { - *tbh = t->next; - t->next = NULL; - t->used = 0; - t->commit = 0; - t->read = 0; - tty->buf.memory_used += t->size; - return t; - } - tbh = &((*tbh)->next); - } - /* Round the buffer size out */ - size = (size + 0xFF) & ~0xFF; - return tty_buffer_alloc(tty, size); - /* Should possibly check if this fails for the largest buffer we - have queued and recycle that ? */ -} - -/** - * tty_buffer_request_room - grow tty buffer if needed - * @tty: tty structure - * @size: size desired - * - * Make at least size bytes of linear space available for the tty - * buffer. If we fail return the size we managed to find. - * - * Locking: Takes tty->buf.lock - */ -int tty_buffer_request_room(struct tty_struct *tty, size_t size) -{ - struct tty_buffer *b, *n; - int left; - unsigned long flags; - - spin_lock_irqsave(&tty->buf.lock, flags); - - /* OPTIMISATION: We could keep a per tty "zero" sized buffer to - remove this conditional if its worth it. This would be invisible - to the callers */ - if ((b = tty->buf.tail) != NULL) - left = b->size - b->used; - else - left = 0; - - if (left < size) { - /* This is the slow path - looking for new buffers to use */ - if ((n = tty_buffer_find(tty, size)) != NULL) { - if (b != NULL) { - b->next = n; - b->commit = b->used; - } else - tty->buf.head = n; - tty->buf.tail = n; - } else - size = left; - } - - spin_unlock_irqrestore(&tty->buf.lock, flags); - return size; -} -EXPORT_SYMBOL_GPL(tty_buffer_request_room); - -/** - * tty_insert_flip_string - Add characters to the tty buffer - * @tty: tty structure - * @chars: characters - * @size: size - * - * Queue a series of bytes to the tty buffering. All the characters - * passed are marked as without error. Returns the number added. - * - * Locking: Called functions may take tty->buf.lock - */ - -int tty_insert_flip_string(struct tty_struct *tty, const unsigned char *chars, - size_t size) -{ - int copied = 0; - do { - int space = tty_buffer_request_room(tty, size - copied); - struct tty_buffer *tb = tty->buf.tail; - /* If there is no space then tb may be NULL */ - if (unlikely(space == 0)) - break; - memcpy(tb->char_buf_ptr + tb->used, chars, space); - memset(tb->flag_buf_ptr + tb->used, TTY_NORMAL, space); - tb->used += space; - copied += space; - chars += space; - /* There is a small chance that we need to split the data over - several buffers. If this is the case we must loop */ - } while (unlikely(size > copied)); - return copied; -} -EXPORT_SYMBOL(tty_insert_flip_string); - -/** - * tty_insert_flip_string_flags - Add characters to the tty buffer - * @tty: tty structure - * @chars: characters - * @flags: flag bytes - * @size: size - * - * Queue a series of bytes to the tty buffering. For each character - * the flags array indicates the status of the character. Returns the - * number added. - * - * Locking: Called functions may take tty->buf.lock - */ - -int tty_insert_flip_string_flags(struct tty_struct *tty, - const unsigned char *chars, const char *flags, size_t size) -{ - int copied = 0; - do { - int space = tty_buffer_request_room(tty, size - copied); - struct tty_buffer *tb = tty->buf.tail; - /* If there is no space then tb may be NULL */ - if (unlikely(space == 0)) - break; - memcpy(tb->char_buf_ptr + tb->used, chars, space); - memcpy(tb->flag_buf_ptr + tb->used, flags, space); - tb->used += space; - copied += space; - chars += space; - flags += space; - /* There is a small chance that we need to split the data over - several buffers. If this is the case we must loop */ - } while (unlikely(size > copied)); - return copied; -} -EXPORT_SYMBOL(tty_insert_flip_string_flags); - -/** - * tty_schedule_flip - push characters to ldisc - * @tty: tty to push from - * - * Takes any pending buffers and transfers their ownership to the - * ldisc side of the queue. It then schedules those characters for - * processing by the line discipline. - * - * Locking: Takes tty->buf.lock - */ - -void tty_schedule_flip(struct tty_struct *tty) -{ - unsigned long flags; - spin_lock_irqsave(&tty->buf.lock, flags); - if (tty->buf.tail != NULL) - tty->buf.tail->commit = tty->buf.tail->used; - spin_unlock_irqrestore(&tty->buf.lock, flags); - schedule_delayed_work(&tty->buf.work, 1); -} -EXPORT_SYMBOL(tty_schedule_flip); - -/** - * tty_prepare_flip_string - make room for characters - * @tty: tty - * @chars: return pointer for character write area - * @size: desired size - * - * Prepare a block of space in the buffer for data. Returns the length - * available and buffer pointer to the space which is now allocated and - * accounted for as ready for normal characters. This is used for drivers - * that need their own block copy routines into the buffer. There is no - * guarantee the buffer is a DMA target! - * - * Locking: May call functions taking tty->buf.lock - */ - -int tty_prepare_flip_string(struct tty_struct *tty, unsigned char **chars, - size_t size) -{ - int space = tty_buffer_request_room(tty, size); - if (likely(space)) { - struct tty_buffer *tb = tty->buf.tail; - *chars = tb->char_buf_ptr + tb->used; - memset(tb->flag_buf_ptr + tb->used, TTY_NORMAL, space); - tb->used += space; - } - return space; -} - -EXPORT_SYMBOL_GPL(tty_prepare_flip_string); - -/** - * tty_prepare_flip_string_flags - make room for characters - * @tty: tty - * @chars: return pointer for character write area - * @flags: return pointer for status flag write area - * @size: desired size - * - * Prepare a block of space in the buffer for data. Returns the length - * available and buffer pointer to the space which is now allocated and - * accounted for as ready for characters. This is used for drivers - * that need their own block copy routines into the buffer. There is no - * guarantee the buffer is a DMA target! - * - * Locking: May call functions taking tty->buf.lock - */ - -int tty_prepare_flip_string_flags(struct tty_struct *tty, - unsigned char **chars, char **flags, size_t size) -{ - int space = tty_buffer_request_room(tty, size); - if (likely(space)) { - struct tty_buffer *tb = tty->buf.tail; - *chars = tb->char_buf_ptr + tb->used; - *flags = tb->flag_buf_ptr + tb->used; - tb->used += space; - } - return space; -} - -EXPORT_SYMBOL_GPL(tty_prepare_flip_string_flags); - - - /** * get_tty_driver - find device of a tty * @dev_t: device identifier @@ -675,7 +274,7 @@ static struct tty_driver *get_tty_driver(dev_t device, int *index) if (device < base || device >= base + p->num) continue; *index = device - base; - return p; + return tty_driver_kref_get(p); } return NULL; } @@ -695,13 +294,23 @@ struct tty_driver *tty_find_polling_driver(char *name, int *line) { struct tty_driver *p, *res = NULL; int tty_line = 0; + int len; char *str; + for (str = name; *str; str++) + if ((*str >= '0' && *str <= '9') || *str == ',') + break; + if (!*str) + return NULL; + + len = str - name; + tty_line = simple_strtoul(str, &str, 10); + mutex_lock(&tty_mutex); /* Search through the tty devices to look for a match */ list_for_each_entry(p, &tty_drivers, tty_drivers) { - str = name + strlen(p->name); - tty_line = simple_strtoul(str, &str, 10); + if (strncmp(name, p->name, len) != 0) + continue; if (*str == ',') str++; if (*str == '\0') @@ -709,7 +318,7 @@ struct tty_driver *tty_find_polling_driver(char *name, int *line) if (tty_line >= 0 && tty_line <= p->num && p->ops && p->ops->poll_init && !p->ops->poll_init(p, tty_line, str)) { - res = p; + res = tty_driver_kref_get(p); *line = tty_line; break; } @@ -809,20 +418,6 @@ static const struct file_operations tty_fops = { .fasync = tty_fasync, }; -#ifdef CONFIG_UNIX98_PTYS -static const struct file_operations ptmx_fops = { - .llseek = no_llseek, - .read = tty_read, - .write = tty_write, - .poll = tty_poll, - .unlocked_ioctl = tty_ioctl, - .compat_ioctl = tty_compat_ioctl, - .open = ptmx_open, - .release = tty_release, - .fasync = tty_fasync, -}; -#endif - static const struct file_operations console_fops = { .llseek = no_llseek, .read = tty_read, @@ -943,6 +538,7 @@ static void do_tty_hangup(struct work_struct *work) struct tty_ldisc *ld; int closecount = 0, n; unsigned long flags; + int refs = 0; if (!tty) return; @@ -1009,8 +605,12 @@ static void do_tty_hangup(struct work_struct *work) if (tty->session) { do_each_pid_task(tty->session, PIDTYPE_SID, p) { spin_lock_irq(&p->sighand->siglock); - if (p->signal->tty == tty) + if (p->signal->tty == tty) { p->signal->tty = NULL; + /* We defer the dereferences outside fo + the tasklist lock */ + refs++; + } if (!p->signal->leader) { spin_unlock_irq(&p->sighand->siglock); continue; @@ -1036,6 +636,10 @@ static void do_tty_hangup(struct work_struct *work) tty->ctrl_status = 0; spin_unlock_irqrestore(&tty->ctrl_lock, flags); + /* Account for the p->signal references we killed */ + while (refs--) + tty_kref_put(tty); + /* * If one of the devices matches a console pointer, we * cannot just call hangup() because that will cause @@ -1105,6 +709,23 @@ void tty_vhangup(struct tty_struct *tty) EXPORT_SYMBOL(tty_vhangup); /** + * tty_vhangup_self - process vhangup for own ctty + * + * Perform a vhangup on the current controlling tty + */ + +void tty_vhangup_self(void) +{ + struct tty_struct *tty; + + tty = get_current_tty(); + if (tty) { + tty_vhangup(tty); + tty_kref_put(tty); + } +} + +/** * tty_hung_up_p - was tty hung up * @filp: file pointer of tty * @@ -1157,16 +778,14 @@ void disassociate_ctty(int on_exit) struct pid *tty_pgrp = NULL; - mutex_lock(&tty_mutex); tty = get_current_tty(); if (tty) { tty_pgrp = get_pid(tty->pgrp); - mutex_unlock(&tty_mutex); lock_kernel(); - /* XXX: here we race, there is nothing protecting tty */ if (on_exit && tty->driver->type != TTY_DRIVER_TYPE_PTY) tty_vhangup(tty); unlock_kernel(); + tty_kref_put(tty); } else if (on_exit) { struct pid *old_pgrp; spin_lock_irq(¤t->sighand->siglock); @@ -1178,7 +797,6 @@ void disassociate_ctty(int on_exit) kill_pgrp(old_pgrp, SIGCONT, on_exit); put_pid(old_pgrp); } - mutex_unlock(&tty_mutex); return; } if (tty_pgrp) { @@ -1193,8 +811,6 @@ void disassociate_ctty(int on_exit) current->signal->tty_old_pgrp = NULL; spin_unlock_irq(¤t->sighand->siglock); - mutex_lock(&tty_mutex); - /* It is possible that do_tty_hangup has free'd this tty */ tty = get_current_tty(); if (tty) { unsigned long flags; @@ -1204,13 +820,13 @@ void disassociate_ctty(int on_exit) tty->session = NULL; tty->pgrp = NULL; spin_unlock_irqrestore(&tty->ctrl_lock, flags); + tty_kref_put(tty); } else { #ifdef TTY_DEBUG_HANGUP printk(KERN_DEBUG "error attempted to write to tty [0x%p]" " = NULL", tty); #endif } - mutex_unlock(&tty_mutex); /* Now clear signal->tty under the lock */ read_lock(&tasklist_lock); @@ -1410,19 +1026,19 @@ static inline ssize_t do_tty_write( /* write_buf/write_cnt is protected by the atomic_write_lock mutex */ if (tty->write_cnt < chunk) { - unsigned char *buf; + unsigned char *buf_chunk; if (chunk < 1024) chunk = 1024; - buf = kmalloc(chunk, GFP_KERNEL); - if (!buf) { + buf_chunk = kmalloc(chunk, GFP_KERNEL); + if (!buf_chunk) { ret = -ENOMEM; goto out; } kfree(tty->write_buf); tty->write_cnt = chunk; - tty->write_buf = buf; + tty->write_buf = buf_chunk; } /* Do the write .. */ @@ -1456,6 +1072,31 @@ out: return ret; } +/** + * tty_write_message - write a message to a certain tty, not just the console. + * @tty: the destination tty_struct + * @msg: the message to write + * + * This is used for messages that need to be redirected to a specific tty. + * 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. + */ + +void tty_write_message(struct tty_struct *tty, char *msg) +{ + lock_kernel(); + if (tty) { + mutex_lock(&tty->atomic_write_lock); + if (tty->ops->write && !test_bit(TTY_CLOSING, &tty->flags)) + tty->ops->write(tty, msg, strlen(msg)); + tty_write_unlock(tty); + } + unlock_kernel(); + return; +} + /** * tty_write - write method for tty device file @@ -1523,42 +1164,6 @@ ssize_t redirected_tty_write(struct file *file, const char __user *buf, return tty_write(file, buf, count, ppos); } -void tty_port_init(struct tty_port *port) -{ - memset(port, 0, sizeof(*port)); - init_waitqueue_head(&port->open_wait); - init_waitqueue_head(&port->close_wait); - mutex_init(&port->mutex); - port->close_delay = (50 * HZ) / 100; - port->closing_wait = (3000 * HZ) / 100; -} -EXPORT_SYMBOL(tty_port_init); - -int tty_port_alloc_xmit_buf(struct tty_port *port) -{ - /* We may sleep in get_zeroed_page() */ - mutex_lock(&port->mutex); - if (port->xmit_buf == NULL) - port->xmit_buf = (unsigned char *)get_zeroed_page(GFP_KERNEL); - mutex_unlock(&port->mutex); - if (port->xmit_buf == NULL) - return -ENOMEM; - return 0; -} -EXPORT_SYMBOL(tty_port_alloc_xmit_buf); - -void tty_port_free_xmit_buf(struct tty_port *port) -{ - mutex_lock(&port->mutex); - if (port->xmit_buf != NULL) { - free_page((unsigned long)port->xmit_buf); - port->xmit_buf = NULL; - } - mutex_unlock(&port->mutex); -} -EXPORT_SYMBOL(tty_port_free_xmit_buf); - - static char ptychar[] = "pqrstuvwxyzabcde"; /** @@ -1582,7 +1187,7 @@ static void pty_line_name(struct tty_driver *driver, int index, char *p) } /** - * pty_line_name - generate name for a tty + * tty_line_name - generate name for a tty * @driver: the tty driver in use * @index: the minor number * @p: output buffer of at least 7 bytes @@ -1598,10 +1203,148 @@ static void tty_line_name(struct tty_driver *driver, int index, char *p) } /** - * init_dev - initialise a tty device + * tty_driver_lookup_tty() - find an existing tty, if any + * @driver: the driver for the tty + * @idx: the minor number + * + * Return the tty, if found or ERR_PTR() otherwise. + * + * Locking: tty_mutex must be held. If tty is found, the mutex must + * be held until the 'fast-open' is also done. Will change once we + * have refcounting in the driver and per driver locking + */ +struct tty_struct *tty_driver_lookup_tty(struct tty_driver *driver, + struct inode *inode, int idx) +{ + struct tty_struct *tty; + + if (driver->ops->lookup) + return driver->ops->lookup(driver, inode, idx); + + tty = driver->ttys[idx]; + return tty; +} + +/** + * tty_init_termios - helper for termios setup + * @tty: the tty to set up + * + * Initialise the termios structures for this tty. Thus runs under + * the tty_mutex currently so we can be relaxed about ordering. + */ + +int tty_init_termios(struct tty_struct *tty) +{ + struct ktermios *tp; + int idx = tty->index; + + tp = tty->driver->termios[idx]; + if (tp == NULL) { + tp = kzalloc(sizeof(struct ktermios[2]), GFP_KERNEL); + if (tp == NULL) + return -ENOMEM; + memcpy(tp, &tty->driver->init_termios, + sizeof(struct ktermios)); + tty->driver->termios[idx] = tp; + } + tty->termios = tp; + tty->termios_locked = tp + 1; + + /* Compatibility until drivers always set this */ + tty->termios->c_ispeed = tty_termios_input_baud_rate(tty->termios); + tty->termios->c_ospeed = tty_termios_baud_rate(tty->termios); + return 0; +} + +/** + * tty_driver_install_tty() - install a tty entry in the driver + * @driver: the driver for the tty + * @tty: the tty + * + * Install a tty object into the driver tables. The tty->index field + * will be set by the time this is called. This method is responsible + * for ensuring any need additional structures are allocated and + * configured. + * + * Locking: tty_mutex for now + */ +static int tty_driver_install_tty(struct tty_driver *driver, + struct tty_struct *tty) +{ + int idx = tty->index; + + if (driver->ops->install) + return driver->ops->install(driver, tty); + + if (tty_init_termios(tty) == 0) { + tty_driver_kref_get(driver); + tty->count++; + driver->ttys[idx] = tty; + return 0; + } + return -ENOMEM; +} + +/** + * tty_driver_remove_tty() - remove a tty from the driver tables + * @driver: the driver for the tty + * @idx: the minor number + * + * Remvoe a tty object from the driver tables. The tty->index field + * will be set by the time this is called. + * + * Locking: tty_mutex for now + */ +static void tty_driver_remove_tty(struct tty_driver *driver, + struct tty_struct *tty) +{ + if (driver->ops->remove) + driver->ops->remove(driver, tty); + else + driver->ttys[tty->index] = NULL; +} + +/* + * tty_reopen() - fast re-open of an open tty + * @tty - the tty to open + * + * Return 0 on success, -errno on error. + * + * Locking: tty_mutex must be held from the time the tty was found + * till this open completes. + */ +static int tty_reopen(struct tty_struct *tty) +{ + struct tty_driver *driver = tty->driver; + + if (test_bit(TTY_CLOSING, &tty->flags)) + return -EIO; + + if (driver->type == TTY_DRIVER_TYPE_PTY && + driver->subtype == PTY_TYPE_MASTER) { + /* + * special case for PTY masters: only one open permitted, + * and the slave side open count is incremented as well. + */ + if (tty->count) + return -EIO; + + tty->link->count++; + } + tty->count++; + tty->driver = driver; /* N.B. why do this every time?? */ + + WARN_ON(!test_bit(TTY_LDISC, &tty->flags)); + + return 0; +} + +/** + * tty_init_dev - initialise a tty device * @driver: tty driver we are opening a device on * @idx: device index - * @tty: returned tty structure + * @ret_tty: returned tty structure + * @first_ok: ok to open a new device (used by ptmx) * * Prepare a tty device. This may not be a "new" clean device but * could also be an active device. The pty drivers require special @@ -1621,37 +1364,16 @@ static void tty_line_name(struct tty_driver *driver, int index, char *p) * relaxed for the (most common) case of reopening a tty. */ -static int init_dev(struct tty_driver *driver, int idx, - struct tty_struct **ret_tty) +struct tty_struct *tty_init_dev(struct tty_driver *driver, int idx, + int first_ok) { - struct tty_struct *tty, *o_tty; - struct ktermios *tp, **tp_loc, *o_tp, **o_tp_loc; - struct ktermios *ltp, **ltp_loc, *o_ltp, **o_ltp_loc; - int retval = 0; + struct tty_struct *tty; + int retval; - /* check whether we're reopening an existing tty */ - if (driver->flags & TTY_DRIVER_DEVPTS_MEM) { - tty = devpts_get_tty(idx); - /* - * If we don't have a tty here on a slave open, it's because - * the master already started the close process and there's - * no relation between devpts file and tty anymore. - */ - if (!tty && driver->subtype == PTY_TYPE_SLAVE) { - retval = -EIO; - goto end_init; - } - /* - * It's safe from now on because init_dev() is called with - * tty_mutex held and release_dev() won't change tty->count - * or tty->flags without having to grab tty_mutex - */ - if (tty && driver->subtype == PTY_TYPE_MASTER) - tty = tty->link; - } else { - tty = driver->ttys[idx]; - } - if (tty) goto fast_track; + /* Check if pty master is being opened multiple times */ + if (driver->subtype == PTY_TYPE_MASTER && + (driver->flags & TTY_DRIVER_DEVPTS_MEM) && !first_ok) + return ERR_PTR(-EIO); /* * First time open is complex, especially for PTY devices. @@ -1661,189 +1383,69 @@ static int init_dev(struct tty_driver *driver, int idx, * and locked termios may be retained.) */ - if (!try_module_get(driver->owner)) { - retval = -ENODEV; - goto end_init; - } - - o_tty = NULL; - tp = o_tp = NULL; - ltp = o_ltp = NULL; + if (!try_module_get(driver->owner)) + return ERR_PTR(-ENODEV); tty = alloc_tty_struct(); if (!tty) goto fail_no_mem; - initialize_tty_struct(tty); - tty->driver = driver; - tty->ops = driver->ops; - tty->index = idx; - tty_line_name(driver, idx, tty->name); - - if (driver->flags & TTY_DRIVER_DEVPTS_MEM) { - tp_loc = &tty->termios; - ltp_loc = &tty->termios_locked; - } else { - tp_loc = &driver->termios[idx]; - ltp_loc = &driver->termios_locked[idx]; - } - - if (!*tp_loc) { - tp = kmalloc(sizeof(struct ktermios), GFP_KERNEL); - if (!tp) - goto free_mem_out; - *tp = driver->init_termios; - } - - if (!*ltp_loc) { - ltp = kzalloc(sizeof(struct ktermios), GFP_KERNEL); - if (!ltp) - goto free_mem_out; - } - - if (driver->type == TTY_DRIVER_TYPE_PTY) { - o_tty = alloc_tty_struct(); - if (!o_tty) - goto free_mem_out; - initialize_tty_struct(o_tty); - o_tty->driver = driver->other; - o_tty->ops = driver->ops; - o_tty->index = idx; - tty_line_name(driver->other, idx, o_tty->name); - - if (driver->flags & TTY_DRIVER_DEVPTS_MEM) { - o_tp_loc = &o_tty->termios; - o_ltp_loc = &o_tty->termios_locked; - } else { - o_tp_loc = &driver->other->termios[idx]; - o_ltp_loc = &driver->other->termios_locked[idx]; - } - - if (!*o_tp_loc) { - o_tp = kmalloc(sizeof(struct ktermios), GFP_KERNEL); - if (!o_tp) - goto free_mem_out; - *o_tp = driver->other->init_termios; - } + initialize_tty_struct(tty, driver, idx); - if (!*o_ltp_loc) { - o_ltp = kzalloc(sizeof(struct ktermios), GFP_KERNEL); - if (!o_ltp) - goto free_mem_out; - } - - /* - * Everything allocated ... set up the o_tty structure. - */ - if (!(driver->other->flags & TTY_DRIVER_DEVPTS_MEM)) - driver->other->ttys[idx] = o_tty; - if (!*o_tp_loc) - *o_tp_loc = o_tp; - if (!*o_ltp_loc) - *o_ltp_loc = o_ltp; - o_tty->termios = *o_tp_loc; - o_tty->termios_locked = *o_ltp_loc; - driver->other->refcount++; - if (driver->subtype == PTY_TYPE_MASTER) - o_tty->count++; - - /* Establish the links in both directions */ - tty->link = o_tty; - o_tty->link = tty; + retval = tty_driver_install_tty(driver, tty); + if (retval < 0) { + free_tty_struct(tty); + module_put(driver->owner); + return ERR_PTR(retval); } /* - * All structures have been allocated, so now we install them. - * Failures after this point use release_tty to clean up, so - * there's no need to null out the local pointers. - */ - if (!(driver->flags & TTY_DRIVER_DEVPTS_MEM)) - driver->ttys[idx] = tty; - - if (!*tp_loc) - *tp_loc = tp; - if (!*ltp_loc) - *ltp_loc = ltp; - tty->termios = *tp_loc; - tty->termios_locked = *ltp_loc; - /* Compatibility until drivers always set this */ - tty->termios->c_ispeed = tty_termios_input_baud_rate(tty->termios); - tty->termios->c_ospeed = tty_termios_baud_rate(tty->termios); - driver->refcount++; - tty->count++; - - /* * Structures all installed ... call the ldisc open routines. * If we fail here just call release_tty to clean up. No need * to decrement the use counts, as release_tty doesn't care. */ - retval = tty_ldisc_setup(tty, o_tty); - + retval = tty_ldisc_setup(tty, tty->link); if (retval) goto release_mem_out; - goto success; - - /* - * This fast open can be used if the tty is already open. - * No memory is allocated, and the only failures are from - * attempting to open a closing tty or attempting multiple - * opens on a pty master. - */ -fast_track: - if (test_bit(TTY_CLOSING, &tty->flags)) { - retval = -EIO; - goto end_init; - } - if (driver->type == TTY_DRIVER_TYPE_PTY && - driver->subtype == PTY_TYPE_MASTER) { - /* - * special case for PTY masters: only one open permitted, - * and the slave side open count is incremented as well. - */ - if (tty->count) { - retval = -EIO; - goto end_init; - } - tty->link->count++; - } - tty->count++; - tty->driver = driver; /* N.B. why do this every time?? */ - - /* FIXME */ - if (!test_bit(TTY_LDISC, &tty->flags)) - printk(KERN_ERR "init_dev but no ldisc\n"); -success: - *ret_tty = tty; - - /* All paths come through here to release the mutex */ -end_init: - return retval; - - /* Release locally allocated memory ... nothing placed in slots */ -free_mem_out: - kfree(o_tp); - if (o_tty) - free_tty_struct(o_tty); - kfree(ltp); - kfree(tp); - free_tty_struct(tty); + return tty; fail_no_mem: module_put(driver->owner); - retval = -ENOMEM; - goto end_init; + return ERR_PTR(-ENOMEM); /* call the tty release_tty routine to clean out this slot */ release_mem_out: if (printk_ratelimit()) - printk(KERN_INFO "init_dev: ldisc open failed, " + printk(KERN_INFO "tty_init_dev: ldisc open failed, " "clearing slot %d\n", idx); release_tty(tty, idx); - goto end_init; + return ERR_PTR(retval); } +void tty_free_termios(struct tty_struct *tty) +{ + struct ktermios *tp; + int idx = tty->index; + /* Kill this flag and push into drivers for locking etc */ + if (tty->driver->flags & TTY_DRIVER_RESET_TERMIOS) { + /* FIXME: Locking on ->termios array */ + tp = tty->termios; + tty->driver->termios[idx] = NULL; + kfree(tp); + } +} +EXPORT_SYMBOL(tty_free_termios); + +void tty_shutdown(struct tty_struct *tty) +{ + tty_driver_remove_tty(tty->driver, tty); + tty_free_termios(tty); +} +EXPORT_SYMBOL(tty_shutdown); + /** * release_one_tty - release tty structure memory + * @kref: kref of tty we are obliterating * * Releases memory associated with a tty structure, and clears out the * driver table slots. This function is called when a device is no longer @@ -1853,31 +1455,19 @@ release_mem_out: * tty_mutex - sometimes only * takes the file list lock internally when working on the list * of ttys that the driver keeps. - * FIXME: should we require tty_mutex is held here ?? */ -static void release_one_tty(struct tty_struct *tty, int idx) +static void release_one_tty(struct kref *kref) { - int devpts = tty->driver->flags & TTY_DRIVER_DEVPTS_MEM; - struct ktermios *tp; - - if (!devpts) - tty->driver->ttys[idx] = NULL; - - if (tty->driver->flags & TTY_DRIVER_RESET_TERMIOS) { - tp = tty->termios; - if (!devpts) - tty->driver->termios[idx] = NULL; - kfree(tp); - - tp = tty->termios_locked; - if (!devpts) - tty->driver->termios_locked[idx] = NULL; - kfree(tp); - } - + struct tty_struct *tty = container_of(kref, struct tty_struct, kref); + struct tty_driver *driver = tty->driver; + if (tty->ops->shutdown) + tty->ops->shutdown(tty); + else + tty_shutdown(tty); tty->magic = 0; - tty->driver->refcount--; + tty_driver_kref_put(driver); + module_put(driver->owner); file_list_lock(); list_del_init(&tty->tty_files); @@ -1887,6 +1477,21 @@ static void release_one_tty(struct tty_struct *tty, int idx) } /** + * tty_kref_put - release a tty kref + * @tty: tty device + * + * Release a reference to a tty device and if need be let the kref + * layer destruct the object for us + */ + +void tty_kref_put(struct tty_struct *tty) +{ + if (tty) + kref_put(&tty->kref, release_one_tty); +} +EXPORT_SYMBOL(tty_kref_put); + +/** * release_tty - release tty structure memory * * Release both @tty and a possible linked partner (think pty pair), @@ -1897,15 +1502,16 @@ static void release_one_tty(struct tty_struct *tty, int idx) * takes the file list lock internally when working on the list * of ttys that the driver keeps. * FIXME: should we require tty_mutex is held here ?? + * */ static void release_tty(struct tty_struct *tty, int idx) { - struct tty_driver *driver = tty->driver; + /* This should always be true but check for the moment */ + WARN_ON(tty->index != idx); if (tty->link) - release_one_tty(tty->link, idx); - release_one_tty(tty, idx); - module_put(driver->owner); + tty_kref_put(tty->link); + tty_kref_put(tty); } /* @@ -1916,20 +1522,21 @@ static void release_tty(struct tty_struct *tty, int idx) * WSH 09/09/97: rewritten to avoid some nasty race conditions that could * lead to double frees or releasing memory still in use. */ -static void release_dev(struct file *filp) +void tty_release_dev(struct file *filp) { struct tty_struct *tty, *o_tty; int pty_master, tty_closing, o_tty_closing, do_sleep; int devpts; int idx; char buf[64]; + struct inode *inode; + inode = filp->f_path.dentry->d_inode; tty = (struct tty_struct *)filp->private_data; - if (tty_paranoia_check(tty, filp->f_path.dentry->d_inode, - "release_dev")) + if (tty_paranoia_check(tty, inode, "tty_release_dev")) return; - check_tty_count(tty, "release_dev"); + check_tty_count(tty, "tty_release_dev"); tty_fasync(-1, filp, 0); @@ -1941,33 +1548,27 @@ static void release_dev(struct file *filp) #ifdef TTY_PARANOIA_CHECK if (idx < 0 || idx >= tty->driver->num) { - printk(KERN_DEBUG "release_dev: bad idx when trying to " + printk(KERN_DEBUG "tty_release_dev: bad idx when trying to " "free (%s)\n", tty->name); return; } - if (!(tty->driver->flags & TTY_DRIVER_DEVPTS_MEM)) { + if (!devpts) { if (tty != tty->driver->ttys[idx]) { - printk(KERN_DEBUG "release_dev: driver.table[%d] not tty " + printk(KERN_DEBUG "tty_release_dev: driver.table[%d] not tty " "for (%s)\n", idx, tty->name); return; } if (tty->termios != tty->driver->termios[idx]) { - printk(KERN_DEBUG "release_dev: driver.termios[%d] not termios " + printk(KERN_DEBUG "tty_release_dev: driver.termios[%d] not termios " "for (%s)\n", idx, tty->name); return; } - if (tty->termios_locked != tty->driver->termios_locked[idx]) { - printk(KERN_DEBUG "release_dev: driver.termios_locked[%d] not " - "termios_locked for (%s)\n", - idx, tty->name); - return; - } } #endif #ifdef TTY_DEBUG_HANGUP - printk(KERN_DEBUG "release_dev of %s (tty count=%d)...", + printk(KERN_DEBUG "tty_release_dev of %s (tty count=%d)...", tty_name(tty, buf), tty->count); #endif @@ -1975,26 +1576,19 @@ static void release_dev(struct file *filp) if (tty->driver->other && !(tty->driver->flags & TTY_DRIVER_DEVPTS_MEM)) { if (o_tty != tty->driver->other->ttys[idx]) { - printk(KERN_DEBUG "release_dev: other->table[%d] " + printk(KERN_DEBUG "tty_release_dev: other->table[%d] " "not o_tty for (%s)\n", idx, tty->name); return; } if (o_tty->termios != tty->driver->other->termios[idx]) { - printk(KERN_DEBUG "release_dev: other->termios[%d] " + printk(KERN_DEBUG "tty_release_dev: other->termios[%d] " "not o_termios for (%s)\n", idx, tty->name); return; } - if (o_tty->termios_locked != - tty->driver->other->termios_locked[idx]) { - printk(KERN_DEBUG "release_dev: other->termios_locked[" - "%d] not o_termios_locked for (%s)\n", - idx, tty->name); - return; - } if (o_tty->link != tty) { - printk(KERN_DEBUG "release_dev: bad pty pointers\n"); + printk(KERN_DEBUG "tty_release_dev: bad pty pointers\n"); return; } } @@ -2052,7 +1646,7 @@ static void release_dev(struct file *filp) if (!do_sleep) break; - printk(KERN_WARNING "release_dev: %s: read/write wait queue " + printk(KERN_WARNING "tty_release_dev: %s: read/write wait queue " "active!\n", tty_name(tty, buf)); mutex_unlock(&tty_mutex); schedule(); @@ -2065,14 +1659,14 @@ static void release_dev(struct file *filp) */ if (pty_master) { if (--o_tty->count < 0) { - printk(KERN_WARNING "release_dev: bad pty slave count " + printk(KERN_WARNING "tty_release_dev: bad pty slave count " "(%d) for %s\n", o_tty->count, tty_name(o_tty, buf)); o_tty->count = 0; } } if (--tty->count < 0) { - printk(KERN_WARNING "release_dev: bad tty->count (%d) for %s\n", + printk(KERN_WARNING "tty_release_dev: bad tty->count (%d) for %s\n", tty->count, tty_name(tty, buf)); tty->count = 0; } @@ -2135,11 +1729,11 @@ static void release_dev(struct file *filp) /* Make this pty number available for reallocation */ if (devpts) - devpts_kill_index(idx); + devpts_kill_index(inode, idx); } /** - * tty_open - open a tty device + * __tty_open - open a tty device * @inode: inode of device file * @filp: file pointer to tty * @@ -2154,14 +1748,14 @@ static void release_dev(struct file *filp) * The termios state of a pty is reset on first open so that * settings don't persist across reuse. * - * Locking: tty_mutex protects tty, get_tty_driver and init_dev work. + * Locking: tty_mutex protects tty, get_tty_driver and tty_init_dev work. * tty->count should protect the rest. * ->siglock protects ->signal/->sighand */ static int __tty_open(struct inode *inode, struct file *filp) { - struct tty_struct *tty; + struct tty_struct *tty = NULL; int noctty, retval; struct tty_driver *driver; int index; @@ -2183,23 +1777,25 @@ retry_open: mutex_unlock(&tty_mutex); return -ENXIO; } - driver = tty->driver; + driver = tty_driver_kref_get(tty->driver); index = tty->index; filp->f_flags |= O_NONBLOCK; /* Don't let /dev/tty block */ /* noctty = 1; */ + /* FIXME: Should we take a driver reference ? */ + tty_kref_put(tty); goto got_driver; } #ifdef CONFIG_VT if (device == MKDEV(TTY_MAJOR, 0)) { extern struct tty_driver *console_driver; - driver = console_driver; + driver = tty_driver_kref_get(console_driver); index = fg_console; noctty = 1; goto got_driver; } #endif if (device == MKDEV(TTYAUX_MAJOR, 1)) { - driver = console_device(&index); + driver = tty_driver_kref_get(console_device(&index)); if (driver) { /* Don't let /dev/console block */ filp->f_flags |= O_NONBLOCK; @@ -2216,10 +1812,25 @@ retry_open: return -ENODEV; } got_driver: - retval = init_dev(driver, index, &tty); + if (!tty) { + /* check whether we're reopening an existing tty */ + tty = tty_driver_lookup_tty(driver, inode, index); + + if (IS_ERR(tty)) + return PTR_ERR(tty); + } + + if (tty) { + retval = tty_reopen(tty); + if (retval) + tty = ERR_PTR(retval); + } else + tty = tty_init_dev(driver, index, 0); + mutex_unlock(&tty_mutex); - if (retval) - return retval; + tty_driver_kref_put(driver); + if (IS_ERR(tty)) + return PTR_ERR(tty); filp->private_data = tty; file_move(filp, &tty->tty_files); @@ -2247,7 +1858,7 @@ got_driver: printk(KERN_DEBUG "error %d in opening %s...", retval, tty->name); #endif - release_dev(filp); + tty_release_dev(filp); if (retval != -ERESTARTSYS) return retval; if (signal_pending(current)) @@ -2286,69 +1897,6 @@ static int tty_open(struct inode *inode, struct file *filp) -#ifdef CONFIG_UNIX98_PTYS -/** - * ptmx_open - open a unix 98 pty master - * @inode: inode of device file - * @filp: file pointer to tty - * - * Allocate a unix98 pty master device from the ptmx driver. - * - * Locking: tty_mutex protects theinit_dev work. tty->count should - * protect the rest. - * allocated_ptys_lock handles the list of free pty numbers - */ - -static int __ptmx_open(struct inode *inode, struct file *filp) -{ - struct tty_struct *tty; - int retval; - int index; - - nonseekable_open(inode, filp); - - /* find a device that is not in use. */ - index = devpts_new_index(); - if (index < 0) - return index; - - mutex_lock(&tty_mutex); - retval = init_dev(ptm_driver, index, &tty); - mutex_unlock(&tty_mutex); - - if (retval) - goto out; - - set_bit(TTY_PTY_LOCK, &tty->flags); /* LOCK THE SLAVE */ - filp->private_data = tty; - file_move(filp, &tty->tty_files); - - retval = devpts_pty_new(tty->link); - if (retval) - goto out1; - - check_tty_count(tty, "ptmx_open"); - retval = ptm_driver->ops->open(tty, filp); - if (!retval) - return 0; -out1: - release_dev(filp); - return retval; -out: - devpts_kill_index(index); - 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; -} -#endif /** * tty_release - vfs callback for close @@ -2359,13 +1907,13 @@ static int ptmx_open(struct inode *inode, struct file *filp) * this tty. There may however be several such references. * * Locking: - * Takes bkl. See release_dev + * Takes bkl. See tty_release_dev */ static int tty_release(struct inode *inode, struct file *filp) { lock_kernel(); - release_dev(filp); + tty_release_dev(filp); unlock_kernel(); return 0; } @@ -2496,45 +2044,26 @@ static int tiocgwinsz(struct tty_struct *tty, struct winsize __user *arg) } /** - * tiocswinsz - implement window size set ioctl - * @tty; tty - * @arg: user buffer for result - * - * Copies the user idea of the window size to the kernel. Traditionally - * this is just advisory information but for the Linux console it - * actually has driver level meaning and triggers a VC resize. + * tty_do_resize - resize event + * @tty: tty being resized + * @real_tty: real tty (not the same as tty if using a pty/tty pair) + * @rows: rows (character) + * @cols: cols (character) * - * Locking: - * Called function use the console_sem is used to ensure we do - * not try and resize the console twice at once. - * The tty->termios_mutex is used to ensure we don't double - * resize and get confused. Lock order - tty->termios_mutex before - * console sem + * Update the termios variables and send the neccessary signals to + * peform a terminal resize correctly */ -static int tiocswinsz(struct tty_struct *tty, struct tty_struct *real_tty, - struct winsize __user *arg) +int tty_do_resize(struct tty_struct *tty, struct tty_struct *real_tty, + struct winsize *ws) { - struct winsize tmp_ws; struct pid *pgrp, *rpgrp; unsigned long flags; - if (copy_from_user(&tmp_ws, arg, sizeof(*arg))) - return -EFAULT; - - mutex_lock(&tty->termios_mutex); - if (!memcmp(&tmp_ws, &tty->winsize, sizeof(*arg))) + /* For a PTY we need to lock the tty side */ + mutex_lock(&real_tty->termios_mutex); + if (!memcmp(ws, &real_tty->winsize, sizeof(*ws))) goto done; - -#ifdef CONFIG_VT - if (tty->driver->type == TTY_DRIVER_TYPE_CONSOLE) { - if (vc_lock_resize(tty->driver_data, tmp_ws.ws_col, - tmp_ws.ws_row)) { - mutex_unlock(&tty->termios_mutex); - return -ENXIO; - } - } -#endif /* Get the PID values and reference them so we can avoid holding the tty ctrl lock while sending signals */ spin_lock_irqsave(&tty->ctrl_lock, flags); @@ -2550,14 +2079,42 @@ static int tiocswinsz(struct tty_struct *tty, struct tty_struct *real_tty, put_pid(pgrp); put_pid(rpgrp); - tty->winsize = tmp_ws; - real_tty->winsize = tmp_ws; + tty->winsize = *ws; + real_tty->winsize = *ws; done: - mutex_unlock(&tty->termios_mutex); + mutex_unlock(&real_tty->termios_mutex); return 0; } /** + * tiocswinsz - implement window size set ioctl + * @tty; tty + * @arg: user buffer for result + * + * Copies the user idea of the window size to the kernel. Traditionally + * this is just advisory information but for the Linux console it + * actually has driver level meaning and triggers a VC resize. + * + * Locking: + * Driver dependant. The default do_resize method takes the + * tty termios mutex and ctrl_lock. The console takes its own lock + * then calls into the default method. + */ + +static int tiocswinsz(struct tty_struct *tty, struct tty_struct *real_tty, + struct winsize __user *arg) +{ + struct winsize tmp_ws; + if (copy_from_user(&tmp_ws, arg, sizeof(*arg))) + return -EFAULT; + + if (tty->ops->resize) + return tty->ops->resize(tty, real_tty, &tmp_ws); + else + return tty_do_resize(tty, real_tty, &tmp_ws); +} + +/** * tioccons - allow admin to move logical console * @file: the file to become console * @@ -2977,7 +2534,7 @@ long tty_ioctl(struct file *file, unsigned int cmd, unsigned long arg) case TIOCSTI: return tiocsti(tty, p); case TIOCGWINSZ: - return tiocgwinsz(tty, p); + return tiocgwinsz(real_tty, p); case TIOCSWINSZ: return tiocswinsz(tty, real_tty, p); case TIOCCONS: @@ -3007,10 +2564,6 @@ long tty_ioctl(struct file *file, unsigned int cmd, unsigned long arg) return put_user(tty->ldisc.ops->num, (int __user *)p); case TIOCSETD: return tiocsetd(tty, p); -#ifdef CONFIG_VT - case TIOCLINUX: - return tioclinux(tty, arg); -#endif /* * Break handling */ @@ -3201,113 +2754,6 @@ void do_SAK(struct tty_struct *tty) EXPORT_SYMBOL(do_SAK); /** - * flush_to_ldisc - * @work: tty structure passed from work queue. - * - * This routine is called out of the software interrupt to flush data - * from the buffer chain to the line discipline. - * - * Locking: holds tty->buf.lock to guard buffer list. Drops the lock - * while invoking the line discipline receive_buf method. The - * receive_buf method is single threaded for each tty instance. - */ - -static void flush_to_ldisc(struct work_struct *work) -{ - struct tty_struct *tty = - container_of(work, struct tty_struct, buf.work.work); - unsigned long flags; - struct tty_ldisc *disc; - struct tty_buffer *tbuf, *head; - char *char_buf; - unsigned char *flag_buf; - - disc = tty_ldisc_ref(tty); - if (disc == NULL) /* !TTY_LDISC */ - return; - - spin_lock_irqsave(&tty->buf.lock, flags); - /* So we know a flush is running */ - set_bit(TTY_FLUSHING, &tty->flags); - head = tty->buf.head; - if (head != NULL) { - tty->buf.head = NULL; - for (;;) { - int count = head->commit - head->read; - if (!count) { - if (head->next == NULL) - break; - tbuf = head; - head = head->next; - tty_buffer_free(tty, tbuf); - continue; - } - /* Ldisc or user is trying to flush the buffers - we are feeding to the ldisc, stop feeding the - line discipline as we want to empty the queue */ - if (test_bit(TTY_FLUSHPENDING, &tty->flags)) - break; - if (!tty->receive_room) { - schedule_delayed_work(&tty->buf.work, 1); - break; - } - if (count > tty->receive_room) - count = tty->receive_room; - char_buf = head->char_buf_ptr + head->read; - flag_buf = head->flag_buf_ptr + head->read; - head->read += count; - spin_unlock_irqrestore(&tty->buf.lock, flags); - disc->ops->receive_buf(tty, char_buf, - flag_buf, count); - spin_lock_irqsave(&tty->buf.lock, flags); - } - /* Restore the queue head */ - tty->buf.head = head; - } - /* We may have a deferred request to flush the input buffer, - if so pull the chain under the lock and empty the queue */ - if (test_bit(TTY_FLUSHPENDING, &tty->flags)) { - __tty_buffer_flush(tty); - clear_bit(TTY_FLUSHPENDING, &tty->flags); - wake_up(&tty->read_wait); - } - clear_bit(TTY_FLUSHING, &tty->flags); - spin_unlock_irqrestore(&tty->buf.lock, flags); - - tty_ldisc_deref(disc); -} - -/** - * tty_flip_buffer_push - terminal - * @tty: tty to push - * - * Queue a push of the terminal flip buffers to the line discipline. This - * function must not be called from IRQ context if tty->low_latency is set. - * - * In the event of the queue being busy for flipping the work will be - * held off and retried later. - * - * Locking: tty buffer lock. Driver locks in low latency mode. - */ - -void tty_flip_buffer_push(struct tty_struct *tty) -{ - unsigned long flags; - spin_lock_irqsave(&tty->buf.lock, flags); - if (tty->buf.tail != NULL) - tty->buf.tail->commit = tty->buf.tail->used; - spin_unlock_irqrestore(&tty->buf.lock, flags); - - if (tty->low_latency) - flush_to_ldisc(&tty->buf.work.work); - else - schedule_delayed_work(&tty->buf.work, 1); -} - -EXPORT_SYMBOL(tty_flip_buffer_push); - - -/** * initialize_tty_struct * @tty: tty to initialize * @@ -3317,9 +2763,11 @@ EXPORT_SYMBOL(tty_flip_buffer_push); * Locking: none - tty in question must not be exposed at this point */ -static void initialize_tty_struct(struct tty_struct *tty) +void initialize_tty_struct(struct tty_struct *tty, + struct tty_driver *driver, int idx) { memset(tty, 0, sizeof(struct tty_struct)); + kref_init(&tty->kref); tty->magic = TTY_MAGIC; tty_ldisc_init(tty); tty->session = NULL; @@ -3327,7 +2775,6 @@ static void initialize_tty_struct(struct tty_struct *tty) tty->overrun_time = jiffies; tty->buf.head = tty->buf.tail = NULL; tty_buffer_init(tty); - INIT_DELAYED_WORK(&tty->buf.work, flush_to_ldisc); mutex_init(&tty->termios_mutex); init_waitqueue_head(&tty->write_wait); init_waitqueue_head(&tty->read_wait); @@ -3338,6 +2785,11 @@ static void initialize_tty_struct(struct tty_struct *tty) spin_lock_init(&tty->ctrl_lock); INIT_LIST_HEAD(&tty->tty_files); INIT_WORK(&tty->SAK_work, do_SAK_work); + + tty->driver = driver; + tty->ops = driver->ops; + tty->index = idx; + tty_line_name(driver, idx, tty->name); } /** @@ -3358,10 +2810,9 @@ int tty_put_char(struct tty_struct *tty, unsigned char ch) return tty->ops->put_char(tty, ch); return tty->ops->write(tty, &ch, 1); } - EXPORT_SYMBOL_GPL(tty_put_char); -static struct class *tty_class; +struct class *tty_class; /** * tty_register_device - register a tty device @@ -3401,6 +2852,7 @@ struct device *tty_register_device(struct tty_driver *driver, unsigned index, return device_create_drvdata(tty_class, device, dev, NULL, name); } +EXPORT_SYMBOL(tty_register_device); /** * tty_unregister_device - unregister a tty device @@ -3418,8 +2870,6 @@ void tty_unregister_device(struct tty_driver *driver, unsigned index) device_destroy(tty_class, MKDEV(driver->major, driver->minor_start) + index); } - -EXPORT_SYMBOL(tty_register_device); EXPORT_SYMBOL(tty_unregister_device); struct tty_driver *alloc_tty_driver(int lines) @@ -3428,27 +2878,65 @@ struct tty_driver *alloc_tty_driver(int lines) driver = kzalloc(sizeof(struct tty_driver), GFP_KERNEL); if (driver) { + kref_init(&driver->kref); driver->magic = TTY_DRIVER_MAGIC; driver->num = lines; /* later we'll move allocation of tables here */ } return driver; } +EXPORT_SYMBOL(alloc_tty_driver); -void put_tty_driver(struct tty_driver *driver) +static void destruct_tty_driver(struct kref *kref) { + struct tty_driver *driver = container_of(kref, struct tty_driver, kref); + int i; + struct ktermios *tp; + void *p; + + if (driver->flags & TTY_DRIVER_INSTALLED) { + /* + * Free the termios and termios_locked structures because + * we don't want to get memory leaks when modular tty + * drivers are removed from the kernel. + */ + for (i = 0; i < driver->num; i++) { + tp = driver->termios[i]; + if (tp) { + driver->termios[i] = NULL; + kfree(tp); + } + if (!(driver->flags & TTY_DRIVER_DYNAMIC_DEV)) + tty_unregister_device(driver, i); + } + p = driver->ttys; + proc_tty_unregister_driver(driver); + driver->ttys = NULL; + driver->termios = NULL; + kfree(p); + cdev_del(&driver->cdev); + } kfree(driver); } +void tty_driver_kref_put(struct tty_driver *driver) +{ + kref_put(&driver->kref, destruct_tty_driver); +} +EXPORT_SYMBOL(tty_driver_kref_put); + void tty_set_operations(struct tty_driver *driver, const struct tty_operations *op) { driver->ops = op; }; +EXPORT_SYMBOL(tty_set_operations); -EXPORT_SYMBOL(alloc_tty_driver); +void put_tty_driver(struct tty_driver *d) +{ + tty_driver_kref_put(d); +} EXPORT_SYMBOL(put_tty_driver); -EXPORT_SYMBOL(tty_set_operations); /* * Called by a tty driver to register itself. @@ -3460,11 +2948,8 @@ int tty_register_driver(struct tty_driver *driver) dev_t dev; void **p = NULL; - if (driver->flags & TTY_DRIVER_INSTALLED) - return 0; - if (!(driver->flags & TTY_DRIVER_DEVPTS_MEM) && driver->num) { - p = kzalloc(driver->num * 3 * sizeof(void *), GFP_KERNEL); + p = kzalloc(driver->num * 2 * sizeof(void *), GFP_KERNEL); if (!p) return -ENOMEM; } @@ -3488,12 +2973,9 @@ int tty_register_driver(struct tty_driver *driver) if (p) { driver->ttys = (struct tty_struct **)p; driver->termios = (struct ktermios **)(p + driver->num); - driver->termios_locked = (struct ktermios **) - (p + driver->num * 2); } else { driver->ttys = NULL; driver->termios = NULL; - driver->termios_locked = NULL; } cdev_init(&driver->cdev, &tty_fops); @@ -3502,7 +2984,7 @@ int tty_register_driver(struct tty_driver *driver) if (error) { unregister_chrdev_region(dev, driver->num); driver->ttys = NULL; - driver->termios = driver->termios_locked = NULL; + driver->termios = NULL; kfree(p); return error; } @@ -3516,6 +2998,7 @@ int tty_register_driver(struct tty_driver *driver) tty_register_device(driver, i, NULL); } proc_tty_register_driver(driver); + driver->flags |= TTY_DRIVER_INSTALLED; return 0; } @@ -3526,46 +3009,19 @@ EXPORT_SYMBOL(tty_register_driver); */ int tty_unregister_driver(struct tty_driver *driver) { - int i; - struct ktermios *tp; - void *p; - +#if 0 + /* FIXME */ if (driver->refcount) return -EBUSY; - +#endif unregister_chrdev_region(MKDEV(driver->major, driver->minor_start), driver->num); mutex_lock(&tty_mutex); list_del(&driver->tty_drivers); mutex_unlock(&tty_mutex); - - /* - * Free the termios and termios_locked structures because - * we don't want to get memory leaks when modular tty - * drivers are removed from the kernel. - */ - for (i = 0; i < driver->num; i++) { - tp = driver->termios[i]; - if (tp) { - driver->termios[i] = NULL; - kfree(tp); - } - tp = driver->termios_locked[i]; - if (tp) { - driver->termios_locked[i] = NULL; - kfree(tp); - } - if (!(driver->flags & TTY_DRIVER_DYNAMIC_DEV)) - tty_unregister_device(driver, i); - } - p = driver->ttys; - proc_tty_unregister_driver(driver); - driver->ttys = NULL; - driver->termios = driver->termios_locked = NULL; - kfree(p); - cdev_del(&driver->cdev); return 0; } + EXPORT_SYMBOL(tty_unregister_driver); dev_t tty_devnum(struct tty_struct *tty) @@ -3576,9 +3032,12 @@ EXPORT_SYMBOL(tty_devnum); void proc_clear_tty(struct task_struct *p) { + struct tty_struct *tty; spin_lock_irq(&p->sighand->siglock); + tty = p->signal->tty; p->signal->tty = NULL; spin_unlock_irq(&p->sighand->siglock); + tty_kref_put(tty); } /* Called under the sighand lock */ @@ -3594,9 +3053,13 @@ static void __proc_set_tty(struct task_struct *tsk, struct tty_struct *tty) tty->pgrp = get_pid(task_pgrp(tsk)); spin_unlock_irqrestore(&tty->ctrl_lock, flags); tty->session = get_pid(task_session(tsk)); + if (tsk->signal->tty) { + printk(KERN_DEBUG "tty not NULL!!\n"); + tty_kref_put(tsk->signal->tty); + } } put_pid(tsk->signal->tty_old_pgrp); - tsk->signal->tty = tty; + tsk->signal->tty = tty_kref_get(tty); tsk->signal->tty_old_pgrp = NULL; } @@ -3610,18 +3073,20 @@ static void proc_set_tty(struct task_struct *tsk, struct tty_struct *tty) struct tty_struct *get_current_tty(void) { struct tty_struct *tty; - WARN_ON_ONCE(!mutex_is_locked(&tty_mutex)); - tty = current->signal->tty; - /* - * session->tty can be changed/cleared from under us, make sure we - * issue the load. The obtained pointer, when not NULL, is valid as - * long as we hold tty_mutex. - */ - barrier(); + unsigned long flags; + + spin_lock_irqsave(¤t->sighand->siglock, flags); + tty = tty_kref_get(current->signal->tty); + spin_unlock_irqrestore(¤t->sighand->siglock, flags); return tty; } EXPORT_SYMBOL_GPL(get_current_tty); +void tty_default_fops(struct file_operations *fops) +{ + *fops = tty_fops; +} + /* * Initialize the console device. This is called *early*, so * we can't necessarily depend on lots of kernel help here. @@ -3659,12 +3124,6 @@ postcore_initcall(tty_class_init); /* 3/2004 jmc: why do these devices exist? */ static struct cdev tty_cdev, console_cdev; -#ifdef CONFIG_UNIX98_PTYS -static struct cdev ptmx_cdev; -#endif -#ifdef CONFIG_VT -static struct cdev vc0_cdev; -#endif /* * Ok, now we can initialize the rest of the tty devices and can count @@ -3676,32 +3135,18 @@ static int __init tty_init(void) if (cdev_add(&tty_cdev, MKDEV(TTYAUX_MAJOR, 0), 1) || register_chrdev_region(MKDEV(TTYAUX_MAJOR, 0), 1, "/dev/tty") < 0) panic("Couldn't register /dev/tty driver\n"); - device_create_drvdata(tty_class, NULL, MKDEV(TTYAUX_MAJOR, 0), NULL, + device_create(tty_class, NULL, MKDEV(TTYAUX_MAJOR, 0), NULL, "tty"); cdev_init(&console_cdev, &console_fops); if (cdev_add(&console_cdev, MKDEV(TTYAUX_MAJOR, 1), 1) || register_chrdev_region(MKDEV(TTYAUX_MAJOR, 1), 1, "/dev/console") < 0) panic("Couldn't register /dev/console driver\n"); - device_create_drvdata(tty_class, NULL, MKDEV(TTYAUX_MAJOR, 1), NULL, + device_create(tty_class, NULL, MKDEV(TTYAUX_MAJOR, 1), NULL, "console"); -#ifdef CONFIG_UNIX98_PTYS - cdev_init(&ptmx_cdev, &ptmx_fops); - if (cdev_add(&ptmx_cdev, MKDEV(TTYAUX_MAJOR, 2), 1) || - register_chrdev_region(MKDEV(TTYAUX_MAJOR, 2), 1, "/dev/ptmx") < 0) - panic("Couldn't register /dev/ptmx driver\n"); - device_create_drvdata(tty_class, NULL, MKDEV(TTYAUX_MAJOR, 2), NULL, "ptmx"); -#endif - #ifdef CONFIG_VT - cdev_init(&vc0_cdev, &console_fops); - if (cdev_add(&vc0_cdev, MKDEV(TTY_MAJOR, 0), 1) || - register_chrdev_region(MKDEV(TTY_MAJOR, 0), 1, "/dev/vc/0") < 0) - panic("Couldn't register /dev/tty0 driver\n"); - device_create_drvdata(tty_class, NULL, MKDEV(TTY_MAJOR, 0), NULL, "tty0"); - - vty_init(); + vty_init(&console_fops); #endif return 0; } diff --git a/drivers/char/tty_ioctl.c b/drivers/char/tty_ioctl.c index ea9fc5d03b9..a408c8e487e 100644 --- a/drivers/char/tty_ioctl.c +++ b/drivers/char/tty_ioctl.c @@ -40,6 +40,15 @@ #define TERMIOS_OLD 8 +/** + * tty_chars_in_buffer - characters pending + * @tty: terminal + * + * Return the number of bytes of data in the device private + * output queue. If no private method is supplied there is assumed + * to be no queue on the device. + */ + int tty_chars_in_buffer(struct tty_struct *tty) { if (tty->ops->chars_in_buffer) @@ -47,26 +56,49 @@ int tty_chars_in_buffer(struct tty_struct *tty) else return 0; } - EXPORT_SYMBOL(tty_chars_in_buffer); +/** + * tty_write_room - write queue space + * @tty: terminal + * + * Return the number of bytes that can be queued to this device + * at the present time. The result should be treated as a guarantee + * and the driver cannot offer a value it later shrinks by more than + * the number of bytes written. If no method is provided 2K is always + * returned and data may be lost as there will be no flow control. + */ + int tty_write_room(struct tty_struct *tty) { if (tty->ops->write_room) return tty->ops->write_room(tty); return 2048; } - EXPORT_SYMBOL(tty_write_room); +/** + * tty_driver_flush_buffer - discard internal buffer + * @tty: terminal + * + * Discard the internal output buffer for this device. If no method + * is provided then either the buffer cannot be hardware flushed or + * there is no buffer driver side. + */ void tty_driver_flush_buffer(struct tty_struct *tty) { if (tty->ops->flush_buffer) tty->ops->flush_buffer(tty); } - EXPORT_SYMBOL(tty_driver_flush_buffer); +/** + * tty_throttle - flow control + * @tty: terminal + * + * Indicate that a tty should stop transmitting data down the stack. + */ + void tty_throttle(struct tty_struct *tty) { /* check TTY_THROTTLED first so it indicates our state */ @@ -76,6 +108,13 @@ void tty_throttle(struct tty_struct *tty) } EXPORT_SYMBOL(tty_throttle); +/** + * tty_unthrottle - flow control + * @tty: terminal + * + * Indicate that a tty may continue transmitting data down the stack. + */ + void tty_unthrottle(struct tty_struct *tty) { if (test_and_clear_bit(TTY_THROTTLED, &tty->flags) && @@ -112,6 +151,11 @@ void tty_wait_until_sent(struct tty_struct *tty, long timeout) } EXPORT_SYMBOL(tty_wait_until_sent); + +/* + * Termios Helper Methods + */ + static void unset_locked_termios(struct ktermios *termios, struct ktermios *old, struct ktermios *locked) @@ -346,6 +390,16 @@ void tty_termios_encode_baud_rate(struct ktermios *termios, } EXPORT_SYMBOL_GPL(tty_termios_encode_baud_rate); +/** + * tty_encode_baud_rate - set baud rate of the tty + * @ibaud: input baud rate + * @obad: output baud rate + * + * Update the current termios data for the tty with the new speed + * settings. The caller must hold the termios_mutex for the tty in + * question. + */ + void tty_encode_baud_rate(struct tty_struct *tty, speed_t ibaud, speed_t obaud) { tty_termios_encode_baud_rate(tty->termios, ibaud, obaud); @@ -430,12 +484,11 @@ EXPORT_SYMBOL(tty_termios_hw_change); * is a bit of layering violation here with n_tty in terms of the * internal knowledge of this function. * - * Locking: termios_sem + * Locking: termios_mutex */ static void change_termios(struct tty_struct *tty, struct ktermios *new_termios) { - int canon_change; struct ktermios old_termios; struct tty_ldisc *ld; unsigned long flags; @@ -451,18 +504,6 @@ static void change_termios(struct tty_struct *tty, struct ktermios *new_termios) old_termios = *tty->termios; *tty->termios = *new_termios; unset_locked_termios(tty->termios, &old_termios, tty->termios_locked); - canon_change = (old_termios.c_lflag ^ tty->termios->c_lflag) & ICANON; - if (canon_change) { - memset(&tty->read_flags, 0, sizeof tty->read_flags); - tty->canon_head = tty->read_tail; - tty->canon_data = 0; - tty->erasing = 0; - } - - /* This bit should be in the ldisc code */ - if (canon_change && !L_ICANON(tty) && tty->read_cnt) - /* Get characters left over from canonical mode. */ - wake_up_interruptible(&tty->read_wait); /* See if packet mode change of state. */ if (tty->link && tty->link->packet) { @@ -508,7 +549,7 @@ static void change_termios(struct tty_struct *tty, struct ktermios *new_termios) * functions before using change_termios to do the actual changes. * * Locking: - * Called functions take ldisc and termios_sem locks + * Called functions take ldisc and termios_mutex locks */ static int set_termios(struct tty_struct *tty, void __user *arg, int opt) @@ -579,25 +620,51 @@ static int get_termio(struct tty_struct *tty, struct termio __user *termio) return 0; } -static unsigned long inq_canon(struct tty_struct *tty) + +#ifdef TCGETX + +/** + * set_termiox - set termiox fields if possible + * @tty: terminal + * @arg: termiox structure from user + * @opt: option flags for ioctl type + * + * Implement the device calling points for the SYS5 termiox ioctl + * interface in Linux + */ + +static int set_termiox(struct tty_struct *tty, void __user *arg, int opt) { - int nr, head, tail; + struct termiox tnew; + struct tty_ldisc *ld; - if (!tty->canon_data || !tty->read_buf) - return 0; - head = tty->canon_head; - tail = tty->read_tail; - nr = (head - tail) & (N_TTY_BUF_SIZE-1); - /* Skip EOF-chars.. */ - while (head != tail) { - if (test_bit(tail, tty->read_flags) && - tty->read_buf[tail] == __DISABLED_CHAR) - nr--; - tail = (tail+1) & (N_TTY_BUF_SIZE-1); + if (tty->termiox == NULL) + return -EINVAL; + if (copy_from_user(&tnew, arg, sizeof(struct termiox))) + return -EFAULT; + + ld = tty_ldisc_ref(tty); + if (ld != NULL) { + if ((opt & TERMIOS_FLUSH) && ld->ops->flush_buffer) + ld->ops->flush_buffer(tty); + tty_ldisc_deref(ld); } - return nr; + if (opt & TERMIOS_WAIT) { + tty_wait_until_sent(tty, 0); + if (signal_pending(current)) + return -EINTR; + } + + mutex_lock(&tty->termios_mutex); + if (tty->ops->set_termiox) + tty->ops->set_termiox(tty, &tnew); + mutex_unlock(&tty->termios_mutex); + return 0; } +#endif + + #ifdef TIOCGETP /* * These are deprecated, but there is limited support.. @@ -671,7 +738,7 @@ static void set_sgflags(struct ktermios *termios, int flags) * Updates a terminal from the legacy BSD style terminal information * structure. * - * Locking: termios_sem + * Locking: termios_mutex */ static int set_sgttyb(struct tty_struct *tty, struct sgttyb __user *sgttyb) @@ -849,6 +916,7 @@ int tty_mode_ioctl(struct tty_struct *tty, struct file *file, { struct tty_struct *real_tty; void __user *p = (void __user *)arg; + int ret = 0; if (tty->driver->type == TTY_DRIVER_TYPE_PTY && tty->driver->subtype == PTY_TYPE_MASTER) @@ -884,18 +952,24 @@ int tty_mode_ioctl(struct tty_struct *tty, struct file *file, return set_termios(real_tty, p, TERMIOS_OLD); #ifndef TCGETS2 case TCGETS: + mutex_lock(&real_tty->termios_mutex); if (kernel_termios_to_user_termios((struct termios __user *)arg, real_tty->termios)) - return -EFAULT; - return 0; + ret = -EFAULT; + mutex_unlock(&real_tty->termios_mutex); + return ret; #else case TCGETS: + mutex_lock(&real_tty->termios_mutex); if (kernel_termios_to_user_termios_1((struct termios __user *)arg, real_tty->termios)) - return -EFAULT; - return 0; + ret = -EFAULT; + mutex_unlock(&real_tty->termios_mutex); + return ret; case TCGETS2: + mutex_lock(&real_tty->termios_mutex); if (kernel_termios_to_user_termios((struct termios2 __user *)arg, real_tty->termios)) - return -EFAULT; - return 0; + ret = -EFAULT; + mutex_unlock(&real_tty->termios_mutex); + return ret; case TCSETSF2: return set_termios(real_tty, p, TERMIOS_FLUSH | TERMIOS_WAIT); case TCSETSW2: @@ -913,36 +987,63 @@ int tty_mode_ioctl(struct tty_struct *tty, struct file *file, return set_termios(real_tty, p, TERMIOS_TERMIO); #ifndef TCGETS2 case TIOCGLCKTRMIOS: + mutex_lock(&real_tty->termios_mutex); if (kernel_termios_to_user_termios((struct termios __user *)arg, real_tty->termios_locked)) - return -EFAULT; - return 0; + ret = -EFAULT; + mutex_unlock(&real_tty->termios_mutex); + return ret; case TIOCSLCKTRMIOS: if (!capable(CAP_SYS_ADMIN)) return -EPERM; + mutex_lock(&real_tty->termios_mutex); if (user_termios_to_kernel_termios(real_tty->termios_locked, (struct termios __user *) arg)) - return -EFAULT; - return 0; + ret = -EFAULT; + mutex_unlock(&real_tty->termios_mutex); + return ret; #else case TIOCGLCKTRMIOS: + mutex_lock(&real_tty->termios_mutex); if (kernel_termios_to_user_termios_1((struct termios __user *)arg, real_tty->termios_locked)) - return -EFAULT; - return 0; + ret = -EFAULT; + mutex_unlock(&real_tty->termios_mutex); + return ret; case TIOCSLCKTRMIOS: if (!capable(CAP_SYS_ADMIN)) - return -EPERM; + ret = -EPERM; + mutex_lock(&real_tty->termios_mutex); if (user_termios_to_kernel_termios_1(real_tty->termios_locked, (struct termios __user *) arg)) - return -EFAULT; - return 0; + ret = -EFAULT; + mutex_unlock(&real_tty->termios_mutex); + return ret; #endif +#ifdef TCGETX + case TCGETX: + if (real_tty->termiox == NULL) + return -EINVAL; + mutex_lock(&real_tty->termios_mutex); + if (copy_to_user(p, real_tty->termiox, sizeof(struct termiox))) + ret = -EFAULT; + mutex_unlock(&real_tty->termios_mutex); + return ret; + case TCSETX: + return set_termiox(real_tty, p, 0); + case TCSETXW: + return set_termiox(real_tty, p, TERMIOS_WAIT); + case TCSETXF: + return set_termiox(real_tty, p, TERMIOS_FLUSH); +#endif case TIOCGSOFTCAR: - return put_user(C_CLOCAL(tty) ? 1 : 0, + mutex_lock(&real_tty->termios_mutex); + ret = put_user(C_CLOCAL(real_tty) ? 1 : 0, (int __user *)arg); + mutex_unlock(&real_tty->termios_mutex); + return ret; case TIOCSSOFTCAR: if (get_user(arg, (unsigned int __user *) arg)) return -EFAULT; - return tty_change_softcar(tty, arg); + return tty_change_softcar(real_tty, arg); default: return -ENOIOCTLCMD; } @@ -978,7 +1079,7 @@ int tty_perform_flush(struct tty_struct *tty, unsigned long arg) } EXPORT_SYMBOL_GPL(tty_perform_flush); -int n_tty_ioctl(struct tty_struct *tty, struct file *file, +int n_tty_ioctl_helper(struct tty_struct *tty, struct file *file, unsigned int cmd, unsigned long arg) { unsigned long flags; @@ -1016,13 +1117,6 @@ int n_tty_ioctl(struct tty_struct *tty, struct file *file, return 0; case TCFLSH: return tty_perform_flush(tty, arg); - case TIOCOUTQ: - return put_user(tty_chars_in_buffer(tty), (int __user *) arg); - case TIOCINQ: - retval = tty->read_cnt; - if (L_ICANON(tty)) - retval = inq_canon(tty); - return put_user(retval, (unsigned int __user *) arg); case TIOCPKT: { int pktmode; @@ -1048,4 +1142,4 @@ int n_tty_ioctl(struct tty_struct *tty, struct file *file, return tty_mode_ioctl(tty, file, cmd, arg); } } -EXPORT_SYMBOL(n_tty_ioctl); +EXPORT_SYMBOL(n_tty_ioctl_helper); diff --git a/drivers/char/tty_ldisc.c b/drivers/char/tty_ldisc.c index 241cbdea65a..f307f135cbf 100644 --- a/drivers/char/tty_ldisc.c +++ b/drivers/char/tty_ldisc.c @@ -169,7 +169,7 @@ static int tty_ldisc_get(int disc, struct tty_ldisc *ld) if (disc < N_TTY || disc >= NR_LDISCS) return -EINVAL; err = tty_ldisc_try_get(disc, ld); - if (err == -EAGAIN) { + if (err < 0) { request_module("tty-ldisc-%d", disc); err = tty_ldisc_try_get(disc, ld); } diff --git a/drivers/char/tty_port.c b/drivers/char/tty_port.c new file mode 100644 index 00000000000..553b0e9d8d1 --- /dev/null +++ b/drivers/char/tty_port.c @@ -0,0 +1,96 @@ +/* + * Tty port functions + */ + +#include <linux/types.h> +#include <linux/errno.h> +#include <linux/tty.h> +#include <linux/tty_driver.h> +#include <linux/tty_flip.h> +#include <linux/timer.h> +#include <linux/string.h> +#include <linux/slab.h> +#include <linux/sched.h> +#include <linux/init.h> +#include <linux/wait.h> +#include <linux/bitops.h> +#include <linux/delay.h> +#include <linux/module.h> + +void tty_port_init(struct tty_port *port) +{ + memset(port, 0, sizeof(*port)); + init_waitqueue_head(&port->open_wait); + init_waitqueue_head(&port->close_wait); + mutex_init(&port->mutex); + spin_lock_init(&port->lock); + port->close_delay = (50 * HZ) / 100; + port->closing_wait = (3000 * HZ) / 100; +} +EXPORT_SYMBOL(tty_port_init); + +int tty_port_alloc_xmit_buf(struct tty_port *port) +{ + /* We may sleep in get_zeroed_page() */ + mutex_lock(&port->mutex); + if (port->xmit_buf == NULL) + port->xmit_buf = (unsigned char *)get_zeroed_page(GFP_KERNEL); + mutex_unlock(&port->mutex); + if (port->xmit_buf == NULL) + return -ENOMEM; + return 0; +} +EXPORT_SYMBOL(tty_port_alloc_xmit_buf); + +void tty_port_free_xmit_buf(struct tty_port *port) +{ + mutex_lock(&port->mutex); + if (port->xmit_buf != NULL) { + free_page((unsigned long)port->xmit_buf); + port->xmit_buf = NULL; + } + mutex_unlock(&port->mutex); +} +EXPORT_SYMBOL(tty_port_free_xmit_buf); + + +/** + * tty_port_tty_get - get a tty reference + * @port: tty port + * + * Return a refcount protected tty instance or NULL if the port is not + * associated with a tty (eg due to close or hangup) + */ + +struct tty_struct *tty_port_tty_get(struct tty_port *port) +{ + unsigned long flags; + struct tty_struct *tty; + + spin_lock_irqsave(&port->lock, flags); + tty = tty_kref_get(port->tty); + spin_unlock_irqrestore(&port->lock, flags); + return tty; +} +EXPORT_SYMBOL(tty_port_tty_get); + +/** + * tty_port_tty_set - set the tty of a port + * @port: tty port + * @tty: the tty + * + * Associate the port and tty pair. Manages any internal refcounts. + * Pass NULL to deassociate a port + */ + +void tty_port_tty_set(struct tty_port *port, struct tty_struct *tty) +{ + unsigned long flags; + + spin_lock_irqsave(&port->lock, flags); + if (port->tty) + tty_kref_put(port->tty); + port->tty = tty; + spin_unlock_irqrestore(&port->lock, flags); +} +EXPORT_SYMBOL(tty_port_tty_set); diff --git a/drivers/char/viocons.c b/drivers/char/viocons.c deleted file mode 100644 index 65fb848e1cc..00000000000 --- a/drivers/char/viocons.c +++ /dev/null @@ -1,1171 +0,0 @@ -/* -*- linux-c -*- - * - * drivers/char/viocons.c - * - * iSeries Virtual Terminal - * - * Authors: Dave Boutcher <boutcher@us.ibm.com> - * Ryan Arnold <ryanarn@us.ibm.com> - * Colin Devilbiss <devilbis@us.ibm.com> - * Stephen Rothwell - * - * (C) Copyright 2000, 2001, 2002, 2003, 2004 IBM Corporation - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of the - * License, or (at your option) anyu later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ -#include <linux/kernel.h> -#include <linux/proc_fs.h> -#include <linux/errno.h> -#include <linux/vmalloc.h> -#include <linux/mm.h> -#include <linux/console.h> -#include <linux/module.h> -#include <asm/uaccess.h> -#include <linux/init.h> -#include <linux/wait.h> -#include <linux/spinlock.h> -#include <asm/ioctls.h> -#include <linux/kd.h> -#include <linux/tty.h> -#include <linux/tty_flip.h> -#include <linux/sysrq.h> - -#include <asm/firmware.h> -#include <asm/iseries/vio.h> -#include <asm/iseries/hv_lp_event.h> -#include <asm/iseries/hv_call_event.h> -#include <asm/iseries/hv_lp_config.h> -#include <asm/iseries/hv_call.h> - -#ifdef CONFIG_VT -#error You must turn off CONFIG_VT to use CONFIG_VIOCONS -#endif - -#define VIOTTY_MAGIC (0x0DCB) -#define VTTY_PORTS 10 - -#define VIOCONS_KERN_WARN KERN_WARNING "viocons: " -#define VIOCONS_KERN_INFO KERN_INFO "viocons: " - -static DEFINE_SPINLOCK(consolelock); -static DEFINE_SPINLOCK(consoleloglock); - -static int vio_sysrq_pressed; - -#define VIOCHAR_NUM_BUF 16 - -/* - * Our port information. We store a pointer to one entry in the - * tty_driver_data - */ -static struct port_info { - int magic; - struct tty_struct *tty; - HvLpIndex lp; - u8 vcons; - u64 seq; /* sequence number of last HV send */ - u64 ack; /* last ack from HV */ -/* - * When we get writes faster than we can send it to the partition, - * buffer the data here. Note that used is a bit map of used buffers. - * It had better have enough bits to hold VIOCHAR_NUM_BUF the bitops assume - * it is a multiple of unsigned long - */ - unsigned long used; - u8 *buffer[VIOCHAR_NUM_BUF]; - int bufferBytes[VIOCHAR_NUM_BUF]; - int curbuf; - int bufferOverflow; - int overflowMessage; -} port_info[VTTY_PORTS]; - -#define viochar_is_console(pi) ((pi) == &port_info[0]) -#define viochar_port(pi) ((pi) - &port_info[0]) - -static void initDataEvent(struct viocharlpevent *viochar, HvLpIndex lp); - -static struct tty_driver *viotty_driver; - -static void hvlog(char *fmt, ...) -{ - int i; - unsigned long flags; - va_list args; - static char buf[256]; - - spin_lock_irqsave(&consoleloglock, flags); - va_start(args, fmt); - i = vscnprintf(buf, sizeof(buf) - 1, fmt, args); - va_end(args); - buf[i++] = '\r'; - HvCall_writeLogBuffer(buf, i); - spin_unlock_irqrestore(&consoleloglock, flags); -} - -static void hvlogOutput(const char *buf, int count) -{ - unsigned long flags; - int begin; - int index; - static const char cr = '\r'; - - begin = 0; - spin_lock_irqsave(&consoleloglock, flags); - for (index = 0; index < count; index++) { - if (buf[index] == '\n') { - /* - * Start right after the last '\n' or at the zeroth - * array position and output the number of characters - * including the newline. - */ - HvCall_writeLogBuffer(&buf[begin], index - begin + 1); - begin = index + 1; - HvCall_writeLogBuffer(&cr, 1); - } - } - if ((index - begin) > 0) - HvCall_writeLogBuffer(&buf[begin], index - begin); - spin_unlock_irqrestore(&consoleloglock, flags); -} - -/* - * Make sure we're pointing to a valid port_info structure. Shamelessly - * plagerized from serial.c - */ -static inline int viotty_paranoia_check(struct port_info *pi, - char *name, const char *routine) -{ - static const char *bad_pi_addr = VIOCONS_KERN_WARN - "warning: bad address for port_info struct (%s) in %s\n"; - static const char *badmagic = VIOCONS_KERN_WARN - "warning: bad magic number for port_info struct (%s) in %s\n"; - - if ((pi < &port_info[0]) || (viochar_port(pi) > VTTY_PORTS)) { - printk(bad_pi_addr, name, routine); - return 1; - } - if (pi->magic != VIOTTY_MAGIC) { - printk(badmagic, name, routine); - return 1; - } - return 0; -} - -/* - * Add data to our pending-send buffers. - * - * NOTE: Don't use printk in here because it gets nastily recursive. - * hvlog can be used to log to the hypervisor buffer - */ -static int buffer_add(struct port_info *pi, const char *buf, size_t len) -{ - size_t bleft; - size_t curlen; - const char *curbuf; - int nextbuf; - - curbuf = buf; - bleft = len; - while (bleft > 0) { - /* - * If there is no space left in the current buffer, we have - * filled everything up, so return. If we filled the previous - * buffer we would already have moved to the next one. - */ - if (pi->bufferBytes[pi->curbuf] == VIOCHAR_MAX_DATA) { - hvlog ("\n\rviocons: No overflow buffer available for memcpy().\n"); - pi->bufferOverflow++; - pi->overflowMessage = 1; - break; - } - - /* - * Turn on the "used" bit for this buffer. If it's already on, - * that's fine. - */ - set_bit(pi->curbuf, &pi->used); - - /* - * See if this buffer has been allocated. If not, allocate it. - */ - if (pi->buffer[pi->curbuf] == NULL) { - pi->buffer[pi->curbuf] = - kmalloc(VIOCHAR_MAX_DATA, GFP_ATOMIC); - if (pi->buffer[pi->curbuf] == NULL) { - hvlog("\n\rviocons: kmalloc failed allocating spaces for buffer %d.", - pi->curbuf); - break; - } - } - - /* Figure out how much we can copy into this buffer. */ - if (bleft < (VIOCHAR_MAX_DATA - pi->bufferBytes[pi->curbuf])) - curlen = bleft; - else - curlen = VIOCHAR_MAX_DATA - pi->bufferBytes[pi->curbuf]; - - /* Copy the data into the buffer. */ - memcpy(pi->buffer[pi->curbuf] + pi->bufferBytes[pi->curbuf], - curbuf, curlen); - - pi->bufferBytes[pi->curbuf] += curlen; - curbuf += curlen; - bleft -= curlen; - - /* - * Now see if we've filled this buffer. If not then - * we'll try to use it again later. If we've filled it - * up then we'll advance the curbuf to the next in the - * circular queue. - */ - if (pi->bufferBytes[pi->curbuf] == VIOCHAR_MAX_DATA) { - nextbuf = (pi->curbuf + 1) % VIOCHAR_NUM_BUF; - /* - * Move to the next buffer if it hasn't been used yet - */ - if (test_bit(nextbuf, &pi->used) == 0) - pi->curbuf = nextbuf; - } - } - return len - bleft; -} - -/* - * Send pending data - * - * NOTE: Don't use printk in here because it gets nastily recursive. - * hvlog can be used to log to the hypervisor buffer - */ -static void send_buffers(struct port_info *pi) -{ - HvLpEvent_Rc hvrc; - int nextbuf; - struct viocharlpevent *viochar; - unsigned long flags; - - spin_lock_irqsave(&consolelock, flags); - - viochar = (struct viocharlpevent *) - vio_get_event_buffer(viomajorsubtype_chario); - - /* Make sure we got a buffer */ - if (viochar == NULL) { - hvlog("\n\rviocons: Can't get viochar buffer in sendBuffers()."); - spin_unlock_irqrestore(&consolelock, flags); - return; - } - - if (pi->used == 0) { - hvlog("\n\rviocons: in sendbuffers(), but no buffers used.\n"); - vio_free_event_buffer(viomajorsubtype_chario, viochar); - spin_unlock_irqrestore(&consolelock, flags); - return; - } - - /* - * curbuf points to the buffer we're filling. We want to - * start sending AFTER this one. - */ - nextbuf = (pi->curbuf + 1) % VIOCHAR_NUM_BUF; - - /* - * Loop until we find a buffer with the used bit on - */ - while (test_bit(nextbuf, &pi->used) == 0) - nextbuf = (nextbuf + 1) % VIOCHAR_NUM_BUF; - - initDataEvent(viochar, pi->lp); - - /* - * While we have buffers with data, and our send window - * is open, send them - */ - while ((test_bit(nextbuf, &pi->used)) && - ((pi->seq - pi->ack) < VIOCHAR_WINDOW)) { - viochar->len = pi->bufferBytes[nextbuf]; - viochar->event.xCorrelationToken = pi->seq++; - viochar->event.xSizeMinus1 = - offsetof(struct viocharlpevent, data) + viochar->len; - - memcpy(viochar->data, pi->buffer[nextbuf], viochar->len); - - hvrc = HvCallEvent_signalLpEvent(&viochar->event); - if (hvrc) { - /* - * MUST unlock the spinlock before doing a printk - */ - vio_free_event_buffer(viomajorsubtype_chario, viochar); - spin_unlock_irqrestore(&consolelock, flags); - - printk(VIOCONS_KERN_WARN - "error sending event! return code %d\n", - (int)hvrc); - return; - } - - /* - * clear the used bit, zero the number of bytes in - * this buffer, and move to the next buffer - */ - clear_bit(nextbuf, &pi->used); - pi->bufferBytes[nextbuf] = 0; - nextbuf = (nextbuf + 1) % VIOCHAR_NUM_BUF; - } - - /* - * If we have emptied all the buffers, start at 0 again. - * this will re-use any allocated buffers - */ - if (pi->used == 0) { - pi->curbuf = 0; - - if (pi->overflowMessage) - pi->overflowMessage = 0; - - if (pi->tty) { - tty_wakeup(pi->tty); - } - } - - vio_free_event_buffer(viomajorsubtype_chario, viochar); - spin_unlock_irqrestore(&consolelock, flags); -} - -/* - * Our internal writer. Gets called both from the console device and - * the tty device. the tty pointer will be NULL if called from the console. - * Return total number of bytes "written". - * - * NOTE: Don't use printk in here because it gets nastily recursive. hvlog - * can be used to log to the hypervisor buffer - */ -static int internal_write(struct port_info *pi, const char *buf, size_t len) -{ - HvLpEvent_Rc hvrc; - size_t bleft; - size_t curlen; - const char *curbuf; - unsigned long flags; - struct viocharlpevent *viochar; - - /* - * Write to the hvlog of inbound data are now done prior to - * calling internal_write() since internal_write() is only called in - * the event that an lp event path is active, which isn't the case for - * logging attempts prior to console initialization. - * - * If there is already data queued for this port, send it prior to - * attempting to send any new data. - */ - if (pi->used) - send_buffers(pi); - - spin_lock_irqsave(&consolelock, flags); - - viochar = vio_get_event_buffer(viomajorsubtype_chario); - if (viochar == NULL) { - spin_unlock_irqrestore(&consolelock, flags); - hvlog("\n\rviocons: Can't get vio buffer in internal_write()."); - return -EAGAIN; - } - initDataEvent(viochar, pi->lp); - - curbuf = buf; - bleft = len; - - while ((bleft > 0) && (pi->used == 0) && - ((pi->seq - pi->ack) < VIOCHAR_WINDOW)) { - if (bleft > VIOCHAR_MAX_DATA) - curlen = VIOCHAR_MAX_DATA; - else - curlen = bleft; - - viochar->event.xCorrelationToken = pi->seq++; - memcpy(viochar->data, curbuf, curlen); - viochar->len = curlen; - viochar->event.xSizeMinus1 = - offsetof(struct viocharlpevent, data) + curlen; - - hvrc = HvCallEvent_signalLpEvent(&viochar->event); - if (hvrc) { - hvlog("viocons: error sending event! %d\n", (int)hvrc); - goto out; - } - curbuf += curlen; - bleft -= curlen; - } - - /* If we didn't send it all, buffer as much of it as we can. */ - if (bleft > 0) - bleft -= buffer_add(pi, curbuf, bleft); -out: - vio_free_event_buffer(viomajorsubtype_chario, viochar); - spin_unlock_irqrestore(&consolelock, flags); - return len - bleft; -} - -static struct port_info *get_port_data(struct tty_struct *tty) -{ - unsigned long flags; - struct port_info *pi; - - spin_lock_irqsave(&consolelock, flags); - if (tty) { - pi = (struct port_info *)tty->driver_data; - if (!pi || viotty_paranoia_check(pi, tty->name, - "get_port_data")) { - pi = NULL; - } - } else - /* - * If this is the console device, use the lp from - * the first port entry - */ - pi = &port_info[0]; - spin_unlock_irqrestore(&consolelock, flags); - return pi; -} - -/* - * Initialize the common fields in a charLpEvent - */ -static void initDataEvent(struct viocharlpevent *viochar, HvLpIndex lp) -{ - struct HvLpEvent *hev = &viochar->event; - - memset(viochar, 0, sizeof(struct viocharlpevent)); - - hev->flags = HV_LP_EVENT_VALID | HV_LP_EVENT_DEFERRED_ACK | - HV_LP_EVENT_INT; - hev->xType = HvLpEvent_Type_VirtualIo; - hev->xSubtype = viomajorsubtype_chario | viochardata; - hev->xSourceLp = HvLpConfig_getLpIndex(); - hev->xTargetLp = lp; - hev->xSizeMinus1 = sizeof(struct viocharlpevent); - hev->xSourceInstanceId = viopath_sourceinst(lp); - hev->xTargetInstanceId = viopath_targetinst(lp); -} - -/* - * early console device write - */ -static void viocons_write_early(struct console *co, const char *s, unsigned count) -{ - hvlogOutput(s, count); -} - -/* - * console device write - */ -static void viocons_write(struct console *co, const char *s, unsigned count) -{ - int index; - int begin; - struct port_info *pi; - - static const char cr = '\r'; - - /* - * Check port data first because the target LP might be valid but - * simply not active, in which case we want to hvlog the output. - */ - pi = get_port_data(NULL); - if (pi == NULL) { - hvlog("\n\rviocons_write: unable to get port data."); - return; - } - - hvlogOutput(s, count); - - if (!viopath_isactive(pi->lp)) - return; - - /* - * Any newline character found will cause a - * carriage return character to be emitted as well. - */ - begin = 0; - for (index = 0; index < count; index++) { - if (s[index] == '\n') { - /* - * Newline found. Print everything up to and - * including the newline - */ - internal_write(pi, &s[begin], index - begin + 1); - begin = index + 1; - /* Emit a carriage return as well */ - internal_write(pi, &cr, 1); - } - } - - /* If any characters left to write, write them now */ - if ((index - begin) > 0) - internal_write(pi, &s[begin], index - begin); -} - -/* - * Work out the device associate with this console - */ -static struct tty_driver *viocons_device(struct console *c, int *index) -{ - *index = c->index; - return viotty_driver; -} - -/* - * console device I/O methods - */ -static struct console viocons_early = { - .name = "viocons", - .write = viocons_write_early, - .flags = CON_PRINTBUFFER, - .index = -1, -}; - -static struct console viocons = { - .name = "viocons", - .write = viocons_write, - .device = viocons_device, - .flags = CON_PRINTBUFFER, - .index = -1, -}; - -/* - * TTY Open method - */ -static int viotty_open(struct tty_struct *tty, struct file *filp) -{ - int port; - unsigned long flags; - struct port_info *pi; - - port = tty->index; - - if ((port < 0) || (port >= VTTY_PORTS)) - return -ENODEV; - - spin_lock_irqsave(&consolelock, flags); - - pi = &port_info[port]; - /* If some other TTY is already connected here, reject the open */ - if ((pi->tty) && (pi->tty != tty)) { - spin_unlock_irqrestore(&consolelock, flags); - printk(VIOCONS_KERN_WARN - "attempt to open device twice from different ttys\n"); - return -EBUSY; - } - tty->driver_data = pi; - pi->tty = tty; - spin_unlock_irqrestore(&consolelock, flags); - - return 0; -} - -/* - * TTY Close method - */ -static void viotty_close(struct tty_struct *tty, struct file *filp) -{ - unsigned long flags; - struct port_info *pi; - - spin_lock_irqsave(&consolelock, flags); - pi = (struct port_info *)tty->driver_data; - - if (!pi || viotty_paranoia_check(pi, tty->name, "viotty_close")) { - spin_unlock_irqrestore(&consolelock, flags); - return; - } - if (tty->count == 1) - pi->tty = NULL; - spin_unlock_irqrestore(&consolelock, flags); -} - -/* - * TTY Write method - */ -static int viotty_write(struct tty_struct *tty, const unsigned char *buf, - int count) -{ - struct port_info *pi; - - pi = get_port_data(tty); - if (pi == NULL) { - hvlog("\n\rviotty_write: no port data."); - return -ENODEV; - } - - if (viochar_is_console(pi)) - hvlogOutput(buf, count); - - /* - * If the path to this LP is closed, don't bother doing anything more. - * just dump the data on the floor and return count. For some reason - * some user level programs will attempt to probe available tty's and - * they'll attempt a viotty_write on an invalid port which maps to an - * invalid target lp. If this is the case then ignore the - * viotty_write call and, since the viopath isn't active to this - * partition, return count. - */ - if (!viopath_isactive(pi->lp)) - return count; - - return internal_write(pi, buf, count); -} - -/* - * TTY put_char method - */ -static int viotty_put_char(struct tty_struct *tty, unsigned char ch) -{ - struct port_info *pi; - - pi = get_port_data(tty); - if (pi == NULL) - return 0; - - /* This will append '\r' as well if the char is '\n' */ - if (viochar_is_console(pi)) - hvlogOutput(&ch, 1); - - if (viopath_isactive(pi->lp)) - internal_write(pi, &ch, 1); - return 1; -} - -/* - * TTY write_room method - */ -static int viotty_write_room(struct tty_struct *tty) -{ - int i; - int room = 0; - struct port_info *pi; - unsigned long flags; - - spin_lock_irqsave(&consolelock, flags); - pi = (struct port_info *)tty->driver_data; - if (!pi || viotty_paranoia_check(pi, tty->name, "viotty_write_room")) { - spin_unlock_irqrestore(&consolelock, flags); - return 0; - } - - /* If no buffers are used, return the max size. */ - if (pi->used == 0) { - spin_unlock_irqrestore(&consolelock, flags); - return VIOCHAR_MAX_DATA * VIOCHAR_NUM_BUF; - } - - /* - * We retain the spinlock because we want to get an accurate - * count and it can change on us between each operation if we - * don't hold the spinlock. - */ - for (i = 0; ((i < VIOCHAR_NUM_BUF) && (room < VIOCHAR_MAX_DATA)); i++) - room += (VIOCHAR_MAX_DATA - pi->bufferBytes[i]); - spin_unlock_irqrestore(&consolelock, flags); - - if (room > VIOCHAR_MAX_DATA) - room = VIOCHAR_MAX_DATA; - return room; -} - -/* - * TTY chars_in_buffer method - */ -static int viotty_chars_in_buffer(struct tty_struct *tty) -{ - return 0; -} - -static int viotty_ioctl(struct tty_struct *tty, struct file *file, - unsigned int cmd, unsigned long arg) -{ - switch (cmd) { - /* - * the ioctls below read/set the flags usually shown in the leds - * don't use them - they will go away without warning - */ - case KDGETLED: - case KDGKBLED: - return put_user(0, (char *)arg); - - case KDSKBLED: - return 0; - } - /* FIXME: WTF is this being called for ??? */ - lock_kernel(); - ret = n_tty_ioctl(tty, file, cmd, arg); - unlock_kernel(); - return ret; -} - -/* - * Handle an open charLpEvent. Could be either interrupt or ack - */ -static void vioHandleOpenEvent(struct HvLpEvent *event) -{ - unsigned long flags; - struct viocharlpevent *cevent = (struct viocharlpevent *)event; - u8 port = cevent->virtual_device; - struct port_info *pi; - int reject = 0; - - if (hvlpevent_is_ack(event)) { - if (port >= VTTY_PORTS) - return; - - spin_lock_irqsave(&consolelock, flags); - /* Got the lock, don't cause console output */ - - pi = &port_info[port]; - if (event->xRc == HvLpEvent_Rc_Good) { - pi->seq = pi->ack = 0; - /* - * This line allows connections from the primary - * partition but once one is connected from the - * primary partition nothing short of a reboot - * of linux will allow access from the hosting - * partition again without a required iSeries fix. - */ - pi->lp = event->xTargetLp; - } - - spin_unlock_irqrestore(&consolelock, flags); - if (event->xRc != HvLpEvent_Rc_Good) - printk(VIOCONS_KERN_WARN - "handle_open_event: event->xRc == (%d).\n", - event->xRc); - - if (event->xCorrelationToken != 0) { - atomic_t *aptr= (atomic_t *)event->xCorrelationToken; - atomic_set(aptr, 1); - } else - printk(VIOCONS_KERN_WARN - "weird...got open ack without atomic\n"); - return; - } - - /* This had better require an ack, otherwise complain */ - if (!hvlpevent_need_ack(event)) { - printk(VIOCONS_KERN_WARN "viocharopen without ack bit!\n"); - return; - } - - spin_lock_irqsave(&consolelock, flags); - /* Got the lock, don't cause console output */ - - /* Make sure this is a good virtual tty */ - if (port >= VTTY_PORTS) { - event->xRc = HvLpEvent_Rc_SubtypeError; - cevent->subtype_result_code = viorc_openRejected; - /* - * Flag state here since we can't printk while holding - * a spinlock. - */ - reject = 1; - } else { - pi = &port_info[port]; - if ((pi->lp != HvLpIndexInvalid) && - (pi->lp != event->xSourceLp)) { - /* - * If this is tty is already connected to a different - * partition, fail. - */ - event->xRc = HvLpEvent_Rc_SubtypeError; - cevent->subtype_result_code = viorc_openRejected; - reject = 2; - } else { - pi->lp = event->xSourceLp; - event->xRc = HvLpEvent_Rc_Good; - cevent->subtype_result_code = viorc_good; - pi->seq = pi->ack = 0; - reject = 0; - } - } - - spin_unlock_irqrestore(&consolelock, flags); - - if (reject == 1) - printk(VIOCONS_KERN_WARN "open rejected: bad virtual tty.\n"); - else if (reject == 2) - printk(VIOCONS_KERN_WARN - "open rejected: console in exclusive use by another partition.\n"); - - /* Return the acknowledgement */ - HvCallEvent_ackLpEvent(event); -} - -/* - * Handle a close charLpEvent. This should ONLY be an Interrupt because the - * virtual console should never actually issue a close event to the hypervisor - * because the virtual console never goes away. A close event coming from the - * hypervisor simply means that there are no client consoles connected to the - * virtual console. - * - * Regardless of the number of connections masqueraded on the other side of - * the hypervisor ONLY ONE close event should be called to accompany the ONE - * open event that is called. The close event should ONLY be called when NO - * MORE connections (masqueraded or not) exist on the other side of the - * hypervisor. - */ -static void vioHandleCloseEvent(struct HvLpEvent *event) -{ - unsigned long flags; - struct viocharlpevent *cevent = (struct viocharlpevent *)event; - u8 port = cevent->virtual_device; - - if (hvlpevent_is_int(event)) { - if (port >= VTTY_PORTS) { - printk(VIOCONS_KERN_WARN - "close message from invalid virtual device.\n"); - return; - } - - /* For closes, just mark the console partition invalid */ - spin_lock_irqsave(&consolelock, flags); - /* Got the lock, don't cause console output */ - - if (port_info[port].lp == event->xSourceLp) - port_info[port].lp = HvLpIndexInvalid; - - spin_unlock_irqrestore(&consolelock, flags); - printk(VIOCONS_KERN_INFO "close from %d\n", event->xSourceLp); - } else - printk(VIOCONS_KERN_WARN - "got unexpected close acknowlegement\n"); -} - -/* - * Handle a config charLpEvent. Could be either interrupt or ack - */ -static void vioHandleConfig(struct HvLpEvent *event) -{ - struct viocharlpevent *cevent = (struct viocharlpevent *)event; - - HvCall_writeLogBuffer(cevent->data, cevent->len); - - if (cevent->data[0] == 0x01) - printk(VIOCONS_KERN_INFO "window resized to %d: %d: %d: %d\n", - cevent->data[1], cevent->data[2], - cevent->data[3], cevent->data[4]); - else - printk(VIOCONS_KERN_WARN "unknown config event\n"); -} - -/* - * Handle a data charLpEvent. - */ -static void vioHandleData(struct HvLpEvent *event) -{ - struct tty_struct *tty; - unsigned long flags; - struct viocharlpevent *cevent = (struct viocharlpevent *)event; - struct port_info *pi; - int index; - int num_pushed; - u8 port = cevent->virtual_device; - - if (port >= VTTY_PORTS) { - printk(VIOCONS_KERN_WARN "data on invalid virtual device %d\n", - port); - return; - } - - /* - * Hold the spinlock so that we don't take an interrupt that - * changes tty between the time we fetch the port_info - * pointer and the time we paranoia check. - */ - spin_lock_irqsave(&consolelock, flags); - pi = &port_info[port]; - - /* - * Change 05/01/2003 - Ryan Arnold: If a partition other than - * the current exclusive partition tries to send us data - * events then just drop them on the floor because we don't - * want his stinking data. He isn't authorized to receive - * data because he wasn't the first one to get the console, - * therefore he shouldn't be allowed to send data either. - * This will work without an iSeries fix. - */ - if (pi->lp != event->xSourceLp) { - spin_unlock_irqrestore(&consolelock, flags); - return; - } - - tty = pi->tty; - if (tty == NULL) { - spin_unlock_irqrestore(&consolelock, flags); - printk(VIOCONS_KERN_WARN "no tty for virtual device %d\n", - port); - return; - } - - if (tty->magic != TTY_MAGIC) { - spin_unlock_irqrestore(&consolelock, flags); - printk(VIOCONS_KERN_WARN "tty bad magic\n"); - return; - } - - /* - * Just to be paranoid, make sure the tty points back to this port - */ - pi = (struct port_info *)tty->driver_data; - if (!pi || viotty_paranoia_check(pi, tty->name, "vioHandleData")) { - spin_unlock_irqrestore(&consolelock, flags); - return; - } - spin_unlock_irqrestore(&consolelock, flags); - - /* - * Change 07/21/2003 - Ryan Arnold: functionality added to - * support sysrq utilizing ^O as the sysrq key. The sysrq - * functionality will only work if built into the kernel and - * then only if sysrq is enabled through the proc filesystem. - */ - num_pushed = 0; - for (index = 0; index < cevent->len; index++) { - /* - * Will be optimized away if !CONFIG_MAGIC_SYSRQ: - */ - if (sysrq_on()) { - /* 0x0f is the ascii character for ^O */ - if (cevent->data[index] == '\x0f') { - vio_sysrq_pressed = 1; - /* - * continue because we don't want to add - * the sysrq key into the data string. - */ - continue; - } else if (vio_sysrq_pressed) { - handle_sysrq(cevent->data[index], tty); - vio_sysrq_pressed = 0; - /* - * continue because we don't want to add - * the sysrq sequence into the data string. - */ - continue; - } - } - /* - * The sysrq sequence isn't included in this check if - * sysrq is enabled and compiled into the kernel because - * the sequence will never get inserted into the buffer. - * Don't attempt to copy more data into the buffer than we - * have room for because it would fail without indication. - */ - if(tty_insert_flip_char(tty, cevent->data[index], TTY_NORMAL) == 0) { - printk(VIOCONS_KERN_WARN "input buffer overflow!\n"); - break; - } - num_pushed++; - } - - if (num_pushed) - tty_flip_buffer_push(tty); -} - -/* - * Handle an ack charLpEvent. - */ -static void vioHandleAck(struct HvLpEvent *event) -{ - struct viocharlpevent *cevent = (struct viocharlpevent *)event; - unsigned long flags; - u8 port = cevent->virtual_device; - - if (port >= VTTY_PORTS) { - printk(VIOCONS_KERN_WARN "data on invalid virtual device\n"); - return; - } - - spin_lock_irqsave(&consolelock, flags); - port_info[port].ack = event->xCorrelationToken; - spin_unlock_irqrestore(&consolelock, flags); - - if (port_info[port].used) - send_buffers(&port_info[port]); -} - -/* - * Handle charLpEvents and route to the appropriate routine - */ -static void vioHandleCharEvent(struct HvLpEvent *event) -{ - int charminor; - - if (event == NULL) - return; - - charminor = event->xSubtype & VIOMINOR_SUBTYPE_MASK; - switch (charminor) { - case viocharopen: - vioHandleOpenEvent(event); - break; - case viocharclose: - vioHandleCloseEvent(event); - break; - case viochardata: - vioHandleData(event); - break; - case viocharack: - vioHandleAck(event); - break; - case viocharconfig: - vioHandleConfig(event); - break; - default: - if (hvlpevent_is_int(event) && hvlpevent_need_ack(event)) { - event->xRc = HvLpEvent_Rc_InvalidSubtype; - HvCallEvent_ackLpEvent(event); - } - } -} - -/* - * Send an open event - */ -static int send_open(HvLpIndex remoteLp, void *sem) -{ - return HvCallEvent_signalLpEventFast(remoteLp, - HvLpEvent_Type_VirtualIo, - viomajorsubtype_chario | viocharopen, - HvLpEvent_AckInd_DoAck, HvLpEvent_AckType_ImmediateAck, - viopath_sourceinst(remoteLp), - viopath_targetinst(remoteLp), - (u64)(unsigned long)sem, VIOVERSION << 16, - 0, 0, 0, 0); -} - -static const struct tty_operations serial_ops = { - .open = viotty_open, - .close = viotty_close, - .write = viotty_write, - .put_char = viotty_put_char, - .write_room = viotty_write_room, - .chars_in_buffer = viotty_chars_in_buffer, - .ioctl = viotty_ioctl, -}; - -static int __init viocons_init2(void) -{ - atomic_t wait_flag; - int rc; - - if (!firmware_has_feature(FW_FEATURE_ISERIES)) - return -ENODEV; - - /* +2 for fudge */ - rc = viopath_open(HvLpConfig_getPrimaryLpIndex(), - viomajorsubtype_chario, VIOCHAR_WINDOW + 2); - if (rc) - printk(VIOCONS_KERN_WARN "error opening to primary %d\n", rc); - - if (viopath_hostLp == HvLpIndexInvalid) - vio_set_hostlp(); - - /* - * And if the primary is not the same as the hosting LP, open to the - * hosting lp - */ - if ((viopath_hostLp != HvLpIndexInvalid) && - (viopath_hostLp != HvLpConfig_getPrimaryLpIndex())) { - printk(VIOCONS_KERN_INFO "open path to hosting (%d)\n", - viopath_hostLp); - rc = viopath_open(viopath_hostLp, viomajorsubtype_chario, - VIOCHAR_WINDOW + 2); /* +2 for fudge */ - if (rc) - printk(VIOCONS_KERN_WARN - "error opening to partition %d: %d\n", - viopath_hostLp, rc); - } - - if (vio_setHandler(viomajorsubtype_chario, vioHandleCharEvent) < 0) - printk(VIOCONS_KERN_WARN - "error seting handler for console events!\n"); - - /* - * First, try to open the console to the hosting lp. - * Wait on a semaphore for the response. - */ - atomic_set(&wait_flag, 0); - if ((viopath_isactive(viopath_hostLp)) && - (send_open(viopath_hostLp, (void *)&wait_flag) == 0)) { - printk(VIOCONS_KERN_INFO "hosting partition %d\n", - viopath_hostLp); - while (atomic_read(&wait_flag) == 0) - mb(); - atomic_set(&wait_flag, 0); - } - - /* - * If we don't have an active console, try the primary - */ - if ((!viopath_isactive(port_info[0].lp)) && - (viopath_isactive(HvLpConfig_getPrimaryLpIndex())) && - (send_open(HvLpConfig_getPrimaryLpIndex(), (void *)&wait_flag) - == 0)) { - printk(VIOCONS_KERN_INFO "opening console to primary partition\n"); - while (atomic_read(&wait_flag) == 0) - mb(); - } - - /* Initialize the tty_driver structure */ - viotty_driver = alloc_tty_driver(VTTY_PORTS); - viotty_driver->owner = THIS_MODULE; - viotty_driver->driver_name = "vioconsole"; - viotty_driver->name = "tty"; - viotty_driver->name_base = 1; - viotty_driver->major = TTY_MAJOR; - viotty_driver->minor_start = 1; - viotty_driver->type = TTY_DRIVER_TYPE_CONSOLE; - viotty_driver->subtype = 1; - viotty_driver->init_termios = tty_std_termios; - viotty_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_RESET_TERMIOS; - tty_set_operations(viotty_driver, &serial_ops); - - if (tty_register_driver(viotty_driver)) { - printk(VIOCONS_KERN_WARN "couldn't register console driver\n"); - put_tty_driver(viotty_driver); - viotty_driver = NULL; - } - - unregister_console(&viocons_early); - register_console(&viocons); - - return 0; -} - -static int __init viocons_init(void) -{ - int i; - - if (!firmware_has_feature(FW_FEATURE_ISERIES)) - return -ENODEV; - - printk(VIOCONS_KERN_INFO "registering console\n"); - for (i = 0; i < VTTY_PORTS; i++) { - port_info[i].lp = HvLpIndexInvalid; - port_info[i].magic = VIOTTY_MAGIC; - } - HvCall_setLogBufferFormatAndCodepage(HvCall_LogBuffer_ASCII, 437); - add_preferred_console("viocons", 0, NULL); - register_console(&viocons_early); - return 0; -} - -console_initcall(viocons_init); -module_init(viocons_init2); diff --git a/drivers/char/vt.c b/drivers/char/vt.c index 82a51f38a54..57029fefd64 100644 --- a/drivers/char/vt.c +++ b/drivers/char/vt.c @@ -100,10 +100,10 @@ #include <linux/font.h> #include <linux/bitops.h> #include <linux/notifier.h> - -#include <asm/io.h> +#include <linux/device.h> +#include <linux/io.h> #include <asm/system.h> -#include <asm/uaccess.h> +#include <linux/uaccess.h> #define MAX_NR_CON_DRIVER 16 @@ -803,7 +803,25 @@ static inline int resize_screen(struct vc_data *vc, int width, int height, */ #define VC_RESIZE_MAXCOL (32767) #define VC_RESIZE_MAXROW (32767) -int vc_resize(struct vc_data *vc, unsigned int cols, unsigned int lines) + +/** + * vc_do_resize - resizing method for the tty + * @tty: tty being resized + * @real_tty: real tty (different to tty if a pty/tty pair) + * @vc: virtual console private data + * @cols: columns + * @lines: lines + * + * Resize a virtual console, clipping according to the actual constraints. + * If the caller passes a tty structure then update the termios winsize + * information and perform any neccessary signal handling. + * + * Caller must hold the console semaphore. Takes the termios mutex and + * ctrl_lock of the tty IFF a tty is passed. + */ + +static int vc_do_resize(struct tty_struct *tty, struct tty_struct *real_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 int old_cols, old_rows, old_row_size, old_screen_size; @@ -907,26 +925,15 @@ int vc_resize(struct vc_data *vc, unsigned int cols, unsigned int lines) gotoxy(vc, vc->vc_x, vc->vc_y); save_cur(vc); - if (vc->vc_tty) { - struct winsize ws, *cws = &vc->vc_tty->winsize; - struct pid *pgrp = NULL; - + if (tty) { + /* Rewrite the requested winsize data with the actual + resulting sizes */ + struct winsize ws; memset(&ws, 0, sizeof(ws)); ws.ws_row = vc->vc_rows; ws.ws_col = vc->vc_cols; ws.ws_ypixel = vc->vc_scan_lines; - - mutex_lock(&vc->vc_tty->termios_mutex); - spin_lock_irq(&vc->vc_tty->ctrl_lock); - if ((ws.ws_row != cws->ws_row || ws.ws_col != cws->ws_col)) - pgrp = get_pid(vc->vc_tty->pgrp); - spin_unlock_irq(&vc->vc_tty->ctrl_lock); - if (pgrp) { - kill_pgrp(vc->vc_tty->pgrp, SIGWINCH, 1); - put_pid(pgrp); - } - *cws = ws; - mutex_unlock(&vc->vc_tty->termios_mutex); + tty_do_resize(tty, real_tty, &ws); } if (CON_IS_VISIBLE(vc)) @@ -934,14 +941,47 @@ int vc_resize(struct vc_data *vc, unsigned int cols, unsigned int lines) return err; } -int vc_lock_resize(struct vc_data *vc, unsigned int cols, unsigned int lines) +/** + * vc_resize - resize a VT + * @vc: virtual console + * @cols: columns + * @rows: rows + * + * 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 + */ + +int vc_resize(struct vc_data *vc, unsigned int cols, unsigned int rows) { - int rc; + return vc_do_resize(vc->vc_tty, vc->vc_tty, vc, cols, rows); +} + +/** + * vt_resize - resize a VT + * @tty: tty to resize + * @real_tty: tty if a pty/tty pair + * @ws: winsize attributes + * + * Resize a virtual terminal. This is called by the tty layer as we + * register our own handler for resizing. The mutual helper does all + * the actual work. + * + * Takes the console sem and the called methods then take the tty + * termios_mutex and the tty ctrl_lock in that order. + */ + +int vt_resize(struct tty_struct *tty, struct tty_struct *real_tty, + struct winsize *ws) +{ + struct vc_data *vc = tty->driver_data; + int ret; acquire_console_sem(); - rc = vc_resize(vc, cols, lines); + ret = vc_do_resize(tty, real_tty, vc, ws->ws_col, ws->ws_row); release_console_sem(); - return rc; + return ret; } void vc_deallocate(unsigned int currcons) @@ -2096,27 +2136,9 @@ static int do_con_write(struct tty_struct *tty, const unsigned char *buf, int co release_console_sem(); return 0; } - release_console_sem(); - orig_buf = buf; orig_count = count; - /* At this point 'buf' is guaranteed to be a kernel buffer - * and therefore no access to userspace (and therefore sleeping) - * will be needed. The con_buf_mtx serializes all tty based - * console rendering and vcs write/read operations. We hold - * the console spinlock during the entire write. - */ - - acquire_console_sem(); - - vc = tty->driver_data; - if (vc == NULL) { - printk(KERN_ERR "vt: argh, driver_data _became_ NULL !\n"); - release_console_sem(); - goto out; - } - himask = vc->vc_hi_font_mask; charmask = himask ? 0x1ff : 0xff; @@ -2330,8 +2352,6 @@ rescan_last_byte: FLUSH console_conditional_schedule(); release_console_sem(); - -out: notify_update(vc); return n; #undef FLUSH @@ -2543,8 +2563,6 @@ int tioclinux(struct tty_struct *tty, unsigned long arg) int lines; int ret; - if (tty->driver->type != TTY_DRIVER_TYPE_CONSOLE) - return -EINVAL; if (current->signal->tty != tty && !capable(CAP_SYS_ADMIN)) return -EPERM; if (get_user(type, p)) @@ -2738,6 +2756,12 @@ static int con_open(struct tty_struct *tty, struct file *filp) ret = vc_allocate(currcons); if (ret == 0) { struct vc_data *vc = vc_cons[currcons].d; + + /* Still being freed */ + if (vc->vc_tty) { + release_console_sem(); + return -ERESTARTSYS; + } tty->driver_data = vc; vc->vc_tty = tty; @@ -2758,34 +2782,20 @@ static int con_open(struct tty_struct *tty, struct file *filp) return ret; } -/* - * We take tty_mutex in here to prevent another thread from coming in via init_dev - * and taking a ref against the tty while we're in the process of forgetting - * about it and cleaning things up. - * - * This is because vcs_remove_sysfs() can sleep and will drop the BKL. - */ static void con_close(struct tty_struct *tty, struct file *filp) { - mutex_lock(&tty_mutex); - acquire_console_sem(); - if (tty && tty->count == 1) { - struct vc_data *vc = tty->driver_data; + /* Nothing to do - we defer to shutdown */ +} - if (vc) - vc->vc_tty = NULL; - tty->driver_data = NULL; - vcs_remove_sysfs(tty); - release_console_sem(); - mutex_unlock(&tty_mutex); - /* - * tty_mutex is released, but we still hold BKL, so there is - * still exclusion against init_dev() - */ - return; - } +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; + vcs_remove_sysfs(tty); release_console_sem(); - mutex_unlock(&tty_mutex); + tty_shutdown(tty); } static int default_italic_color = 2; // green (ASCII) @@ -2909,10 +2919,20 @@ static const struct tty_operations con_ops = { .start = con_start, .throttle = con_throttle, .unthrottle = con_unthrottle, + .resize = vt_resize, + .shutdown = con_shutdown }; -int __init vty_init(void) +static struct cdev vc0_cdev; + +int __init vty_init(const struct file_operations *console_fops) { + cdev_init(&vc0_cdev, console_fops); + if (cdev_add(&vc0_cdev, MKDEV(TTY_MAJOR, 0), 1) || + register_chrdev_region(MKDEV(TTY_MAJOR, 0), 1, "/dev/vc/0") < 0) + panic("Couldn't register /dev/tty0 driver\n"); + device_create(tty_class, NULL, MKDEV(TTY_MAJOR, 0), NULL, "tty0"); + vcs_init(); console_driver = alloc_tty_driver(MAX_NR_CONSOLES); @@ -2931,7 +2951,6 @@ int __init vty_init(void) tty_set_operations(console_driver, &con_ops); if (tty_register_driver(console_driver)) panic("Couldn't register console driver\n"); - kbd_init(); console_map_init(); #ifdef CONFIG_PROM_CONSOLE @@ -3425,7 +3444,7 @@ int register_con_driver(const struct consw *csw, int first, int last) if (retval) goto err; - con_driver->dev = device_create_drvdata(vtconsole_class, NULL, + con_driver->dev = device_create(vtconsole_class, NULL, MKDEV(0, con_driver->node), NULL, "vtcon%i", con_driver->node); @@ -3536,7 +3555,7 @@ static int __init vtconsole_class_init(void) struct con_driver *con = ®istered_con_driver[i]; if (con->con && !con->dev) { - con->dev = device_create_drvdata(vtconsole_class, NULL, + con->dev = device_create(vtconsole_class, NULL, MKDEV(0, con->node), NULL, "vtcon%i", con->node); @@ -4063,7 +4082,6 @@ EXPORT_SYMBOL(default_blu); EXPORT_SYMBOL(update_region); EXPORT_SYMBOL(redraw_screen); EXPORT_SYMBOL(vc_resize); -EXPORT_SYMBOL(vc_lock_resize); EXPORT_SYMBOL(fg_console); EXPORT_SYMBOL(console_blank_hook); EXPORT_SYMBOL(console_blanked); diff --git a/drivers/char/vt_ioctl.c b/drivers/char/vt_ioctl.c index 3211afd9d57..8944ce508e2 100644 --- a/drivers/char/vt_ioctl.c +++ b/drivers/char/vt_ioctl.c @@ -395,6 +395,8 @@ int vt_ioctl(struct tty_struct *tty, struct file * file, kbd = kbd_table + console; switch (cmd) { + case TIOCLINUX: + return tioclinux(tty, arg); case KIOCSOUND: if (!perm) goto eperm; @@ -947,14 +949,16 @@ int vt_ioctl(struct tty_struct *tty, struct file * file, get_user(cc, &vtsizes->v_cols)) ret = -EFAULT; else { + acquire_console_sem(); for (i = 0; i < MAX_NR_CONSOLES; i++) { vc = vc_cons[i].d; if (vc) { vc->vc_resize_user = 1; - vc_lock_resize(vc_cons[i].d, cc, ll); + vc_resize(vc_cons[i].d, cc, ll); } } + release_console_sem(); } break; } diff --git a/drivers/char/xilinx_hwicap/buffer_icap.h b/drivers/char/xilinx_hwicap/buffer_icap.h index c5b1840906b..8b0252bf06e 100644 --- a/drivers/char/xilinx_hwicap/buffer_icap.h +++ b/drivers/char/xilinx_hwicap/buffer_icap.h @@ -38,7 +38,6 @@ #include <linux/types.h> #include <linux/cdev.h> -#include <linux/version.h> #include <linux/platform_device.h> #include <asm/io.h> diff --git a/drivers/char/xilinx_hwicap/fifo_icap.h b/drivers/char/xilinx_hwicap/fifo_icap.h index ffabd3ba2bd..62bda453c90 100644 --- a/drivers/char/xilinx_hwicap/fifo_icap.h +++ b/drivers/char/xilinx_hwicap/fifo_icap.h @@ -38,7 +38,6 @@ #include <linux/types.h> #include <linux/cdev.h> -#include <linux/version.h> #include <linux/platform_device.h> #include <asm/io.h> diff --git a/drivers/char/xilinx_hwicap/xilinx_hwicap.c b/drivers/char/xilinx_hwicap/xilinx_hwicap.c index 8bfee5fb722..278c9857bcf 100644 --- a/drivers/char/xilinx_hwicap/xilinx_hwicap.c +++ b/drivers/char/xilinx_hwicap/xilinx_hwicap.c @@ -74,7 +74,6 @@ * currently programmed in the FPGA. */ -#include <linux/version.h> #include <linux/module.h> #include <linux/kernel.h> #include <linux/types.h> diff --git a/drivers/char/xilinx_hwicap/xilinx_hwicap.h b/drivers/char/xilinx_hwicap/xilinx_hwicap.h index 1f9c8b082db..24d0d9b938f 100644 --- a/drivers/char/xilinx_hwicap/xilinx_hwicap.h +++ b/drivers/char/xilinx_hwicap/xilinx_hwicap.h @@ -38,7 +38,6 @@ #include <linux/types.h> #include <linux/cdev.h> -#include <linux/version.h> #include <linux/platform_device.h> #include <asm/io.h> |