aboutsummaryrefslogtreecommitdiff
path: root/drivers/char
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/char')
-rw-r--r--drivers/char/Kconfig6
-rw-r--r--drivers/char/Makefile1
-rw-r--r--drivers/char/agp/agp.h12
-rw-r--r--drivers/char/agp/ali-agp.c28
-rw-r--r--drivers/char/agp/amd-k7-agp.c2
-rw-r--r--drivers/char/agp/amd64-agp.c2
-rw-r--r--drivers/char/agp/ati-agp.c23
-rw-r--r--drivers/char/agp/backend.c8
-rw-r--r--drivers/char/agp/efficeon-agp.c5
-rw-r--r--drivers/char/agp/generic.c69
-rw-r--r--drivers/char/agp/hp-agp.c14
-rw-r--r--drivers/char/agp/i460-agp.c47
-rw-r--r--drivers/char/agp/intel-agp.c49
-rw-r--r--drivers/char/agp/nvidia-agp.c2
-rw-r--r--drivers/char/agp/parisc-agp.c22
-rw-r--r--drivers/char/agp/sgi-agp.c9
-rw-r--r--drivers/char/agp/sworks-agp.c2
-rw-r--r--drivers/char/agp/uninorth-agp.c30
-rw-r--r--drivers/char/amiserial.c1
-rw-r--r--drivers/char/bfin_jtag_comm.c30
-rw-r--r--drivers/char/bsr.c42
-rw-r--r--drivers/char/cyclades.c1
-rw-r--r--drivers/char/dtlk.c6
-rw-r--r--drivers/char/epca.c1
-rw-r--r--drivers/char/hvc_console.c2
-rw-r--r--drivers/char/hvc_iseries.c2
-rw-r--r--drivers/char/hvc_vio.c2
-rw-r--r--drivers/char/hvcs.c2
-rw-r--r--drivers/char/hw_random/Kconfig13
-rw-r--r--drivers/char/hw_random/Makefile1
-rw-r--r--drivers/char/hw_random/intel-rng.c9
-rw-r--r--drivers/char/hw_random/tx4939-rng.c184
-rw-r--r--drivers/char/isicom.c19
-rw-r--r--drivers/char/istallion.c3
-rw-r--r--drivers/char/keyboard.c2
-rw-r--r--drivers/char/mem.c115
-rw-r--r--drivers/char/moxa.c1
-rw-r--r--drivers/char/mxser.c3
-rw-r--r--drivers/char/n_hdlc.c47
-rw-r--r--drivers/char/n_r3964.c27
-rw-r--r--drivers/char/n_tty.c7
-rw-r--r--drivers/char/nozomi.c18
-rw-r--r--drivers/char/pcmcia/cm4000_cs.c3
-rw-r--r--drivers/char/pcmcia/ipwireless/tty.c4
-rw-r--r--drivers/char/ppdev.c29
-rw-r--r--drivers/char/pty.c151
-rw-r--r--drivers/char/rio/rio_linux.c1
-rw-r--r--drivers/char/riscom8.c1
-rw-r--r--drivers/char/rocket.c1
-rw-r--r--drivers/char/serial167.c1
-rw-r--r--drivers/char/specialix.c25
-rw-r--r--drivers/char/sx.c1
-rw-r--r--drivers/char/synclink.c1
-rw-r--r--drivers/char/synclink_gt.c73
-rw-r--r--drivers/char/synclinkmp.c1
-rw-r--r--drivers/char/sysrq.c23
-rw-r--r--drivers/char/tb0219.c4
-rw-r--r--drivers/char/tpm/tpm.c1
-rw-r--r--drivers/char/tty_buffer.c13
-rw-r--r--drivers/char/tty_ioctl.c1
-rw-r--r--drivers/char/tty_ldisc.c197
-rw-r--r--drivers/char/tty_port.c4
-rw-r--r--drivers/char/vc_screen.c4
-rw-r--r--drivers/char/vr41xx_giu.c680
-rw-r--r--drivers/char/vt.c13
-rw-r--r--drivers/char/vt_ioctl.c4
66 files changed, 802 insertions, 1303 deletions
diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig
index 30bae6de6a0..6a06913b01d 100644
--- a/drivers/char/Kconfig
+++ b/drivers/char/Kconfig
@@ -807,7 +807,7 @@ if RTC_LIB=n
config RTC
tristate "Enhanced Real Time Clock Support (legacy PC RTC driver)"
depends on !PPC && !PARISC && !IA64 && !M68K && !SPARC && !FRV \
- && !ARM && !SUPERH && !S390 && !AVR32
+ && !ARM && !SUPERH && !S390 && !AVR32 && !BLACKFIN
---help---
If you say Y here and create a character special file /dev/rtc with
major number 10 and minor number 135 using mknod ("man mknod"), you
@@ -1029,10 +1029,6 @@ config CS5535_GPIO
If compiled as a module, it will be called cs5535_gpio.
-config GPIO_VR41XX
- tristate "NEC VR4100 series General-purpose I/O Unit support"
- depends on CPU_VR41XX
-
config RAW_DRIVER
tristate "RAW driver (/dev/raw/rawN)"
depends on BLOCK
diff --git a/drivers/char/Makefile b/drivers/char/Makefile
index 189efcff08c..66f779ad4f4 100644
--- a/drivers/char/Makefile
+++ b/drivers/char/Makefile
@@ -95,7 +95,6 @@ obj-$(CONFIG_SCx200_GPIO) += scx200_gpio.o
obj-$(CONFIG_PC8736x_GPIO) += pc8736x_gpio.o
obj-$(CONFIG_NSC_GPIO) += nsc_gpio.o
obj-$(CONFIG_CS5535_GPIO) += cs5535_gpio.o
-obj-$(CONFIG_GPIO_VR41XX) += vr41xx_giu.o
obj-$(CONFIG_GPIO_TB0219) += tb0219.o
obj-$(CONFIG_TELCLOCK) += tlclk.o
diff --git a/drivers/char/agp/agp.h b/drivers/char/agp/agp.h
index 46f50753117..178e2e9e9f0 100644
--- a/drivers/char/agp/agp.h
+++ b/drivers/char/agp/agp.h
@@ -107,7 +107,7 @@ struct agp_bridge_driver {
void (*agp_enable)(struct agp_bridge_data *, u32);
void (*cleanup)(void);
void (*tlb_flush)(struct agp_memory *);
- unsigned long (*mask_memory)(struct agp_bridge_data *, unsigned long, int);
+ unsigned long (*mask_memory)(struct agp_bridge_data *, struct page *, int);
void (*cache_flush)(void);
int (*create_gatt_table)(struct agp_bridge_data *);
int (*free_gatt_table)(struct agp_bridge_data *);
@@ -115,9 +115,9 @@ struct agp_bridge_driver {
int (*remove_memory)(struct agp_memory *, off_t, int);
struct agp_memory *(*alloc_by_type) (size_t, int);
void (*free_by_type)(struct agp_memory *);
- void *(*agp_alloc_page)(struct agp_bridge_data *);
+ struct page *(*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_page)(struct page *, 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 *);
@@ -278,10 +278,10 @@ int agp_generic_insert_memory(struct agp_memory *mem, off_t pg_start, int type);
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);
+struct page *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_page(struct page *page, int flags);
void agp_generic_destroy_pages(struct agp_memory *memory);
void agp_free_key(int key);
int agp_num_entries(void);
@@ -291,7 +291,7 @@ int agp_3_5_enable(struct agp_bridge_data *bridge);
void global_cache_flush(void);
void get_agp_version(struct agp_bridge_data *bridge);
unsigned long agp_generic_mask_memory(struct agp_bridge_data *bridge,
- unsigned long addr, int type);
+ struct page *page, int type);
int agp_generic_type_to_mask_type(struct agp_bridge_data *bridge,
int type);
struct agp_bridge_data *agp_generic_find_bridge(struct pci_dev *pdev);
diff --git a/drivers/char/agp/ali-agp.c b/drivers/char/agp/ali-agp.c
index dc8d1a90971..201ef3ffd48 100644
--- a/drivers/char/agp/ali-agp.c
+++ b/drivers/char/agp/ali-agp.c
@@ -141,37 +141,37 @@ static void m1541_cache_flush(void)
}
}
-static void *m1541_alloc_page(struct agp_bridge_data *bridge)
+static struct page *m1541_alloc_page(struct agp_bridge_data *bridge)
{
- void *addr = agp_generic_alloc_page(agp_bridge);
+ struct page *page = agp_generic_alloc_page(agp_bridge);
u32 temp;
- if (!addr)
+ if (!page)
return NULL;
pci_read_config_dword(agp_bridge->dev, ALI_CACHE_FLUSH_CTRL, &temp);
pci_write_config_dword(agp_bridge->dev, ALI_CACHE_FLUSH_CTRL,
(((temp & ALI_CACHE_FLUSH_ADDR_MASK) |
- virt_to_gart(addr)) | ALI_CACHE_FLUSH_EN ));
- return addr;
+ phys_to_gart(page_to_phys(page))) | ALI_CACHE_FLUSH_EN ));
+ return page;
}
-static void ali_destroy_page(void * addr, int flags)
+static void ali_destroy_page(struct page *page, int flags)
{
- if (addr) {
+ if (page) {
if (flags & AGP_PAGE_DESTROY_UNMAP) {
global_cache_flush(); /* is this really needed? --hch */
- agp_generic_destroy_page(addr, flags);
+ agp_generic_destroy_page(page, flags);
} else
- agp_generic_destroy_page(addr, flags);
+ agp_generic_destroy_page(page, flags);
}
}
-static void m1541_destroy_page(void * addr, int flags)
+static void m1541_destroy_page(struct page *page, int flags)
{
u32 temp;
- if (addr == NULL)
+ if (page == NULL)
return;
if (flags & AGP_PAGE_DESTROY_UNMAP) {
@@ -180,9 +180,9 @@ static void m1541_destroy_page(void * addr, int flags)
pci_read_config_dword(agp_bridge->dev, ALI_CACHE_FLUSH_CTRL, &temp);
pci_write_config_dword(agp_bridge->dev, ALI_CACHE_FLUSH_CTRL,
(((temp & ALI_CACHE_FLUSH_ADDR_MASK) |
- virt_to_gart(addr)) | ALI_CACHE_FLUSH_EN));
+ phys_to_gart(page_to_phys(page))) | ALI_CACHE_FLUSH_EN));
}
- agp_generic_destroy_page(addr, flags);
+ agp_generic_destroy_page(page, flags);
}
@@ -346,7 +346,7 @@ found:
devs[j].chipset_name = "M1641";
break;
case 0x43:
- devs[j].chipset_name = "M????";
+ devs[j].chipset_name = "M1621";
break;
case 0x47:
devs[j].chipset_name = "M1647";
diff --git a/drivers/char/agp/amd-k7-agp.c b/drivers/char/agp/amd-k7-agp.c
index 3f98254b911..ba9bde71eaa 100644
--- a/drivers/char/agp/amd-k7-agp.c
+++ b/drivers/char/agp/amd-k7-agp.c
@@ -325,7 +325,7 @@ static int amd_insert_memory(struct agp_memory *mem, off_t pg_start, int type)
addr = (j * PAGE_SIZE) + agp_bridge->gart_bus_addr;
cur_gatt = GET_GATT(addr);
writel(agp_generic_mask_memory(agp_bridge,
- mem->memory[i], mem->type), cur_gatt+GET_GATT_OFF(addr));
+ mem->pages[i], mem->type), cur_gatt+GET_GATT_OFF(addr));
readl(cur_gatt+GET_GATT_OFF(addr)); /* PCI Posting. */
}
amd_irongate_tlbflush(mem);
diff --git a/drivers/char/agp/amd64-agp.c b/drivers/char/agp/amd64-agp.c
index d765afda9c2..3bf5dda90f4 100644
--- a/drivers/char/agp/amd64-agp.c
+++ b/drivers/char/agp/amd64-agp.c
@@ -79,7 +79,7 @@ static int amd64_insert_memory(struct agp_memory *mem, off_t pg_start, int type)
for (i = 0, j = pg_start; i < mem->page_count; i++, j++) {
tmp = agp_bridge->driver->mask_memory(agp_bridge,
- mem->memory[i], mask_type);
+ mem->pages[i], mask_type);
BUG_ON(tmp & 0xffffff0000000ffcULL);
pte = (tmp & 0x000000ff00000000ULL) >> 28;
diff --git a/drivers/char/agp/ati-agp.c b/drivers/char/agp/ati-agp.c
index f1537eece07..33656e144cc 100644
--- a/drivers/char/agp/ati-agp.c
+++ b/drivers/char/agp/ati-agp.c
@@ -269,12 +269,17 @@ static int ati_insert_memory(struct agp_memory * mem,
int i, j, num_entries;
unsigned long __iomem *cur_gatt;
unsigned long addr;
+ int mask_type;
num_entries = A_SIZE_LVL2(agp_bridge->current_size)->num_entries;
- if (type != 0 || mem->type != 0)
+ mask_type = agp_generic_type_to_mask_type(mem->bridge, type);
+ if (mask_type != 0 || type != mem->type)
return -EINVAL;
+ if (mem->page_count == 0)
+ return 0;
+
if ((pg_start + mem->page_count) > num_entries)
return -EINVAL;
@@ -296,10 +301,11 @@ static int ati_insert_memory(struct agp_memory * mem,
for (i = 0, j = pg_start; i < mem->page_count; i++, j++) {
addr = (j * PAGE_SIZE) + agp_bridge->gart_bus_addr;
cur_gatt = GET_GATT(addr);
- writel(agp_bridge->driver->mask_memory(agp_bridge,
- mem->memory[i], mem->type), cur_gatt+GET_GATT_OFF(addr));
- readl(cur_gatt+GET_GATT_OFF(addr)); /* PCI Posting. */
+ writel(agp_bridge->driver->mask_memory(agp_bridge,
+ mem->pages[i], mem->type),
+ cur_gatt+GET_GATT_OFF(addr));
}
+ readl(GET_GATT(agp_bridge->gart_bus_addr)); /* PCI posting */
agp_bridge->driver->tlb_flush(mem);
return 0;
}
@@ -310,17 +316,22 @@ static int ati_remove_memory(struct agp_memory * mem, off_t pg_start,
int i;
unsigned long __iomem *cur_gatt;
unsigned long addr;
+ int mask_type;
- if (type != 0 || mem->type != 0)
+ mask_type = agp_generic_type_to_mask_type(mem->bridge, type);
+ if (mask_type != 0 || type != mem->type)
return -EINVAL;
+ if (mem->page_count == 0)
+ return 0;
+
for (i = pg_start; i < (mem->page_count + pg_start); i++) {
addr = (i * PAGE_SIZE) + agp_bridge->gart_bus_addr;
cur_gatt = GET_GATT(addr);
writel(agp_bridge->scratch_page, cur_gatt+GET_GATT_OFF(addr));
- readl(cur_gatt+GET_GATT_OFF(addr)); /* PCI Posting. */
}
+ readl(GET_GATT(agp_bridge->gart_bus_addr)); /* PCI posting */
agp_bridge->driver->tlb_flush(mem);
return 0;
}
diff --git a/drivers/char/agp/backend.c b/drivers/char/agp/backend.c
index 8c617ad7497..cfa5a649dfe 100644
--- a/drivers/char/agp/backend.c
+++ b/drivers/char/agp/backend.c
@@ -141,17 +141,17 @@ static int agp_backend_initialize(struct agp_bridge_data *bridge)
bridge->version = &agp_current_version;
if (bridge->driver->needs_scratch_page) {
- void *addr = bridge->driver->agp_alloc_page(bridge);
+ struct page *page = bridge->driver->agp_alloc_page(bridge);
- if (!addr) {
+ if (!page) {
dev_err(&bridge->dev->dev,
"can't get memory for scratch page\n");
return -ENOMEM;
}
- bridge->scratch_page_real = virt_to_gart(addr);
+ bridge->scratch_page_real = phys_to_gart(page_to_phys(page));
bridge->scratch_page =
- bridge->driver->mask_memory(bridge, bridge->scratch_page_real, 0);
+ bridge->driver->mask_memory(bridge, page, 0);
}
size_value = bridge->driver->fetch_size();
diff --git a/drivers/char/agp/efficeon-agp.c b/drivers/char/agp/efficeon-agp.c
index 453543a1f29..35d50f2861b 100644
--- a/drivers/char/agp/efficeon-agp.c
+++ b/drivers/char/agp/efficeon-agp.c
@@ -65,8 +65,9 @@ static const struct gatt_mask efficeon_generic_masks[] =
};
/* This function does the same thing as mask_memory() for this chipset... */
-static inline unsigned long efficeon_mask_memory(unsigned long addr)
+static inline unsigned long efficeon_mask_memory(struct page *page)
{
+ unsigned long addr = phys_to_gart(page_to_phys(page));
return addr | 0x00000001;
}
@@ -257,7 +258,7 @@ static int efficeon_insert_memory(struct agp_memory * mem, off_t pg_start, int t
last_page = NULL;
for (i = 0; i < count; i++) {
int index = pg_start + i;
- unsigned long insert = efficeon_mask_memory(mem->memory[i]);
+ unsigned long insert = efficeon_mask_memory(mem->pages[i]);
page = (unsigned int *) efficeon_private.l1_table[index >> 10];
diff --git a/drivers/char/agp/generic.c b/drivers/char/agp/generic.c
index 2224b762b7f..1e8b461b91f 100644
--- a/drivers/char/agp/generic.c
+++ b/drivers/char/agp/generic.c
@@ -95,13 +95,13 @@ EXPORT_SYMBOL(agp_flush_chipset);
void agp_alloc_page_array(size_t size, struct agp_memory *mem)
{
- mem->memory = NULL;
+ mem->pages = NULL;
mem->vmalloc_flag = false;
if (size <= 2*PAGE_SIZE)
- mem->memory = kmalloc(size, GFP_KERNEL | __GFP_NORETRY);
- if (mem->memory == NULL) {
- mem->memory = vmalloc(size);
+ mem->pages = kmalloc(size, GFP_KERNEL | __GFP_NORETRY);
+ if (mem->pages == NULL) {
+ mem->pages = vmalloc(size);
mem->vmalloc_flag = true;
}
}
@@ -110,9 +110,9 @@ EXPORT_SYMBOL(agp_alloc_page_array);
void agp_free_page_array(struct agp_memory *mem)
{
if (mem->vmalloc_flag) {
- vfree(mem->memory);
+ vfree(mem->pages);
} else {
- kfree(mem->memory);
+ kfree(mem->pages);
}
}
EXPORT_SYMBOL(agp_free_page_array);
@@ -136,7 +136,7 @@ static struct agp_memory *agp_create_user_memory(unsigned long num_agp_pages)
agp_alloc_page_array(alloc_size, new);
- if (new->memory == NULL) {
+ if (new->pages == NULL) {
agp_free_key(new->key);
kfree(new);
return NULL;
@@ -162,7 +162,7 @@ struct agp_memory *agp_create_memory(int scratch_pages)
agp_alloc_page_array(PAGE_SIZE * scratch_pages, new);
- if (new->memory == NULL) {
+ if (new->pages == NULL) {
agp_free_key(new->key);
kfree(new);
return NULL;
@@ -206,15 +206,13 @@ void agp_free_memory(struct agp_memory *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],
+ curr->pages[i],
AGP_PAGE_DESTROY_UNMAP);
}
for (i = 0; i < curr->page_count; i++) {
curr->bridge->driver->agp_destroy_page(
- (void *)curr->memory[i],
+ curr->pages[i],
AGP_PAGE_DESTROY_FREE);
}
}
@@ -282,13 +280,13 @@ struct agp_memory *agp_allocate_memory(struct agp_bridge_data *bridge,
}
for (i = 0; i < page_count; i++) {
- void *addr = bridge->driver->agp_alloc_page(bridge);
+ struct page *page = bridge->driver->agp_alloc_page(bridge);
- if (addr == NULL) {
+ if (page == NULL) {
agp_free_memory(new);
return NULL;
}
- new->memory[i] = virt_to_gart(addr);
+ new->pages[i] = page;
new->page_count++;
}
new->bridge = bridge;
@@ -1134,7 +1132,7 @@ int agp_generic_insert_memory(struct agp_memory * mem, off_t pg_start, int type)
}
for (i = 0, j = pg_start; i < mem->page_count; i++, j++) {
- writel(bridge->driver->mask_memory(bridge, mem->memory[i], mask_type),
+ writel(bridge->driver->mask_memory(bridge, mem->pages[i], mask_type),
bridge->gatt_table+j);
}
readl(bridge->gatt_table+j-1); /* PCI Posting. */
@@ -1204,7 +1202,7 @@ struct agp_memory *agp_generic_alloc_user(size_t page_count, int type)
return NULL;
for (i = 0; i < page_count; i++)
- new->memory[i] = 0;
+ new->pages[i] = 0;
new->page_count = 0;
new->type = type;
new->num_scratch_pages = pages;
@@ -1237,23 +1235,20 @@ int agp_generic_alloc_pages(struct agp_bridge_data *bridge, struct agp_memory *m
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->pages[i] = page;
mem->page_count++;
}
#ifdef CONFIG_X86
- set_memory_array_uc(mem->memory, num_pages);
+ set_pages_array_uc(mem->pages, 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 *agp_generic_alloc_page(struct agp_bridge_data *bridge)
{
struct page * page;
@@ -1265,56 +1260,47 @@ void *agp_generic_alloc_page(struct agp_bridge_data *bridge)
get_page(page);
atomic_inc(&agp_bridge->current_memory_agp);
- return page_address(page);
+ return page;
}
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);
+ set_pages_array_wb(mem->pages, mem->page_count);
#endif
for (i = 0; i < mem->page_count; i++) {
- addr = (void *)mem->memory[i];
- page = virt_to_page(addr);
+ page = mem->pages[i];
#ifndef CONFIG_X86
unmap_page_from_agp(page);
#endif
-
put_page(page);
- free_page((unsigned long)addr);
+ __free_page(page);
atomic_dec(&agp_bridge->current_memory_agp);
- mem->memory[i] = 0;
+ mem->pages[i] = NULL;
}
}
EXPORT_SYMBOL(agp_generic_destroy_pages);
-void agp_generic_destroy_page(void *addr, int flags)
+void agp_generic_destroy_page(struct page *page, int flags)
{
- struct page *page;
-
- if (addr == NULL)
+ if (page == NULL)
return;
- page = virt_to_page(addr);
if (flags & AGP_PAGE_DESTROY_UNMAP)
unmap_page_from_agp(page);
if (flags & AGP_PAGE_DESTROY_FREE) {
put_page(page);
- free_page((unsigned long)addr);
+ __free_page(page);
atomic_dec(&agp_bridge->current_memory_agp);
}
}
@@ -1361,8 +1347,9 @@ void global_cache_flush(void)
EXPORT_SYMBOL(global_cache_flush);
unsigned long agp_generic_mask_memory(struct agp_bridge_data *bridge,
- unsigned long addr, int type)
+ struct page *page, int type)
{
+ unsigned long addr = phys_to_gart(page_to_phys(page));
/* memory type is ignored in the generic routine */
if (bridge->driver->masks)
return addr | bridge->driver->masks[0].mask;
diff --git a/drivers/char/agp/hp-agp.c b/drivers/char/agp/hp-agp.c
index 183ac3fe44f..8f3d4c18491 100644
--- a/drivers/char/agp/hp-agp.c
+++ b/drivers/char/agp/hp-agp.c
@@ -361,13 +361,11 @@ hp_zx1_insert_memory (struct agp_memory *mem, off_t pg_start, int type)
for (i = 0, j = io_pg_start; i < mem->page_count; i++) {
unsigned long paddr;
- paddr = mem->memory[i];
+ paddr = page_to_phys(mem->pages[i]);
for (k = 0;
k < hp->io_pages_per_kpage;
k++, j++, paddr += hp->io_page_size) {
- hp->gatt[j] =
- agp_bridge->driver->mask_memory(agp_bridge,
- paddr, type);
+ hp->gatt[j] = HP_ZX1_PDIR_VALID_BIT | paddr;
}
}
@@ -397,8 +395,9 @@ hp_zx1_remove_memory (struct agp_memory *mem, off_t pg_start, int type)
static unsigned long
hp_zx1_mask_memory (struct agp_bridge_data *bridge,
- unsigned long addr, int type)
+ struct page *page, int type)
{
+ unsigned long addr = phys_to_gart(page_to_phys(page));
return HP_ZX1_PDIR_VALID_BIT | addr;
}
@@ -518,8 +517,9 @@ zx1_gart_probe (acpi_handle obj, u32 depth, void *context, void **ret)
if (hp_zx1_setup(sba_hpa + HP_ZX1_IOC_OFFSET, lba_hpa))
return AE_OK;
- printk(KERN_INFO PFX "Detected HP ZX1 %s AGP chipset (ioc=%lx, lba=%lx)\n",
- (char *) context, sba_hpa + HP_ZX1_IOC_OFFSET, lba_hpa);
+ printk(KERN_INFO PFX "Detected HP ZX1 %s AGP chipset "
+ "(ioc=%llx, lba=%llx)\n", (char *)context,
+ sba_hpa + HP_ZX1_IOC_OFFSET, lba_hpa);
hp_zx1_gart_found = 1;
return AE_CTRL_TERMINATE; /* we only support one bridge; quit looking */
diff --git a/drivers/char/agp/i460-agp.c b/drivers/char/agp/i460-agp.c
index 10da687d131..60cc35bb5db 100644
--- a/drivers/char/agp/i460-agp.c
+++ b/drivers/char/agp/i460-agp.c
@@ -60,6 +60,9 @@
*/
#define WR_FLUSH_GATT(index) RD_GATT(index)
+static unsigned long i460_mask_memory (struct agp_bridge_data *bridge,
+ unsigned long addr, int type);
+
static struct {
void *gatt; /* ioremap'd GATT area */
@@ -74,6 +77,7 @@ static struct {
unsigned long *alloced_map; /* bitmap of kernel-pages in use */
int refcount; /* number of kernel pages using the large page */
u64 paddr; /* physical address of large page */
+ struct page *page; /* page pointer */
} *lp_desc;
} i460;
@@ -294,7 +298,7 @@ static int i460_insert_memory_small_io_page (struct agp_memory *mem,
void *temp;
pr_debug("i460_insert_memory_small_io_page(mem=%p, pg_start=%ld, type=%d, paddr0=0x%lx)\n",
- mem, pg_start, type, mem->memory[0]);
+ mem, pg_start, type, page_to_phys(mem->pages[0]));
if (type >= AGP_USER_TYPES || mem->type >= AGP_USER_TYPES)
return -EINVAL;
@@ -321,10 +325,9 @@ static int i460_insert_memory_small_io_page (struct agp_memory *mem,
io_page_size = 1UL << I460_IO_PAGE_SHIFT;
for (i = 0, j = io_pg_start; i < mem->page_count; i++) {
- paddr = mem->memory[i];
+ paddr = phys_to_gart(page_to_phys(mem->pages[i]));
for (k = 0; k < I460_IOPAGES_PER_KPAGE; k++, j++, paddr += io_page_size)
- WR_GATT(j, agp_bridge->driver->mask_memory(agp_bridge,
- paddr, mem->type));
+ WR_GATT(j, i460_mask_memory(agp_bridge, paddr, mem->type));
}
WR_FLUSH_GATT(j - 1);
return 0;
@@ -364,10 +367,9 @@ static int i460_alloc_large_page (struct lp_desc *lp)
{
unsigned long order = I460_IO_PAGE_SHIFT - PAGE_SHIFT;
size_t map_size;
- void *lpage;
- lpage = (void *) __get_free_pages(GFP_KERNEL, order);
- if (!lpage) {
+ lp->page = alloc_pages(GFP_KERNEL, order);
+ if (!lp->page) {
printk(KERN_ERR PFX "Couldn't alloc 4M GART page...\n");
return -ENOMEM;
}
@@ -375,12 +377,12 @@ static int i460_alloc_large_page (struct lp_desc *lp)
map_size = ((I460_KPAGES_PER_IOPAGE + BITS_PER_LONG - 1) & -BITS_PER_LONG)/8;
lp->alloced_map = kzalloc(map_size, GFP_KERNEL);
if (!lp->alloced_map) {
- free_pages((unsigned long) lpage, order);
+ __free_pages(lp->page, order);
printk(KERN_ERR PFX "Out of memory, we're in trouble...\n");
return -ENOMEM;
}
- lp->paddr = virt_to_gart(lpage);
+ lp->paddr = phys_to_gart(page_to_phys(lp->page));
lp->refcount = 0;
atomic_add(I460_KPAGES_PER_IOPAGE, &agp_bridge->current_memory_agp);
return 0;
@@ -391,7 +393,7 @@ static void i460_free_large_page (struct lp_desc *lp)
kfree(lp->alloced_map);
lp->alloced_map = NULL;
- free_pages((unsigned long) gart_to_virt(lp->paddr), I460_IO_PAGE_SHIFT - PAGE_SHIFT);
+ __free_pages(lp->page, I460_IO_PAGE_SHIFT - PAGE_SHIFT);
atomic_sub(I460_KPAGES_PER_IOPAGE, &agp_bridge->current_memory_agp);
}
@@ -439,8 +441,8 @@ static int i460_insert_memory_large_io_page (struct agp_memory *mem,
if (i460_alloc_large_page(lp) < 0)
return -ENOMEM;
pg = lp - i460.lp_desc;
- WR_GATT(pg, agp_bridge->driver->mask_memory(agp_bridge,
- lp->paddr, 0));
+ WR_GATT(pg, i460_mask_memory(agp_bridge,
+ lp->paddr, 0));
WR_FLUSH_GATT(pg);
}
@@ -448,7 +450,7 @@ static int i460_insert_memory_large_io_page (struct agp_memory *mem,
idx < ((lp == end) ? (end_offset + 1) : I460_KPAGES_PER_IOPAGE);
idx++, i++)
{
- mem->memory[i] = lp->paddr + idx*PAGE_SIZE;
+ mem->pages[i] = lp->page;
__set_bit(idx, lp->alloced_map);
++lp->refcount;
}
@@ -463,7 +465,7 @@ static int i460_remove_memory_large_io_page (struct agp_memory *mem,
struct lp_desc *start, *end, *lp;
void *temp;
- temp = agp_bridge->driver->current_size;
+ temp = agp_bridge->current_size;
num_entries = A_SIZE_8(temp)->num_entries;
/* Figure out what pg_start means in terms of our large GART pages */
@@ -477,7 +479,7 @@ static int i460_remove_memory_large_io_page (struct agp_memory *mem,
idx < ((lp == end) ? (end_offset + 1) : I460_KPAGES_PER_IOPAGE);
idx++, i++)
{
- mem->memory[i] = 0;
+ mem->pages[i] = NULL;
__clear_bit(idx, lp->alloced_map);
--lp->refcount;
}
@@ -521,7 +523,7 @@ static int i460_remove_memory (struct agp_memory *mem,
* Let's just hope nobody counts on the allocated AGP memory being there before bind time
* (I don't think current drivers do)...
*/
-static void *i460_alloc_page (struct agp_bridge_data *bridge)
+static struct page *i460_alloc_page (struct agp_bridge_data *bridge)
{
void *page;
@@ -534,7 +536,7 @@ static void *i460_alloc_page (struct agp_bridge_data *bridge)
return page;
}
-static void i460_destroy_page (void *page, int flags)
+static void i460_destroy_page (struct page *page, int flags)
{
if (I460_IO_PAGE_SHIFT <= PAGE_SHIFT) {
agp_generic_destroy_page(page, flags);
@@ -544,13 +546,20 @@ static void i460_destroy_page (void *page, int flags)
#endif /* I460_LARGE_IO_PAGES */
static unsigned long i460_mask_memory (struct agp_bridge_data *bridge,
- unsigned long addr, int type)
+ unsigned long addr, int type)
{
/* Make sure the returned address is a valid GATT entry */
return bridge->driver->masks[0].mask
| (((addr & ~((1 << I460_IO_PAGE_SHIFT) - 1)) & 0xfffff000) >> 12);
}
+static unsigned long i460_page_mask_memory(struct agp_bridge_data *bridge,
+ struct page *page, int type)
+{
+ unsigned long addr = phys_to_gart(page_to_phys(page));
+ return i460_mask_memory(bridge, addr, type);
+}
+
const struct agp_bridge_driver intel_i460_driver = {
.owner = THIS_MODULE,
.aperture_sizes = i460_sizes,
@@ -560,7 +569,7 @@ const struct agp_bridge_driver intel_i460_driver = {
.fetch_size = i460_fetch_size,
.cleanup = i460_cleanup,
.tlb_flush = i460_tlb_flush,
- .mask_memory = i460_mask_memory,
+ .mask_memory = i460_page_mask_memory,
.masks = i460_masks,
.agp_enable = agp_generic_enable,
.cache_flush = global_cache_flush,
diff --git a/drivers/char/agp/intel-agp.c b/drivers/char/agp/intel-agp.c
index 7a748fa0dfc..8c9d50db5c3 100644
--- a/drivers/char/agp/intel-agp.c
+++ b/drivers/char/agp/intel-agp.c
@@ -257,7 +257,7 @@ static void intel_i810_agp_enable(struct agp_bridge_data *bridge, u32 mode)
}
/* Exists to support ARGB cursors */
-static void *i8xx_alloc_pages(void)
+static struct page *i8xx_alloc_pages(void)
{
struct page *page;
@@ -272,17 +272,14 @@ static void *i8xx_alloc_pages(void)
}
get_page(page);
atomic_inc(&agp_bridge->current_memory_agp);
- return page_address(page);
+ return page;
}
-static void i8xx_destroy_pages(void *addr)
+static void i8xx_destroy_pages(struct page *page)
{
- struct page *page;
-
- if (addr == NULL)
+ if (page == NULL)
return;
- page = virt_to_page(addr);
set_pages_wb(page, 4);
put_page(page);
__free_pages(page, 2);
@@ -346,7 +343,7 @@ static int intel_i810_insert_entries(struct agp_memory *mem, off_t pg_start,
global_cache_flush();
for (i = 0, j = pg_start; i < mem->page_count; i++, j++) {
writel(agp_bridge->driver->mask_memory(agp_bridge,
- mem->memory[i],
+ mem->pages[i],
mask_type),
intel_private.registers+I810_PTE_BASE+(j*4));
}
@@ -389,37 +386,37 @@ static int intel_i810_remove_entries(struct agp_memory *mem, off_t pg_start,
static struct agp_memory *alloc_agpphysmem_i8xx(size_t pg_count, int type)
{
struct agp_memory *new;
- void *addr;
+ struct page *page;
switch (pg_count) {
- case 1: addr = agp_bridge->driver->agp_alloc_page(agp_bridge);
+ case 1: page = agp_bridge->driver->agp_alloc_page(agp_bridge);
break;
case 4:
/* kludge to get 4 physical pages for ARGB cursor */
- addr = i8xx_alloc_pages();
+ page = i8xx_alloc_pages();
break;
default:
return NULL;
}
- if (addr == NULL)
+ if (page == NULL)
return NULL;
new = agp_create_memory(pg_count);
if (new == NULL)
return NULL;
- new->memory[0] = virt_to_gart(addr);
+ new->pages[0] = page;
if (pg_count == 4) {
/* kludge to get 4 physical pages for ARGB cursor */
- new->memory[1] = new->memory[0] + PAGE_SIZE;
- new->memory[2] = new->memory[1] + PAGE_SIZE;
- new->memory[3] = new->memory[2] + PAGE_SIZE;
+ new->pages[1] = new->pages[0] + 1;
+ new->pages[2] = new->pages[1] + 1;
+ new->pages[3] = new->pages[2] + 1;
}
new->page_count = pg_count;
new->num_scratch_pages = pg_count;
new->type = AGP_PHYS_MEMORY;
- new->physical = new->memory[0];
+ new->physical = page_to_phys(new->pages[0]);
return new;
}
@@ -451,13 +448,11 @@ static void intel_i810_free_by_type(struct agp_memory *curr)
agp_free_key(curr->key);
if (curr->type == AGP_PHYS_MEMORY) {
if (curr->page_count == 4)
- i8xx_destroy_pages(gart_to_virt(curr->memory[0]));
+ i8xx_destroy_pages(curr->pages[0]);
else {
- void *va = gart_to_virt(curr->memory[0]);
-
- agp_bridge->driver->agp_destroy_page(va,
+ agp_bridge->driver->agp_destroy_page(curr->pages[0],
AGP_PAGE_DESTROY_UNMAP);
- agp_bridge->driver->agp_destroy_page(va,
+ agp_bridge->driver->agp_destroy_page(curr->pages[0],
AGP_PAGE_DESTROY_FREE);
}
agp_free_page_array(curr);
@@ -466,8 +461,9 @@ static void intel_i810_free_by_type(struct agp_memory *curr)
}
static unsigned long intel_i810_mask_memory(struct agp_bridge_data *bridge,
- unsigned long addr, int type)
+ struct page *page, int type)
{
+ unsigned long addr = phys_to_gart(page_to_phys(page));
/* Type checking must be done elsewhere */
return addr | bridge->driver->masks[type].mask;
}
@@ -855,7 +851,7 @@ static int intel_i830_insert_entries(struct agp_memory *mem, off_t pg_start,
for (i = 0, j = pg_start; i < mem->page_count; i++, j++) {
writel(agp_bridge->driver->mask_memory(agp_bridge,
- mem->memory[i], mask_type),
+ mem->pages[i], mask_type),
intel_private.registers+I810_PTE_BASE+(j*4));
}
readl(intel_private.registers+I810_PTE_BASE+((j-1)*4));
@@ -1085,7 +1081,7 @@ static int intel_i915_insert_entries(struct agp_memory *mem, off_t pg_start,
for (i = 0, j = pg_start; i < mem->page_count; i++, j++) {
writel(agp_bridge->driver->mask_memory(agp_bridge,
- mem->memory[i], mask_type), intel_private.gtt+j);
+ mem->pages[i], mask_type), intel_private.gtt+j);
}
readl(intel_private.gtt+j-1);
@@ -1200,8 +1196,9 @@ static int intel_i915_create_gatt_table(struct agp_bridge_data *bridge)
* this conditional.
*/
static unsigned long intel_i965_mask_memory(struct agp_bridge_data *bridge,
- unsigned long addr, int type)
+ struct page *page, int type)
{
+ dma_addr_t addr = phys_to_gart(page_to_phys(page));
/* Shift high bits down */
addr |= (addr >> 28) & 0xf0;
diff --git a/drivers/char/agp/nvidia-agp.c b/drivers/char/agp/nvidia-agp.c
index 16acee2de11..263d71dd441 100644
--- a/drivers/char/agp/nvidia-agp.c
+++ b/drivers/char/agp/nvidia-agp.c
@@ -225,7 +225,7 @@ static int nvidia_insert_memory(struct agp_memory *mem, off_t pg_start, int type
}
for (i = 0, j = pg_start; i < mem->page_count; i++, j++) {
writel(agp_bridge->driver->mask_memory(agp_bridge,
- mem->memory[i], mask_type),
+ mem->pages[i], mask_type),
agp_bridge->gatt_table+nvidia_private.pg_offset+j);
}
diff --git a/drivers/char/agp/parisc-agp.c b/drivers/char/agp/parisc-agp.c
index 699e3422ad9..e077701ae3d 100644
--- a/drivers/char/agp/parisc-agp.c
+++ b/drivers/char/agp/parisc-agp.c
@@ -31,6 +31,10 @@
#define AGP8X_MODE_BIT 3
#define AGP8X_MODE (1 << AGP8X_MODE_BIT)
+static unsigned long
+parisc_agp_mask_memory(struct agp_bridge_data *bridge, unsigned long addr,
+ int type);
+
static struct _parisc_agp_info {
void __iomem *ioc_regs;
void __iomem *lba_regs;
@@ -149,12 +153,12 @@ parisc_agp_insert_memory(struct agp_memory *mem, off_t pg_start, int type)
for (i = 0, j = io_pg_start; i < mem->page_count; i++) {
unsigned long paddr;
- paddr = mem->memory[i];
+ paddr = page_to_phys(mem->pages[i]);
for (k = 0;
k < info->io_pages_per_kpage;
k++, j++, paddr += info->io_page_size) {
info->gatt[j] =
- agp_bridge->driver->mask_memory(agp_bridge,
+ parisc_agp_mask_memory(agp_bridge,
paddr, type);
}
}
@@ -185,9 +189,17 @@ parisc_agp_remove_memory(struct agp_memory *mem, off_t pg_start, int type)
}
static unsigned long
-parisc_agp_mask_memory(struct agp_bridge_data *bridge,
- unsigned long addr, int type)
+parisc_agp_mask_memory(struct agp_bridge_data *bridge, unsigned long addr,
+ int type)
+{
+ return SBA_PDIR_VALID_BIT | addr;
+}
+
+static unsigned long
+parisc_agp_page_mask_memory(struct agp_bridge_data *bridge, struct page *page,
+ int type)
{
+ unsigned long addr = phys_to_gart(page_to_phys(page));
return SBA_PDIR_VALID_BIT | addr;
}
@@ -213,7 +225,7 @@ static const struct agp_bridge_driver parisc_agp_driver = {
.configure = parisc_agp_configure,
.fetch_size = parisc_agp_fetch_size,
.tlb_flush = parisc_agp_tlbflush,
- .mask_memory = parisc_agp_mask_memory,
+ .mask_memory = parisc_agp_page_mask_memory,
.masks = parisc_agp_masks,
.agp_enable = parisc_agp_enable,
.cache_flush = global_cache_flush,
diff --git a/drivers/char/agp/sgi-agp.c b/drivers/char/agp/sgi-agp.c
index b972d83bb1b..d3ea2e4226b 100644
--- a/drivers/char/agp/sgi-agp.c
+++ b/drivers/char/agp/sgi-agp.c
@@ -38,7 +38,7 @@ static struct aper_size_info_fixed sgi_tioca_sizes[] = {
{0, 0, 0},
};
-static void *sgi_tioca_alloc_page(struct agp_bridge_data *bridge)
+static struct page *sgi_tioca_alloc_page(struct agp_bridge_data *bridge)
{
struct page *page;
int nid;
@@ -52,7 +52,7 @@ static void *sgi_tioca_alloc_page(struct agp_bridge_data *bridge)
get_page(page);
atomic_inc(&agp_bridge->current_memory_agp);
- return page_address(page);
+ return page;
}
/*
@@ -71,8 +71,9 @@ static void sgi_tioca_tlbflush(struct agp_memory *mem)
*/
static unsigned long
sgi_tioca_mask_memory(struct agp_bridge_data *bridge,
- unsigned long addr, int type)
+ struct page *page, int type)
{
+ unsigned long addr = phys_to_gart(page_to_phys(page));
return tioca_physpage_to_gart(addr);
}
@@ -189,7 +190,7 @@ static int sgi_tioca_insert_memory(struct agp_memory *mem, off_t pg_start,
for (i = 0, j = pg_start; i < mem->page_count; i++, j++) {
table[j] =
- bridge->driver->mask_memory(bridge, mem->memory[i],
+ bridge->driver->mask_memory(bridge, mem->pages[i],
mem->type);
}
diff --git a/drivers/char/agp/sworks-agp.c b/drivers/char/agp/sworks-agp.c
index 6224df8b7f0..b964a219932 100644
--- a/drivers/char/agp/sworks-agp.c
+++ b/drivers/char/agp/sworks-agp.c
@@ -349,7 +349,7 @@ static int serverworks_insert_memory(struct agp_memory *mem,
for (i = 0, j = pg_start; i < mem->page_count; i++, j++) {
addr = (j * PAGE_SIZE) + agp_bridge->gart_bus_addr;
cur_gatt = SVRWRKS_GET_GATT(addr);
- writel(agp_bridge->driver->mask_memory(agp_bridge, mem->memory[i], mem->type), cur_gatt+GET_GATT_OFF(addr));
+ writel(agp_bridge->driver->mask_memory(agp_bridge, mem->pages[i], mem->type), cur_gatt+GET_GATT_OFF(addr));
}
serverworks_tlbflush(mem);
return 0;
diff --git a/drivers/char/agp/uninorth-agp.c b/drivers/char/agp/uninorth-agp.c
index 03f95ec08f5..f192c3b9ad4 100644
--- a/drivers/char/agp/uninorth-agp.c
+++ b/drivers/char/agp/uninorth-agp.c
@@ -146,13 +146,20 @@ static int uninorth_insert_memory(struct agp_memory *mem, off_t pg_start,
{
int i, j, num_entries;
void *temp;
+ int mask_type;
temp = agp_bridge->current_size;
num_entries = A_SIZE_32(temp)->num_entries;
- if (type != 0 || mem->type != 0)
+ if (type != mem->type)
+ return -EINVAL;
+
+ mask_type = agp_bridge->driver->agp_type_to_mask_type(agp_bridge, type);
+ if (mask_type != 0) {
/* We know nothing of memory types */
return -EINVAL;
+ }
+
if ((pg_start + mem->page_count) > num_entries)
return -EINVAL;
@@ -166,9 +173,9 @@ static int uninorth_insert_memory(struct agp_memory *mem, off_t pg_start,
for (i = 0, j = pg_start; i < mem->page_count; i++, j++) {
agp_bridge->gatt_table[j] =
- cpu_to_le32((mem->memory[i] & 0xFFFFF000UL) | 0x1UL);
- flush_dcache_range((unsigned long)__va(mem->memory[i]),
- (unsigned long)__va(mem->memory[i])+0x1000);
+ cpu_to_le32((page_to_phys(mem->pages[i]) & 0xFFFFF000UL) | 0x1UL);
+ flush_dcache_range((unsigned long)__va(page_to_phys(mem->pages[i])),
+ (unsigned long)__va(page_to_phys(mem->pages[i]))+0x1000);
}
(void)in_le32((volatile u32*)&agp_bridge->gatt_table[pg_start]);
mb();
@@ -184,13 +191,20 @@ static int u3_insert_memory(struct agp_memory *mem, off_t pg_start, int type)
int i, num_entries;
void *temp;
u32 *gp;
+ int mask_type;
temp = agp_bridge->current_size;
num_entries = A_SIZE_32(temp)->num_entries;
- if (type != 0 || mem->type != 0)
+ if (type != mem->type)
+ return -EINVAL;
+
+ mask_type = agp_bridge->driver->agp_type_to_mask_type(agp_bridge, type);
+ if (mask_type != 0) {
/* We know nothing of memory types */
return -EINVAL;
+ }
+
if ((pg_start + mem->page_count) > num_entries)
return -EINVAL;
@@ -205,9 +219,9 @@ static int u3_insert_memory(struct agp_memory *mem, off_t pg_start, int type)
}
for (i = 0; i < mem->page_count; i++) {
- gp[i] = (mem->memory[i] >> PAGE_SHIFT) | 0x80000000UL;
- flush_dcache_range((unsigned long)__va(mem->memory[i]),
- (unsigned long)__va(mem->memory[i])+0x1000);
+ gp[i] = (page_to_phys(mem->pages[i]) >> PAGE_SHIFT) | 0x80000000UL;
+ flush_dcache_range((unsigned long)__va(page_to_phys(mem->pages[i])),
+ (unsigned long)__va(page_to_phys(mem->pages[i]))+0x1000);
}
mb();
flush_dcache_range((unsigned long)gp, (unsigned long) &gp[i]);
diff --git a/drivers/char/amiserial.c b/drivers/char/amiserial.c
index 72429b6b2fa..6c32fbf0716 100644
--- a/drivers/char/amiserial.c
+++ b/drivers/char/amiserial.c
@@ -81,6 +81,7 @@ static char *serial_version = "4.30";
#include <linux/mm.h>
#include <linux/seq_file.h>
#include <linux/slab.h>
+#include <linux/smp_lock.h>
#include <linux/init.h>
#include <linux/bitops.h>
diff --git a/drivers/char/bfin_jtag_comm.c b/drivers/char/bfin_jtag_comm.c
index 44c113d5604..1d7c34c73b2 100644
--- a/drivers/char/bfin_jtag_comm.c
+++ b/drivers/char/bfin_jtag_comm.c
@@ -8,6 +8,10 @@
* Licensed under the GPL-2 or later.
*/
+#define DRV_NAME "bfin-jtag-comm"
+#define DEV_NAME "ttyBFJC"
+#define pr_fmt(fmt) DRV_NAME ": " fmt
+
#include <linux/circ_buf.h>
#include <linux/console.h>
#include <linux/delay.h>
@@ -22,18 +26,14 @@
#include <linux/tty_flip.h>
#include <asm/atomic.h>
+#define pr_init(fmt, args...) ({ static const __initconst char __fmt[] = fmt; printk(__fmt, ## args); })
+
/* See the Debug/Emulation chapter in the HRM */
#define EMUDOF 0x00000001 /* EMUDAT_OUT full & valid */
#define EMUDIF 0x00000002 /* EMUDAT_IN full & valid */
#define EMUDOOVF 0x00000004 /* EMUDAT_OUT overflow */
#define EMUDIOVF 0x00000008 /* EMUDAT_IN overflow */
-#define DRV_NAME "bfin-jtag-comm"
-#define DEV_NAME "ttyBFJC"
-
-#define pr_init(fmt, args...) ({ static const __initdata char __fmt[] = fmt; printk(__fmt, ## args); })
-#define debug(fmt, args...) pr_debug(DRV_NAME ": " fmt, ## args)
-
static inline uint32_t bfin_write_emudat(uint32_t emudat)
{
__asm__ __volatile__("emudat = %0;" : : "d"(emudat));
@@ -74,7 +74,7 @@ bfin_jc_emudat_manager(void *arg)
while (!kthread_should_stop()) {
/* no one left to give data to, so sleep */
if (bfin_jc_tty == NULL && circ_empty(&bfin_jc_write_buf)) {
- debug("waiting for readers\n");
+ pr_debug("waiting for readers\n");
__set_current_state(TASK_UNINTERRUPTIBLE);
schedule();
__set_current_state(TASK_RUNNING);
@@ -82,7 +82,7 @@ bfin_jc_emudat_manager(void *arg)
/* no data available, so just chill */
if (!(bfin_read_DBGSTAT() & EMUDIF) && circ_empty(&bfin_jc_write_buf)) {
- debug("waiting for data (in_len = %i) (circ: %i %i)\n",
+ pr_debug("waiting for data (in_len = %i) (circ: %i %i)\n",
inbound_len, bfin_jc_write_buf.tail, bfin_jc_write_buf.head);
if (inbound_len)
schedule();
@@ -99,11 +99,11 @@ bfin_jc_emudat_manager(void *arg)
if (tty != NULL) {
uint32_t emudat = bfin_read_emudat();
if (inbound_len == 0) {
- debug("incoming length: 0x%08x\n", emudat);
+ pr_debug("incoming length: 0x%08x\n", emudat);
inbound_len = emudat;
} else {
size_t num_chars = (4 <= inbound_len ? 4 : inbound_len);
- debug(" incoming data: 0x%08x (pushing %zu)\n", emudat, num_chars);
+ pr_debug(" incoming data: 0x%08x (pushing %zu)\n", emudat, num_chars);
inbound_len -= num_chars;
tty_insert_flip_string(tty, (unsigned char *)&emudat, num_chars);
tty_flip_buffer_push(tty);
@@ -117,7 +117,7 @@ bfin_jc_emudat_manager(void *arg)
if (outbound_len == 0) {
outbound_len = circ_cnt(&bfin_jc_write_buf);
bfin_write_emudat(outbound_len);
- debug("outgoing length: 0x%08x\n", outbound_len);
+ pr_debug("outgoing length: 0x%08x\n", outbound_len);
} else {
struct tty_struct *tty;
int tail = bfin_jc_write_buf.tail;
@@ -136,7 +136,7 @@ bfin_jc_emudat_manager(void *arg)
if (tty)
tty_wakeup(tty);
mutex_unlock(&bfin_jc_tty_mutex);
- debug(" outgoing data: 0x%08x (pushing %zu)\n", emudat, ate);
+ pr_debug(" outgoing data: 0x%08x (pushing %zu)\n", emudat, ate);
}
}
}
@@ -149,7 +149,7 @@ static int
bfin_jc_open(struct tty_struct *tty, struct file *filp)
{
mutex_lock(&bfin_jc_tty_mutex);
- debug("open %lu\n", bfin_jc_count);
+ pr_debug("open %lu\n", bfin_jc_count);
++bfin_jc_count;
bfin_jc_tty = tty;
wake_up_process(bfin_jc_kthread);
@@ -161,7 +161,7 @@ static void
bfin_jc_close(struct tty_struct *tty, struct file *filp)
{
mutex_lock(&bfin_jc_tty_mutex);
- debug("close %lu\n", bfin_jc_count);
+ pr_debug("close %lu\n", bfin_jc_count);
if (--bfin_jc_count == 0)
bfin_jc_tty = NULL;
wake_up_process(bfin_jc_kthread);
@@ -174,7 +174,7 @@ bfin_jc_circ_write(const unsigned char *buf, int count)
{
int i;
count = min(count, circ_free(&bfin_jc_write_buf));
- debug("going to write chunk of %i bytes\n", count);
+ pr_debug("going to write chunk of %i bytes\n", count);
for (i = 0; i < count; ++i)
circ_byte(&bfin_jc_write_buf, bfin_jc_write_buf.head + i) = buf[i];
bfin_jc_write_buf.head += i;
diff --git a/drivers/char/bsr.c b/drivers/char/bsr.c
index 140ea10ecb8..c02db01f736 100644
--- a/drivers/char/bsr.c
+++ b/drivers/char/bsr.c
@@ -27,6 +27,7 @@
#include <linux/cdev.h>
#include <linux/list.h>
#include <linux/mm.h>
+#include <asm/pgtable.h>
#include <asm/io.h>
/*
@@ -75,12 +76,13 @@ static struct class *bsr_class;
static int bsr_major;
enum {
- BSR_8 = 0,
- BSR_16 = 1,
- BSR_64 = 2,
- BSR_128 = 3,
- BSR_UNKNOWN = 4,
- BSR_MAX = 5,
+ BSR_8 = 0,
+ BSR_16 = 1,
+ BSR_64 = 2,
+ BSR_128 = 3,
+ BSR_4096 = 4,
+ BSR_UNKNOWN = 5,
+ BSR_MAX = 6,
};
static unsigned bsr_types[BSR_MAX];
@@ -117,15 +119,22 @@ static int bsr_mmap(struct file *filp, struct vm_area_struct *vma)
{
unsigned long size = vma->vm_end - vma->vm_start;
struct bsr_dev *dev = filp->private_data;
+ int ret;
- if (size > dev->bsr_len || (size & (PAGE_SIZE-1)))
- return -EINVAL;
-
- vma->vm_flags |= (VM_IO | VM_DONTEXPAND);
vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
- if (io_remap_pfn_range(vma, vma->vm_start, dev->bsr_addr >> PAGE_SHIFT,
- size, vma->vm_page_prot))
+ /* check for the case of a small BSR device and map one 4k page for it*/
+ if (dev->bsr_len < PAGE_SIZE && size == PAGE_SIZE)
+ ret = remap_4k_pfn(vma, vma->vm_start, dev->bsr_addr >> 12,
+ vma->vm_page_prot);
+ else if (size <= dev->bsr_len)
+ ret = io_remap_pfn_range(vma, vma->vm_start,
+ dev->bsr_addr >> PAGE_SHIFT,
+ size, vma->vm_page_prot);
+ else
+ return -EINVAL;
+
+ if (ret)
return -EAGAIN;
return 0;
@@ -205,6 +214,11 @@ static int bsr_add_node(struct device_node *bn)
cur->bsr_stride = bsr_stride[i];
cur->bsr_dev = MKDEV(bsr_major, i + total_bsr_devs);
+ /* if we have a bsr_len of > 4k and less then PAGE_SIZE (64k pages) */
+ /* we can only map 4k of it, so only advertise the 4k in sysfs */
+ if (cur->bsr_len > 4096 && cur->bsr_len < PAGE_SIZE)
+ cur->bsr_len = 4096;
+
switch(cur->bsr_bytes) {
case 8:
cur->bsr_type = BSR_8;
@@ -218,9 +232,11 @@ static int bsr_add_node(struct device_node *bn)
case 128:
cur->bsr_type = BSR_128;
break;
+ case 4096:
+ cur->bsr_type = BSR_4096;
+ break;
default:
cur->bsr_type = BSR_UNKNOWN;
- printk(KERN_INFO "unknown BSR size %d\n",cur->bsr_bytes);
}
cur->bsr_num = bsr_types[cur->bsr_type];
diff --git a/drivers/char/cyclades.c b/drivers/char/cyclades.c
index f3366d3f06c..2dafc2da064 100644
--- a/drivers/char/cyclades.c
+++ b/drivers/char/cyclades.c
@@ -633,6 +633,7 @@
#include <linux/tty.h>
#include <linux/tty_flip.h>
#include <linux/serial.h>
+#include <linux/smp_lock.h>
#include <linux/major.h>
#include <linux/string.h>
#include <linux/fcntl.h>
diff --git a/drivers/char/dtlk.c b/drivers/char/dtlk.c
index 6b900b297cc..52e06589821 100644
--- a/drivers/char/dtlk.c
+++ b/drivers/char/dtlk.c
@@ -571,7 +571,7 @@ static char dtlk_read_tts(void)
portval = inb_p(dtlk_port_tts);
} while ((portval & TTS_READABLE) == 0 &&
retries++ < DTLK_MAX_RETRIES);
- if (retries == DTLK_MAX_RETRIES)
+ if (retries > DTLK_MAX_RETRIES)
printk(KERN_ERR "dtlk_read_tts() timeout\n");
ch = inb_p(dtlk_port_tts); /* input from TTS port */
@@ -583,7 +583,7 @@ static char dtlk_read_tts(void)
portval = inb_p(dtlk_port_tts);
} while ((portval & TTS_READABLE) != 0 &&
retries++ < DTLK_MAX_RETRIES);
- if (retries == DTLK_MAX_RETRIES)
+ if (retries > DTLK_MAX_RETRIES)
printk(KERN_ERR "dtlk_read_tts() timeout\n");
TRACE_RET;
@@ -640,7 +640,7 @@ static char dtlk_write_tts(char ch)
while ((inb_p(dtlk_port_tts) & TTS_WRITABLE) == 0 &&
retries++ < DTLK_MAX_RETRIES) /* DT ready? */
;
- if (retries == DTLK_MAX_RETRIES)
+ if (retries > DTLK_MAX_RETRIES)
printk(KERN_ERR "dtlk_write_tts() timeout\n");
outb_p(ch, dtlk_port_tts); /* output to TTS port */
diff --git a/drivers/char/epca.c b/drivers/char/epca.c
index abef1f7d84f..ff647ca1c48 100644
--- a/drivers/char/epca.c
+++ b/drivers/char/epca.c
@@ -36,6 +36,7 @@
#include <linux/tty.h>
#include <linux/tty_flip.h>
#include <linux/slab.h>
+#include <linux/smp_lock.h>
#include <linux/ioport.h>
#include <linux/interrupt.h>
#include <linux/uaccess.h>
diff --git a/drivers/char/hvc_console.c b/drivers/char/hvc_console.c
index 94e7e3c8c05..d97779ef72c 100644
--- a/drivers/char/hvc_console.c
+++ b/drivers/char/hvc_console.c
@@ -552,7 +552,7 @@ static int hvc_chars_in_buffer(struct tty_struct *tty)
struct hvc_struct *hp = tty->driver_data;
if (!hp)
- return -1;
+ return 0;
return hp->n_outbuf;
}
diff --git a/drivers/char/hvc_iseries.c b/drivers/char/hvc_iseries.c
index 449727b6166..936d05bf37f 100644
--- a/drivers/char/hvc_iseries.c
+++ b/drivers/char/hvc_iseries.c
@@ -241,7 +241,7 @@ static int __devexit hvc_vio_remove(struct vio_dev *vdev)
static struct vio_driver hvc_vio_driver = {
.id_table = hvc_driver_table,
.probe = hvc_vio_probe,
- .remove = hvc_vio_remove,
+ .remove = __devexit_p(hvc_vio_remove),
.driver = {
.name = hvc_driver_name,
.owner = THIS_MODULE,
diff --git a/drivers/char/hvc_vio.c b/drivers/char/hvc_vio.c
index bd62dc86b47..c72b994652a 100644
--- a/drivers/char/hvc_vio.c
+++ b/drivers/char/hvc_vio.c
@@ -113,7 +113,7 @@ static int __devexit hvc_vio_remove(struct vio_dev *vdev)
static struct vio_driver hvc_vio_driver = {
.id_table = hvc_driver_table,
.probe = hvc_vio_probe,
- .remove = hvc_vio_remove,
+ .remove = __devexit_p(hvc_vio_remove),
.driver = {
.name = hvc_driver_name,
.owner = THIS_MODULE,
diff --git a/drivers/char/hvcs.c b/drivers/char/hvcs.c
index 7d64e4230e6..266b858b8f8 100644
--- a/drivers/char/hvcs.c
+++ b/drivers/char/hvcs.c
@@ -868,7 +868,7 @@ static int __devexit hvcs_remove(struct vio_dev *dev)
static struct vio_driver hvcs_vio_driver = {
.id_table = hvcs_driver_table,
.probe = hvcs_probe,
- .remove = hvcs_remove,
+ .remove = __devexit_p(hvcs_remove),
.driver = {
.name = hvcs_driver_name,
.owner = THIS_MODULE,
diff --git a/drivers/char/hw_random/Kconfig b/drivers/char/hw_random/Kconfig
index f4b3f7293fe..ce66a70184f 100644
--- a/drivers/char/hw_random/Kconfig
+++ b/drivers/char/hw_random/Kconfig
@@ -149,6 +149,19 @@ config HW_RANDOM_VIRTIO
To compile this driver as a module, choose M here: the
module will be called virtio-rng. If unsure, say N.
+config HW_RANDOM_TX4939
+ tristate "TX4939 Random Number Generator support"
+ depends on HW_RANDOM && SOC_TX4939
+ default HW_RANDOM
+ ---help---
+ This driver provides kernel-side support for the Random Number
+ Generator hardware found on TX4939 SoC.
+
+ To compile this driver as a module, choose M here: the
+ module will be called tx4939-rng.
+
+ If unsure, say Y.
+
config HW_RANDOM_MXC_RNGA
tristate "Freescale i.MX RNGA Random Number Generator"
depends on HW_RANDOM && ARCH_HAS_RNGA
diff --git a/drivers/char/hw_random/Makefile b/drivers/char/hw_random/Makefile
index fd1ecd2f673..676828ba812 100644
--- a/drivers/char/hw_random/Makefile
+++ b/drivers/char/hw_random/Makefile
@@ -15,4 +15,5 @@ obj-$(CONFIG_HW_RANDOM_IXP4XX) += ixp4xx-rng.o
obj-$(CONFIG_HW_RANDOM_OMAP) += omap-rng.o
obj-$(CONFIG_HW_RANDOM_PASEMI) += pasemi-rng.o
obj-$(CONFIG_HW_RANDOM_VIRTIO) += virtio-rng.o
+obj-$(CONFIG_HW_RANDOM_TX4939) += tx4939-rng.o
obj-$(CONFIG_HW_RANDOM_MXC_RNGA) += mxc-rnga.o
diff --git a/drivers/char/hw_random/intel-rng.c b/drivers/char/hw_random/intel-rng.c
index 5dcbe603eca..91b53eb1c05 100644
--- a/drivers/char/hw_random/intel-rng.c
+++ b/drivers/char/hw_random/intel-rng.c
@@ -305,10 +305,11 @@ static int __init intel_init_hw_struct(struct intel_rng_hw *intel_rng_hw,
(BIOS_CNTL_LOCK_ENABLE_MASK|BIOS_CNTL_WRITE_ENABLE_MASK))
== BIOS_CNTL_LOCK_ENABLE_MASK) {
static __initdata /*const*/ char warning[] =
- KERN_WARNING PFX "Firmware space is locked read-only. If you can't or\n"
- KERN_WARNING PFX "don't want to disable this in firmware setup, and if\n"
- KERN_WARNING PFX "you are certain that your system has a functional\n"
- KERN_WARNING PFX "RNG, try using the 'no_fwh_detect' option.\n";
+ KERN_WARNING
+PFX "Firmware space is locked read-only. If you can't or\n"
+PFX "don't want to disable this in firmware setup, and if\n"
+PFX "you are certain that your system has a functional\n"
+PFX "RNG, try using the 'no_fwh_detect' option.\n";
if (no_fwh_detect)
return -ENODEV;
diff --git a/drivers/char/hw_random/tx4939-rng.c b/drivers/char/hw_random/tx4939-rng.c
new file mode 100644
index 00000000000..544d9085a8e
--- /dev/null
+++ b/drivers/char/hw_random/tx4939-rng.c
@@ -0,0 +1,184 @@
+/*
+ * RNG driver for TX4939 Random Number Generators (RNG)
+ *
+ * Copyright (C) 2009 Atsushi Nemoto <anemo@mba.ocn.ne.jp>
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/platform_device.h>
+#include <linux/hw_random.h>
+
+#define TX4939_RNG_RCSR 0x00000000
+#define TX4939_RNG_ROR(n) (0x00000018 + (n) * 8)
+
+#define TX4939_RNG_RCSR_INTE 0x00000008
+#define TX4939_RNG_RCSR_RST 0x00000004
+#define TX4939_RNG_RCSR_FIN 0x00000002
+#define TX4939_RNG_RCSR_ST 0x00000001
+
+struct tx4939_rng {
+ struct hwrng rng;
+ void __iomem *base;
+ u64 databuf[3];
+ unsigned int data_avail;
+};
+
+static void rng_io_start(void)
+{
+#ifndef CONFIG_64BIT
+ /*
+ * readq is reading a 64-bit register using a 64-bit load. On
+ * a 32-bit kernel however interrupts or any other processor
+ * exception would clobber the upper 32-bit of the processor
+ * register so interrupts need to be disabled.
+ */
+ local_irq_disable();
+#endif
+}
+
+static void rng_io_end(void)
+{
+#ifndef CONFIG_64BIT
+ local_irq_enable();
+#endif
+}
+
+static u64 read_rng(void __iomem *base, unsigned int offset)
+{
+ return ____raw_readq(base + offset);
+}
+
+static void write_rng(u64 val, void __iomem *base, unsigned int offset)
+{
+ return ____raw_writeq(val, base + offset);
+}
+
+static int tx4939_rng_data_present(struct hwrng *rng, int wait)
+{
+ struct tx4939_rng *rngdev = container_of(rng, struct tx4939_rng, rng);
+ int i;
+
+ if (rngdev->data_avail)
+ return rngdev->data_avail;
+ for (i = 0; i < 20; i++) {
+ rng_io_start();
+ if (!(read_rng(rngdev->base, TX4939_RNG_RCSR)
+ & TX4939_RNG_RCSR_ST)) {
+ rngdev->databuf[0] =
+ read_rng(rngdev->base, TX4939_RNG_ROR(0));
+ rngdev->databuf[1] =
+ read_rng(rngdev->base, TX4939_RNG_ROR(1));
+ rngdev->databuf[2] =
+ read_rng(rngdev->base, TX4939_RNG_ROR(2));
+ rngdev->data_avail =
+ sizeof(rngdev->databuf) / sizeof(u32);
+ /* Start RNG */
+ write_rng(TX4939_RNG_RCSR_ST,
+ rngdev->base, TX4939_RNG_RCSR);
+ wait = 0;
+ }
+ rng_io_end();
+ if (!wait)
+ break;
+ /* 90 bus clock cycles by default for generation */
+ ndelay(90 * 5);
+ }
+ return rngdev->data_avail;
+}
+
+static int tx4939_rng_data_read(struct hwrng *rng, u32 *buffer)
+{
+ struct tx4939_rng *rngdev = container_of(rng, struct tx4939_rng, rng);
+
+ rngdev->data_avail--;
+ *buffer = *((u32 *)&rngdev->databuf + rngdev->data_avail);
+ return sizeof(u32);
+}
+
+static int __init tx4939_rng_probe(struct platform_device *dev)
+{
+ struct tx4939_rng *rngdev;
+ struct resource *r;
+ int i;
+
+ r = platform_get_resource(dev, IORESOURCE_MEM, 0);
+ if (!r)
+ return -EBUSY;
+ rngdev = devm_kzalloc(&dev->dev, sizeof(*rngdev), GFP_KERNEL);
+ if (!rngdev)
+ return -ENOMEM;
+ if (!devm_request_mem_region(&dev->dev, r->start, resource_size(r),
+ dev_name(&dev->dev)))
+ return -EBUSY;
+ rngdev->base = devm_ioremap(&dev->dev, r->start, resource_size(r));
+ if (!rngdev->base)
+ return -EBUSY;
+
+ rngdev->rng.name = dev_name(&dev->dev);
+ rngdev->rng.data_present = tx4939_rng_data_present;
+ rngdev->rng.data_read = tx4939_rng_data_read;
+
+ rng_io_start();
+ /* Reset RNG */
+ write_rng(TX4939_RNG_RCSR_RST, rngdev->base, TX4939_RNG_RCSR);
+ write_rng(0, rngdev->base, TX4939_RNG_RCSR);
+ /* Start RNG */
+ write_rng(TX4939_RNG_RCSR_ST, rngdev->base, TX4939_RNG_RCSR);
+ rng_io_end();
+ /*
+ * Drop first two results. From the datasheet:
+ * The quality of the random numbers generated immediately
+ * after reset can be insufficient. Therefore, do not use
+ * random numbers obtained from the first and second
+ * generations; use the ones from the third or subsequent
+ * generation.
+ */
+ for (i = 0; i < 2; i++) {
+ rngdev->data_avail = 0;
+ if (!tx4939_rng_data_present(&rngdev->rng, 1))
+ return -EIO;
+ }
+
+ platform_set_drvdata(dev, rngdev);
+ return hwrng_register(&rngdev->rng);
+}
+
+static int __exit tx4939_rng_remove(struct platform_device *dev)
+{
+ struct tx4939_rng *rngdev = platform_get_drvdata(dev);
+
+ hwrng_unregister(&rngdev->rng);
+ platform_set_drvdata(dev, NULL);
+ return 0;
+}
+
+static struct platform_driver tx4939_rng_driver = {
+ .driver = {
+ .name = "tx4939-rng",
+ .owner = THIS_MODULE,
+ },
+ .remove = tx4939_rng_remove,
+};
+
+static int __init tx4939rng_init(void)
+{
+ return platform_driver_probe(&tx4939_rng_driver, tx4939_rng_probe);
+}
+
+static void __exit tx4939rng_exit(void)
+{
+ platform_driver_unregister(&tx4939_rng_driver);
+}
+
+module_init(tx4939rng_init);
+module_exit(tx4939rng_exit);
+
+MODULE_DESCRIPTION("H/W Random Number Generator (RNG) driver for TX4939");
+MODULE_LICENSE("GPL");
diff --git a/drivers/char/isicom.c b/drivers/char/isicom.c
index 4d745a89504..4f1f4cd670d 100644
--- a/drivers/char/isicom.c
+++ b/drivers/char/isicom.c
@@ -122,6 +122,7 @@
#include <linux/fs.h>
#include <linux/sched.h>
#include <linux/serial.h>
+#include <linux/smp_lock.h>
#include <linux/mm.h>
#include <linux/interrupt.h>
#include <linux/timer.h>
@@ -1478,10 +1479,10 @@ static int __devinit load_firmware(struct pci_dev *pdev,
status = inw(base + 0x4);
if (status != 0) {
dev_warn(&pdev->dev, "Card%d rejected load header:\n"
- KERN_WARNING "Address:0x%x\n"
- KERN_WARNING "Count:0x%x\n"
- KERN_WARNING "Status:0x%x\n",
- index + 1, frame->addr, frame->count, status);
+ "Address:0x%x\n"
+ "Count:0x%x\n"
+ "Status:0x%x\n",
+ index + 1, frame->addr, frame->count, status);
goto errrelfw;
}
outsw(base, frame->data, word_count);
@@ -1526,10 +1527,10 @@ static int __devinit load_firmware(struct pci_dev *pdev,
status = inw(base + 0x4);
if (status != 0) {
dev_warn(&pdev->dev, "Card%d rejected verify header:\n"
- KERN_WARNING "Address:0x%x\n"
- KERN_WARNING "Count:0x%x\n"
- KERN_WARNING "Status: 0x%x\n",
- index + 1, frame->addr, frame->count, status);
+ "Address:0x%x\n"
+ "Count:0x%x\n"
+ "Status: 0x%x\n",
+ index + 1, frame->addr, frame->count, status);
goto errrelfw;
}
@@ -1593,7 +1594,7 @@ static unsigned int card_count;
static int __devinit isicom_probe(struct pci_dev *pdev,
const struct pci_device_id *ent)
{
- unsigned int signature, index;
+ unsigned int uninitialized_var(signature), index;
int retval = -EPERM;
struct isi_board *board = NULL;
diff --git a/drivers/char/istallion.c b/drivers/char/istallion.c
index e18800c400b..ab2f3349c5c 100644
--- a/drivers/char/istallion.c
+++ b/drivers/char/istallion.c
@@ -20,6 +20,7 @@
#include <linux/module.h>
#include <linux/slab.h>
+#include <linux/smp_lock.h>
#include <linux/interrupt.h>
#include <linux/tty.h>
#include <linux/tty_flip.h>
@@ -3785,7 +3786,7 @@ err:
return retval;
}
-static void stli_pciremove(struct pci_dev *pdev)
+static void __devexit stli_pciremove(struct pci_dev *pdev)
{
struct stlibrd *brdp = pci_get_drvdata(pdev);
diff --git a/drivers/char/keyboard.c b/drivers/char/keyboard.c
index de26a978fbd..737be953cc5 100644
--- a/drivers/char/keyboard.c
+++ b/drivers/char/keyboard.c
@@ -1123,8 +1123,6 @@ static int emulate_raw(struct vc_data *vc, unsigned int keycode,
#define HW_RAW(dev) 0
-#warning "Cannot generate rawmode keyboard for your architecture yet."
-
static int emulate_raw(struct vc_data *vc, unsigned int keycode, unsigned char up_flag)
{
if (keycode > 127)
diff --git a/drivers/char/mem.c b/drivers/char/mem.c
index f96d0bef855..afa8813e737 100644
--- a/drivers/char/mem.c
+++ b/drivers/char/mem.c
@@ -863,59 +863,58 @@ static const struct file_operations kmsg_fops = {
.write = kmsg_write,
};
-static int memory_open(struct inode * inode, struct file * filp)
-{
- int ret = 0;
-
- lock_kernel();
- switch (iminor(inode)) {
- case 1:
- filp->f_op = &mem_fops;
- filp->f_mapping->backing_dev_info =
- &directly_mappable_cdev_bdi;
- break;
+static const struct {
+ unsigned int minor;
+ char *name;
+ umode_t mode;
+ const struct file_operations *fops;
+ struct backing_dev_info *dev_info;
+} devlist[] = { /* list of minor devices */
+ {1, "mem", S_IRUSR | S_IWUSR | S_IRGRP, &mem_fops,
+ &directly_mappable_cdev_bdi},
#ifdef CONFIG_DEVKMEM
- case 2:
- filp->f_op = &kmem_fops;
- filp->f_mapping->backing_dev_info =
- &directly_mappable_cdev_bdi;
- break;
+ {2, "kmem", S_IRUSR | S_IWUSR | S_IRGRP, &kmem_fops,
+ &directly_mappable_cdev_bdi},
#endif
- case 3:
- filp->f_op = &null_fops;
- break;
+ {3, "null", S_IRUGO | S_IWUGO, &null_fops, NULL},
#ifdef CONFIG_DEVPORT
- case 4:
- filp->f_op = &port_fops;
- break;
+ {4, "port", S_IRUSR | S_IWUSR | S_IRGRP, &port_fops, NULL},
#endif
- case 5:
- filp->f_mapping->backing_dev_info = &zero_bdi;
- filp->f_op = &zero_fops;
- break;
- case 7:
- filp->f_op = &full_fops;
- break;
- case 8:
- filp->f_op = &random_fops;
- break;
- case 9:
- filp->f_op = &urandom_fops;
- break;
- case 11:
- filp->f_op = &kmsg_fops;
- break;
+ {5, "zero", S_IRUGO | S_IWUGO, &zero_fops, &zero_bdi},
+ {7, "full", S_IRUGO | S_IWUGO, &full_fops, NULL},
+ {8, "random", S_IRUGO | S_IWUSR, &random_fops, NULL},
+ {9, "urandom", S_IRUGO | S_IWUSR, &urandom_fops, NULL},
+ {11,"kmsg", S_IRUGO | S_IWUSR, &kmsg_fops, NULL},
#ifdef CONFIG_CRASH_DUMP
- case 12:
- filp->f_op = &oldmem_fops;
- break;
+ {12,"oldmem", S_IRUSR | S_IWUSR | S_IRGRP, &oldmem_fops, NULL},
#endif
- default:
- unlock_kernel();
- return -ENXIO;
+};
+
+static int memory_open(struct inode *inode, struct file *filp)
+{
+ int ret = 0;
+ int i;
+
+ lock_kernel();
+
+ for (i = 0; i < ARRAY_SIZE(devlist); i++) {
+ if (devlist[i].minor == iminor(inode)) {
+ filp->f_op = devlist[i].fops;
+ if (devlist[i].dev_info) {
+ filp->f_mapping->backing_dev_info =
+ devlist[i].dev_info;
+ }
+
+ break;
+ }
}
- if (filp->f_op && filp->f_op->open)
- ret = filp->f_op->open(inode,filp);
+
+ if (i == ARRAY_SIZE(devlist))
+ ret = -ENXIO;
+ else
+ if (filp->f_op && filp->f_op->open)
+ ret = filp->f_op->open(inode, filp);
+
unlock_kernel();
return ret;
}
@@ -924,30 +923,6 @@ static const struct file_operations memory_fops = {
.open = memory_open, /* just a selector for the real open */
};
-static const struct {
- unsigned int minor;
- char *name;
- umode_t mode;
- const struct file_operations *fops;
-} devlist[] = { /* list of minor devices */
- {1, "mem", S_IRUSR | S_IWUSR | S_IRGRP, &mem_fops},
-#ifdef CONFIG_DEVKMEM
- {2, "kmem", S_IRUSR | S_IWUSR | S_IRGRP, &kmem_fops},
-#endif
- {3, "null", S_IRUGO | S_IWUGO, &null_fops},
-#ifdef CONFIG_DEVPORT
- {4, "port", S_IRUSR | S_IWUSR | S_IRGRP, &port_fops},
-#endif
- {5, "zero", S_IRUGO | S_IWUGO, &zero_fops},
- {7, "full", S_IRUGO | S_IWUGO, &full_fops},
- {8, "random", S_IRUGO | S_IWUSR, &random_fops},
- {9, "urandom", S_IRUGO | S_IWUSR, &urandom_fops},
- {11,"kmsg", S_IRUGO | S_IWUSR, &kmsg_fops},
-#ifdef CONFIG_CRASH_DUMP
- {12,"oldmem", S_IRUSR | S_IWUSR | S_IRGRP, &oldmem_fops},
-#endif
-};
-
static struct class *mem_class;
static int __init chr_dev_init(void)
diff --git a/drivers/char/moxa.c b/drivers/char/moxa.c
index 65b6ff2442c..dd0083bbb64 100644
--- a/drivers/char/moxa.c
+++ b/drivers/char/moxa.c
@@ -34,6 +34,7 @@
#include <linux/tty.h>
#include <linux/tty_flip.h>
#include <linux/major.h>
+#include <linux/smp_lock.h>
#include <linux/string.h>
#include <linux/fcntl.h>
#include <linux/ptrace.h>
diff --git a/drivers/char/mxser.c b/drivers/char/mxser.c
index 9533f43a30b..dbf8d52f31d 100644
--- a/drivers/char/mxser.c
+++ b/drivers/char/mxser.c
@@ -23,6 +23,7 @@
#include <linux/errno.h>
#include <linux/signal.h>
#include <linux/sched.h>
+#include <linux/smp_lock.h>
#include <linux/timer.h>
#include <linux/interrupt.h>
#include <linux/tty.h>
@@ -1048,8 +1049,6 @@ static int mxser_open(struct tty_struct *tty, struct file *filp)
if (retval)
return retval;
- /* unmark here for very high baud rate (ex. 921600 bps) used */
- tty->low_latency = 1;
return 0;
}
diff --git a/drivers/char/n_hdlc.c b/drivers/char/n_hdlc.c
index 461ece591a5..c68118efad8 100644
--- a/drivers/char/n_hdlc.c
+++ b/drivers/char/n_hdlc.c
@@ -10,7 +10,6 @@
* Paul Mackerras <Paul.Mackerras@cs.anu.edu.au>
*
* Original release 01/11/99
- * $Id: n_hdlc.c,v 4.8 2003/05/06 21:18:51 paulkf Exp $
*
* This code is released under the GNU General Public License (GPL)
*
@@ -79,7 +78,6 @@
*/
#define HDLC_MAGIC 0x239e
-#define HDLC_VERSION "$Revision: 4.8 $"
#include <linux/module.h>
#include <linux/init.h>
@@ -99,6 +97,7 @@
#include <linux/slab.h>
#include <linux/tty.h>
#include <linux/errno.h>
+#include <linux/smp_lock.h>
#include <linux/string.h> /* used in new tty drivers */
#include <linux/signal.h> /* used in new tty drivers */
#include <linux/if.h>
@@ -114,7 +113,7 @@
#define MAX_HDLC_FRAME_SIZE 65535
#define DEFAULT_RX_BUF_COUNT 10
#define MAX_RX_BUF_COUNT 60
-#define DEFAULT_TX_BUF_COUNT 1
+#define DEFAULT_TX_BUF_COUNT 3
struct n_hdlc_buf {
struct n_hdlc_buf *link;
@@ -199,6 +198,31 @@ static void n_hdlc_tty_wakeup(struct tty_struct *tty);
#define tty2n_hdlc(tty) ((struct n_hdlc *) ((tty)->disc_data))
#define n_hdlc2tty(n_hdlc) ((n_hdlc)->tty)
+static void flush_rx_queue(struct tty_struct *tty)
+{
+ struct n_hdlc *n_hdlc = tty2n_hdlc(tty);
+ struct n_hdlc_buf *buf;
+
+ while ((buf = n_hdlc_buf_get(&n_hdlc->rx_buf_list)))
+ n_hdlc_buf_put(&n_hdlc->rx_free_buf_list, buf);
+}
+
+static void flush_tx_queue(struct tty_struct *tty)
+{
+ struct n_hdlc *n_hdlc = tty2n_hdlc(tty);
+ struct n_hdlc_buf *buf;
+ unsigned long flags;
+
+ while ((buf = n_hdlc_buf_get(&n_hdlc->tx_buf_list)))
+ n_hdlc_buf_put(&n_hdlc->tx_free_buf_list, buf);
+ spin_lock_irqsave(&n_hdlc->tx_buf_list.spinlock, flags);
+ if (n_hdlc->tbuf) {
+ n_hdlc_buf_put(&n_hdlc->tx_free_buf_list, n_hdlc->tbuf);
+ n_hdlc->tbuf = NULL;
+ }
+ spin_unlock_irqrestore(&n_hdlc->tx_buf_list.spinlock, flags);
+}
+
static struct tty_ldisc_ops n_hdlc_ldisc = {
.owner = THIS_MODULE,
.magic = TTY_LDISC_MAGIC,
@@ -211,6 +235,7 @@ static struct tty_ldisc_ops n_hdlc_ldisc = {
.poll = n_hdlc_tty_poll,
.receive_buf = n_hdlc_tty_receive,
.write_wakeup = n_hdlc_tty_wakeup,
+ .flush_buffer = flush_rx_queue,
};
/**
@@ -341,10 +366,7 @@ static int n_hdlc_tty_open (struct tty_struct *tty)
set_bit(TTY_NO_WRITE_SPLIT,&tty->flags);
#endif
- /* Flush any pending characters in the driver and discipline. */
- if (tty->ldisc->ops->flush_buffer)
- tty->ldisc->ops->flush_buffer(tty);
-
+ /* flush receive data from driver */
tty_driver_flush_buffer(tty);
if (debuglevel >= DEBUG_LEVEL_INFO)
@@ -763,6 +785,14 @@ static int n_hdlc_tty_ioctl(struct tty_struct *tty, struct file *file,
error = put_user(count, (int __user *)arg);
break;
+ case TCFLSH:
+ switch (arg) {
+ case TCIOFLUSH:
+ case TCOFLUSH:
+ flush_tx_queue(tty);
+ }
+ /* fall through to default */
+
default:
error = n_tty_ioctl_helper(tty, file, cmd, arg);
break;
@@ -919,8 +949,7 @@ static struct n_hdlc_buf* n_hdlc_buf_get(struct n_hdlc_buf_list *list)
} /* end of n_hdlc_buf_get() */
static char hdlc_banner[] __initdata =
- KERN_INFO "HDLC line discipline: version " HDLC_VERSION
- ", maxframe=%u\n";
+ KERN_INFO "HDLC line discipline maxframe=%u\n";
static char hdlc_register_ok[] __initdata =
KERN_INFO "N_HDLC line discipline registered.\n";
static char hdlc_register_fail[] __initdata =
diff --git a/drivers/char/n_r3964.c b/drivers/char/n_r3964.c
index d2e93e34322..6934025a1ac 100644
--- a/drivers/char/n_r3964.c
+++ b/drivers/char/n_r3964.c
@@ -58,6 +58,7 @@
#include <linux/ioport.h>
#include <linux/in.h>
#include <linux/slab.h>
+#include <linux/smp_lock.h>
#include <linux/tty.h>
#include <linux/errno.h>
#include <linux/string.h> /* used in new tty drivers */
@@ -1062,7 +1063,7 @@ static ssize_t r3964_read(struct tty_struct *tty, struct file *file,
struct r3964_client_info *pClient;
struct r3964_message *pMsg;
struct r3964_client_message theMsg;
- int count;
+ int ret;
TRACE_L("read()");
@@ -1074,8 +1075,8 @@ static ssize_t r3964_read(struct tty_struct *tty, struct file *file,
if (pMsg == NULL) {
/* no messages available. */
if (file->f_flags & O_NONBLOCK) {
- unlock_kernel();
- return -EAGAIN;
+ ret = -EAGAIN;
+ goto unlock;
}
/* block until there is a message: */
wait_event_interruptible(pInfo->read_wait,
@@ -1085,29 +1086,31 @@ static ssize_t r3964_read(struct tty_struct *tty, struct file *file,
/* If we still haven't got a message, we must have been signalled */
if (!pMsg) {
- unlock_kernel();
- return -EINTR;
+ ret = -EINTR;
+ goto unlock;
}
/* deliver msg to client process: */
theMsg.msg_id = pMsg->msg_id;
theMsg.arg = pMsg->arg;
theMsg.error_code = pMsg->error_code;
- count = sizeof(struct r3964_client_message);
+ ret = sizeof(struct r3964_client_message);
kfree(pMsg);
TRACE_M("r3964_read - msg kfree %p", pMsg);
- if (copy_to_user(buf, &theMsg, count)) {
- unlock_kernel();
- return -EFAULT;
+ if (copy_to_user(buf, &theMsg, ret)) {
+ ret = -EFAULT;
+ goto unlock;
}
- TRACE_PS("read - return %d", count);
- return count;
+ TRACE_PS("read - return %d", ret);
+ goto unlock;
}
+ ret = -EPERM;
+unlock:
unlock_kernel();
- return -EPERM;
+ return ret;
}
static ssize_t r3964_write(struct tty_struct *tty, struct file *file,
diff --git a/drivers/char/n_tty.c b/drivers/char/n_tty.c
index 94a5d5020ab..4e28b35024e 100644
--- a/drivers/char/n_tty.c
+++ b/drivers/char/n_tty.c
@@ -300,8 +300,7 @@ static int do_output_char(unsigned char c, struct tty_struct *tty, int space)
if (space < 2)
return -1;
tty->canon_column = tty->column = 0;
- tty_put_char(tty, '\r');
- tty_put_char(tty, c);
+ tty->ops->write(tty, "\r\n", 2);
return 2;
}
tty->canon_column = tty->column;
@@ -1331,9 +1330,6 @@ handle_newline:
static void n_tty_write_wakeup(struct tty_struct *tty)
{
- /* Write out any echoed characters that are still pending */
- process_echoes(tty);
-
if (tty->fasync && test_and_clear_bit(TTY_DO_WRITE_WAKEUP, &tty->flags))
kill_fasync(&tty->fasync, SIGIO, POLL_OUT);
}
@@ -1586,6 +1582,7 @@ static int n_tty_open(struct tty_struct *tty)
static inline int input_available_p(struct tty_struct *tty, int amt)
{
+ tty_flush_to_ldisc(tty);
if (tty->icanon) {
if (tty->canon_data)
return 1;
diff --git a/drivers/char/nozomi.c b/drivers/char/nozomi.c
index d6102b644b5..ec58d8c387f 100644
--- a/drivers/char/nozomi.c
+++ b/drivers/char/nozomi.c
@@ -828,7 +828,7 @@ static int receive_data(enum port_type index, struct nozomi *dc)
struct port *port = &dc->port[index];
void __iomem *addr = port->dl_addr[port->toggle_dl];
struct tty_struct *tty = tty_port_tty_get(&port->port);
- int i;
+ int i, ret;
if (unlikely(!tty)) {
DBG1("tty not open for port: %d?", index);
@@ -844,12 +844,14 @@ static int receive_data(enum port_type index, struct nozomi *dc)
/* disable interrupt in downlink... */
disable_transmit_dl(index, dc);
- return 0;
+ ret = 0;
+ goto put;
}
if (unlikely(size == 0)) {
dev_err(&dc->pdev->dev, "size == 0?\n");
- return 1;
+ ret = 1;
+ goto put;
}
tty_buffer_request_room(tty, size);
@@ -871,8 +873,10 @@ static int receive_data(enum port_type index, struct nozomi *dc)
}
set_bit(index, &dc->flip);
+ ret = 1;
+put:
tty_kref_put(tty);
- return 1;
+ return ret;
}
/* Debug for interrupts */
@@ -1591,8 +1595,6 @@ static int ntty_open(struct tty_struct *tty, struct file *file)
/* Enable interrupt downlink for channel */
if (port->port.count == 1) {
- /* FIXME: is this needed now ? */
- tty->low_latency = 1;
tty->driver_data = port;
tty_port_tty_set(&port->port, tty);
DBG1("open: %d", port->token_dl);
@@ -1864,16 +1866,14 @@ static s32 ntty_chars_in_buffer(struct tty_struct *tty)
{
struct port *port = tty->driver_data;
struct nozomi *dc = get_dc_by_tty(tty);
- s32 rval;
+ s32 rval = 0;
if (unlikely(!dc || !port)) {
- rval = -ENODEV;
goto exit_in_buffer;
}
if (unlikely(!port->port.count)) {
dev_err(&dc->pdev->dev, "No tty open?\n");
- rval = -ENODEV;
goto exit_in_buffer;
}
diff --git a/drivers/char/pcmcia/cm4000_cs.c b/drivers/char/pcmcia/cm4000_cs.c
index dbb91257456..881934c068c 100644
--- a/drivers/char/pcmcia/cm4000_cs.c
+++ b/drivers/char/pcmcia/cm4000_cs.c
@@ -1575,7 +1575,8 @@ static long cmm_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
clear_bit(LOCK_IO, &dev->flags);
wake_up_interruptible(&dev->ioq);
- return 0;
+ rc = 0;
+ break;
case CM_IOCSPTS:
{
struct ptsreq krnptsreq;
diff --git a/drivers/char/pcmcia/ipwireless/tty.c b/drivers/char/pcmcia/ipwireless/tty.c
index 569f2f7743a..674b3ab3587 100644
--- a/drivers/char/pcmcia/ipwireless/tty.c
+++ b/drivers/char/pcmcia/ipwireless/tty.c
@@ -320,10 +320,10 @@ static int ipw_chars_in_buffer(struct tty_struct *linux_tty)
struct ipw_tty *tty = linux_tty->driver_data;
if (!tty)
- return -ENODEV;
+ return 0;
if (!tty->open_count)
- return -EINVAL;
+ return 0;
return tty->tx_bytes_queued;
}
diff --git a/drivers/char/ppdev.c b/drivers/char/ppdev.c
index c84c34fb123..432655bcb04 100644
--- a/drivers/char/ppdev.c
+++ b/drivers/char/ppdev.c
@@ -114,8 +114,7 @@ static ssize_t pp_read (struct file * file, char __user * buf, size_t count,
if (!(pp->flags & PP_CLAIMED)) {
/* Don't have the port claimed */
- printk (KERN_DEBUG CHRDEV "%x: claim the port first\n",
- minor);
+ pr_debug(CHRDEV "%x: claim the port first\n", minor);
return -EINVAL;
}
@@ -198,8 +197,7 @@ static ssize_t pp_write (struct file * file, const char __user * buf,
if (!(pp->flags & PP_CLAIMED)) {
/* Don't have the port claimed */
- printk (KERN_DEBUG CHRDEV "%x: claim the port first\n",
- minor);
+ pr_debug(CHRDEV "%x: claim the port first\n", minor);
return -EINVAL;
}
@@ -313,7 +311,7 @@ static int register_device (int minor, struct pp_struct *pp)
}
pp->pdev = pdev;
- printk (KERN_DEBUG "%s: registered pardevice\n", name);
+ pr_debug("%s: registered pardevice\n", name);
return 0;
}
@@ -343,8 +341,7 @@ static int pp_do_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
int ret;
if (pp->flags & PP_CLAIMED) {
- printk (KERN_DEBUG CHRDEV
- "%x: you've already got it!\n", minor);
+ pr_debug(CHRDEV "%x: you've already got it!\n", minor);
return -EINVAL;
}
@@ -379,7 +376,7 @@ static int pp_do_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
}
case PPEXCL:
if (pp->pdev) {
- printk (KERN_DEBUG CHRDEV "%x: too late for PPEXCL; "
+ pr_debug(CHRDEV "%x: too late for PPEXCL; "
"already registered\n", minor);
if (pp->flags & PP_EXCL)
/* But it's not really an error. */
@@ -491,8 +488,7 @@ static int pp_do_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
/* Everything else requires the port to be claimed, so check
* that now. */
if ((pp->flags & PP_CLAIMED) == 0) {
- printk (KERN_DEBUG CHRDEV "%x: claim the port first\n",
- minor);
+ pr_debug(CHRDEV "%x: claim the port first\n", minor);
return -EINVAL;
}
@@ -624,8 +620,7 @@ static int pp_do_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
return 0;
default:
- printk (KERN_DEBUG CHRDEV "%x: What? (cmd=0x%x)\n", minor,
- cmd);
+ pr_debug(CHRDEV "%x: What? (cmd=0x%x)\n", minor, cmd);
return -EINVAL;
}
@@ -698,9 +693,8 @@ static int pp_release (struct inode * inode, struct file * file)
}
if (compat_negot) {
parport_negotiate (pp->pdev->port, IEEE1284_MODE_COMPAT);
- printk (KERN_DEBUG CHRDEV
- "%x: negotiated back to compatibility mode because "
- "user-space forgot\n", minor);
+ pr_debug(CHRDEV "%x: negotiated back to compatibility "
+ "mode because user-space forgot\n", minor);
}
if (pp->flags & PP_CLAIMED) {
@@ -713,7 +707,7 @@ static int pp_release (struct inode * inode, struct file * file)
info->phase = pp->saved_state.phase;
parport_release (pp->pdev);
if (compat_negot != 1) {
- printk (KERN_DEBUG CHRDEV "%x: released pardevice "
+ pr_debug(CHRDEV "%x: released pardevice "
"because user-space forgot\n", minor);
}
}
@@ -723,8 +717,7 @@ static int pp_release (struct inode * inode, struct file * file)
parport_unregister_device (pp->pdev);
kfree (name);
pp->pdev = NULL;
- printk (KERN_DEBUG CHRDEV "%x: unregistered pardevice\n",
- minor);
+ pr_debug(CHRDEV "%x: unregistered pardevice\n", minor);
}
kfree (pp);
diff --git a/drivers/char/pty.c b/drivers/char/pty.c
index daebe1ba43d..b33d6688e91 100644
--- a/drivers/char/pty.c
+++ b/drivers/char/pty.c
@@ -22,6 +22,7 @@
#include <linux/major.h>
#include <linux/mm.h>
#include <linux/init.h>
+#include <linux/smp_lock.h>
#include <linux/sysctl.h>
#include <linux/device.h>
#include <linux/uaccess.h>
@@ -75,114 +76,82 @@ static void pty_close(struct tty_struct *tty, struct file *filp)
*/
static void pty_unthrottle(struct tty_struct *tty)
{
- struct tty_struct *o_tty = tty->link;
-
- if (!o_tty)
- return;
-
- tty_wakeup(o_tty);
+ tty_wakeup(tty->link);
set_bit(TTY_THROTTLED, &tty->flags);
}
-/*
- * 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
- * semaphore that should almost never come under contention.
- * (2) avoid redundant copying for cases where count >> receive_room
- * N.B. Calls from user space may now return an error code instead of
- * a count.
+/**
+ * pty_space - report space left for writing
+ * @to: tty we are writing into
*
- * FIXME: Our pty_write method is called with our ldisc lock held but
- * not our partners. We can't just wait on the other one blindly without
- * risking deadlocks. At some point when everything has settled down we need
- * to look into making pty_write at least able to sleep over an ldisc change.
+ * The tty buffers allow 64K but we sneak a peak and clip at 8K this
+ * allows a lot of overspill room for echo and other fun messes to
+ * be handled properly
+ */
+
+static int pty_space(struct tty_struct *to)
+{
+ int n = 8192 - to->buf.memory_used;
+ if (n < 0)
+ return 0;
+ return n;
+}
+
+/**
+ * pty_write - write to a pty
+ * @tty: the tty we write from
+ * @buf: kernel buffer of data
+ * @count: bytes to write
*
- * The return on no ldisc is a bit counter intuitive but the logic works
- * like this. During an ldisc change the other end will flush its buffers. We
- * thus return the full length which is identical to the case where we had
- * proper locking and happened to queue the bytes just before the flush during
- * the ldisc change.
+ * Our "hardware" write method. Data is coming from the ldisc which
+ * may be in a non sleeping state. We simply throw this at the other
+ * end of the link as if we were an IRQ handler receiving stuff for
+ * the other side of the pty/tty pair.
*/
-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 c)
{
struct tty_struct *to = tty->link;
- struct tty_ldisc *ld;
- int c = count;
- if (!to || tty->stopped)
+ if (tty->stopped)
return 0;
- ld = tty_ldisc_ref(to);
-
- if (ld) {
- c = to->receive_room;
- if (c > count)
- c = count;
- ld->ops->receive_buf(to, buf, NULL, c);
- tty_ldisc_deref(ld);
+
+ if (c > 0) {
+ /* Stuff the data into the input queue of the other end */
+ c = tty_insert_flip_string(to, buf, c);
+ /* And shovel */
+ tty_flip_buffer_push(to);
+ tty_wakeup(tty);
}
return c;
}
+/**
+ * pty_write_room - write space
+ * @tty: tty we are writing from
+ *
+ * Report how many bytes the ldisc can send into the queue for
+ * the other device.
+ */
+
static int pty_write_room(struct tty_struct *tty)
{
- struct tty_struct *to = tty->link;
-
- if (!to || tty->stopped)
+ if (tty->stopped)
return 0;
-
- return to->receive_room;
+ return pty_space(tty->link);
}
-/*
- * WSH 05/24/97: Modified for asymmetric MASTER/SLAVE behavior
- * 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
- * read. (The N_TTY ldisc.chars_in_buffer now knows this.)
+/**
+ * pty_chars_in_buffer - characters currently in our tx queue
+ * @tty: our tty
*
- * 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.
+ * Report how much we have in the transmit queue. As everything is
+ * instantly at the other end this is easy to implement.
*/
+
static int pty_chars_in_buffer(struct tty_struct *tty)
{
- struct tty_struct *to = tty->link;
- struct tty_ldisc *ld;
- int count = 0;
-
- /* We should get the line discipline lock for "tty->link" */
- if (!to)
- return 0;
- /* We cannot take a sleeping reference here without deadlocking with
- an ldisc change - but it doesn't really matter */
- ld = tty_ldisc_ref(to);
- if (ld == NULL)
- return 0;
-
- /* The ldisc must report 0 if no characters available to be read */
- if (ld->ops->chars_in_buffer)
- count = ld->ops->chars_in_buffer(to);
-
- tty_ldisc_deref(ld);
-
- if (tty->driver->subtype == PTY_TYPE_SLAVE)
- return count;
-
- /* 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,
- * and still allows half a buffer's worth of typed-ahead commands.
- */
- return (count < N_TTY_BUF_SIZE/2) ? 0 : count;
+ return 0;
}
/* Set the lock flag on a pty */
@@ -202,20 +171,10 @@ static void pty_flush_buffer(struct tty_struct *tty)
{
struct tty_struct *to = tty->link;
unsigned long flags;
- struct tty_ldisc *ld;
if (!to)
return;
- ld = tty_ldisc_ref(to);
-
- /* The other end is changing discipline */
- if (!ld)
- return;
-
- if (ld->ops->flush_buffer)
- to->ldisc->ops->flush_buffer(to);
- tty_ldisc_deref(ld);
-
+ /* tty_buffer_flush(to); FIXME */
if (to->packet) {
spin_lock_irqsave(&tty->ctrl_lock, flags);
tty->ctrl_status |= TIOCPKT_FLUSHWRITE;
diff --git a/drivers/char/rio/rio_linux.c b/drivers/char/rio/rio_linux.c
index ce81da5b2da..d58c2eb07f0 100644
--- a/drivers/char/rio/rio_linux.c
+++ b/drivers/char/rio/rio_linux.c
@@ -44,6 +44,7 @@
#include <linux/delay.h>
#include <linux/pci.h>
#include <linux/slab.h>
+#include <linux/smp_lock.h>
#include <linux/miscdevice.h>
#include <linux/init.h>
diff --git a/drivers/char/riscom8.c b/drivers/char/riscom8.c
index 21766045123..171711acf5c 100644
--- a/drivers/char/riscom8.c
+++ b/drivers/char/riscom8.c
@@ -47,6 +47,7 @@
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/tty_flip.h>
+#include <linux/smp_lock.h>
#include <linux/spinlock.h>
#include <linux/device.h>
diff --git a/drivers/char/rocket.c b/drivers/char/rocket.c
index 63d5b628477..0e29a23ec4c 100644
--- a/drivers/char/rocket.c
+++ b/drivers/char/rocket.c
@@ -73,6 +73,7 @@
#include <linux/tty_driver.h>
#include <linux/tty_flip.h>
#include <linux/serial.h>
+#include <linux/smp_lock.h>
#include <linux/string.h>
#include <linux/fcntl.h>
#include <linux/ptrace.h>
diff --git a/drivers/char/serial167.c b/drivers/char/serial167.c
index f1f24f0ee26..51e7a46787b 100644
--- a/drivers/char/serial167.c
+++ b/drivers/char/serial167.c
@@ -52,6 +52,7 @@
#include <linux/interrupt.h>
#include <linux/serial.h>
#include <linux/serialP.h>
+#include <linux/smp_lock.h>
#include <linux/string.h>
#include <linux/fcntl.h>
#include <linux/ptrace.h>
diff --git a/drivers/char/specialix.c b/drivers/char/specialix.c
index e72be4190a4..268e17f9ec3 100644
--- a/drivers/char/specialix.c
+++ b/drivers/char/specialix.c
@@ -87,6 +87,7 @@
#include <linux/tty_flip.h>
#include <linux/mm.h>
#include <linux/serial.h>
+#include <linux/smp_lock.h>
#include <linux/fcntl.h>
#include <linux/major.h>
#include <linux/delay.h>
@@ -1808,10 +1809,10 @@ static int sx_tiocmset(struct tty_struct *tty, struct file *file,
if (clear & TIOCM_DTR)
port->MSVR &= ~MSVR_DTR;
}
- spin_lock_irqsave(&bp->lock, flags);
+ spin_lock(&bp->lock);
sx_out(bp, CD186x_CAR, port_No(port));
sx_out(bp, CD186x_MSVR, port->MSVR);
- spin_unlock_irqrestore(&bp->lock, flags);
+ spin_unlock(&bp->lock);
spin_unlock_irqrestore(&port->lock, flags);
func_exit();
return 0;
@@ -1832,11 +1833,11 @@ static int sx_send_break(struct tty_struct *tty, int length)
port->break_length = SPECIALIX_TPS / HZ * length;
port->COR2 |= COR2_ETC;
port->IER |= IER_TXRDY;
- spin_lock_irqsave(&bp->lock, flags);
+ spin_lock(&bp->lock);
sx_out(bp, CD186x_CAR, port_No(port));
sx_out(bp, CD186x_COR2, port->COR2);
sx_out(bp, CD186x_IER, port->IER);
- spin_unlock_irqrestore(&bp->lock, flags);
+ spin_unlock(&bp->lock);
spin_unlock_irqrestore(&port->lock, flags);
sx_wait_CCR(bp);
spin_lock_irqsave(&bp->lock, flags);
@@ -2022,9 +2023,9 @@ static void sx_unthrottle(struct tty_struct *tty)
if (sx_crtscts(tty))
port->MSVR |= MSVR_DTR;
/* Else clause: see remark in "sx_throttle"... */
- spin_lock_irqsave(&bp->lock, flags);
+ spin_lock(&bp->lock);
sx_out(bp, CD186x_CAR, port_No(port));
- spin_unlock_irqrestore(&bp->lock, flags);
+ spin_unlock(&bp->lock);
if (I_IXOFF(tty)) {
spin_unlock_irqrestore(&port->lock, flags);
sx_wait_CCR(bp);
@@ -2034,9 +2035,9 @@ static void sx_unthrottle(struct tty_struct *tty)
sx_wait_CCR(bp);
spin_lock_irqsave(&port->lock, flags);
}
- spin_lock_irqsave(&bp->lock, flags);
+ spin_lock(&bp->lock);
sx_out(bp, CD186x_MSVR, port->MSVR);
- spin_unlock_irqrestore(&bp->lock, flags);
+ spin_unlock(&bp->lock);
spin_unlock_irqrestore(&port->lock, flags);
func_exit();
@@ -2060,10 +2061,10 @@ static void sx_stop(struct tty_struct *tty)
spin_lock_irqsave(&port->lock, flags);
port->IER &= ~IER_TXRDY;
- spin_lock_irqsave(&bp->lock, flags);
+ spin_lock(&bp->lock);
sx_out(bp, CD186x_CAR, port_No(port));
sx_out(bp, CD186x_IER, port->IER);
- spin_unlock_irqrestore(&bp->lock, flags);
+ spin_unlock(&bp->lock);
spin_unlock_irqrestore(&port->lock, flags);
func_exit();
@@ -2088,10 +2089,10 @@ static void sx_start(struct tty_struct *tty)
spin_lock_irqsave(&port->lock, flags);
if (port->xmit_cnt && port->xmit_buf && !(port->IER & IER_TXRDY)) {
port->IER |= IER_TXRDY;
- spin_lock_irqsave(&bp->lock, flags);
+ spin_lock(&bp->lock);
sx_out(bp, CD186x_CAR, port_No(port));
sx_out(bp, CD186x_IER, port->IER);
- spin_unlock_irqrestore(&bp->lock, flags);
+ spin_unlock(&bp->lock);
}
spin_unlock_irqrestore(&port->lock, flags);
diff --git a/drivers/char/sx.c b/drivers/char/sx.c
index 518f2a25d91..a81ec4fcf6f 100644
--- a/drivers/char/sx.c
+++ b/drivers/char/sx.c
@@ -216,6 +216,7 @@
#include <linux/eisa.h>
#include <linux/pci.h>
#include <linux/slab.h>
+#include <linux/smp_lock.h>
#include <linux/init.h>
#include <linux/miscdevice.h>
#include <linux/bitops.h>
diff --git a/drivers/char/synclink.c b/drivers/char/synclink.c
index afded3a2379..813552f1488 100644
--- a/drivers/char/synclink.c
+++ b/drivers/char/synclink.c
@@ -81,6 +81,7 @@
#include <linux/mm.h>
#include <linux/seq_file.h>
#include <linux/slab.h>
+#include <linux/smp_lock.h>
#include <linux/delay.h>
#include <linux/netdevice.h>
#include <linux/vmalloc.h>
diff --git a/drivers/char/synclink_gt.c b/drivers/char/synclink_gt.c
index 1386625fc4c..91f20a92fdd 100644
--- a/drivers/char/synclink_gt.c
+++ b/drivers/char/synclink_gt.c
@@ -62,6 +62,7 @@
#include <linux/mm.h>
#include <linux/seq_file.h>
#include <linux/slab.h>
+#include <linux/smp_lock.h>
#include <linux/netdevice.h>
#include <linux/vmalloc.h>
#include <linux/init.h>
@@ -467,7 +468,6 @@ static unsigned int free_tbuf_count(struct slgt_info *info);
static unsigned int tbuf_bytes(struct slgt_info *info);
static void reset_tbufs(struct slgt_info *info);
static void tdma_reset(struct slgt_info *info);
-static void tdma_start(struct slgt_info *info);
static void tx_load(struct slgt_info *info, const char *buf, unsigned int count);
static void get_signals(struct slgt_info *info);
@@ -795,6 +795,18 @@ static void set_termios(struct tty_struct *tty, struct ktermios *old_termios)
}
}
+static void update_tx_timer(struct slgt_info *info)
+{
+ /*
+ * use worst case speed of 1200bps to calculate transmit timeout
+ * based on data in buffers (tbuf_bytes) and FIFO (128 bytes)
+ */
+ if (info->params.mode == MGSL_MODE_HDLC) {
+ int timeout = (tbuf_bytes(info) * 7) + 1000;
+ mod_timer(&info->tx_timer, jiffies + msecs_to_jiffies(timeout));
+ }
+}
+
static int write(struct tty_struct *tty,
const unsigned char *buf, int count)
{
@@ -838,8 +850,18 @@ start:
spin_lock_irqsave(&info->lock,flags);
if (!info->tx_active)
tx_start(info);
- else
- tdma_start(info);
+ else if (!(rd_reg32(info, TDCSR) & BIT0)) {
+ /* transmit still active but transmit DMA stopped */
+ unsigned int i = info->tbuf_current;
+ if (!i)
+ i = info->tbuf_count;
+ i--;
+ /* if DMA buf unsent must try later after tx idle */
+ if (desc_count(info->tbufs[i]))
+ ret = 0;
+ }
+ if (ret > 0)
+ update_tx_timer(info);
spin_unlock_irqrestore(&info->lock,flags);
}
@@ -1502,10 +1524,9 @@ static int hdlcdev_xmit(struct sk_buff *skb, struct net_device *dev)
/* save start time for transmit timeout detection */
dev->trans_start = jiffies;
- /* start hardware transmitter if necessary */
spin_lock_irqsave(&info->lock,flags);
- if (!info->tx_active)
- tx_start(info);
+ tx_start(info);
+ update_tx_timer(info);
spin_unlock_irqrestore(&info->lock,flags);
return 0;
@@ -3946,50 +3967,19 @@ static void tx_start(struct slgt_info *info)
slgt_irq_on(info, IRQ_TXUNDER + IRQ_TXIDLE);
/* clear tx idle and underrun status bits */
wr_reg16(info, SSR, (unsigned short)(IRQ_TXIDLE + IRQ_TXUNDER));
- if (info->params.mode == MGSL_MODE_HDLC)
- mod_timer(&info->tx_timer, jiffies +
- msecs_to_jiffies(5000));
} else {
slgt_irq_off(info, IRQ_TXDATA);
slgt_irq_on(info, IRQ_TXIDLE);
/* clear tx idle status bit */
wr_reg16(info, SSR, IRQ_TXIDLE);
}
- tdma_start(info);
+ /* set 1st descriptor address and start DMA */
+ wr_reg32(info, TDDAR, info->tbufs[info->tbuf_start].pdesc);
+ wr_reg32(info, TDCSR, BIT2 + BIT0);
info->tx_active = true;
}
}
-/*
- * start transmit DMA if inactive and there are unsent buffers
- */
-static void tdma_start(struct slgt_info *info)
-{
- unsigned int i;
-
- if (rd_reg32(info, TDCSR) & BIT0)
- return;
-
- /* transmit DMA inactive, check for unsent buffers */
- i = info->tbuf_start;
- while (!desc_count(info->tbufs[i])) {
- if (++i == info->tbuf_count)
- i = 0;
- if (i == info->tbuf_current)
- return;
- }
- info->tbuf_start = i;
-
- /* there are unsent buffers, start transmit DMA */
-
- /* reset needed if previous error condition */
- tdma_reset(info);
-
- /* set 1st descriptor address */
- wr_reg32(info, TDDAR, info->tbufs[info->tbuf_start].pdesc);
- wr_reg32(info, TDCSR, BIT2 + BIT0); /* IRQ + DMA enable */
-}
-
static void tx_stop(struct slgt_info *info)
{
unsigned short val;
@@ -5004,8 +4994,7 @@ static void tx_timeout(unsigned long context)
info->icount.txtimeout++;
}
spin_lock_irqsave(&info->lock,flags);
- info->tx_active = false;
- info->tx_count = 0;
+ tx_stop(info);
spin_unlock_irqrestore(&info->lock,flags);
#if SYNCLINK_GENERIC_HDLC
diff --git a/drivers/char/synclinkmp.c b/drivers/char/synclinkmp.c
index 6f727e3c53a..8d4a2a8a0a7 100644
--- a/drivers/char/synclinkmp.c
+++ b/drivers/char/synclinkmp.c
@@ -52,6 +52,7 @@
#include <linux/mm.h>
#include <linux/seq_file.h>
#include <linux/slab.h>
+#include <linux/smp_lock.h>
#include <linux/netdevice.h>
#include <linux/vmalloc.h>
#include <linux/init.h>
diff --git a/drivers/char/sysrq.c b/drivers/char/sysrq.c
index 39a05b5fa9c..5d7a02f63e1 100644
--- a/drivers/char/sysrq.c
+++ b/drivers/char/sysrq.c
@@ -35,7 +35,6 @@
#include <linux/spinlock.h>
#include <linux/vt_kern.h>
#include <linux/workqueue.h>
-#include <linux/kexec.h>
#include <linux/hrtimer.h>
#include <linux/oom.h>
@@ -121,20 +120,20 @@ static struct sysrq_key_op sysrq_unraw_op = {
#define sysrq_unraw_op (*(struct sysrq_key_op *)0)
#endif /* CONFIG_VT */
-#ifdef CONFIG_KEXEC
-static void sysrq_handle_crashdump(int key, struct tty_struct *tty)
+static void sysrq_handle_crash(int key, struct tty_struct *tty)
{
- crash_kexec(get_irq_regs());
+ char *killer = NULL;
+
+ panic_on_oops = 1; /* force panic */
+ wmb();
+ *killer = 1;
}
-static struct sysrq_key_op sysrq_crashdump_op = {
- .handler = sysrq_handle_crashdump,
- .help_msg = "Crashdump",
- .action_msg = "Trigger a crashdump",
+static struct sysrq_key_op sysrq_crash_op = {
+ .handler = sysrq_handle_crash,
+ .help_msg = "Crash",
+ .action_msg = "Trigger a crash",
.enable_mask = SYSRQ_ENABLE_DUMP,
};
-#else
-#define sysrq_crashdump_op (*(struct sysrq_key_op *)0)
-#endif
static void sysrq_handle_reboot(int key, struct tty_struct *tty)
{
@@ -404,7 +403,7 @@ static struct sysrq_key_op *sysrq_key_table[36] = {
*/
NULL, /* a */
&sysrq_reboot_op, /* b */
- &sysrq_crashdump_op, /* c & ibm_emac driver debug */
+ &sysrq_crash_op, /* c & ibm_emac driver debug */
&sysrq_showlocks_op, /* d */
&sysrq_term_op, /* e */
&sysrq_moom_op, /* f */
diff --git a/drivers/char/tb0219.c b/drivers/char/tb0219.c
index 6062b62800f..b3ec9b10e29 100644
--- a/drivers/char/tb0219.c
+++ b/drivers/char/tb0219.c
@@ -1,7 +1,7 @@
/*
* Driver for TANBAC TB0219 base board.
*
- * Copyright (C) 2005 Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp>
+ * Copyright (C) 2005 Yoichi Yuasa <yuasa@linux-mips.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -28,7 +28,7 @@
#include <asm/vr41xx/giu.h>
#include <asm/vr41xx/tb0219.h>
-MODULE_AUTHOR("Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp>");
+MODULE_AUTHOR("Yoichi Yuasa <yuasa@linux-mips.org>");
MODULE_DESCRIPTION("TANBAC TB0219 base board driver");
MODULE_LICENSE("GPL");
diff --git a/drivers/char/tpm/tpm.c b/drivers/char/tpm/tpm.c
index ccdd828adce..b0603b2e568 100644
--- a/drivers/char/tpm/tpm.c
+++ b/drivers/char/tpm/tpm.c
@@ -26,7 +26,6 @@
#include <linux/poll.h>
#include <linux/mutex.h>
#include <linux/spinlock.h>
-#include <linux/smp_lock.h>
#include "tpm.h"
diff --git a/drivers/char/tty_buffer.c b/drivers/char/tty_buffer.c
index 810ee25d66a..3108991c5c8 100644
--- a/drivers/char/tty_buffer.c
+++ b/drivers/char/tty_buffer.c
@@ -462,6 +462,19 @@ static void flush_to_ldisc(struct work_struct *work)
}
/**
+ * tty_flush_to_ldisc
+ * @tty: tty to push
+ *
+ * Push the terminal flip buffers to the line discipline.
+ *
+ * Must not be called from IRQ context.
+ */
+void tty_flush_to_ldisc(struct tty_struct *tty)
+{
+ flush_to_ldisc(&tty->buf.work.work);
+}
+
+/**
* tty_flip_buffer_push - terminal
* @tty: tty to push
*
diff --git a/drivers/char/tty_ioctl.c b/drivers/char/tty_ioctl.c
index b24f6c6a1ea..ad6ba4ed280 100644
--- a/drivers/char/tty_ioctl.c
+++ b/drivers/char/tty_ioctl.c
@@ -21,7 +21,6 @@
#include <linux/module.h>
#include <linux/bitops.h>
#include <linux/mutex.h>
-#include <linux/smp_lock.h>
#include <asm/io.h>
#include <asm/uaccess.h>
diff --git a/drivers/char/tty_ldisc.c b/drivers/char/tty_ldisc.c
index a19e935847b..e48af9f7921 100644
--- a/drivers/char/tty_ldisc.c
+++ b/drivers/char/tty_ldisc.c
@@ -21,7 +21,6 @@
#include <linux/proc_fs.h>
#include <linux/init.h>
#include <linux/module.h>
-#include <linux/smp_lock.h>
#include <linux/device.h>
#include <linux/wait.h>
#include <linux/bitops.h>
@@ -49,6 +48,41 @@ static DECLARE_WAIT_QUEUE_HEAD(tty_ldisc_wait);
/* Line disc dispatch table */
static struct tty_ldisc_ops *tty_ldiscs[NR_LDISCS];
+static inline struct tty_ldisc *get_ldisc(struct tty_ldisc *ld)
+{
+ if (ld)
+ atomic_inc(&ld->users);
+ return ld;
+}
+
+static void put_ldisc(struct tty_ldisc *ld)
+{
+ unsigned long flags;
+
+ if (WARN_ON_ONCE(!ld))
+ return;
+
+ /*
+ * If this is the last user, free the ldisc, and
+ * release the ldisc ops.
+ *
+ * We really want an "atomic_dec_and_lock_irqsave()",
+ * but we don't have it, so this does it by hand.
+ */
+ local_irq_save(flags);
+ if (atomic_dec_and_lock(&ld->users, &tty_ldisc_lock)) {
+ struct tty_ldisc_ops *ldo = ld->ops;
+
+ ldo->refcount--;
+ module_put(ldo->owner);
+ spin_unlock_irqrestore(&tty_ldisc_lock, flags);
+
+ kfree(ld);
+ return;
+ }
+ local_irq_restore(flags);
+}
+
/**
* tty_register_ldisc - install a line discipline
* @disc: ldisc number
@@ -143,7 +177,7 @@ static struct tty_ldisc *tty_ldisc_try_get(int disc)
/* lock it */
ldops->refcount++;
ld->ops = ldops;
- ld->refcount = 0;
+ atomic_set(&ld->users, 1);
err = 0;
}
}
@@ -182,35 +216,6 @@ static struct tty_ldisc *tty_ldisc_get(int disc)
return ld;
}
-/**
- * tty_ldisc_put - drop ldisc reference
- * @ld: ldisc
- *
- * Drop a reference to a line discipline. Manage refcounts and
- * module usage counts. Free the ldisc once the recount hits zero.
- *
- * Locking:
- * takes tty_ldisc_lock to guard against ldisc races
- */
-
-static void tty_ldisc_put(struct tty_ldisc *ld)
-{
- unsigned long flags;
- int disc = ld->ops->num;
- struct tty_ldisc_ops *ldo;
-
- BUG_ON(disc < N_TTY || disc >= NR_LDISCS);
-
- spin_lock_irqsave(&tty_ldisc_lock, flags);
- ldo = tty_ldiscs[disc];
- BUG_ON(ldo->refcount == 0);
- ldo->refcount--;
- module_put(ldo->owner);
- spin_unlock_irqrestore(&tty_ldisc_lock, flags);
- WARN_ON(ld->refcount);
- kfree(ld);
-}
-
static void *tty_ldiscs_seq_start(struct seq_file *m, loff_t *pos)
{
return (*pos < NR_LDISCS) ? pos : NULL;
@@ -235,7 +240,7 @@ static int tty_ldiscs_seq_show(struct seq_file *m, void *v)
if (IS_ERR(ld))
return 0;
seq_printf(m, "%-10s %2d\n", ld->ops->name ? ld->ops->name : "???", i);
- tty_ldisc_put(ld);
+ put_ldisc(ld);
return 0;
}
@@ -289,20 +294,17 @@ static void tty_ldisc_assign(struct tty_struct *tty, struct tty_ldisc *ld)
* Locking: takes tty_ldisc_lock
*/
-static int tty_ldisc_try(struct tty_struct *tty)
+static struct tty_ldisc *tty_ldisc_try(struct tty_struct *tty)
{
unsigned long flags;
struct tty_ldisc *ld;
- int ret = 0;
spin_lock_irqsave(&tty_ldisc_lock, flags);
- ld = tty->ldisc;
- if (test_bit(TTY_LDISC, &tty->flags)) {
- ld->refcount++;
- ret = 1;
- }
+ ld = NULL;
+ if (test_bit(TTY_LDISC, &tty->flags))
+ ld = get_ldisc(tty->ldisc);
spin_unlock_irqrestore(&tty_ldisc_lock, flags);
- return ret;
+ return ld;
}
/**
@@ -323,10 +325,11 @@ static int tty_ldisc_try(struct tty_struct *tty)
struct tty_ldisc *tty_ldisc_ref_wait(struct tty_struct *tty)
{
+ struct tty_ldisc *ld;
+
/* wait_event is a macro */
- wait_event(tty_ldisc_wait, tty_ldisc_try(tty));
- WARN_ON(tty->ldisc->refcount == 0);
- return tty->ldisc;
+ wait_event(tty_ldisc_wait, (ld = tty_ldisc_try(tty)) != NULL);
+ return ld;
}
EXPORT_SYMBOL_GPL(tty_ldisc_ref_wait);
@@ -343,9 +346,7 @@ EXPORT_SYMBOL_GPL(tty_ldisc_ref_wait);
struct tty_ldisc *tty_ldisc_ref(struct tty_struct *tty)
{
- if (tty_ldisc_try(tty))
- return tty->ldisc;
- return NULL;
+ return tty_ldisc_try(tty);
}
EXPORT_SYMBOL_GPL(tty_ldisc_ref);
@@ -361,21 +362,15 @@ EXPORT_SYMBOL_GPL(tty_ldisc_ref);
void tty_ldisc_deref(struct tty_ldisc *ld)
{
- unsigned long flags;
-
- BUG_ON(ld == NULL);
-
- spin_lock_irqsave(&tty_ldisc_lock, flags);
- if (ld->refcount == 0)
- printk(KERN_ERR "tty_ldisc_deref: no references.\n");
- else
- ld->refcount--;
- if (ld->refcount == 0)
- wake_up(&tty_ldisc_wait);
- spin_unlock_irqrestore(&tty_ldisc_lock, flags);
+ put_ldisc(ld);
}
EXPORT_SYMBOL_GPL(tty_ldisc_deref);
+static inline void tty_ldisc_put(struct tty_ldisc *ld)
+{
+ put_ldisc(ld);
+}
+
/**
* tty_ldisc_enable - allow ldisc use
* @tty: terminal to activate ldisc on
@@ -513,8 +508,9 @@ static void tty_ldisc_restore(struct tty_struct *tty, struct tty_ldisc *old)
* be obtained while the delayed work queue halt ensures that no more
* data is fed to the ldisc.
*
- * In order to wait for any existing references to complete see
- * tty_ldisc_wait_idle.
+ * You need to do a 'flush_scheduled_work()' (outside the ldisc_mutex)
+ * in order to make sure any currently executing ldisc work is also
+ * flushed.
*/
static int tty_ldisc_halt(struct tty_struct *tty)
@@ -524,31 +520,6 @@ static int tty_ldisc_halt(struct tty_struct *tty)
}
/**
- * tty_ldisc_wait_idle - wait for the ldisc to become idle
- * @tty: tty to wait for
- *
- * Wait for the line discipline to become idle. The discipline must
- * have been halted for this to guarantee it remains idle.
- *
- * tty_ldisc_lock protects the ref counts currently.
- */
-
-static int tty_ldisc_wait_idle(struct tty_struct *tty)
-{
- unsigned long flags;
- spin_lock_irqsave(&tty_ldisc_lock, flags);
- while (tty->ldisc->refcount) {
- spin_unlock_irqrestore(&tty_ldisc_lock, flags);
- if (wait_event_timeout(tty_ldisc_wait,
- tty->ldisc->refcount == 0, 5 * HZ) == 0)
- return -EBUSY;
- spin_lock_irqsave(&tty_ldisc_lock, flags);
- }
- spin_unlock_irqrestore(&tty_ldisc_lock, flags);
- return 0;
-}
-
-/**
* tty_set_ldisc - set line discipline
* @tty: the terminal to set
* @ldisc: the line discipline
@@ -643,14 +614,6 @@ int tty_set_ldisc(struct tty_struct *tty, int ldisc)
flush_scheduled_work();
- /* Let any existing reference holders finish */
- retval = tty_ldisc_wait_idle(tty);
- if (retval < 0) {
- clear_bit(TTY_LDISC_CHANGING, &tty->flags);
- tty_ldisc_put(new_ldisc);
- return retval;
- }
-
mutex_lock(&tty->ldisc_mutex);
if (test_bit(TTY_HUPPED, &tty->flags)) {
/* We were raced by the hangup method. It will have stomped
@@ -791,17 +754,22 @@ void tty_ldisc_hangup(struct tty_struct *tty)
* N_TTY.
*/
if (tty->driver->flags & TTY_DRIVER_RESET_TERMIOS) {
- /* Avoid racing set_ldisc */
- mutex_lock(&tty->ldisc_mutex);
- /* Switch back to N_TTY */
+ /* Make sure the old ldisc is quiescent */
tty_ldisc_halt(tty);
- tty_ldisc_wait_idle(tty);
- tty_ldisc_reinit(tty);
- /* At this point we have a closed ldisc and we want to
- reopen it. We could defer this to the next open but
- it means auditing a lot of other paths so this is a FIXME */
- WARN_ON(tty_ldisc_open(tty, tty->ldisc));
- tty_ldisc_enable(tty);
+ flush_scheduled_work();
+
+ /* Avoid racing set_ldisc or tty_ldisc_release */
+ mutex_lock(&tty->ldisc_mutex);
+ if (tty->ldisc) { /* Not yet closed */
+ /* Switch back to N_TTY */
+ tty_ldisc_reinit(tty);
+ /* At this point we have a closed ldisc and we want to
+ reopen it. We could defer this to the next open but
+ it means auditing a lot of other paths so this is
+ a FIXME */
+ WARN_ON(tty_ldisc_open(tty, tty->ldisc));
+ tty_ldisc_enable(tty);
+ }
mutex_unlock(&tty->ldisc_mutex);
tty_reset_termios(tty);
}
@@ -858,24 +826,25 @@ void tty_ldisc_release(struct tty_struct *tty, struct tty_struct *o_tty)
tty_ldisc_halt(tty);
flush_scheduled_work();
+ mutex_lock(&tty->ldisc_mutex);
/*
- * Wait for any short term users (we know they are just driver
- * side waiters as the file is closing so user count on the file
- * side is zero.
+ * Now kill off the ldisc
*/
+ tty_ldisc_close(tty, tty->ldisc);
+ tty_ldisc_put(tty->ldisc);
+ /* Force an oops if we mess this up */
+ tty->ldisc = NULL;
- tty_ldisc_wait_idle(tty);
-
- /*
- * Shutdown the current line discipline, and reset it to N_TTY.
- *
- * FIXME: this MUST get fixed for the new reflocking
- */
+ /* Ensure the next open requests the N_TTY ldisc */
+ tty_set_termios_ldisc(tty, N_TTY);
+ mutex_unlock(&tty->ldisc_mutex);
- tty_ldisc_reinit(tty);
/* This will need doing differently if we need to lock */
if (o_tty)
tty_ldisc_release(o_tty, NULL);
+
+ /* And the memory resources remaining (buffers, termios) will be
+ disposed of when the kref hits zero */
}
/**
diff --git a/drivers/char/tty_port.c b/drivers/char/tty_port.c
index 62dadfc95e3..9769b1149f7 100644
--- a/drivers/char/tty_port.c
+++ b/drivers/char/tty_port.c
@@ -193,7 +193,7 @@ int tty_port_block_til_ready(struct tty_port *port,
{
int do_clocal = 0, retval;
unsigned long flags;
- DECLARE_WAITQUEUE(wait, current);
+ DEFINE_WAIT(wait);
int cd;
/* block if port is in the process of being closed */
@@ -267,7 +267,7 @@ int tty_port_block_til_ready(struct tty_port *port,
if (retval == 0)
port->flags |= ASYNC_NORMAL_ACTIVE;
spin_unlock_irqrestore(&port->lock, flags);
- return 0;
+ return retval;
}
EXPORT_SYMBOL(tty_port_block_til_ready);
diff --git a/drivers/char/vc_screen.c b/drivers/char/vc_screen.c
index d94d25c12aa..c1791a63d99 100644
--- a/drivers/char/vc_screen.c
+++ b/drivers/char/vc_screen.c
@@ -495,11 +495,15 @@ void vcs_remove_sysfs(int index)
int __init vcs_init(void)
{
+ unsigned int i;
+
if (register_chrdev(VCS_MAJOR, "vcs", &vcs_fops))
panic("unable to get major %d for vcs device", VCS_MAJOR);
vc_class = class_create(THIS_MODULE, "vc");
device_create(vc_class, NULL, MKDEV(VCS_MAJOR, 0), NULL, "vcs");
device_create(vc_class, NULL, MKDEV(VCS_MAJOR, 128), NULL, "vcsa");
+ for (i = 0; i < MIN_NR_CONSOLES; i++)
+ vcs_make_sysfs(i);
return 0;
}
diff --git a/drivers/char/vr41xx_giu.c b/drivers/char/vr41xx_giu.c
deleted file mode 100644
index 54c837288d1..00000000000
--- a/drivers/char/vr41xx_giu.c
+++ /dev/null
@@ -1,680 +0,0 @@
-/*
- * Driver for NEC VR4100 series General-purpose I/O Unit.
- *
- * Copyright (C) 2002 MontaVista Software Inc.
- * Author: Yoichi Yuasa <yyuasa@mvista.com or source@mvista.com>
- * Copyright (C) 2003-2007 Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-#include <linux/errno.h>
-#include <linux/fs.h>
-#include <linux/init.h>
-#include <linux/interrupt.h>
-#include <linux/irq.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/platform_device.h>
-#include <linux/smp_lock.h>
-#include <linux/spinlock.h>
-#include <linux/types.h>
-
-#include <asm/io.h>
-#include <asm/vr41xx/giu.h>
-#include <asm/vr41xx/irq.h>
-#include <asm/vr41xx/vr41xx.h>
-
-MODULE_AUTHOR("Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp>");
-MODULE_DESCRIPTION("NEC VR4100 series General-purpose I/O Unit driver");
-MODULE_LICENSE("GPL");
-
-static int major; /* default is dynamic major device number */
-module_param(major, int, 0);
-MODULE_PARM_DESC(major, "Major device number");
-
-#define GIUIOSELL 0x00
-#define GIUIOSELH 0x02
-#define GIUPIODL 0x04
-#define GIUPIODH 0x06
-#define GIUINTSTATL 0x08
-#define GIUINTSTATH 0x0a
-#define GIUINTENL 0x0c
-#define GIUINTENH 0x0e
-#define GIUINTTYPL 0x10
-#define GIUINTTYPH 0x12
-#define GIUINTALSELL 0x14
-#define GIUINTALSELH 0x16
-#define GIUINTHTSELL 0x18
-#define GIUINTHTSELH 0x1a
-#define GIUPODATL 0x1c
-#define GIUPODATEN 0x1c
-#define GIUPODATH 0x1e
- #define PIOEN0 0x0100
- #define PIOEN1 0x0200
-#define GIUPODAT 0x1e
-#define GIUFEDGEINHL 0x20
-#define GIUFEDGEINHH 0x22
-#define GIUREDGEINHL 0x24
-#define GIUREDGEINHH 0x26
-
-#define GIUUSEUPDN 0x1e0
-#define GIUTERMUPDN 0x1e2
-
-#define GPIO_HAS_PULLUPDOWN_IO 0x0001
-#define GPIO_HAS_OUTPUT_ENABLE 0x0002
-#define GPIO_HAS_INTERRUPT_EDGE_SELECT 0x0100
-
-static spinlock_t giu_lock;
-static unsigned long giu_flags;
-static unsigned int giu_nr_pins;
-
-static void __iomem *giu_base;
-
-#define giu_read(offset) readw(giu_base + (offset))
-#define giu_write(offset, value) writew((value), giu_base + (offset))
-
-#define GPIO_PIN_OF_IRQ(irq) ((irq) - GIU_IRQ_BASE)
-#define GIUINT_HIGH_OFFSET 16
-#define GIUINT_HIGH_MAX 32
-
-static inline uint16_t giu_set(uint16_t offset, uint16_t set)
-{
- uint16_t data;
-
- data = giu_read(offset);
- data |= set;
- giu_write(offset, data);
-
- return data;
-}
-
-static inline uint16_t giu_clear(uint16_t offset, uint16_t clear)
-{
- uint16_t data;
-
- data = giu_read(offset);
- data &= ~clear;
- giu_write(offset, data);
-
- return data;
-}
-
-static void ack_giuint_low(unsigned int irq)
-{
- giu_write(GIUINTSTATL, 1 << GPIO_PIN_OF_IRQ(irq));
-}
-
-static void mask_giuint_low(unsigned int irq)
-{
- giu_clear(GIUINTENL, 1 << GPIO_PIN_OF_IRQ(irq));
-}
-
-static void mask_ack_giuint_low(unsigned int irq)
-{
- unsigned int pin;
-
- pin = GPIO_PIN_OF_IRQ(irq);
- giu_clear(GIUINTENL, 1 << pin);
- giu_write(GIUINTSTATL, 1 << pin);
-}
-
-static void unmask_giuint_low(unsigned int irq)
-{
- giu_set(GIUINTENL, 1 << GPIO_PIN_OF_IRQ(irq));
-}
-
-static struct irq_chip giuint_low_irq_chip = {
- .name = "GIUINTL",
- .ack = ack_giuint_low,
- .mask = mask_giuint_low,
- .mask_ack = mask_ack_giuint_low,
- .unmask = unmask_giuint_low,
-};
-
-static void ack_giuint_high(unsigned int irq)
-{
- giu_write(GIUINTSTATH, 1 << (GPIO_PIN_OF_IRQ(irq) - GIUINT_HIGH_OFFSET));
-}
-
-static void mask_giuint_high(unsigned int irq)
-{
- giu_clear(GIUINTENH, 1 << (GPIO_PIN_OF_IRQ(irq) - GIUINT_HIGH_OFFSET));
-}
-
-static void mask_ack_giuint_high(unsigned int irq)
-{
- unsigned int pin;
-
- pin = GPIO_PIN_OF_IRQ(irq) - GIUINT_HIGH_OFFSET;
- giu_clear(GIUINTENH, 1 << pin);
- giu_write(GIUINTSTATH, 1 << pin);
-}
-
-static void unmask_giuint_high(unsigned int irq)
-{
- giu_set(GIUINTENH, 1 << (GPIO_PIN_OF_IRQ(irq) - GIUINT_HIGH_OFFSET));
-}
-
-static struct irq_chip giuint_high_irq_chip = {
- .name = "GIUINTH",
- .ack = ack_giuint_high,
- .mask = mask_giuint_high,
- .mask_ack = mask_ack_giuint_high,
- .unmask = unmask_giuint_high,
-};
-
-static int giu_get_irq(unsigned int irq)
-{
- uint16_t pendl, pendh, maskl, maskh;
- int i;
-
- pendl = giu_read(GIUINTSTATL);
- pendh = giu_read(GIUINTSTATH);
- maskl = giu_read(GIUINTENL);
- maskh = giu_read(GIUINTENH);
-
- maskl &= pendl;
- maskh &= pendh;
-
- if (maskl) {
- for (i = 0; i < 16; i++) {
- if (maskl & (1 << i))
- return GIU_IRQ(i);
- }
- } else if (maskh) {
- for (i = 0; i < 16; i++) {
- if (maskh & (1 << i))
- return GIU_IRQ(i + GIUINT_HIGH_OFFSET);
- }
- }
-
- printk(KERN_ERR "spurious GIU interrupt: %04x(%04x),%04x(%04x)\n",
- maskl, pendl, maskh, pendh);
-
- atomic_inc(&irq_err_count);
-
- return -EINVAL;
-}
-
-void vr41xx_set_irq_trigger(unsigned int pin, irq_trigger_t trigger, irq_signal_t signal)
-{
- uint16_t mask;
-
- if (pin < GIUINT_HIGH_OFFSET) {
- mask = 1 << pin;
- if (trigger != IRQ_TRIGGER_LEVEL) {
- giu_set(GIUINTTYPL, mask);
- if (signal == IRQ_SIGNAL_HOLD)
- giu_set(GIUINTHTSELL, mask);
- else
- giu_clear(GIUINTHTSELL, mask);
- if (giu_flags & GPIO_HAS_INTERRUPT_EDGE_SELECT) {
- switch (trigger) {
- case IRQ_TRIGGER_EDGE_FALLING:
- giu_set(GIUFEDGEINHL, mask);
- giu_clear(GIUREDGEINHL, mask);
- break;
- case IRQ_TRIGGER_EDGE_RISING:
- giu_clear(GIUFEDGEINHL, mask);
- giu_set(GIUREDGEINHL, mask);
- break;
- default:
- giu_set(GIUFEDGEINHL, mask);
- giu_set(GIUREDGEINHL, mask);
- break;
- }
- }
- set_irq_chip_and_handler(GIU_IRQ(pin),
- &giuint_low_irq_chip,
- handle_edge_irq);
- } else {
- giu_clear(GIUINTTYPL, mask);
- giu_clear(GIUINTHTSELL, mask);
- set_irq_chip_and_handler(GIU_IRQ(pin),
- &giuint_low_irq_chip,
- handle_level_irq);
- }
- giu_write(GIUINTSTATL, mask);
- } else if (pin < GIUINT_HIGH_MAX) {
- mask = 1 << (pin - GIUINT_HIGH_OFFSET);
- if (trigger != IRQ_TRIGGER_LEVEL) {
- giu_set(GIUINTTYPH, mask);
- if (signal == IRQ_SIGNAL_HOLD)
- giu_set(GIUINTHTSELH, mask);
- else
- giu_clear(GIUINTHTSELH, mask);
- if (giu_flags & GPIO_HAS_INTERRUPT_EDGE_SELECT) {
- switch (trigger) {
- case IRQ_TRIGGER_EDGE_FALLING:
- giu_set(GIUFEDGEINHH, mask);
- giu_clear(GIUREDGEINHH, mask);
- break;
- case IRQ_TRIGGER_EDGE_RISING:
- giu_clear(GIUFEDGEINHH, mask);
- giu_set(GIUREDGEINHH, mask);
- break;
- default:
- giu_set(GIUFEDGEINHH, mask);
- giu_set(GIUREDGEINHH, mask);
- break;
- }
- }
- set_irq_chip_and_handler(GIU_IRQ(pin),
- &giuint_high_irq_chip,
- handle_edge_irq);
- } else {
- giu_clear(GIUINTTYPH, mask);
- giu_clear(GIUINTHTSELH, mask);
- set_irq_chip_and_handler(GIU_IRQ(pin),
- &giuint_high_irq_chip,
- handle_level_irq);
- }
- giu_write(GIUINTSTATH, mask);
- }
-}
-EXPORT_SYMBOL_GPL(vr41xx_set_irq_trigger);
-
-void vr41xx_set_irq_level(unsigned int pin, irq_level_t level)
-{
- uint16_t mask;
-
- if (pin < GIUINT_HIGH_OFFSET) {
- mask = 1 << pin;
- if (level == IRQ_LEVEL_HIGH)
- giu_set(GIUINTALSELL, mask);
- else
- giu_clear(GIUINTALSELL, mask);
- giu_write(GIUINTSTATL, mask);
- } else if (pin < GIUINT_HIGH_MAX) {
- mask = 1 << (pin - GIUINT_HIGH_OFFSET);
- if (level == IRQ_LEVEL_HIGH)
- giu_set(GIUINTALSELH, mask);
- else
- giu_clear(GIUINTALSELH, mask);
- giu_write(GIUINTSTATH, mask);
- }
-}
-EXPORT_SYMBOL_GPL(vr41xx_set_irq_level);
-
-gpio_data_t vr41xx_gpio_get_pin(unsigned int pin)
-{
- uint16_t reg, mask;
-
- if (pin >= giu_nr_pins)
- return GPIO_DATA_INVAL;
-
- if (pin < 16) {
- reg = giu_read(GIUPIODL);
- mask = (uint16_t)1 << pin;
- } else if (pin < 32) {
- reg = giu_read(GIUPIODH);
- mask = (uint16_t)1 << (pin - 16);
- } else if (pin < 48) {
- reg = giu_read(GIUPODATL);
- mask = (uint16_t)1 << (pin - 32);
- } else {
- reg = giu_read(GIUPODATH);
- mask = (uint16_t)1 << (pin - 48);
- }
-
- if (reg & mask)
- return GPIO_DATA_HIGH;
-
- return GPIO_DATA_LOW;
-}
-EXPORT_SYMBOL_GPL(vr41xx_gpio_get_pin);
-
-int vr41xx_gpio_set_pin(unsigned int pin, gpio_data_t data)
-{
- uint16_t offset, mask, reg;
- unsigned long flags;
-
- if (pin >= giu_nr_pins)
- return -EINVAL;
-
- if (pin < 16) {
- offset = GIUPIODL;
- mask = (uint16_t)1 << pin;
- } else if (pin < 32) {
- offset = GIUPIODH;
- mask = (uint16_t)1 << (pin - 16);
- } else if (pin < 48) {
- offset = GIUPODATL;
- mask = (uint16_t)1 << (pin - 32);
- } else {
- offset = GIUPODATH;
- mask = (uint16_t)1 << (pin - 48);
- }
-
- spin_lock_irqsave(&giu_lock, flags);
-
- reg = giu_read(offset);
- if (data == GPIO_DATA_HIGH)
- reg |= mask;
- else
- reg &= ~mask;
- giu_write(offset, reg);
-
- spin_unlock_irqrestore(&giu_lock, flags);
-
- return 0;
-}
-EXPORT_SYMBOL_GPL(vr41xx_gpio_set_pin);
-
-int vr41xx_gpio_set_direction(unsigned int pin, gpio_direction_t dir)
-{
- uint16_t offset, mask, reg;
- unsigned long flags;
-
- if (pin >= giu_nr_pins)
- return -EINVAL;
-
- if (pin < 16) {
- offset = GIUIOSELL;
- mask = (uint16_t)1 << pin;
- } else if (pin < 32) {
- offset = GIUIOSELH;
- mask = (uint16_t)1 << (pin - 16);
- } else {
- if (giu_flags & GPIO_HAS_OUTPUT_ENABLE) {
- offset = GIUPODATEN;
- mask = (uint16_t)1 << (pin - 32);
- } else {
- switch (pin) {
- case 48:
- offset = GIUPODATH;
- mask = PIOEN0;
- break;
- case 49:
- offset = GIUPODATH;
- mask = PIOEN1;
- break;
- default:
- return -EINVAL;
- }
- }
- }
-
- spin_lock_irqsave(&giu_lock, flags);
-
- reg = giu_read(offset);
- if (dir == GPIO_OUTPUT)
- reg |= mask;
- else
- reg &= ~mask;
- giu_write(offset, reg);
-
- spin_unlock_irqrestore(&giu_lock, flags);
-
- return 0;
-}
-EXPORT_SYMBOL_GPL(vr41xx_gpio_set_direction);
-
-int vr41xx_gpio_pullupdown(unsigned int pin, gpio_pull_t pull)
-{
- uint16_t reg, mask;
- unsigned long flags;
-
- if ((giu_flags & GPIO_HAS_PULLUPDOWN_IO) != GPIO_HAS_PULLUPDOWN_IO)
- return -EPERM;
-
- if (pin >= 15)
- return -EINVAL;
-
- mask = (uint16_t)1 << pin;
-
- spin_lock_irqsave(&giu_lock, flags);
-
- if (pull == GPIO_PULL_UP || pull == GPIO_PULL_DOWN) {
- reg = giu_read(GIUTERMUPDN);
- if (pull == GPIO_PULL_UP)
- reg |= mask;
- else
- reg &= ~mask;
- giu_write(GIUTERMUPDN, reg);
-
- reg = giu_read(GIUUSEUPDN);
- reg |= mask;
- giu_write(GIUUSEUPDN, reg);
- } else {
- reg = giu_read(GIUUSEUPDN);
- reg &= ~mask;
- giu_write(GIUUSEUPDN, reg);
- }
-
- spin_unlock_irqrestore(&giu_lock, flags);
-
- return 0;
-}
-EXPORT_SYMBOL_GPL(vr41xx_gpio_pullupdown);
-
-static ssize_t gpio_read(struct file *file, char __user *buf, size_t len,
- loff_t *ppos)
-{
- unsigned int pin;
- char value = '0';
-
- pin = iminor(file->f_path.dentry->d_inode);
- if (pin >= giu_nr_pins)
- return -EBADF;
-
- if (vr41xx_gpio_get_pin(pin) == GPIO_DATA_HIGH)
- value = '1';
-
- if (len <= 0)
- return -EFAULT;
-
- if (put_user(value, buf))
- return -EFAULT;
-
- return 1;
-}
-
-static ssize_t gpio_write(struct file *file, const char __user *data,
- size_t len, loff_t *ppos)
-{
- unsigned int pin;
- size_t i;
- char c;
- int retval = 0;
-
- pin = iminor(file->f_path.dentry->d_inode);
- if (pin >= giu_nr_pins)
- return -EBADF;
-
- for (i = 0; i < len; i++) {
- if (get_user(c, data + i))
- return -EFAULT;
-
- switch (c) {
- case '0':
- retval = vr41xx_gpio_set_pin(pin, GPIO_DATA_LOW);
- break;
- case '1':
- retval = vr41xx_gpio_set_pin(pin, GPIO_DATA_HIGH);
- break;
- case 'D':
- printk(KERN_INFO "GPIO%d: pull down\n", pin);
- retval = vr41xx_gpio_pullupdown(pin, GPIO_PULL_DOWN);
- break;
- case 'd':
- printk(KERN_INFO "GPIO%d: pull up/down disable\n", pin);
- retval = vr41xx_gpio_pullupdown(pin, GPIO_PULL_DISABLE);
- break;
- case 'I':
- printk(KERN_INFO "GPIO%d: input\n", pin);
- retval = vr41xx_gpio_set_direction(pin, GPIO_INPUT);
- break;
- case 'O':
- printk(KERN_INFO "GPIO%d: output\n", pin);
- retval = vr41xx_gpio_set_direction(pin, GPIO_OUTPUT);
- break;
- case 'o':
- printk(KERN_INFO "GPIO%d: output disable\n", pin);
- retval = vr41xx_gpio_set_direction(pin, GPIO_OUTPUT_DISABLE);
- break;
- case 'P':
- printk(KERN_INFO "GPIO%d: pull up\n", pin);
- retval = vr41xx_gpio_pullupdown(pin, GPIO_PULL_UP);
- break;
- case 'p':
- printk(KERN_INFO "GPIO%d: pull up/down disable\n", pin);
- retval = vr41xx_gpio_pullupdown(pin, GPIO_PULL_DISABLE);
- break;
- default:
- break;
- }
-
- if (retval < 0)
- break;
- }
-
- return i;
-}
-
-static int gpio_open(struct inode *inode, struct file *file)
-{
- unsigned int pin;
-
- cycle_kernel_lock();
- pin = iminor(inode);
- if (pin >= giu_nr_pins)
- return -EBADF;
-
- return nonseekable_open(inode, file);
-}
-
-static int gpio_release(struct inode *inode, struct file *file)
-{
- unsigned int pin;
-
- pin = iminor(inode);
- if (pin >= giu_nr_pins)
- return -EBADF;
-
- return 0;
-}
-
-static const struct file_operations gpio_fops = {
- .owner = THIS_MODULE,
- .read = gpio_read,
- .write = gpio_write,
- .open = gpio_open,
- .release = gpio_release,
-};
-
-static int __devinit giu_probe(struct platform_device *dev)
-{
- struct resource *res;
- unsigned int trigger, i, pin;
- struct irq_chip *chip;
- int irq, retval;
-
- switch (dev->id) {
- case GPIO_50PINS_PULLUPDOWN:
- giu_flags = GPIO_HAS_PULLUPDOWN_IO;
- giu_nr_pins = 50;
- break;
- case GPIO_36PINS:
- giu_nr_pins = 36;
- break;
- case GPIO_48PINS_EDGE_SELECT:
- giu_flags = GPIO_HAS_INTERRUPT_EDGE_SELECT;
- giu_nr_pins = 48;
- break;
- default:
- printk(KERN_ERR "GIU: unknown ID %d\n", dev->id);
- return -ENODEV;
- }
-
- res = platform_get_resource(dev, IORESOURCE_MEM, 0);
- if (!res)
- return -EBUSY;
-
- giu_base = ioremap(res->start, res->end - res->start + 1);
- if (!giu_base)
- return -ENOMEM;
-
- retval = register_chrdev(major, "GIU", &gpio_fops);
- if (retval < 0) {
- iounmap(giu_base);
- giu_base = NULL;
- return retval;
- }
-
- if (major == 0) {
- major = retval;
- printk(KERN_INFO "GIU: major number %d\n", major);
- }
-
- spin_lock_init(&giu_lock);
-
- giu_write(GIUINTENL, 0);
- giu_write(GIUINTENH, 0);
-
- trigger = giu_read(GIUINTTYPH) << 16;
- trigger |= giu_read(GIUINTTYPL);
- for (i = GIU_IRQ_BASE; i <= GIU_IRQ_LAST; i++) {
- pin = GPIO_PIN_OF_IRQ(i);
- if (pin < GIUINT_HIGH_OFFSET)
- chip = &giuint_low_irq_chip;
- else
- chip = &giuint_high_irq_chip;
-
- if (trigger & (1 << pin))
- set_irq_chip_and_handler(i, chip, handle_edge_irq);
- else
- set_irq_chip_and_handler(i, chip, handle_level_irq);
-
- }
-
- irq = platform_get_irq(dev, 0);
- if (irq < 0 || irq >= nr_irqs)
- return -EBUSY;
-
- return cascade_irq(irq, giu_get_irq);
-}
-
-static int __devexit giu_remove(struct platform_device *dev)
-{
- if (giu_base) {
- iounmap(giu_base);
- giu_base = NULL;
- }
-
- return 0;
-}
-
-static struct platform_driver giu_device_driver = {
- .probe = giu_probe,
- .remove = __devexit_p(giu_remove),
- .driver = {
- .name = "GIU",
- .owner = THIS_MODULE,
- },
-};
-
-static int __init vr41xx_giu_init(void)
-{
- return platform_driver_register(&giu_device_driver);
-}
-
-static void __exit vr41xx_giu_exit(void)
-{
- platform_driver_unregister(&giu_device_driver);
-}
-
-module_init(vr41xx_giu_init);
-module_exit(vr41xx_giu_exit);
diff --git a/drivers/char/vt.c b/drivers/char/vt.c
index d9113b4c76e..404f4c1ee43 100644
--- a/drivers/char/vt.c
+++ b/drivers/char/vt.c
@@ -89,6 +89,7 @@
#include <linux/mutex.h>
#include <linux/vt_kern.h>
#include <linux/selection.h>
+#include <linux/smp_lock.h>
#include <linux/tiocl.h>
#include <linux/kbd_kern.h>
#include <linux/consolemap.h>
@@ -769,14 +770,12 @@ int vc_allocate(unsigned int currcons) /* return 0 on success */
visual_init(vc, currcons, 1);
if (!*vc->vc_uni_pagedir_loc)
con_set_default_unimap(vc);
- if (!vc->vc_kmalloced)
- vc->vc_screenbuf = kmalloc(vc->vc_screenbuf_size, GFP_KERNEL);
+ vc->vc_screenbuf = kmalloc(vc->vc_screenbuf_size, GFP_KERNEL);
if (!vc->vc_screenbuf) {
kfree(vc);
vc_cons[currcons].d = NULL;
return -ENOMEM;
}
- vc->vc_kmalloced = 1;
vc_init(vc, vc->vc_rows, vc->vc_cols, 1);
vcs_make_sysfs(currcons);
atomic_notifier_call_chain(&vt_notifier_list, VT_ALLOCATE, &param);
@@ -912,10 +911,8 @@ static int vc_do_resize(struct tty_struct *tty, struct vc_data *vc,
if (new_scr_end > new_origin)
scr_memsetw((void *)new_origin, vc->vc_video_erase_char,
new_scr_end - new_origin);
- if (vc->vc_kmalloced)
- kfree(vc->vc_screenbuf);
+ kfree(vc->vc_screenbuf);
vc->vc_screenbuf = newscreen;
- vc->vc_kmalloced = 1;
vc->vc_screenbuf_size = new_screen_size;
set_origin(vc);
@@ -994,8 +991,7 @@ void vc_deallocate(unsigned int currcons)
vc->vc_sw->con_deinit(vc);
put_pid(vc->vt_pid);
module_put(vc->vc_sw->owner);
- if (vc->vc_kmalloced)
- kfree(vc->vc_screenbuf);
+ kfree(vc->vc_screenbuf);
if (currcons >= MIN_NR_CONSOLES)
kfree(vc);
vc_cons[currcons].d = NULL;
@@ -2880,7 +2876,6 @@ static int __init con_init(void)
INIT_WORK(&vc_cons[currcons].SAK_work, vc_SAK);
visual_init(vc, currcons, 1);
vc->vc_screenbuf = kzalloc(vc->vc_screenbuf_size, GFP_NOWAIT);
- vc->vc_kmalloced = 0;
vc_init(vc, vc->vc_rows, vc->vc_cols,
currcons || !vc->vc_sw->con_save_screen);
}
diff --git a/drivers/char/vt_ioctl.c b/drivers/char/vt_ioctl.c
index e6ce632a393..95189f288f8 100644
--- a/drivers/char/vt_ioctl.c
+++ b/drivers/char/vt_ioctl.c
@@ -25,6 +25,7 @@
#include <linux/console.h>
#include <linux/consolemap.h>
#include <linux/signal.h>
+#include <linux/smp_lock.h>
#include <linux/timex.h>
#include <asm/io.h>
@@ -396,7 +397,8 @@ int vt_ioctl(struct tty_struct *tty, struct file * file,
kbd = kbd_table + console;
switch (cmd) {
case TIOCLINUX:
- return tioclinux(tty, arg);
+ ret = tioclinux(tty, arg);
+ break;
case KIOCSOUND:
if (!perm)
goto eperm;