Merge branch 'fixes' into for-linus

Conflicts:

	arch/arm/mach-versatile/core.c
This commit is contained in:
Russell King 2008-10-15 23:16:07 +01:00 • committed by Russell King
commit 2502991560
4009 changed files with 236373 additions and 124037 deletions

View file

@ -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

View file

@ -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

View file

@ -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 *);
};
@ -277,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);

View file

@ -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,
};

View file

@ -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,
};

View file

@ -224,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,
};

View file

@ -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,
};

View file

@ -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,
};

View file

@ -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);
@ -1203,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;
@ -1219,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)
{

View file

@ -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,
};

View file

@ -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,

View file

@ -1711,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,
};
@ -1736,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,
};
@ -1760,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,
};
@ -1785,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,
};
@ -1810,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,
};
@ -1834,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,
};
@ -1858,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,
};
@ -1882,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,
};
@ -1907,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,
};
@ -1931,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,
};
@ -1956,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,
};
@ -1982,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,
};
@ -2007,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,
};
@ -2032,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,
};

View file

@ -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,
};

View file

@ -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,
};

View file

@ -140,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,
};

View file

@ -437,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,
};

View file

@ -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,

View file

@ -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,
};

View file

@ -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"))

View file

@ -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);

View file

@ -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)

View file

@ -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);
}

View file

@ -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;

View file

@ -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;
}

View file

@ -819,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;
}

View file

@ -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);

View file

@ -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",

View file

@ -4,5 +4,5 @@
obj-$(CONFIG_COMPUTONE) += ip2.o
ip2-objs := ip2base.o ip2main.o
ip2-objs := ip2main.o

View file

@ -68,38 +68,6 @@ static DEFINE_RWLOCK(Dl_spinlock);
// iiInitialize
//=======================================================
//******************************************************************************
// 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

View file

@ -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);

View file

@ -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 */

View file

@ -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;
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]);
ip2config.irq[i] = 0;// 0 is polling and is valid in that sense
}
/* 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");
}
// 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);
}
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 (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);
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 ) {
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). */
}
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);
}
for( i = 0; i < IP2_MAX_BOARDS; ++i ) {
if ( i2BoardPtrTable[i] ) {
set_irq( i, ip2config.irq[i] ); /* set and enable board interrupt */
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 (!timer_pending(&PollTimer)) {
mod_timer(&PollTimer, POLL_TIMEOUT);
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: 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;

View file

@ -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);
}

View file

@ -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:

View file

@ -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;

View file

@ -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,6 +1606,7 @@ 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;
@ -1643,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;
@ -1704,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;
@ -1822,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 */
@ -1896,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)
@ -1909,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;
@ -1958,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);
}
@ -1995,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);
}
@ -2040,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) &&
@ -2138,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);
}
@ -2164,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;
@ -2174,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)
@ -2253,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;
@ -2267,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++;
@ -2284,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;
@ -2302,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;
@ -2328,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]) {
@ -2360,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;
}
@ -2387,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);
}

View file

@ -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;

View file

@ -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;
}

View file

@ -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
};

View file

@ -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);

View file

@ -1759,65 +1759,40 @@ static void cmm_cm4000_release(struct pcmcia_device * link)
/*==== Interface to PCMCIA Layer =======================================*/
static int cm4000_config_check(struct pcmcia_device *p_dev,
cistpl_cftable_entry_t *cfg,
cistpl_cftable_entry_t *dflt,
unsigned int vcc,
void *priv_data)
{
if (!cfg->io.nwin)
return -ENODEV;
/* Get the IOaddr */
p_dev->io.BasePort1 = cfg->io.win[0].base;
p_dev->io.NumPorts1 = cfg->io.win[0].len;
p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO;
if (!(cfg->io.flags & CISTPL_IO_8BIT))
p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_16;
if (!(cfg->io.flags & CISTPL_IO_16BIT))
p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
p_dev->io.IOAddrLines = cfg->io.flags & CISTPL_IO_LINES_MASK;
return pcmcia_request_io(p_dev, &p_dev->io);
}
static int cm4000_config(struct pcmcia_device * link, int devno)
{
struct cm4000_dev *dev;
tuple_t tuple;
cisparse_t parse;
u_char buf[64];
int fail_fn, fail_rc;
int rc;
/* read the config-tuples */
tuple.Attributes = 0;
tuple.TupleData = buf;
tuple.TupleDataMax = sizeof(buf);
tuple.TupleOffset = 0;
link->io.BasePort2 = 0;
link->io.NumPorts2 = 0;
link->io.Attributes2 = 0;
tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
for (rc = pcmcia_get_first_tuple(link, &tuple);
rc == CS_SUCCESS; rc = pcmcia_get_next_tuple(link, &tuple)) {
rc = pcmcia_get_tuple_data(link, &tuple);
if (rc != CS_SUCCESS)
continue;
rc = pcmcia_parse_tuple(link, &tuple, &parse);
if (rc != CS_SUCCESS)
continue;
link->conf.ConfigIndex = parse.cftable_entry.index;
if (!parse.cftable_entry.io.nwin)
continue;
/* Get the IOaddr */
link->io.BasePort1 = parse.cftable_entry.io.win[0].base;
link->io.NumPorts1 = parse.cftable_entry.io.win[0].len;
link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO;
if (!(parse.cftable_entry.io.flags & CISTPL_IO_8BIT))
link->io.Attributes1 = IO_DATA_PATH_WIDTH_16;
if (!(parse.cftable_entry.io.flags & CISTPL_IO_16BIT))
link->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
link->io.IOAddrLines = parse.cftable_entry.io.flags
& CISTPL_IO_LINES_MASK;
rc = pcmcia_request_io(link, &link->io);
if (rc == CS_SUCCESS)
break; /* we are done */
}
if (rc != CS_SUCCESS)
if (pcmcia_loop_config(link, cm4000_config_check, NULL))
goto cs_release;
link->conf.IntType = 00000002;
if ((fail_rc =
pcmcia_request_configuration(link, &link->conf)) != CS_SUCCESS) {
fail_fn = RequestConfiguration;
if (pcmcia_request_configuration(link, &link->conf))
goto cs_release;
}
dev = link->priv;
sprintf(dev->node.dev_name, DEVICE_NAME "%d", devno);

View file

@ -526,65 +526,49 @@ static void cm4040_reader_release(struct pcmcia_device *link)
return;
}
static int cm4040_config_check(struct pcmcia_device *p_dev,
cistpl_cftable_entry_t *cfg,
cistpl_cftable_entry_t *dflt,
unsigned int vcc,
void *priv_data)
{
int rc;
if (!cfg->io.nwin)
return -ENODEV;
/* Get the IOaddr */
p_dev->io.BasePort1 = cfg->io.win[0].base;
p_dev->io.NumPorts1 = cfg->io.win[0].len;
p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO;
if (!(cfg->io.flags & CISTPL_IO_8BIT))
p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_16;
if (!(cfg->io.flags & CISTPL_IO_16BIT))
p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
p_dev->io.IOAddrLines = cfg->io.flags & CISTPL_IO_LINES_MASK;
rc = pcmcia_request_io(p_dev, &p_dev->io);
dev_printk(KERN_INFO, &handle_to_dev(p_dev),
"pcmcia_request_io returned 0x%x\n", rc);
return rc;
}
static int reader_config(struct pcmcia_device *link, int devno)
{
struct reader_dev *dev;
tuple_t tuple;
cisparse_t parse;
u_char buf[64];
int fail_fn, fail_rc;
int rc;
tuple.Attributes = 0;
tuple.TupleData = buf;
tuple.TupleDataMax = sizeof(buf);
tuple.TupleOffset = 0;
int fail_rc;
link->io.BasePort2 = 0;
link->io.NumPorts2 = 0;
link->io.Attributes2 = 0;
tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
for (rc = pcmcia_get_first_tuple(link, &tuple);
rc == CS_SUCCESS;
rc = pcmcia_get_next_tuple(link, &tuple)) {
rc = pcmcia_get_tuple_data(link, &tuple);
if (rc != CS_SUCCESS)
continue;
rc = pcmcia_parse_tuple(link, &tuple, &parse);
if (rc != CS_SUCCESS)
continue;
link->conf.ConfigIndex = parse.cftable_entry.index;
if (!parse.cftable_entry.io.nwin)
continue;
link->io.BasePort1 = parse.cftable_entry.io.win[0].base;
link->io.NumPorts1 = parse.cftable_entry.io.win[0].len;
link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO;
if (!(parse.cftable_entry.io.flags & CISTPL_IO_8BIT))
link->io.Attributes1 = IO_DATA_PATH_WIDTH_16;
if (!(parse.cftable_entry.io.flags & CISTPL_IO_16BIT))
link->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
link->io.IOAddrLines = parse.cftable_entry.io.flags
& CISTPL_IO_LINES_MASK;
rc = pcmcia_request_io(link, &link->io);
dev_printk(KERN_INFO, &handle_to_dev(link), "foo");
if (rc == CS_SUCCESS)
break;
else
dev_printk(KERN_INFO, &handle_to_dev(link),
"pcmcia_request_io failed 0x%x\n", rc);
}
if (rc != CS_SUCCESS)
if (pcmcia_loop_config(link, cm4040_config_check, NULL))
goto cs_release;
link->conf.IntType = 00000002;
if ((fail_rc = pcmcia_request_configuration(link,&link->conf))
!=CS_SUCCESS) {
fail_fn = RequestConfiguration;
fail_rc = pcmcia_request_configuration(link, &link->conf);
if (fail_rc != 0) {
dev_printk(KERN_INFO, &handle_to_dev(link),
"pcmcia_request_configuration failed 0x%x\n",
fail_rc);

View file

@ -65,9 +65,9 @@ static void signalled_reboot_work(struct work_struct *work_reboot)
struct ipw_dev *ipw = container_of(work_reboot, struct ipw_dev,
work_reboot);
struct pcmcia_device *link = ipw->link;
int ret = pccard_reset_card(link->socket);
int ret = pcmcia_reset_card(link->socket);
if (ret != CS_SUCCESS)
if (ret != 0)
cs_error(link, ResetCard, ret);
}
@ -83,7 +83,6 @@ static int config_ipwireless(struct ipw_dev *ipw)
{
struct pcmcia_device *link = ipw->link;
int ret;
config_info_t conf;
tuple_t tuple;
unsigned short buf[64];
cisparse_t parse;
@ -105,7 +104,7 @@ static int config_ipwireless(struct ipw_dev *ipw)
while (ret == 0) {
ret = pcmcia_get_tuple_data(link, &tuple);
if (ret != CS_SUCCESS) {
if (ret != 0) {
cs_error(link, GetTupleData, ret);
goto exit0;
}
@ -116,21 +115,21 @@ static int config_ipwireless(struct ipw_dev *ipw)
ret = pcmcia_get_first_tuple(link, &tuple);
if (ret != CS_SUCCESS) {
if (ret != 0) {
cs_error(link, GetFirstTuple, ret);
goto exit0;
}
ret = pcmcia_get_tuple_data(link, &tuple);
if (ret != CS_SUCCESS) {
if (ret != 0) {
cs_error(link, GetTupleData, ret);
goto exit0;
}
ret = pcmcia_parse_tuple(link, &tuple, &parse);
ret = pcmcia_parse_tuple(&tuple, &parse);
if (ret != CS_SUCCESS) {
if (ret != 0) {
cs_error(link, ParseTuple, ret);
goto exit0;
}
@ -152,21 +151,21 @@ static int config_ipwireless(struct ipw_dev *ipw)
ret = pcmcia_get_first_tuple(link, &tuple);
if (ret != CS_SUCCESS) {
if (ret != 0) {
cs_error(link, GetFirstTuple, ret);
goto exit0;
}
ret = pcmcia_get_tuple_data(link, &tuple);
if (ret != CS_SUCCESS) {
if (ret != 0) {
cs_error(link, GetTupleData, ret);
goto exit0;
}
ret = pcmcia_parse_tuple(link, &tuple, &parse);
ret = pcmcia_parse_tuple(&tuple, &parse);
if (ret != CS_SUCCESS) {
if (ret != 0) {
cs_error(link, GetTupleData, ret);
goto exit0;
}
@ -181,7 +180,7 @@ static int config_ipwireless(struct ipw_dev *ipw)
ret = pcmcia_request_io(link, &link->io);
if (ret != CS_SUCCESS) {
if (ret != 0) {
cs_error(link, RequestIO, ret);
goto exit0;
}
@ -195,21 +194,21 @@ static int config_ipwireless(struct ipw_dev *ipw)
ret = pcmcia_get_first_tuple(link, &tuple);
if (ret != CS_SUCCESS) {
if (ret != 0) {
cs_error(link, GetFirstTuple, ret);
goto exit1;
}
ret = pcmcia_get_tuple_data(link, &tuple);
if (ret != CS_SUCCESS) {
if (ret != 0) {
cs_error(link, GetTupleData, ret);
goto exit1;
}
ret = pcmcia_parse_tuple(link, &tuple, &parse);
ret = pcmcia_parse_tuple(&tuple, &parse);
if (ret != CS_SUCCESS) {
if (ret != 0) {
cs_error(link, ParseTuple, ret);
goto exit1;
}
@ -227,7 +226,7 @@ static int config_ipwireless(struct ipw_dev *ipw)
ret = pcmcia_request_window(&link, &ipw->request_common_memory,
&ipw->handle_common_memory);
if (ret != CS_SUCCESS) {
if (ret != 0) {
cs_error(link, RequestWindow, ret);
goto exit1;
}
@ -239,7 +238,7 @@ static int config_ipwireless(struct ipw_dev *ipw)
ret = pcmcia_map_mem_page(ipw->handle_common_memory,
&memreq_common_memory);
if (ret != CS_SUCCESS) {
if (ret != 0) {
cs_error(link, MapMemPage, ret);
goto exit1;
}
@ -261,7 +260,7 @@ static int config_ipwireless(struct ipw_dev *ipw)
ret = pcmcia_request_window(&link, &ipw->request_attr_memory,
&ipw->handle_attr_memory);
if (ret != CS_SUCCESS) {
if (ret != 0) {
cs_error(link, RequestWindow, ret);
goto exit2;
}
@ -272,7 +271,7 @@ static int config_ipwireless(struct ipw_dev *ipw)
ret = pcmcia_map_mem_page(ipw->handle_attr_memory,
&memreq_attr_memory);
if (ret != CS_SUCCESS) {
if (ret != 0) {
cs_error(link, MapMemPage, ret);
goto exit2;
}
@ -292,20 +291,11 @@ static int config_ipwireless(struct ipw_dev *ipw)
ret = pcmcia_request_irq(link, &link->irq);
if (ret != CS_SUCCESS) {
if (ret != 0) {
cs_error(link, RequestIRQ, ret);
goto exit3;
}
/* Look up current Vcc */
ret = pcmcia_get_configuration_info(link, &conf);
if (ret != CS_SUCCESS) {
cs_error(link, GetConfigurationInfo, ret);
goto exit4;
}
printk(KERN_INFO IPWIRELESS_PCCARD_NAME ": Card type %s\n",
ipw->is_v2_card ? "V2/V3" : "V1");
printk(KERN_INFO IPWIRELESS_PCCARD_NAME
@ -341,7 +331,7 @@ static int config_ipwireless(struct ipw_dev *ipw)
*/
ret = pcmcia_request_configuration(link, &link->conf);
if (ret != CS_SUCCESS) {
if (ret != 0) {
cs_error(link, RequestConfiguration, ret);
goto exit4;
}

View file

@ -276,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;
@ -397,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;
@ -412,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;
@ -433,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);
@ -467,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;
@ -482,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,
@ -588,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)

View file

@ -601,7 +601,7 @@ static int mgslpc_config(struct pcmcia_device *link)
cfg = &(parse.cftable_entry);
CS_CHECK(GetTupleData, pcmcia_get_tuple_data(link, &tuple));
CS_CHECK(ParseTuple, pcmcia_parse_tuple(link, &tuple, &parse));
CS_CHECK(ParseTuple, pcmcia_parse_tuple(&tuple, &parse));
if (cfg->flags & CISTPL_CFTABLE_DEFAULT) dflt = *cfg;
if (cfg->index == 0)

View file

@ -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);
tty->termios->c_cflag &= ~(CSIZE | PARENB);
tty->termios->c_cflag |= (CS8 | CREAD);
}
static int pty_install(struct tty_driver *driver, struct tty_struct *tty)
{
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,111 @@ static int pty_unix98_ioctl(struct tty_struct *tty, struct file *file,
return -ENOIOCTLCMD;
}
static const struct tty_operations pty_unix98_ops = {
/**
* 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,
@ -397,9 +560,89 @@ 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
.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,
.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,
.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

View file

@ -661,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

View file

@ -88,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
@ -973,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
@ -983,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;
}
}
}
}
@ -997,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;
}

View file

@ -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);
}
/*****************************************************************************/

View file

@ -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:

View file

@ -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,

View file

@ -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;
flush_scheduled_work();
spin_lock(&driver_lock);
file->private_data = NULL;
del_singleshot_timer_sync(&chip->user_read_timer);
flush_scheduled_work();
file->private_data = NULL;
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);

View file

@ -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 *);

View file

@ -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);

View file

@ -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;

511
drivers/char/tty_buffer.c Normal file
View file

@ -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);
}

File diff suppressed because it is too large Load diff

View file

@ -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)
{
int nr, head, tail;
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);
#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)
{
struct termiox tnew;
struct tty_ldisc *ld;
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,34 +987,59 @@ 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:
/* FIXME: for correctness we may need to take the termios
lock here - review */
return put_user(C_CLOCAL(real_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;
@ -980,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;
@ -1018,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;
@ -1050,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);

96
drivers/char/tty_port.c Normal file
View file

@ -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);

View file

@ -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
@ -2136,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;
@ -2370,8 +2352,6 @@ rescan_last_byte:
FLUSH
console_conditional_schedule();
release_console_sem();
out:
notify_update(vc);
return n;
#undef FLUSH
@ -2583,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))
@ -2778,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;
@ -2798,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)
@ -2950,10 +2920,19 @@ static const struct tty_operations con_ops = {
.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);
@ -2972,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
@ -3466,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);
@ -3577,7 +3555,7 @@ static int __init vtconsole_class_init(void)
struct con_driver *con = &registered_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);

View file

@ -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;